2012-10-26 01:23:06 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Copyright ( C ) 1999 - 2005 Id Software , Inc .
This file is part of Quake III Arena source code .
Quake III Arena source code is free software ; you can redistribute it
and / or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation ; either version 2 of the License ,
or ( at your option ) any later version .
Quake III Arena source code is distributed in the hope that it will be
useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Quake III Arena source code ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
// tr_main.c -- main control flow for each frame
# include "tr_local.h"
# include <string.h> // memcpy
trGlobals_t tr ;
static float s_flipMatrix [ 16 ] = {
// convert from our coordinate system (looking down X)
// to OpenGL's coordinate system (looking down -Z)
0 , 0 , - 1 , 0 ,
- 1 , 0 , 0 , 0 ,
0 , 1 , 0 , 0 ,
0 , 0 , 0 , 1
} ;
refimport_t ri ;
// entities that will have procedurally generated surfaces will just
// point at this for their sorting surface
surfaceType_t entitySurface = SF_ENTITY ;
/*
= = = = = = = = = = = = = = = =
R_CompareVert
= = = = = = = = = = = = = = = =
*/
qboolean R_CompareVert ( srfVert_t * v1 , srfVert_t * v2 , qboolean checkST )
{
int i ;
for ( i = 0 ; i < 3 ; i + + )
{
if ( floor ( v1 - > xyz [ i ] + 0.1 ) ! = floor ( v2 - > xyz [ i ] + 0.1 ) )
{
return qfalse ;
}
if ( checkST & & ( ( v1 - > st [ 0 ] ! = v2 - > st [ 0 ] ) | | ( v1 - > st [ 1 ] ! = v2 - > st [ 1 ] ) ) )
{
return qfalse ;
}
}
return qtrue ;
}
/*
= = = = = = = = = = = = =
R_CalcNormalForTriangle
= = = = = = = = = = = = =
*/
void R_CalcNormalForTriangle ( vec3_t normal , const vec3_t v0 , const vec3_t v1 , const vec3_t v2 )
{
vec3_t udir , vdir ;
// compute the face normal based on vertex points
VectorSubtract ( v2 , v0 , udir ) ;
VectorSubtract ( v1 , v0 , vdir ) ;
CrossProduct ( udir , vdir , normal ) ;
VectorNormalize ( normal ) ;
}
/*
= = = = = = = = = = = = =
R_CalcTangentsForTriangle
http : //members.rogers.com/deseric/tangentspace.htm
= = = = = = = = = = = = =
*/
void R_CalcTangentsForTriangle ( vec3_t tangent , vec3_t bitangent ,
const vec3_t v0 , const vec3_t v1 , const vec3_t v2 ,
const vec2_t t0 , const vec2_t t1 , const vec2_t t2 )
{
int i ;
vec3_t planes [ 3 ] ;
vec3_t u , v ;
for ( i = 0 ; i < 3 ; i + + )
{
VectorSet ( u , v1 [ i ] - v0 [ i ] , t1 [ 0 ] - t0 [ 0 ] , t1 [ 1 ] - t0 [ 1 ] ) ;
VectorSet ( v , v2 [ i ] - v0 [ i ] , t2 [ 0 ] - t0 [ 0 ] , t2 [ 1 ] - t0 [ 1 ] ) ;
VectorNormalize ( u ) ;
VectorNormalize ( v ) ;
CrossProduct ( u , v , planes [ i ] ) ;
}
//So your tangent space will be defined by this :
//Normal = Normal of the triangle or Tangent X Bitangent (careful with the cross product,
// you have to make sure the normal points in the right direction)
//Tangent = ( dp(Fx(s,t)) / ds, dp(Fy(s,t)) / ds, dp(Fz(s,t)) / ds ) or ( -Bx/Ax, -By/Ay, - Bz/Az )
//Bitangent = ( dp(Fx(s,t)) / dt, dp(Fy(s,t)) / dt, dp(Fz(s,t)) / dt ) or ( -Cx/Ax, -Cy/Ay, -Cz/Az )
// tangent...
tangent [ 0 ] = - planes [ 0 ] [ 1 ] / planes [ 0 ] [ 0 ] ;
tangent [ 1 ] = - planes [ 1 ] [ 1 ] / planes [ 1 ] [ 0 ] ;
tangent [ 2 ] = - planes [ 2 ] [ 1 ] / planes [ 2 ] [ 0 ] ;
VectorNormalize ( tangent ) ;
// bitangent...
bitangent [ 0 ] = - planes [ 0 ] [ 2 ] / planes [ 0 ] [ 0 ] ;
bitangent [ 1 ] = - planes [ 1 ] [ 2 ] / planes [ 1 ] [ 0 ] ;
bitangent [ 2 ] = - planes [ 2 ] [ 2 ] / planes [ 2 ] [ 0 ] ;
VectorNormalize ( bitangent ) ;
}
/*
= = = = = = = = = = = = =
R_CalcTangentSpace
= = = = = = = = = = = = =
*/
void R_CalcTangentSpace ( vec3_t tangent , vec3_t bitangent , vec3_t normal ,
const vec3_t v0 , const vec3_t v1 , const vec3_t v2 , const vec2_t t0 , const vec2_t t1 , const vec2_t t2 )
{
vec3_t cp , u , v ;
vec3_t faceNormal ;
VectorSet ( u , v1 [ 0 ] - v0 [ 0 ] , t1 [ 0 ] - t0 [ 0 ] , t1 [ 1 ] - t0 [ 1 ] ) ;
VectorSet ( v , v2 [ 0 ] - v0 [ 0 ] , t2 [ 0 ] - t0 [ 0 ] , t2 [ 1 ] - t0 [ 1 ] ) ;
CrossProduct ( u , v , cp ) ;
if ( fabs ( cp [ 0 ] ) > 10e-6 )
{
tangent [ 0 ] = - cp [ 1 ] / cp [ 0 ] ;
bitangent [ 0 ] = - cp [ 2 ] / cp [ 0 ] ;
}
u [ 0 ] = v1 [ 1 ] - v0 [ 1 ] ;
v [ 0 ] = v2 [ 1 ] - v0 [ 1 ] ;
CrossProduct ( u , v , cp ) ;
if ( fabs ( cp [ 0 ] ) > 10e-6 )
{
tangent [ 1 ] = - cp [ 1 ] / cp [ 0 ] ;
bitangent [ 1 ] = - cp [ 2 ] / cp [ 0 ] ;
}
u [ 0 ] = v1 [ 2 ] - v0 [ 2 ] ;
v [ 0 ] = v2 [ 2 ] - v0 [ 2 ] ;
CrossProduct ( u , v , cp ) ;
if ( fabs ( cp [ 0 ] ) > 10e-6 )
{
tangent [ 2 ] = - cp [ 1 ] / cp [ 0 ] ;
bitangent [ 2 ] = - cp [ 2 ] / cp [ 0 ] ;
}
VectorNormalize ( tangent ) ;
VectorNormalize ( bitangent ) ;
// compute the face normal based on vertex points
if ( normal [ 0 ] = = 0.0f & & normal [ 1 ] = = 0.0f & & normal [ 2 ] = = 0.0f )
{
VectorSubtract ( v2 , v0 , u ) ;
VectorSubtract ( v1 , v0 , v ) ;
CrossProduct ( u , v , faceNormal ) ;
}
else
{
VectorCopy ( normal , faceNormal ) ;
}
VectorNormalize ( faceNormal ) ;
# if 1
// Gram-Schmidt orthogonalize
//tangent[a] = (t - n * Dot(n, t)).Normalize();
VectorMA ( tangent , - DotProduct ( faceNormal , tangent ) , faceNormal , tangent ) ;
VectorNormalize ( tangent ) ;
// compute the cross product B=NxT
//CrossProduct(normal, tangent, bitangent);
# else
// normal, compute the cross product N=TxB
CrossProduct ( tangent , bitangent , normal ) ;
VectorNormalize ( normal ) ;
if ( DotProduct ( normal , faceNormal ) < 0 )
{
//VectorInverse(normal);
//VectorInverse(tangent);
//VectorInverse(bitangent);
// compute the cross product T=BxN
CrossProduct ( bitangent , faceNormal , tangent ) ;
// compute the cross product B=NxT
//CrossProduct(normal, tangent, bitangent);
}
# endif
VectorCopy ( faceNormal , normal ) ;
}
void R_CalcTangentSpaceFast ( vec3_t tangent , vec3_t bitangent , vec3_t normal ,
const vec3_t v0 , const vec3_t v1 , const vec3_t v2 , const vec2_t t0 , const vec2_t t1 , const vec2_t t2 )
{
vec3_t cp , u , v ;
vec3_t faceNormal ;
VectorSet ( u , v1 [ 0 ] - v0 [ 0 ] , t1 [ 0 ] - t0 [ 0 ] , t1 [ 1 ] - t0 [ 1 ] ) ;
VectorSet ( v , v2 [ 0 ] - v0 [ 0 ] , t2 [ 0 ] - t0 [ 0 ] , t2 [ 1 ] - t0 [ 1 ] ) ;
CrossProduct ( u , v , cp ) ;
if ( fabs ( cp [ 0 ] ) > 10e-6 )
{
tangent [ 0 ] = - cp [ 1 ] / cp [ 0 ] ;
bitangent [ 0 ] = - cp [ 2 ] / cp [ 0 ] ;
}
u [ 0 ] = v1 [ 1 ] - v0 [ 1 ] ;
v [ 0 ] = v2 [ 1 ] - v0 [ 1 ] ;
CrossProduct ( u , v , cp ) ;
if ( fabs ( cp [ 0 ] ) > 10e-6 )
{
tangent [ 1 ] = - cp [ 1 ] / cp [ 0 ] ;
bitangent [ 1 ] = - cp [ 2 ] / cp [ 0 ] ;
}
u [ 0 ] = v1 [ 2 ] - v0 [ 2 ] ;
v [ 0 ] = v2 [ 2 ] - v0 [ 2 ] ;
CrossProduct ( u , v , cp ) ;
if ( fabs ( cp [ 0 ] ) > 10e-6 )
{
tangent [ 2 ] = - cp [ 1 ] / cp [ 0 ] ;
bitangent [ 2 ] = - cp [ 2 ] / cp [ 0 ] ;
}
VectorNormalizeFast ( tangent ) ;
VectorNormalizeFast ( bitangent ) ;
// compute the face normal based on vertex points
VectorSubtract ( v2 , v0 , u ) ;
VectorSubtract ( v1 , v0 , v ) ;
CrossProduct ( u , v , faceNormal ) ;
VectorNormalizeFast ( faceNormal ) ;
#if 0
// normal, compute the cross product N=TxB
CrossProduct ( tangent , bitangent , normal ) ;
VectorNormalizeFast ( normal ) ;
if ( DotProduct ( normal , faceNormal ) < 0 )
{
VectorInverse ( normal ) ;
//VectorInverse(tangent);
//VectorInverse(bitangent);
CrossProduct ( normal , tangent , bitangent ) ;
}
VectorCopy ( faceNormal , normal ) ;
# else
// Gram-Schmidt orthogonalize
//tangent[a] = (t - n * Dot(n, t)).Normalize();
VectorMA ( tangent , - DotProduct ( faceNormal , tangent ) , faceNormal , tangent ) ;
VectorNormalizeFast ( tangent ) ;
# endif
VectorCopy ( faceNormal , normal ) ;
}
/*
http : //www.terathon.com/code/tangent.html
*/
void R_CalcTBN ( vec3_t tangent , vec3_t bitangent , vec3_t normal ,
const vec3_t v1 , const vec3_t v2 , const vec3_t v3 , const vec2_t w1 , const vec2_t w2 , const vec2_t w3 )
{
vec3_t u , v ;
float x1 , x2 , y1 , y2 , z1 , z2 ;
float s1 , s2 , t1 , t2 ;
float r , dot ;
x1 = v2 [ 0 ] - v1 [ 0 ] ;
x2 = v3 [ 0 ] - v1 [ 0 ] ;
y1 = v2 [ 1 ] - v1 [ 1 ] ;
y2 = v3 [ 1 ] - v1 [ 1 ] ;
z1 = v2 [ 2 ] - v1 [ 2 ] ;
z2 = v3 [ 2 ] - v1 [ 2 ] ;
s1 = w2 [ 0 ] - w1 [ 0 ] ;
s2 = w3 [ 0 ] - w1 [ 0 ] ;
t1 = w2 [ 1 ] - w1 [ 1 ] ;
t2 = w3 [ 1 ] - w1 [ 1 ] ;
r = 1.0f / ( s1 * t2 - s2 * t1 ) ;
VectorSet ( tangent , ( t2 * x1 - t1 * x2 ) * r , ( t2 * y1 - t1 * y2 ) * r , ( t2 * z1 - t1 * z2 ) * r ) ;
VectorSet ( bitangent , ( s1 * x2 - s2 * x1 ) * r , ( s1 * y2 - s2 * y1 ) * r , ( s1 * z2 - s2 * z1 ) * r ) ;
// compute the face normal based on vertex points
VectorSubtract ( v3 , v1 , u ) ;
VectorSubtract ( v2 , v1 , v ) ;
CrossProduct ( u , v , normal ) ;
VectorNormalize ( normal ) ;
// Gram-Schmidt orthogonalize
//tangent[a] = (t - n * Dot(n, t)).Normalize();
dot = DotProduct ( normal , tangent ) ;
VectorMA ( tangent , - dot , normal , tangent ) ;
VectorNormalize ( tangent ) ;
// B=NxT
//CrossProduct(normal, tangent, bitangent);
}
void R_CalcTBN2 ( vec3_t tangent , vec3_t bitangent , vec3_t normal ,
const vec3_t v1 , const vec3_t v2 , const vec3_t v3 , const vec2_t t1 , const vec2_t t2 , const vec2_t t3 )
{
vec3_t v2v1 ;
vec3_t v3v1 ;
float c2c1_T ;
float c2c1_B ;
float c3c1_T ;
float c3c1_B ;
float denominator ;
float scale1 , scale2 ;
vec3_t T , B , N , C ;
// Calculate the tangent basis for each vertex of the triangle
// UPDATE: In the 3rd edition of the accompanying article, the for-loop located here has
// been removed as it was redundant (the entire TBN matrix was calculated three times
// instead of just one).
//
// Please note, that this function relies on the fact that the input geometry are triangles
// and the tangent basis for each vertex thus is identical!
//
// Calculate the vectors from the current vertex to the two other vertices in the triangle
VectorSubtract ( v2 , v1 , v2v1 ) ;
VectorSubtract ( v3 , v1 , v3v1 ) ;
// The equation presented in the article states that:
2012-10-30 03:00:46 +00:00
// c2c1_T = V2.texcoord.x - V1.texcoord.x
// c2c1_B = V2.texcoord.y - V1.texcoord.y
// c3c1_T = V3.texcoord.x - V1.texcoord.x
// c3c1_B = V3.texcoord.y - V1.texcoord.y
2012-10-26 01:23:06 +00:00
// Calculate c2c1_T and c2c1_B
c2c1_T = t2 [ 0 ] - t1 [ 0 ] ;
c2c1_B = t2 [ 1 ] - t2 [ 1 ] ;
// Calculate c3c1_T and c3c1_B
c3c1_T = t3 [ 0 ] - t1 [ 0 ] ;
c3c1_B = t3 [ 1 ] - t1 [ 1 ] ;
denominator = c2c1_T * c3c1_B - c3c1_T * c2c1_B ;
//if(ROUNDOFF(fDenominator) == 0.0f)
if ( denominator = = 0.0f )
{
// We won't risk a divide by zero, so set the tangent matrix to the identity matrix
VectorSet ( tangent , 1 , 0 , 0 ) ;
VectorSet ( bitangent , 0 , 1 , 0 ) ;
VectorSet ( normal , 0 , 0 , 1 ) ;
}
else
{
// Calculate the reciprocal value once and for all (to achieve speed)
scale1 = 1.0f / denominator ;
// T and B are calculated just as the equation in the article states
VectorSet ( T , ( c3c1_B * v2v1 [ 0 ] - c2c1_B * v3v1 [ 0 ] ) * scale1 ,
( c3c1_B * v2v1 [ 1 ] - c2c1_B * v3v1 [ 1 ] ) * scale1 ,
( c3c1_B * v2v1 [ 2 ] - c2c1_B * v3v1 [ 2 ] ) * scale1 ) ;
VectorSet ( B , ( - c3c1_T * v2v1 [ 0 ] + c2c1_T * v3v1 [ 0 ] ) * scale1 ,
( - c3c1_T * v2v1 [ 1 ] + c2c1_T * v3v1 [ 1 ] ) * scale1 ,
( - c3c1_T * v2v1 [ 2 ] + c2c1_T * v3v1 [ 2 ] ) * scale1 ) ;
// The normal N is calculated as the cross product between T and B
CrossProduct ( T , B , N ) ;
#if 0
VectorCopy ( T , tangent ) ;
VectorCopy ( B , bitangent ) ;
VectorCopy ( N , normal ) ;
# else
// Calculate the reciprocal value once and for all (to achieve speed)
scale2 = 1.0f / ( ( T [ 0 ] * B [ 1 ] * N [ 2 ] - T [ 2 ] * B [ 1 ] * N [ 0 ] ) +
( B [ 0 ] * N [ 1 ] * T [ 2 ] - B [ 2 ] * N [ 1 ] * T [ 0 ] ) +
( N [ 0 ] * T [ 1 ] * B [ 2 ] - N [ 2 ] * T [ 1 ] * B [ 0 ] ) ) ;
// Calculate the inverse if the TBN matrix using the formula described in the article.
// We store the basis vectors directly in the provided TBN matrix: pvTBNMatrix
CrossProduct ( B , N , C ) ; tangent [ 0 ] = C [ 0 ] * scale2 ;
CrossProduct ( N , T , C ) ; tangent [ 1 ] = - C [ 0 ] * scale2 ;
CrossProduct ( T , B , C ) ; tangent [ 2 ] = C [ 0 ] * scale2 ;
VectorNormalize ( tangent ) ;
CrossProduct ( B , N , C ) ; bitangent [ 0 ] = - C [ 1 ] * scale2 ;
CrossProduct ( N , T , C ) ; bitangent [ 1 ] = C [ 1 ] * scale2 ;
CrossProduct ( T , B , C ) ; bitangent [ 2 ] = - C [ 1 ] * scale2 ;
VectorNormalize ( bitangent ) ;
CrossProduct ( B , N , C ) ; normal [ 0 ] = C [ 2 ] * scale2 ;
CrossProduct ( N , T , C ) ; normal [ 1 ] = - C [ 2 ] * scale2 ;
CrossProduct ( T , B , C ) ; normal [ 2 ] = C [ 2 ] * scale2 ;
VectorNormalize ( normal ) ;
# endif
}
}
# ifdef USE_VERT_TANGENT_SPACE
qboolean R_CalcTangentVectors ( srfVert_t * dv [ 3 ] )
{
int i ;
float bb , s , t ;
vec3_t bary ;
/* calculate barycentric basis for the triangle */
bb = ( dv [ 1 ] - > st [ 0 ] - dv [ 0 ] - > st [ 0 ] ) * ( dv [ 2 ] - > st [ 1 ] - dv [ 0 ] - > st [ 1 ] ) - ( dv [ 2 ] - > st [ 0 ] - dv [ 0 ] - > st [ 0 ] ) * ( dv [ 1 ] - > st [ 1 ] - dv [ 0 ] - > st [ 1 ] ) ;
if ( fabs ( bb ) < 0.00000001f )
return qfalse ;
/* do each vertex */
for ( i = 0 ; i < 3 ; i + + )
{
// calculate s tangent vector
s = dv [ i ] - > st [ 0 ] + 10.0f ;
t = dv [ i ] - > st [ 1 ] ;
bary [ 0 ] = ( ( dv [ 1 ] - > st [ 0 ] - s ) * ( dv [ 2 ] - > st [ 1 ] - t ) - ( dv [ 2 ] - > st [ 0 ] - s ) * ( dv [ 1 ] - > st [ 1 ] - t ) ) / bb ;
bary [ 1 ] = ( ( dv [ 2 ] - > st [ 0 ] - s ) * ( dv [ 0 ] - > st [ 1 ] - t ) - ( dv [ 0 ] - > st [ 0 ] - s ) * ( dv [ 2 ] - > st [ 1 ] - t ) ) / bb ;
bary [ 2 ] = ( ( dv [ 0 ] - > st [ 0 ] - s ) * ( dv [ 1 ] - > st [ 1 ] - t ) - ( dv [ 1 ] - > st [ 0 ] - s ) * ( dv [ 0 ] - > st [ 1 ] - t ) ) / bb ;
dv [ i ] - > tangent [ 0 ] = bary [ 0 ] * dv [ 0 ] - > xyz [ 0 ] + bary [ 1 ] * dv [ 1 ] - > xyz [ 0 ] + bary [ 2 ] * dv [ 2 ] - > xyz [ 0 ] ;
dv [ i ] - > tangent [ 1 ] = bary [ 0 ] * dv [ 0 ] - > xyz [ 1 ] + bary [ 1 ] * dv [ 1 ] - > xyz [ 1 ] + bary [ 2 ] * dv [ 2 ] - > xyz [ 1 ] ;
dv [ i ] - > tangent [ 2 ] = bary [ 0 ] * dv [ 0 ] - > xyz [ 2 ] + bary [ 1 ] * dv [ 1 ] - > xyz [ 2 ] + bary [ 2 ] * dv [ 2 ] - > xyz [ 2 ] ;
VectorSubtract ( dv [ i ] - > tangent , dv [ i ] - > xyz , dv [ i ] - > tangent ) ;
VectorNormalize ( dv [ i ] - > tangent ) ;
// calculate t tangent vector
s = dv [ i ] - > st [ 0 ] ;
t = dv [ i ] - > st [ 1 ] + 10.0f ;
bary [ 0 ] = ( ( dv [ 1 ] - > st [ 0 ] - s ) * ( dv [ 2 ] - > st [ 1 ] - t ) - ( dv [ 2 ] - > st [ 0 ] - s ) * ( dv [ 1 ] - > st [ 1 ] - t ) ) / bb ;
bary [ 1 ] = ( ( dv [ 2 ] - > st [ 0 ] - s ) * ( dv [ 0 ] - > st [ 1 ] - t ) - ( dv [ 0 ] - > st [ 0 ] - s ) * ( dv [ 2 ] - > st [ 1 ] - t ) ) / bb ;
bary [ 2 ] = ( ( dv [ 0 ] - > st [ 0 ] - s ) * ( dv [ 1 ] - > st [ 1 ] - t ) - ( dv [ 1 ] - > st [ 0 ] - s ) * ( dv [ 0 ] - > st [ 1 ] - t ) ) / bb ;
dv [ i ] - > bitangent [ 0 ] = bary [ 0 ] * dv [ 0 ] - > xyz [ 0 ] + bary [ 1 ] * dv [ 1 ] - > xyz [ 0 ] + bary [ 2 ] * dv [ 2 ] - > xyz [ 0 ] ;
dv [ i ] - > bitangent [ 1 ] = bary [ 0 ] * dv [ 0 ] - > xyz [ 1 ] + bary [ 1 ] * dv [ 1 ] - > xyz [ 1 ] + bary [ 2 ] * dv [ 2 ] - > xyz [ 1 ] ;
dv [ i ] - > bitangent [ 2 ] = bary [ 0 ] * dv [ 0 ] - > xyz [ 2 ] + bary [ 1 ] * dv [ 1 ] - > xyz [ 2 ] + bary [ 2 ] * dv [ 2 ] - > xyz [ 2 ] ;
VectorSubtract ( dv [ i ] - > bitangent , dv [ i ] - > xyz , dv [ i ] - > bitangent ) ;
VectorNormalize ( dv [ i ] - > bitangent ) ;
// debug code
//% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,
//% stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] );
}
return qtrue ;
}
# endif
/*
= = = = = = = = = = = = = = = = =
R_CullLocalBox
Returns CULL_IN , CULL_CLIP , or CULL_OUT
= = = = = = = = = = = = = = = = =
*/
int R_CullLocalBox ( vec3_t localBounds [ 2 ] ) {
#if 0
int i , j ;
vec3_t transformed [ 8 ] ;
float dists [ 8 ] ;
vec3_t v ;
cplane_t * frust ;
int anyBack ;
int front , back ;
if ( r_nocull - > integer ) {
return CULL_CLIP ;
}
// transform into world space
for ( i = 0 ; i < 8 ; i + + ) {
v [ 0 ] = bounds [ i & 1 ] [ 0 ] ;
v [ 1 ] = bounds [ ( i > > 1 ) & 1 ] [ 1 ] ;
v [ 2 ] = bounds [ ( i > > 2 ) & 1 ] [ 2 ] ;
VectorCopy ( tr . or . origin , transformed [ i ] ) ;
VectorMA ( transformed [ i ] , v [ 0 ] , tr . or . axis [ 0 ] , transformed [ i ] ) ;
VectorMA ( transformed [ i ] , v [ 1 ] , tr . or . axis [ 1 ] , transformed [ i ] ) ;
VectorMA ( transformed [ i ] , v [ 2 ] , tr . or . axis [ 2 ] , transformed [ i ] ) ;
}
// check against frustum planes
anyBack = 0 ;
for ( i = 0 ; i < 4 ; i + + ) {
frust = & tr . viewParms . frustum [ i ] ;
front = back = 0 ;
for ( j = 0 ; j < 8 ; j + + ) {
dists [ j ] = DotProduct ( transformed [ j ] , frust - > normal ) ;
if ( dists [ j ] > frust - > dist ) {
front = 1 ;
if ( back ) {
break ; // a point is in front
}
} else {
back = 1 ;
}
}
if ( ! front ) {
// all points were behind one of the planes
return CULL_OUT ;
}
anyBack | = back ;
}
if ( ! anyBack ) {
return CULL_IN ; // completely inside frustum
}
return CULL_CLIP ; // partially clipped
# else
int j ;
vec3_t transformed ;
vec3_t v ;
vec3_t worldBounds [ 2 ] ;
if ( r_nocull - > integer )
{
return CULL_CLIP ;
}
// transform into world space
ClearBounds ( worldBounds [ 0 ] , worldBounds [ 1 ] ) ;
for ( j = 0 ; j < 8 ; j + + )
{
v [ 0 ] = localBounds [ j & 1 ] [ 0 ] ;
v [ 1 ] = localBounds [ ( j > > 1 ) & 1 ] [ 1 ] ;
v [ 2 ] = localBounds [ ( j > > 2 ) & 1 ] [ 2 ] ;
R_LocalPointToWorld ( v , transformed ) ;
AddPointToBounds ( transformed , worldBounds [ 0 ] , worldBounds [ 1 ] ) ;
}
return R_CullBox ( worldBounds ) ;
# endif
}
/*
= = = = = = = = = = = = = = = = =
R_CullBox
Returns CULL_IN , CULL_CLIP , or CULL_OUT
= = = = = = = = = = = = = = = = =
*/
int R_CullBox ( vec3_t worldBounds [ 2 ] ) {
int i ;
cplane_t * frust ;
qboolean anyClip ;
2013-01-10 02:30:12 +00:00
int r , numPlanes ;
numPlanes = ( tr . viewParms . flags & VPF_FARPLANEFRUSTUM ) ? 5 : 4 ;
2012-10-26 01:23:06 +00:00
// check against frustum planes
anyClip = qfalse ;
2013-01-10 02:30:12 +00:00
for ( i = 0 ; i < numPlanes ; i + + )
2012-10-26 01:23:06 +00:00
{
frust = & tr . viewParms . frustum [ i ] ;
r = BoxOnPlaneSide ( worldBounds [ 0 ] , worldBounds [ 1 ] , frust ) ;
if ( r = = 2 )
{
// completely outside frustum
return CULL_OUT ;
}
if ( r = = 3 )
{
anyClip = qtrue ;
}
}
if ( ! anyClip )
{
// completely inside frustum
return CULL_IN ;
}
// partially clipped
return CULL_CLIP ;
}
/*
* * R_CullLocalPointAndRadius
*/
int R_CullLocalPointAndRadius ( const vec3_t pt , float radius )
{
vec3_t transformed ;
R_LocalPointToWorld ( pt , transformed ) ;
return R_CullPointAndRadius ( transformed , radius ) ;
}
/*
* * R_CullPointAndRadius
*/
int R_CullPointAndRadiusEx ( const vec3_t pt , float radius , const cplane_t * frustum , int numPlanes )
{
int i ;
float dist ;
const cplane_t * frust ;
qboolean mightBeClipped = qfalse ;
if ( r_nocull - > integer ) {
return CULL_CLIP ;
}
// check against frustum planes
for ( i = 0 ; i < numPlanes ; i + + )
{
frust = & frustum [ i ] ;
dist = DotProduct ( pt , frust - > normal ) - frust - > dist ;
if ( dist < - radius )
{
return CULL_OUT ;
}
else if ( dist < = radius )
{
mightBeClipped = qtrue ;
}
}
if ( mightBeClipped )
{
return CULL_CLIP ;
}
return CULL_IN ; // completely inside frustum
}
/*
* * R_CullPointAndRadius
*/
int R_CullPointAndRadius ( const vec3_t pt , float radius )
{
2013-01-10 02:30:12 +00:00
return R_CullPointAndRadiusEx ( pt , radius , tr . viewParms . frustum , ( tr . viewParms . flags & VPF_FARPLANEFRUSTUM ) ? 5 : 4 ) ;
2012-10-26 01:23:06 +00:00
}
/*
= = = = = = = = = = = = = = = = =
R_LocalNormalToWorld
= = = = = = = = = = = = = = = = =
*/
void R_LocalNormalToWorld ( const vec3_t local , vec3_t world ) {
world [ 0 ] = local [ 0 ] * tr . or . axis [ 0 ] [ 0 ] + local [ 1 ] * tr . or . axis [ 1 ] [ 0 ] + local [ 2 ] * tr . or . axis [ 2 ] [ 0 ] ;
world [ 1 ] = local [ 0 ] * tr . or . axis [ 0 ] [ 1 ] + local [ 1 ] * tr . or . axis [ 1 ] [ 1 ] + local [ 2 ] * tr . or . axis [ 2 ] [ 1 ] ;
world [ 2 ] = local [ 0 ] * tr . or . axis [ 0 ] [ 2 ] + local [ 1 ] * tr . or . axis [ 1 ] [ 2 ] + local [ 2 ] * tr . or . axis [ 2 ] [ 2 ] ;
}
/*
= = = = = = = = = = = = = = = = =
R_LocalPointToWorld
= = = = = = = = = = = = = = = = =
*/
void R_LocalPointToWorld ( const vec3_t local , vec3_t world ) {
world [ 0 ] = local [ 0 ] * tr . or . axis [ 0 ] [ 0 ] + local [ 1 ] * tr . or . axis [ 1 ] [ 0 ] + local [ 2 ] * tr . or . axis [ 2 ] [ 0 ] + tr . or . origin [ 0 ] ;
world [ 1 ] = local [ 0 ] * tr . or . axis [ 0 ] [ 1 ] + local [ 1 ] * tr . or . axis [ 1 ] [ 1 ] + local [ 2 ] * tr . or . axis [ 2 ] [ 1 ] + tr . or . origin [ 1 ] ;
world [ 2 ] = local [ 0 ] * tr . or . axis [ 0 ] [ 2 ] + local [ 1 ] * tr . or . axis [ 1 ] [ 2 ] + local [ 2 ] * tr . or . axis [ 2 ] [ 2 ] + tr . or . origin [ 2 ] ;
}
/*
= = = = = = = = = = = = = = = = =
R_WorldToLocal
= = = = = = = = = = = = = = = = =
*/
void R_WorldToLocal ( const vec3_t world , vec3_t local ) {
local [ 0 ] = DotProduct ( world , tr . or . axis [ 0 ] ) ;
local [ 1 ] = DotProduct ( world , tr . or . axis [ 1 ] ) ;
local [ 2 ] = DotProduct ( world , tr . or . axis [ 2 ] ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = =
R_TransformModelToClip
= = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void R_TransformModelToClip ( const vec3_t src , const float * modelMatrix , const float * projectionMatrix ,
vec4_t eye , vec4_t dst ) {
int i ;
for ( i = 0 ; i < 4 ; i + + ) {
eye [ i ] =
src [ 0 ] * modelMatrix [ i + 0 * 4 ] +
src [ 1 ] * modelMatrix [ i + 1 * 4 ] +
src [ 2 ] * modelMatrix [ i + 2 * 4 ] +
1 * modelMatrix [ i + 3 * 4 ] ;
}
for ( i = 0 ; i < 4 ; i + + ) {
dst [ i ] =
eye [ 0 ] * projectionMatrix [ i + 0 * 4 ] +
eye [ 1 ] * projectionMatrix [ i + 1 * 4 ] +
eye [ 2 ] * projectionMatrix [ i + 2 * 4 ] +
eye [ 3 ] * projectionMatrix [ i + 3 * 4 ] ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = =
R_TransformClipToWindow
= = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void R_TransformClipToWindow ( const vec4_t clip , const viewParms_t * view , vec4_t normalized , vec4_t window ) {
normalized [ 0 ] = clip [ 0 ] / clip [ 3 ] ;
normalized [ 1 ] = clip [ 1 ] / clip [ 3 ] ;
normalized [ 2 ] = ( clip [ 2 ] + clip [ 3 ] ) / ( 2 * clip [ 3 ] ) ;
window [ 0 ] = 0.5f * ( 1.0f + normalized [ 0 ] ) * view - > viewportWidth ;
window [ 1 ] = 0.5f * ( 1.0f + normalized [ 1 ] ) * view - > viewportHeight ;
window [ 2 ] = normalized [ 2 ] ;
window [ 0 ] = ( int ) ( window [ 0 ] + 0.5 ) ;
window [ 1 ] = ( int ) ( window [ 1 ] + 0.5 ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = =
myGlMultMatrix
= = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void myGlMultMatrix ( const float * a , const float * b , float * out ) {
int i , j ;
for ( i = 0 ; i < 4 ; i + + ) {
for ( j = 0 ; j < 4 ; j + + ) {
out [ i * 4 + j ] =
a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
+ a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
+ a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
+ a [ i * 4 + 3 ] * b [ 3 * 4 + j ] ;
}
}
}
/*
= = = = = = = = = = = = = = = = =
R_RotateForEntity
Generates an orientation for an entity and viewParms
Does NOT produce any GL calls
Called by both the front end and the back end
= = = = = = = = = = = = = = = = =
*/
void R_RotateForEntity ( const trRefEntity_t * ent , const viewParms_t * viewParms ,
orientationr_t * or ) {
float glMatrix [ 16 ] ;
vec3_t delta ;
float axisLength ;
if ( ent - > e . reType ! = RT_MODEL ) {
* or = viewParms - > world ;
return ;
}
VectorCopy ( ent - > e . origin , or - > origin ) ;
VectorCopy ( ent - > e . axis [ 0 ] , or - > axis [ 0 ] ) ;
VectorCopy ( ent - > e . axis [ 1 ] , or - > axis [ 1 ] ) ;
VectorCopy ( ent - > e . axis [ 2 ] , or - > axis [ 2 ] ) ;
glMatrix [ 0 ] = or - > axis [ 0 ] [ 0 ] ;
glMatrix [ 4 ] = or - > axis [ 1 ] [ 0 ] ;
glMatrix [ 8 ] = or - > axis [ 2 ] [ 0 ] ;
glMatrix [ 12 ] = or - > origin [ 0 ] ;
glMatrix [ 1 ] = or - > axis [ 0 ] [ 1 ] ;
glMatrix [ 5 ] = or - > axis [ 1 ] [ 1 ] ;
glMatrix [ 9 ] = or - > axis [ 2 ] [ 1 ] ;
glMatrix [ 13 ] = or - > origin [ 1 ] ;
glMatrix [ 2 ] = or - > axis [ 0 ] [ 2 ] ;
glMatrix [ 6 ] = or - > axis [ 1 ] [ 2 ] ;
glMatrix [ 10 ] = or - > axis [ 2 ] [ 2 ] ;
glMatrix [ 14 ] = or - > origin [ 2 ] ;
glMatrix [ 3 ] = 0 ;
glMatrix [ 7 ] = 0 ;
glMatrix [ 11 ] = 0 ;
glMatrix [ 15 ] = 1 ;
Matrix16Copy ( glMatrix , or - > transformMatrix ) ;
myGlMultMatrix ( glMatrix , viewParms - > world . modelMatrix , or - > modelMatrix ) ;
// calculate the viewer origin in the model's space
// needed for fog, specular, and environment mapping
VectorSubtract ( viewParms - > or . origin , or - > origin , delta ) ;
// compensate for scale in the axes if necessary
if ( ent - > e . nonNormalizedAxes ) {
axisLength = VectorLength ( ent - > e . axis [ 0 ] ) ;
if ( ! axisLength ) {
axisLength = 0 ;
} else {
axisLength = 1.0f / axisLength ;
}
} else {
axisLength = 1.0f ;
}
or - > viewOrigin [ 0 ] = DotProduct ( delta , or - > axis [ 0 ] ) * axisLength ;
or - > viewOrigin [ 1 ] = DotProduct ( delta , or - > axis [ 1 ] ) * axisLength ;
or - > viewOrigin [ 2 ] = DotProduct ( delta , or - > axis [ 2 ] ) * axisLength ;
}
/*
= = = = = = = = = = = = = = = = =
R_RotateForViewer
Sets up the modelview matrix for a given viewParm
= = = = = = = = = = = = = = = = =
*/
void R_RotateForViewer ( void )
{
float viewerMatrix [ 16 ] ;
vec3_t origin ;
Com_Memset ( & tr . or , 0 , sizeof ( tr . or ) ) ;
tr . or . axis [ 0 ] [ 0 ] = 1 ;
tr . or . axis [ 1 ] [ 1 ] = 1 ;
tr . or . axis [ 2 ] [ 2 ] = 1 ;
VectorCopy ( tr . viewParms . or . origin , tr . or . viewOrigin ) ;
// transform by the camera placement
VectorCopy ( tr . viewParms . or . origin , origin ) ;
viewerMatrix [ 0 ] = tr . viewParms . or . axis [ 0 ] [ 0 ] ;
viewerMatrix [ 4 ] = tr . viewParms . or . axis [ 0 ] [ 1 ] ;
viewerMatrix [ 8 ] = tr . viewParms . or . axis [ 0 ] [ 2 ] ;
viewerMatrix [ 12 ] = - origin [ 0 ] * viewerMatrix [ 0 ] + - origin [ 1 ] * viewerMatrix [ 4 ] + - origin [ 2 ] * viewerMatrix [ 8 ] ;
viewerMatrix [ 1 ] = tr . viewParms . or . axis [ 1 ] [ 0 ] ;
viewerMatrix [ 5 ] = tr . viewParms . or . axis [ 1 ] [ 1 ] ;
viewerMatrix [ 9 ] = tr . viewParms . or . axis [ 1 ] [ 2 ] ;
viewerMatrix [ 13 ] = - origin [ 0 ] * viewerMatrix [ 1 ] + - origin [ 1 ] * viewerMatrix [ 5 ] + - origin [ 2 ] * viewerMatrix [ 9 ] ;
viewerMatrix [ 2 ] = tr . viewParms . or . axis [ 2 ] [ 0 ] ;
viewerMatrix [ 6 ] = tr . viewParms . or . axis [ 2 ] [ 1 ] ;
viewerMatrix [ 10 ] = tr . viewParms . or . axis [ 2 ] [ 2 ] ;
viewerMatrix [ 14 ] = - origin [ 0 ] * viewerMatrix [ 2 ] + - origin [ 1 ] * viewerMatrix [ 6 ] + - origin [ 2 ] * viewerMatrix [ 10 ] ;
viewerMatrix [ 3 ] = 0 ;
viewerMatrix [ 7 ] = 0 ;
viewerMatrix [ 11 ] = 0 ;
viewerMatrix [ 15 ] = 1 ;
// convert from our coordinate system (looking down X)
// to OpenGL's coordinate system (looking down -Z)
myGlMultMatrix ( viewerMatrix , s_flipMatrix , tr . or . modelMatrix ) ;
tr . viewParms . world = tr . or ;
}
/*
* * SetFarClip
*/
static void R_SetFarClip ( void )
{
float farthestCornerDistance = 0 ;
int i ;
// if not rendering the world (icons, menus, etc)
// set a 2k far clip plane
if ( tr . refdef . rdflags & RDF_NOWORLDMODEL ) {
tr . viewParms . zFar = 2048 ;
return ;
}
//
// set far clipping planes dynamically
//
farthestCornerDistance = 0 ;
for ( i = 0 ; i < 8 ; i + + )
{
vec3_t v ;
vec3_t vecTo ;
float distance ;
if ( i & 1 )
{
v [ 0 ] = tr . viewParms . visBounds [ 0 ] [ 0 ] ;
}
else
{
v [ 0 ] = tr . viewParms . visBounds [ 1 ] [ 0 ] ;
}
if ( i & 2 )
{
v [ 1 ] = tr . viewParms . visBounds [ 0 ] [ 1 ] ;
}
else
{
v [ 1 ] = tr . viewParms . visBounds [ 1 ] [ 1 ] ;
}
if ( i & 4 )
{
v [ 2 ] = tr . viewParms . visBounds [ 0 ] [ 2 ] ;
}
else
{
v [ 2 ] = tr . viewParms . visBounds [ 1 ] [ 2 ] ;
}
VectorSubtract ( v , tr . viewParms . or . origin , vecTo ) ;
distance = vecTo [ 0 ] * vecTo [ 0 ] + vecTo [ 1 ] * vecTo [ 1 ] + vecTo [ 2 ] * vecTo [ 2 ] ;
if ( distance > farthestCornerDistance )
{
farthestCornerDistance = distance ;
}
}
tr . viewParms . zFar = sqrt ( farthestCornerDistance ) ;
}
/*
= = = = = = = = = = = = = = = = =
R_SetupFrustum
Set up the culling frustum planes for the current view using the results we got from computing the first two rows of
the projection matrix .
= = = = = = = = = = = = = = = = =
*/
void R_SetupFrustum ( viewParms_t * dest , float xmin , float xmax , float ymax , float zProj , float zFar , float stereoSep )
{
vec3_t ofsorigin ;
float oppleg , adjleg , length ;
int i ;
if ( stereoSep = = 0 & & xmin = = - xmax )
{
// symmetric case can be simplified
VectorCopy ( dest - > or . origin , ofsorigin ) ;
length = sqrt ( xmax * xmax + zProj * zProj ) ;
oppleg = xmax / length ;
adjleg = zProj / length ;
VectorScale ( dest - > or . axis [ 0 ] , oppleg , dest - > frustum [ 0 ] . normal ) ;
VectorMA ( dest - > frustum [ 0 ] . normal , adjleg , dest - > or . axis [ 1 ] , dest - > frustum [ 0 ] . normal ) ;
VectorScale ( dest - > or . axis [ 0 ] , oppleg , dest - > frustum [ 1 ] . normal ) ;
VectorMA ( dest - > frustum [ 1 ] . normal , - adjleg , dest - > or . axis [ 1 ] , dest - > frustum [ 1 ] . normal ) ;
}
else
{
// In stereo rendering, due to the modification of the projection matrix, dest->or.origin is not the
// actual origin that we're rendering so offset the tip of the view pyramid.
VectorMA ( dest - > or . origin , stereoSep , dest - > or . axis [ 1 ] , ofsorigin ) ;
oppleg = xmax + stereoSep ;
length = sqrt ( oppleg * oppleg + zProj * zProj ) ;
VectorScale ( dest - > or . axis [ 0 ] , oppleg / length , dest - > frustum [ 0 ] . normal ) ;
VectorMA ( dest - > frustum [ 0 ] . normal , zProj / length , dest - > or . axis [ 1 ] , dest - > frustum [ 0 ] . normal ) ;
oppleg = xmin + stereoSep ;
length = sqrt ( oppleg * oppleg + zProj * zProj ) ;
VectorScale ( dest - > or . axis [ 0 ] , - oppleg / length , dest - > frustum [ 1 ] . normal ) ;
VectorMA ( dest - > frustum [ 1 ] . normal , - zProj / length , dest - > or . axis [ 1 ] , dest - > frustum [ 1 ] . normal ) ;
}
length = sqrt ( ymax * ymax + zProj * zProj ) ;
oppleg = ymax / length ;
adjleg = zProj / length ;
VectorScale ( dest - > or . axis [ 0 ] , oppleg , dest - > frustum [ 2 ] . normal ) ;
VectorMA ( dest - > frustum [ 2 ] . normal , adjleg , dest - > or . axis [ 2 ] , dest - > frustum [ 2 ] . normal ) ;
VectorScale ( dest - > or . axis [ 0 ] , oppleg , dest - > frustum [ 3 ] . normal ) ;
VectorMA ( dest - > frustum [ 3 ] . normal , - adjleg , dest - > or . axis [ 2 ] , dest - > frustum [ 3 ] . normal ) ;
for ( i = 0 ; i < 4 ; i + + ) {
dest - > frustum [ i ] . type = PLANE_NON_AXIAL ;
dest - > frustum [ i ] . dist = DotProduct ( ofsorigin , dest - > frustum [ i ] . normal ) ;
SetPlaneSignbits ( & dest - > frustum [ i ] ) ;
}
if ( zFar ! = 0.0f )
{
vec3_t farpoint ;
VectorMA ( ofsorigin , zFar , dest - > or . axis [ 0 ] , farpoint ) ;
VectorScale ( dest - > or . axis [ 0 ] , - 1.0f , dest - > frustum [ 4 ] . normal ) ;
dest - > frustum [ 4 ] . type = PLANE_NON_AXIAL ;
dest - > frustum [ 4 ] . dist = DotProduct ( farpoint , dest - > frustum [ 4 ] . normal ) ;
SetPlaneSignbits ( & dest - > frustum [ 4 ] ) ;
2013-01-10 02:30:12 +00:00
dest - > flags | = VPF_FARPLANEFRUSTUM ;
2012-10-26 01:23:06 +00:00
}
}
/*
= = = = = = = = = = = = = = =
R_SetupProjection
= = = = = = = = = = = = = = =
*/
void R_SetupProjection ( viewParms_t * dest , float zProj , float zFar , qboolean computeFrustum )
{
float xmin , xmax , ymin , ymax ;
float width , height , stereoSep = r_stereoSeparation - > value ;
/*
* offset the view origin of the viewer for stereo rendering
* by setting the projection matrix appropriately .
*/
if ( stereoSep ! = 0 )
{
if ( dest - > stereoFrame = = STEREO_LEFT )
stereoSep = zProj / stereoSep ;
else if ( dest - > stereoFrame = = STEREO_RIGHT )
stereoSep = zProj / - stereoSep ;
else
stereoSep = 0 ;
}
ymax = zProj * tan ( dest - > fovY * M_PI / 360.0f ) ;
ymin = - ymax ;
xmax = zProj * tan ( dest - > fovX * M_PI / 360.0f ) ;
xmin = - xmax ;
width = xmax - xmin ;
height = ymax - ymin ;
dest - > projectionMatrix [ 0 ] = 2 * zProj / width ;
dest - > projectionMatrix [ 4 ] = 0 ;
dest - > projectionMatrix [ 8 ] = ( xmax + xmin + 2 * stereoSep ) / width ;
dest - > projectionMatrix [ 12 ] = 2 * zProj * stereoSep / width ;
dest - > projectionMatrix [ 1 ] = 0 ;
dest - > projectionMatrix [ 5 ] = 2 * zProj / height ;
dest - > projectionMatrix [ 9 ] = ( ymax + ymin ) / height ; // normally 0
dest - > projectionMatrix [ 13 ] = 0 ;
dest - > projectionMatrix [ 3 ] = 0 ;
dest - > projectionMatrix [ 7 ] = 0 ;
dest - > projectionMatrix [ 11 ] = - 1 ;
dest - > projectionMatrix [ 15 ] = 0 ;
// Now that we have all the data for the projection matrix we can also setup the view frustum.
if ( computeFrustum )
R_SetupFrustum ( dest , xmin , xmax , ymax , zProj , zFar , stereoSep ) ;
}
/*
= = = = = = = = = = = = = = =
R_SetupProjectionZ
Sets the z - component transformation part in the projection matrix
= = = = = = = = = = = = = = =
*/
void R_SetupProjectionZ ( viewParms_t * dest )
{
float zNear , zFar , depth ;
zNear = r_znear - > value ;
zFar = dest - > zFar ;
depth = zFar - zNear ;
dest - > projectionMatrix [ 2 ] = 0 ;
dest - > projectionMatrix [ 6 ] = 0 ;
dest - > projectionMatrix [ 10 ] = - ( zFar + zNear ) / depth ;
dest - > projectionMatrix [ 14 ] = - 2 * zFar * zNear / depth ;
if ( dest - > isPortal )
{
float plane [ 4 ] ;
float plane2 [ 4 ] ;
vec4_t q , c ;
// transform portal plane into camera space
plane [ 0 ] = dest - > portalPlane . normal [ 0 ] ;
plane [ 1 ] = dest - > portalPlane . normal [ 1 ] ;
plane [ 2 ] = dest - > portalPlane . normal [ 2 ] ;
plane [ 3 ] = dest - > portalPlane . dist ;
plane2 [ 0 ] = - DotProduct ( dest - > or . axis [ 1 ] , plane ) ;
plane2 [ 1 ] = DotProduct ( dest - > or . axis [ 2 ] , plane ) ;
plane2 [ 2 ] = - DotProduct ( dest - > or . axis [ 0 ] , plane ) ;
plane2 [ 3 ] = DotProduct ( plane , dest - > or . origin ) - plane [ 3 ] ;
2012-10-30 03:00:46 +00:00
// Lengyel, Eric. "Modifying the Projection Matrix to Perform Oblique Near-plane Clipping".
2012-10-26 01:23:06 +00:00
// Terathon Software 3D Graphics Library, 2004. http://www.terathon.com/code/oblique.html
q [ 0 ] = ( SGN ( plane2 [ 0 ] ) + dest - > projectionMatrix [ 8 ] ) / dest - > projectionMatrix [ 0 ] ;
q [ 1 ] = ( SGN ( plane2 [ 1 ] ) + dest - > projectionMatrix [ 9 ] ) / dest - > projectionMatrix [ 5 ] ;
q [ 2 ] = - 1.0f ;
q [ 3 ] = ( 1.0f + dest - > projectionMatrix [ 10 ] ) / dest - > projectionMatrix [ 14 ] ;
VectorScale4 ( plane2 , 2.0f / DotProduct4 ( plane2 , q ) , c ) ;
dest - > projectionMatrix [ 2 ] = c [ 0 ] ;
dest - > projectionMatrix [ 6 ] = c [ 1 ] ;
dest - > projectionMatrix [ 10 ] = c [ 2 ] + 1.0f ;
dest - > projectionMatrix [ 14 ] = c [ 3 ] ;
}
}
/*
= = = = = = = = = = = = = = =
R_SetupProjectionOrtho
= = = = = = = = = = = = = = =
*/
void R_SetupProjectionOrtho ( viewParms_t * dest , vec3_t viewBounds [ 2 ] )
{
float xmin , xmax , ymin , ymax , znear , zfar ;
//viewParms_t *dest = &tr.viewParms;
int i ;
vec3_t pop ;
// Quake3: Projection:
//
// Z X Y Z
// | / | /
// |/ |/
// Y--+ +--X
xmin = viewBounds [ 0 ] [ 1 ] ;
xmax = viewBounds [ 1 ] [ 1 ] ;
ymin = - viewBounds [ 1 ] [ 2 ] ;
ymax = - viewBounds [ 0 ] [ 2 ] ;
znear = viewBounds [ 0 ] [ 0 ] ;
zfar = viewBounds [ 1 ] [ 0 ] ;
dest - > projectionMatrix [ 0 ] = 2 / ( xmax - xmin ) ;
dest - > projectionMatrix [ 4 ] = 0 ;
dest - > projectionMatrix [ 8 ] = 0 ;
dest - > projectionMatrix [ 12 ] = ( xmax + xmin ) / ( xmax - xmin ) ;
dest - > projectionMatrix [ 1 ] = 0 ;
dest - > projectionMatrix [ 5 ] = 2 / ( ymax - ymin ) ;
dest - > projectionMatrix [ 9 ] = 0 ;
dest - > projectionMatrix [ 13 ] = ( ymax + ymin ) / ( ymax - ymin ) ;
dest - > projectionMatrix [ 2 ] = 0 ;
dest - > projectionMatrix [ 6 ] = 0 ;
dest - > projectionMatrix [ 10 ] = - 2 / ( zfar - znear ) ;
dest - > projectionMatrix [ 14 ] = - ( zfar + znear ) / ( zfar - znear ) ;
dest - > projectionMatrix [ 3 ] = 0 ;
dest - > projectionMatrix [ 7 ] = 0 ;
dest - > projectionMatrix [ 11 ] = 0 ;
dest - > projectionMatrix [ 15 ] = 1 ;
VectorScale ( dest - > or . axis [ 1 ] , 1.0f , dest - > frustum [ 0 ] . normal ) ;
VectorMA ( dest - > or . origin , viewBounds [ 0 ] [ 1 ] , dest - > frustum [ 0 ] . normal , pop ) ;
dest - > frustum [ 0 ] . dist = DotProduct ( pop , dest - > frustum [ 0 ] . normal ) ;
VectorScale ( dest - > or . axis [ 1 ] , - 1.0f , dest - > frustum [ 1 ] . normal ) ;
VectorMA ( dest - > or . origin , - viewBounds [ 1 ] [ 1 ] , dest - > frustum [ 1 ] . normal , pop ) ;
dest - > frustum [ 1 ] . dist = DotProduct ( pop , dest - > frustum [ 1 ] . normal ) ;
VectorScale ( dest - > or . axis [ 2 ] , 1.0f , dest - > frustum [ 2 ] . normal ) ;
VectorMA ( dest - > or . origin , viewBounds [ 0 ] [ 2 ] , dest - > frustum [ 2 ] . normal , pop ) ;
dest - > frustum [ 2 ] . dist = DotProduct ( pop , dest - > frustum [ 2 ] . normal ) ;
VectorScale ( dest - > or . axis [ 2 ] , - 1.0f , dest - > frustum [ 3 ] . normal ) ;
VectorMA ( dest - > or . origin , - viewBounds [ 1 ] [ 2 ] , dest - > frustum [ 3 ] . normal , pop ) ;
dest - > frustum [ 3 ] . dist = DotProduct ( pop , dest - > frustum [ 3 ] . normal ) ;
VectorScale ( dest - > or . axis [ 0 ] , - 1.0f , dest - > frustum [ 4 ] . normal ) ;
VectorMA ( dest - > or . origin , - viewBounds [ 1 ] [ 0 ] , dest - > frustum [ 4 ] . normal , pop ) ;
dest - > frustum [ 4 ] . dist = DotProduct ( pop , dest - > frustum [ 4 ] . normal ) ;
for ( i = 0 ; i < 5 ; i + + )
{
dest - > frustum [ i ] . type = PLANE_NON_AXIAL ;
SetPlaneSignbits ( & dest - > frustum [ i ] ) ;
}
2013-01-10 02:30:12 +00:00
dest - > flags | = VPF_FARPLANEFRUSTUM ;
2012-10-26 01:23:06 +00:00
}
/*
= = = = = = = = = = = = = = = = =
R_MirrorPoint
= = = = = = = = = = = = = = = = =
*/
void R_MirrorPoint ( vec3_t in , orientation_t * surface , orientation_t * camera , vec3_t out ) {
int i ;
vec3_t local ;
vec3_t transformed ;
float d ;
VectorSubtract ( in , surface - > origin , local ) ;
VectorClear ( transformed ) ;
for ( i = 0 ; i < 3 ; i + + ) {
d = DotProduct ( local , surface - > axis [ i ] ) ;
VectorMA ( transformed , d , camera - > axis [ i ] , transformed ) ;
}
VectorAdd ( transformed , camera - > origin , out ) ;
}
void R_MirrorVector ( vec3_t in , orientation_t * surface , orientation_t * camera , vec3_t out ) {
int i ;
float d ;
VectorClear ( out ) ;
for ( i = 0 ; i < 3 ; i + + ) {
d = DotProduct ( in , surface - > axis [ i ] ) ;
VectorMA ( out , d , camera - > axis [ i ] , out ) ;
}
}
/*
= = = = = = = = = = = = =
R_PlaneForSurface
= = = = = = = = = = = = =
*/
void R_PlaneForSurface ( surfaceType_t * surfType , cplane_t * plane ) {
2013-10-15 08:19:16 +00:00
srfBspSurface_t * tri ;
2012-10-26 01:23:06 +00:00
srfPoly_t * poly ;
srfVert_t * v1 , * v2 , * v3 ;
vec4_t plane4 ;
if ( ! surfType ) {
Com_Memset ( plane , 0 , sizeof ( * plane ) ) ;
plane - > normal [ 0 ] = 1 ;
return ;
}
switch ( * surfType ) {
case SF_FACE :
2013-10-15 08:19:16 +00:00
* plane = ( ( srfBspSurface_t * ) surfType ) - > cullPlane ;
2012-10-26 01:23:06 +00:00
return ;
case SF_TRIANGLES :
2013-10-15 08:19:16 +00:00
tri = ( srfBspSurface_t * ) surfType ;
2012-10-26 01:23:06 +00:00
v1 = tri - > verts + tri - > triangles [ 0 ] . indexes [ 0 ] ;
v2 = tri - > verts + tri - > triangles [ 0 ] . indexes [ 1 ] ;
v3 = tri - > verts + tri - > triangles [ 0 ] . indexes [ 2 ] ;
PlaneFromPoints ( plane4 , v1 - > xyz , v2 - > xyz , v3 - > xyz ) ;
VectorCopy ( plane4 , plane - > normal ) ;
plane - > dist = plane4 [ 3 ] ;
return ;
case SF_POLY :
poly = ( srfPoly_t * ) surfType ;
PlaneFromPoints ( plane4 , poly - > verts [ 0 ] . xyz , poly - > verts [ 1 ] . xyz , poly - > verts [ 2 ] . xyz ) ;
VectorCopy ( plane4 , plane - > normal ) ;
plane - > dist = plane4 [ 3 ] ;
return ;
default :
Com_Memset ( plane , 0 , sizeof ( * plane ) ) ;
plane - > normal [ 0 ] = 1 ;
return ;
}
}
/*
= = = = = = = = = = = = = = = = =
R_GetPortalOrientation
entityNum is the entity that the portal surface is a part of , which may
be moving and rotating .
Returns qtrue if it should be mirrored
= = = = = = = = = = = = = = = = =
*/
qboolean R_GetPortalOrientations ( drawSurf_t * drawSurf , int entityNum ,
orientation_t * surface , orientation_t * camera ,
vec3_t pvsOrigin , qboolean * mirror ) {
int i ;
cplane_t originalPlane , plane ;
trRefEntity_t * e ;
float d ;
vec3_t transformed ;
// create plane axis for the portal we are seeing
R_PlaneForSurface ( drawSurf - > surface , & originalPlane ) ;
// rotate the plane if necessary
if ( entityNum ! = REFENTITYNUM_WORLD ) {
tr . currentEntityNum = entityNum ;
tr . currentEntity = & tr . refdef . entities [ entityNum ] ;
// get the orientation of the entity
R_RotateForEntity ( tr . currentEntity , & tr . viewParms , & tr . or ) ;
// rotate the plane, but keep the non-rotated version for matching
// against the portalSurface entities
R_LocalNormalToWorld ( originalPlane . normal , plane . normal ) ;
plane . dist = originalPlane . dist + DotProduct ( plane . normal , tr . or . origin ) ;
// translate the original plane
originalPlane . dist = originalPlane . dist + DotProduct ( originalPlane . normal , tr . or . origin ) ;
} else {
plane = originalPlane ;
}
VectorCopy ( plane . normal , surface - > axis [ 0 ] ) ;
PerpendicularVector ( surface - > axis [ 1 ] , surface - > axis [ 0 ] ) ;
CrossProduct ( surface - > axis [ 0 ] , surface - > axis [ 1 ] , surface - > axis [ 2 ] ) ;
// locate the portal entity closest to this plane.
// origin will be the origin of the portal, origin2 will be
// the origin of the camera
for ( i = 0 ; i < tr . refdef . num_entities ; i + + ) {
e = & tr . refdef . entities [ i ] ;
if ( e - > e . reType ! = RT_PORTALSURFACE ) {
continue ;
}
d = DotProduct ( e - > e . origin , originalPlane . normal ) - originalPlane . dist ;
if ( d > 64 | | d < - 64 ) {
continue ;
}
// get the pvsOrigin from the entity
VectorCopy ( e - > e . oldorigin , pvsOrigin ) ;
// if the entity is just a mirror, don't use as a camera point
if ( e - > e . oldorigin [ 0 ] = = e - > e . origin [ 0 ] & &
e - > e . oldorigin [ 1 ] = = e - > e . origin [ 1 ] & &
e - > e . oldorigin [ 2 ] = = e - > e . origin [ 2 ] ) {
VectorScale ( plane . normal , plane . dist , surface - > origin ) ;
VectorCopy ( surface - > origin , camera - > origin ) ;
VectorSubtract ( vec3_origin , surface - > axis [ 0 ] , camera - > axis [ 0 ] ) ;
VectorCopy ( surface - > axis [ 1 ] , camera - > axis [ 1 ] ) ;
VectorCopy ( surface - > axis [ 2 ] , camera - > axis [ 2 ] ) ;
* mirror = qtrue ;
return qtrue ;
}
// project the origin onto the surface plane to get
// an origin point we can rotate around
d = DotProduct ( e - > e . origin , plane . normal ) - plane . dist ;
VectorMA ( e - > e . origin , - d , surface - > axis [ 0 ] , surface - > origin ) ;
// now get the camera origin and orientation
VectorCopy ( e - > e . oldorigin , camera - > origin ) ;
AxisCopy ( e - > e . axis , camera - > axis ) ;
VectorSubtract ( vec3_origin , camera - > axis [ 0 ] , camera - > axis [ 0 ] ) ;
VectorSubtract ( vec3_origin , camera - > axis [ 1 ] , camera - > axis [ 1 ] ) ;
// optionally rotate
if ( e - > e . oldframe ) {
// if a speed is specified
if ( e - > e . frame ) {
// continuous rotate
d = ( tr . refdef . time / 1000.0f ) * e - > e . frame ;
VectorCopy ( camera - > axis [ 1 ] , transformed ) ;
RotatePointAroundVector ( camera - > axis [ 1 ] , camera - > axis [ 0 ] , transformed , d ) ;
CrossProduct ( camera - > axis [ 0 ] , camera - > axis [ 1 ] , camera - > axis [ 2 ] ) ;
} else {
// bobbing rotate, with skinNum being the rotation offset
d = sin ( tr . refdef . time * 0.003f ) ;
d = e - > e . skinNum + d * 4 ;
VectorCopy ( camera - > axis [ 1 ] , transformed ) ;
RotatePointAroundVector ( camera - > axis [ 1 ] , camera - > axis [ 0 ] , transformed , d ) ;
CrossProduct ( camera - > axis [ 0 ] , camera - > axis [ 1 ] , camera - > axis [ 2 ] ) ;
}
}
else if ( e - > e . skinNum ) {
d = e - > e . skinNum ;
VectorCopy ( camera - > axis [ 1 ] , transformed ) ;
RotatePointAroundVector ( camera - > axis [ 1 ] , camera - > axis [ 0 ] , transformed , d ) ;
CrossProduct ( camera - > axis [ 0 ] , camera - > axis [ 1 ] , camera - > axis [ 2 ] ) ;
}
* mirror = qfalse ;
return qtrue ;
}
// if we didn't locate a portal entity, don't render anything.
// We don't want to just treat it as a mirror, because without a
// portal entity the server won't have communicated a proper entity set
// in the snapshot
// unfortunately, with local movement prediction it is easily possible
// to see a surface before the server has communicated the matching
// portal surface entity, so we don't want to print anything here...
//ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" );
return qfalse ;
}
static qboolean IsMirror ( const drawSurf_t * drawSurf , int entityNum )
{
int i ;
cplane_t originalPlane , plane ;
trRefEntity_t * e ;
float d ;
// create plane axis for the portal we are seeing
R_PlaneForSurface ( drawSurf - > surface , & originalPlane ) ;
// rotate the plane if necessary
if ( entityNum ! = REFENTITYNUM_WORLD )
{
tr . currentEntityNum = entityNum ;
tr . currentEntity = & tr . refdef . entities [ entityNum ] ;
// get the orientation of the entity
R_RotateForEntity ( tr . currentEntity , & tr . viewParms , & tr . or ) ;
// rotate the plane, but keep the non-rotated version for matching
// against the portalSurface entities
R_LocalNormalToWorld ( originalPlane . normal , plane . normal ) ;
plane . dist = originalPlane . dist + DotProduct ( plane . normal , tr . or . origin ) ;
// translate the original plane
originalPlane . dist = originalPlane . dist + DotProduct ( originalPlane . normal , tr . or . origin ) ;
}
// locate the portal entity closest to this plane.
// origin will be the origin of the portal, origin2 will be
// the origin of the camera
for ( i = 0 ; i < tr . refdef . num_entities ; i + + )
{
e = & tr . refdef . entities [ i ] ;
if ( e - > e . reType ! = RT_PORTALSURFACE ) {
continue ;
}
d = DotProduct ( e - > e . origin , originalPlane . normal ) - originalPlane . dist ;
if ( d > 64 | | d < - 64 ) {
continue ;
}
// if the entity is just a mirror, don't use as a camera point
if ( e - > e . oldorigin [ 0 ] = = e - > e . origin [ 0 ] & &
e - > e . oldorigin [ 1 ] = = e - > e . origin [ 1 ] & &
e - > e . oldorigin [ 2 ] = = e - > e . origin [ 2 ] )
{
return qtrue ;
}
return qfalse ;
}
return qfalse ;
}
/*
* * SurfIsOffscreen
* *
* * Determines if a surface is completely offscreen .
*/
static qboolean SurfIsOffscreen ( const drawSurf_t * drawSurf , vec4_t clipDest [ 128 ] ) {
float shortest = 100000000 ;
int entityNum ;
int numTriangles ;
shader_t * shader ;
int fogNum ;
int dlighted ;
int pshadowed ;
vec4_t clip , eye ;
int i ;
unsigned int pointOr = 0 ;
unsigned int pointAnd = ( unsigned int ) ~ 0 ;
R_RotateForViewer ( ) ;
R_DecomposeSort ( drawSurf - > sort , & entityNum , & shader , & fogNum , & dlighted , & pshadowed ) ;
2013-09-16 07:54:26 +00:00
RB_BeginSurface ( shader , fogNum , drawSurf - > cubemapIndex ) ;
2012-10-26 01:23:06 +00:00
rb_surfaceTable [ * drawSurf - > surface ] ( drawSurf - > surface ) ;
assert ( tess . numVertexes < 128 ) ;
for ( i = 0 ; i < tess . numVertexes ; i + + )
{
int j ;
unsigned int pointFlags = 0 ;
R_TransformModelToClip ( tess . xyz [ i ] , tr . or . modelMatrix , tr . viewParms . projectionMatrix , eye , clip ) ;
for ( j = 0 ; j < 3 ; j + + )
{
if ( clip [ j ] > = clip [ 3 ] )
{
pointFlags | = ( 1 < < ( j * 2 ) ) ;
}
else if ( clip [ j ] < = - clip [ 3 ] )
{
pointFlags | = ( 1 < < ( j * 2 + 1 ) ) ;
}
}
pointAnd & = pointFlags ;
pointOr | = pointFlags ;
}
// trivially reject
if ( pointAnd )
{
return qtrue ;
}
// determine if this surface is backfaced and also determine the distance
// to the nearest vertex so we can cull based on portal range. Culling
// based on vertex distance isn't 100% correct (we should be checking for
// range to the surface), but it's good enough for the types of portals
// we have in the game right now.
numTriangles = tess . numIndexes / 3 ;
for ( i = 0 ; i < tess . numIndexes ; i + = 3 )
{
vec3_t normal ;
float len ;
VectorSubtract ( tess . xyz [ tess . indexes [ i ] ] , tr . viewParms . or . origin , normal ) ;
len = VectorLengthSquared ( normal ) ; // lose the sqrt
if ( len < shortest )
{
shortest = len ;
}
if ( DotProduct ( normal , tess . normal [ tess . indexes [ i ] ] ) > = 0 )
{
numTriangles - - ;
}
}
if ( ! numTriangles )
{
return qtrue ;
}
// mirrors can early out at this point, since we don't do a fade over distance
// with them (although we could)
if ( IsMirror ( drawSurf , entityNum ) )
{
return qfalse ;
}
if ( shortest > ( tess . shader - > portalRange * tess . shader - > portalRange ) )
{
return qtrue ;
}
return qfalse ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
R_MirrorViewBySurface
Returns qtrue if another view has been rendered
= = = = = = = = = = = = = = = = = = = = = = = =
*/
qboolean R_MirrorViewBySurface ( drawSurf_t * drawSurf , int entityNum ) {
vec4_t clipDest [ 128 ] ;
viewParms_t newParms ;
viewParms_t oldParms ;
orientation_t surface , camera ;
// don't recursively mirror
if ( tr . viewParms . isPortal ) {
ri . Printf ( PRINT_DEVELOPER , " WARNING: recursive mirror/portal found \n " ) ;
return qfalse ;
}
if ( r_noportals - > integer | | ( r_fastsky - > integer = = 1 ) ) {
return qfalse ;
}
// trivially reject portal/mirror
if ( SurfIsOffscreen ( drawSurf , clipDest ) ) {
return qfalse ;
}
// save old viewParms so we can return to it after the mirror view
oldParms = tr . viewParms ;
newParms = tr . viewParms ;
newParms . isPortal = qtrue ;
2013-01-10 02:30:12 +00:00
newParms . zFar = 0.0f ;
newParms . flags & = ~ VPF_FARPLANEFRUSTUM ;
2012-10-26 01:23:06 +00:00
if ( ! R_GetPortalOrientations ( drawSurf , entityNum , & surface , & camera ,
newParms . pvsOrigin , & newParms . isMirror ) ) {
return qfalse ; // bad portal, no portalentity
}
2013-09-16 07:54:26 +00:00
if ( newParms . isMirror )
newParms . flags | = VPF_NOVIEWMODEL ;
2012-10-26 01:23:06 +00:00
R_MirrorPoint ( oldParms . or . origin , & surface , & camera , newParms . or . origin ) ;
VectorSubtract ( vec3_origin , camera . axis [ 0 ] , newParms . portalPlane . normal ) ;
newParms . portalPlane . dist = DotProduct ( camera . origin , newParms . portalPlane . normal ) ;
R_MirrorVector ( oldParms . or . axis [ 0 ] , & surface , & camera , newParms . or . axis [ 0 ] ) ;
R_MirrorVector ( oldParms . or . axis [ 1 ] , & surface , & camera , newParms . or . axis [ 1 ] ) ;
R_MirrorVector ( oldParms . or . axis [ 2 ] , & surface , & camera , newParms . or . axis [ 2 ] ) ;
// OPTIMIZE: restrict the viewport on the mirrored view
// render the mirror view
R_RenderView ( & newParms ) ;
tr . viewParms = oldParms ;
return qtrue ;
}
/*
= = = = = = = = = = = = = = = = =
R_SpriteFogNum
See if a sprite is inside a fog volume
= = = = = = = = = = = = = = = = =
*/
int R_SpriteFogNum ( trRefEntity_t * ent ) {
int i , j ;
fog_t * fog ;
if ( tr . refdef . rdflags & RDF_NOWORLDMODEL ) {
return 0 ;
}
for ( i = 1 ; i < tr . world - > numfogs ; i + + ) {
fog = & tr . world - > fogs [ i ] ;
for ( j = 0 ; j < 3 ; j + + ) {
if ( ent - > e . origin [ j ] - ent - > e . radius > = fog - > bounds [ 1 ] [ j ] ) {
break ;
}
if ( ent - > e . origin [ j ] + ent - > e . radius < = fog - > bounds [ 0 ] [ j ] ) {
break ;
}
}
if ( j = = 3 ) {
return i ;
}
}
return 0 ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
DRAWSURF SORTING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = =
R_Radix
= = = = = = = = = = = = = = =
*/
static ID_INLINE void R_Radix ( int byte , int size , drawSurf_t * source , drawSurf_t * dest )
{
int count [ 256 ] = { 0 } ;
int index [ 256 ] ;
int i ;
unsigned char * sortKey = NULL ;
unsigned char * end = NULL ;
sortKey = ( ( unsigned char * ) & source [ 0 ] . sort ) + byte ;
end = sortKey + ( size * sizeof ( drawSurf_t ) ) ;
for ( ; sortKey < end ; sortKey + = sizeof ( drawSurf_t ) )
+ + count [ * sortKey ] ;
index [ 0 ] = 0 ;
for ( i = 1 ; i < 256 ; + + i )
index [ i ] = index [ i - 1 ] + count [ i - 1 ] ;
sortKey = ( ( unsigned char * ) & source [ 0 ] . sort ) + byte ;
for ( i = 0 ; i < size ; + + i , sortKey + = sizeof ( drawSurf_t ) )
dest [ index [ * sortKey ] + + ] = source [ i ] ;
}
/*
= = = = = = = = = = = = = = =
R_RadixSort
Radix sort with 4 byte size buckets
= = = = = = = = = = = = = = =
*/
static void R_RadixSort ( drawSurf_t * source , int size )
{
static drawSurf_t scratch [ MAX_DRAWSURFS ] ;
# ifdef Q3_LITTLE_ENDIAN
R_Radix ( 0 , size , source , scratch ) ;
R_Radix ( 1 , size , scratch , source ) ;
R_Radix ( 2 , size , source , scratch ) ;
R_Radix ( 3 , size , scratch , source ) ;
# else
R_Radix ( 3 , size , source , scratch ) ;
R_Radix ( 2 , size , scratch , source ) ;
R_Radix ( 1 , size , source , scratch ) ;
R_Radix ( 0 , size , scratch , source ) ;
# endif //Q3_LITTLE_ENDIAN
}
//==========================================================================================
/*
= = = = = = = = = = = = = = = = =
R_AddDrawSurf
= = = = = = = = = = = = = = = = =
*/
void R_AddDrawSurf ( surfaceType_t * surface , shader_t * shader ,
2013-09-16 07:54:26 +00:00
int fogIndex , int dlightMap , int pshadowMap , int cubemap ) {
2012-10-26 01:23:06 +00:00
int index ;
// instead of checking for overflow, we just mask the index
// so it wraps around
index = tr . refdef . numDrawSurfs & DRAWSURF_MASK ;
// the sort data is packed into a single 32 bit value so it can be
// compared quickly during the qsorting process
tr . refdef . drawSurfs [ index ] . sort = ( shader - > sortedIndex < < QSORT_SHADERNUM_SHIFT )
| tr . shiftedEntityNum | ( fogIndex < < QSORT_FOGNUM_SHIFT )
| ( ( int ) pshadowMap < < QSORT_PSHADOW_SHIFT ) | ( int ) dlightMap ;
2013-09-16 07:54:26 +00:00
tr . refdef . drawSurfs [ index ] . cubemapIndex = cubemap ;
2012-10-26 01:23:06 +00:00
tr . refdef . drawSurfs [ index ] . surface = surface ;
tr . refdef . numDrawSurfs + + ;
}
/*
= = = = = = = = = = = = = = = = =
R_DecomposeSort
= = = = = = = = = = = = = = = = =
*/
void R_DecomposeSort ( unsigned sort , int * entityNum , shader_t * * shader ,
int * fogNum , int * dlightMap , int * pshadowMap ) {
* fogNum = ( sort > > QSORT_FOGNUM_SHIFT ) & 31 ;
* shader = tr . sortedShaders [ ( sort > > QSORT_SHADERNUM_SHIFT ) & ( MAX_SHADERS - 1 ) ] ;
* entityNum = ( sort > > QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK ;
2012-10-30 09:00:58 +00:00
* pshadowMap = ( sort > > QSORT_PSHADOW_SHIFT ) & 1 ;
2012-10-26 01:23:06 +00:00
* dlightMap = sort & 1 ;
}
/*
= = = = = = = = = = = = = = = = =
R_SortDrawSurfs
= = = = = = = = = = = = = = = = =
*/
void R_SortDrawSurfs ( drawSurf_t * drawSurfs , int numDrawSurfs ) {
shader_t * shader ;
int fogNum ;
int entityNum ;
int dlighted ;
int pshadowed ;
int i ;
//ri.Printf(PRINT_ALL, "firstDrawSurf %d numDrawSurfs %d\n", (int)(drawSurfs - tr.refdef.drawSurfs), numDrawSurfs);
// it is possible for some views to not have any surfaces
if ( numDrawSurfs < 1 ) {
// we still need to add it for hyperspace cases
R_AddDrawSurfCmd ( drawSurfs , numDrawSurfs ) ;
return ;
}
// if we overflowed MAX_DRAWSURFS, the drawsurfs
// wrapped around in the buffer and we will be missing
// the first surfaces, not the last ones
if ( numDrawSurfs > MAX_DRAWSURFS ) {
numDrawSurfs = MAX_DRAWSURFS ;
}
// sort the drawsurfs by sort type, then orientation, then shader
R_RadixSort ( drawSurfs , numDrawSurfs ) ;
// skip pass through drawing if rendering a shadow map
if ( tr . viewParms . flags & ( VPF_SHADOWMAP | VPF_DEPTHSHADOW ) )
{
R_AddDrawSurfCmd ( drawSurfs , numDrawSurfs ) ;
return ;
}
// check for any pass through drawing, which
// may cause another view to be rendered first
for ( i = 0 ; i < numDrawSurfs ; i + + ) {
R_DecomposeSort ( ( drawSurfs + i ) - > sort , & entityNum , & shader , & fogNum , & dlighted , & pshadowed ) ;
if ( shader - > sort > SS_PORTAL ) {
break ;
}
// no shader should ever have this sort type
if ( shader - > sort = = SS_BAD ) {
ri . Error ( ERR_DROP , " Shader '%s'with sort == SS_BAD " , shader - > name ) ;
}
// if the mirror was completely clipped away, we may need to check another surface
if ( R_MirrorViewBySurface ( ( drawSurfs + i ) , entityNum ) ) {
// this is a debug option to see exactly what is being mirrored
if ( r_portalOnly - > integer ) {
return ;
}
break ; // only one mirror view at a time
}
}
R_AddDrawSurfCmd ( drawSurfs , numDrawSurfs ) ;
}
static void R_AddEntitySurface ( int entityNum )
{
trRefEntity_t * ent ;
shader_t * shader ;
tr . currentEntityNum = entityNum ;
ent = tr . currentEntity = & tr . refdef . entities [ tr . currentEntityNum ] ;
ent - > needDlights = qfalse ;
// preshift the value we are going to OR into the drawsurf sort
tr . shiftedEntityNum = tr . currentEntityNum < < QSORT_REFENTITYNUM_SHIFT ;
//
// the weapon model must be handled special --
// we don't want the hacked weapon position showing in
// mirrors, because the true body position will already be drawn
//
2013-09-16 07:54:26 +00:00
if ( ( ent - > e . renderfx & RF_FIRST_PERSON ) & & ( tr . viewParms . flags & VPF_NOVIEWMODEL ) ) {
2012-10-26 01:23:06 +00:00
return ;
}
// simple generated models, like sprites and beams, are not culled
switch ( ent - > e . reType ) {
case RT_PORTALSURFACE :
break ; // don't draw anything
case RT_SPRITE :
case RT_BEAM :
case RT_LIGHTNING :
case RT_RAIL_CORE :
case RT_RAIL_RINGS :
// self blood sprites, talk balloons, etc should not be drawn in the primary
// view. We can't just do this check for all entities, because md3
// entities may still want to cast shadows from them
if ( ( ent - > e . renderfx & RF_THIRD_PERSON ) & & ! tr . viewParms . isPortal ) {
return ;
}
shader = R_GetShaderByHandle ( ent - > e . customShader ) ;
2013-09-16 07:54:26 +00:00
R_AddDrawSurf ( & entitySurface , shader , R_SpriteFogNum ( ent ) , 0 , 0 , 0 /*cubeMap*/ ) ;
2012-10-26 01:23:06 +00:00
break ;
case RT_MODEL :
// we must set up parts of tr.or for model culling
R_RotateForEntity ( ent , & tr . viewParms , & tr . or ) ;
tr . currentModel = R_GetModelByHandle ( ent - > e . hModel ) ;
if ( ! tr . currentModel ) {
2013-09-16 07:54:26 +00:00
R_AddDrawSurf ( & entitySurface , tr . defaultShader , 0 , 0 , 0 , 0 /*cubeMap*/ ) ;
2012-10-26 01:23:06 +00:00
} else {
switch ( tr . currentModel - > type ) {
case MOD_MESH :
R_AddMD3Surfaces ( ent ) ;
break ;
case MOD_MD4 :
R_AddAnimSurfaces ( ent ) ;
break ;
case MOD_MDR :
R_MDRAddAnimSurfaces ( ent ) ;
break ;
case MOD_IQM :
R_AddIQMSurfaces ( ent ) ;
break ;
case MOD_BRUSH :
R_AddBrushModelSurfaces ( ent ) ;
break ;
case MOD_BAD : // null model axis
if ( ( ent - > e . renderfx & RF_THIRD_PERSON ) & & ! tr . viewParms . isPortal ) {
break ;
}
2013-09-16 07:54:26 +00:00
R_AddDrawSurf ( & entitySurface , tr . defaultShader , 0 , 0 , 0 , 0 ) ;
2012-10-26 01:23:06 +00:00
break ;
default :
ri . Error ( ERR_DROP , " R_AddEntitySurfaces: Bad modeltype " ) ;
break ;
}
}
break ;
default :
ri . Error ( ERR_DROP , " R_AddEntitySurfaces: Bad reType " ) ;
}
}
/*
= = = = = = = = = = = = =
R_AddEntitySurfaces
= = = = = = = = = = = = =
*/
void R_AddEntitySurfaces ( void ) {
int i ;
if ( ! r_drawentities - > integer ) {
return ;
}
for ( i = 0 ; i < tr . refdef . num_entities ; i + + )
R_AddEntitySurface ( i ) ;
}
/*
= = = = = = = = = = = = = = = = = = = =
R_GenerateDrawSurfs
= = = = = = = = = = = = = = = = = = = =
*/
void R_GenerateDrawSurfs ( void ) {
R_AddWorldSurfaces ( ) ;
R_AddPolygonSurfaces ( ) ;
// set the projection matrix with the minimum zfar
// now that we have the world bounded
// this needs to be done before entities are
// added, because they use the projection
// matrix for lod calculation
// dynamically compute far clip plane distance
if ( ! ( tr . viewParms . flags & VPF_SHADOWMAP ) )
{
R_SetFarClip ( ) ;
}
// we know the size of the clipping volume. Now set the rest of the projection matrix.
R_SetupProjectionZ ( & tr . viewParms ) ;
R_AddEntitySurfaces ( ) ;
}
/*
= = = = = = = = = = = = = = = =
R_DebugPolygon
= = = = = = = = = = = = = = = =
*/
void R_DebugPolygon ( int color , int numPoints , float * points ) {
// FIXME: implement this
#if 0
int i ;
GL_State ( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ) ;
// draw solid shade
qglColor3f ( color & 1 , ( color > > 1 ) & 1 , ( color > > 2 ) & 1 ) ;
qglBegin ( GL_POLYGON ) ;
for ( i = 0 ; i < numPoints ; i + + ) {
qglVertex3fv ( points + i * 3 ) ;
}
qglEnd ( ) ;
// draw wireframe outline
GL_State ( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE ) ;
qglDepthRange ( 0 , 0 ) ;
qglColor3f ( 1 , 1 , 1 ) ;
qglBegin ( GL_POLYGON ) ;
for ( i = 0 ; i < numPoints ; i + + ) {
qglVertex3fv ( points + i * 3 ) ;
}
qglEnd ( ) ;
qglDepthRange ( 0 , 1 ) ;
# endif
}
/*
= = = = = = = = = = = = = = = = = = = =
R_DebugGraphics
Visualization aid for movement clipping debugging
= = = = = = = = = = = = = = = = = = = =
*/
void R_DebugGraphics ( void ) {
if ( ! r_debugSurface - > integer ) {
return ;
}
2013-01-24 22:53:08 +00:00
R_IssuePendingRenderCommands ( ) ;
2012-10-26 01:23:06 +00:00
GL_Bind ( tr . whiteImage ) ;
GL_Cull ( CT_FRONT_SIDED ) ;
ri . CM_DrawDebugSurface ( R_DebugPolygon ) ;
}
/*
= = = = = = = = = = = = = = = =
R_RenderView
A view may be either the actual camera view ,
or a mirror / remote location
= = = = = = = = = = = = = = = =
*/
void R_RenderView ( viewParms_t * parms ) {
int firstDrawSurf ;
if ( parms - > viewportWidth < = 0 | | parms - > viewportHeight < = 0 ) {
return ;
}
tr . viewCount + + ;
tr . viewParms = * parms ;
tr . viewParms . frameSceneNum = tr . frameSceneNum ;
tr . viewParms . frameCount = tr . frameCount ;
firstDrawSurf = tr . refdef . numDrawSurfs ;
tr . viewCount + + ;
// set viewParms.world
R_RotateForViewer ( ) ;
R_SetupProjection ( & tr . viewParms , r_zproj - > value , tr . viewParms . zFar , qtrue ) ;
R_GenerateDrawSurfs ( ) ;
R_SortDrawSurfs ( tr . refdef . drawSurfs + firstDrawSurf , tr . refdef . numDrawSurfs - firstDrawSurf ) ;
// draw main system development information (surface outlines, etc)
R_DebugGraphics ( ) ;
}
void R_RenderDlightCubemaps ( const refdef_t * fd )
{
int i ;
for ( i = 0 ; i < tr . refdef . num_dlights ; i + + )
{
viewParms_t shadowParms ;
int j ;
// use previous frame to determine visible dlights
if ( ( 1 < < i ) & tr . refdef . dlightMask )
continue ;
Com_Memset ( & shadowParms , 0 , sizeof ( shadowParms ) ) ;
shadowParms . viewportX = tr . refdef . x ;
shadowParms . viewportY = glConfig . vidHeight - ( tr . refdef . y + PSHADOW_MAP_SIZE ) ;
shadowParms . viewportWidth = PSHADOW_MAP_SIZE ;
shadowParms . viewportHeight = PSHADOW_MAP_SIZE ;
shadowParms . isPortal = qfalse ;
shadowParms . isMirror = qtrue ; // because it is
shadowParms . fovX = 90 ;
shadowParms . fovY = 90 ;
2013-09-16 07:54:26 +00:00
shadowParms . flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL ;
2012-10-26 01:23:06 +00:00
shadowParms . zFar = tr . refdef . dlights [ i ] . radius ;
VectorCopy ( tr . refdef . dlights [ i ] . origin , shadowParms . or . origin ) ;
for ( j = 0 ; j < 6 ; j + + )
{
switch ( j )
{
case 0 :
// -X
VectorSet ( shadowParms . or . axis [ 0 ] , - 1 , 0 , 0 ) ;
VectorSet ( shadowParms . or . axis [ 1 ] , 0 , 0 , - 1 ) ;
VectorSet ( shadowParms . or . axis [ 2 ] , 0 , 1 , 0 ) ;
break ;
case 1 :
// +X
VectorSet ( shadowParms . or . axis [ 0 ] , 1 , 0 , 0 ) ;
VectorSet ( shadowParms . or . axis [ 1 ] , 0 , 0 , 1 ) ;
VectorSet ( shadowParms . or . axis [ 2 ] , 0 , 1 , 0 ) ;
break ;
case 2 :
// -Y
VectorSet ( shadowParms . or . axis [ 0 ] , 0 , - 1 , 0 ) ;
VectorSet ( shadowParms . or . axis [ 1 ] , 1 , 0 , 0 ) ;
VectorSet ( shadowParms . or . axis [ 2 ] , 0 , 0 , - 1 ) ;
break ;
case 3 :
// +Y
VectorSet ( shadowParms . or . axis [ 0 ] , 0 , 1 , 0 ) ;
VectorSet ( shadowParms . or . axis [ 1 ] , 1 , 0 , 0 ) ;
VectorSet ( shadowParms . or . axis [ 2 ] , 0 , 0 , 1 ) ;
break ;
case 4 :
// -Z
VectorSet ( shadowParms . or . axis [ 0 ] , 0 , 0 , - 1 ) ;
VectorSet ( shadowParms . or . axis [ 1 ] , 1 , 0 , 0 ) ;
VectorSet ( shadowParms . or . axis [ 2 ] , 0 , 1 , 0 ) ;
break ;
case 5 :
// +Z
VectorSet ( shadowParms . or . axis [ 0 ] , 0 , 0 , 1 ) ;
VectorSet ( shadowParms . or . axis [ 1 ] , - 1 , 0 , 0 ) ;
VectorSet ( shadowParms . or . axis [ 2 ] , 0 , 1 , 0 ) ;
break ;
}
R_RenderView ( & shadowParms ) ;
R_AddCapShadowmapCmd ( i , j ) ;
}
}
}
void R_RenderPshadowMaps ( const refdef_t * fd )
{
viewParms_t shadowParms ;
int i ;
// first, make a list of shadows
for ( i = 0 ; i < tr . refdef . num_entities ; i + + )
{
trRefEntity_t * ent = & tr . refdef . entities [ i ] ;
if ( ( ent - > e . renderfx & ( RF_FIRST_PERSON | RF_NOSHADOW ) ) )
continue ;
//if((ent->e.renderfx & RF_THIRD_PERSON))
//continue;
if ( ent - > e . reType = = RT_MODEL )
{
model_t * model = R_GetModelByHandle ( ent - > e . hModel ) ;
pshadow_t shadow ;
float radius = 0.0f ;
float scale = 1.0f ;
vec3_t diff ;
int j ;
if ( ! model )
continue ;
if ( ent - > e . nonNormalizedAxes )
{
scale = VectorLength ( ent - > e . axis [ 0 ] ) ;
}
switch ( model - > type )
{
case MOD_MESH :
{
mdvFrame_t * frame = & model - > mdv [ 0 ] - > frames [ ent - > e . frame ] ;
radius = frame - > radius * scale ;
}
break ;
case MOD_MD4 :
{
// FIXME: actually calculate the radius and bounds, this is a horrible hack
radius = r_pshadowDist - > value / 2.0f ;
}
break ;
case MOD_MDR :
{
// FIXME: never actually tested this
mdrHeader_t * header = model - > modelData ;
int frameSize = ( size_t ) ( & ( ( mdrFrame_t * ) 0 ) - > bones [ header - > numBones ] ) ;
mdrFrame_t * frame = ( mdrFrame_t * ) ( ( byte * ) header + header - > ofsFrames + frameSize * ent - > e . frame ) ;
radius = frame - > radius ;
}
break ;
case MOD_IQM :
{
// FIXME: never actually tested this
iqmData_t * data = model - > modelData ;
vec3_t diag ;
float * framebounds ;
framebounds = data - > bounds + 6 * ent - > e . frame ;
VectorSubtract ( framebounds + 3 , framebounds , diag ) ;
radius = 0.5f * VectorLength ( diag ) ;
}
break ;
default :
break ;
}
if ( ! radius )
continue ;
// Cull entities that are behind the viewer by more than lightRadius
VectorSubtract ( ent - > e . origin , fd - > vieworg , diff ) ;
if ( DotProduct ( diff , fd - > viewaxis [ 0 ] ) < - r_pshadowDist - > value )
continue ;
memset ( & shadow , 0 , sizeof ( shadow ) ) ;
shadow . numEntities = 1 ;
shadow . entityNums [ 0 ] = i ;
shadow . viewRadius = radius ;
shadow . lightRadius = r_pshadowDist - > value ;
VectorCopy ( ent - > e . origin , shadow . viewOrigin ) ;
shadow . sort = DotProduct ( diff , diff ) / ( radius * radius ) ;
VectorCopy ( ent - > e . origin , shadow . entityOrigins [ 0 ] ) ;
shadow . entityRadiuses [ 0 ] = radius ;
for ( j = 0 ; j < MAX_CALC_PSHADOWS ; j + + )
{
pshadow_t swap ;
if ( j + 1 > tr . refdef . num_pshadows )
{
tr . refdef . num_pshadows = j + 1 ;
tr . refdef . pshadows [ j ] = shadow ;
break ;
}
// sort shadows by distance from camera divided by radius
// FIXME: sort better
if ( tr . refdef . pshadows [ j ] . sort < = shadow . sort )
continue ;
swap = tr . refdef . pshadows [ j ] ;
tr . refdef . pshadows [ j ] = shadow ;
shadow = swap ;
}
}
}
// next, merge touching pshadows
for ( i = 0 ; i < tr . refdef . num_pshadows ; i + + )
{
pshadow_t * ps1 = & tr . refdef . pshadows [ i ] ;
int j ;
for ( j = i + 1 ; j < tr . refdef . num_pshadows ; j + + )
{
pshadow_t * ps2 = & tr . refdef . pshadows [ j ] ;
int k ;
qboolean touch ;
if ( ps1 - > numEntities = = 8 )
break ;
touch = qfalse ;
if ( SpheresIntersect ( ps1 - > viewOrigin , ps1 - > viewRadius , ps2 - > viewOrigin , ps2 - > viewRadius ) )
{
for ( k = 0 ; k < ps1 - > numEntities ; k + + )
{
if ( SpheresIntersect ( ps1 - > entityOrigins [ k ] , ps1 - > entityRadiuses [ k ] , ps2 - > viewOrigin , ps2 - > viewRadius ) )
{
touch = qtrue ;
break ;
}
}
}
if ( touch )
{
vec3_t newOrigin ;
float newRadius ;
BoundingSphereOfSpheres ( ps1 - > viewOrigin , ps1 - > viewRadius , ps2 - > viewOrigin , ps2 - > viewRadius , newOrigin , & newRadius ) ;
VectorCopy ( newOrigin , ps1 - > viewOrigin ) ;
ps1 - > viewRadius = newRadius ;
ps1 - > entityNums [ ps1 - > numEntities ] = ps2 - > entityNums [ 0 ] ;
VectorCopy ( ps2 - > viewOrigin , ps1 - > entityOrigins [ ps1 - > numEntities ] ) ;
ps1 - > entityRadiuses [ ps1 - > numEntities ] = ps2 - > viewRadius ;
ps1 - > numEntities + + ;
for ( k = j ; k < tr . refdef . num_pshadows - 1 ; k + + )
{
tr . refdef . pshadows [ k ] = tr . refdef . pshadows [ k + 1 ] ;
}
j - - ;
tr . refdef . num_pshadows - - ;
}
}
}
// cap number of drawn pshadows
if ( tr . refdef . num_pshadows > MAX_DRAWN_PSHADOWS )
{
tr . refdef . num_pshadows = MAX_DRAWN_PSHADOWS ;
}
// next, fill up the rest of the shadow info
for ( i = 0 ; i < tr . refdef . num_pshadows ; i + + )
{
pshadow_t * shadow = & tr . refdef . pshadows [ i ] ;
vec3_t up ;
vec3_t ambientLight , directedLight , lightDir ;
VectorSet ( lightDir , 0.57735f , 0.57735f , 0.57735f ) ;
# if 1
R_LightForPoint ( shadow - > viewOrigin , ambientLight , directedLight , lightDir ) ;
// sometimes there's no light
if ( DotProduct ( lightDir , lightDir ) < 0.9f )
VectorSet ( lightDir , 0.0f , 0.0f , 1.0f ) ;
# endif
if ( shadow - > viewRadius * 3.0f > shadow - > lightRadius )
{
shadow - > lightRadius = shadow - > viewRadius * 3.0f ;
}
VectorMA ( shadow - > viewOrigin , shadow - > viewRadius , lightDir , shadow - > lightOrigin ) ;
// make up a projection, up doesn't matter
VectorScale ( lightDir , - 1.0f , shadow - > lightViewAxis [ 0 ] ) ;
VectorSet ( up , 0 , 0 , - 1 ) ;
if ( abs ( DotProduct ( up , shadow - > lightViewAxis [ 0 ] ) ) > 0.9f )
{
VectorSet ( up , - 1 , 0 , 0 ) ;
}
CrossProduct ( shadow - > lightViewAxis [ 0 ] , up , shadow - > lightViewAxis [ 1 ] ) ;
VectorNormalize ( shadow - > lightViewAxis [ 1 ] ) ;
CrossProduct ( shadow - > lightViewAxis [ 0 ] , shadow - > lightViewAxis [ 1 ] , shadow - > lightViewAxis [ 2 ] ) ;
VectorCopy ( shadow - > lightViewAxis [ 0 ] , shadow - > cullPlane . normal ) ;
shadow - > cullPlane . dist = DotProduct ( shadow - > cullPlane . normal , shadow - > lightOrigin ) ;
shadow - > cullPlane . type = PLANE_NON_AXIAL ;
SetPlaneSignbits ( & shadow - > cullPlane ) ;
}
// next, render shadowmaps
for ( i = 0 ; i < tr . refdef . num_pshadows ; i + + )
{
int firstDrawSurf ;
pshadow_t * shadow = & tr . refdef . pshadows [ i ] ;
int j ;
Com_Memset ( & shadowParms , 0 , sizeof ( shadowParms ) ) ;
if ( glRefConfig . framebufferObject )
{
shadowParms . viewportX = 0 ;
shadowParms . viewportY = 0 ;
}
else
{
shadowParms . viewportX = tr . refdef . x ;
shadowParms . viewportY = glConfig . vidHeight - ( tr . refdef . y + PSHADOW_MAP_SIZE ) ;
}
shadowParms . viewportWidth = PSHADOW_MAP_SIZE ;
shadowParms . viewportHeight = PSHADOW_MAP_SIZE ;
shadowParms . isPortal = qfalse ;
shadowParms . isMirror = qfalse ;
shadowParms . fovX = 90 ;
shadowParms . fovY = 90 ;
if ( glRefConfig . framebufferObject )
shadowParms . targetFbo = tr . pshadowFbos [ i ] ;
2013-09-16 07:54:26 +00:00
shadowParms . flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL ;
2012-10-26 01:23:06 +00:00
shadowParms . zFar = shadow - > lightRadius ;
VectorCopy ( shadow - > lightOrigin , shadowParms . or . origin ) ;
VectorCopy ( shadow - > lightViewAxis [ 0 ] , shadowParms . or . axis [ 0 ] ) ;
VectorCopy ( shadow - > lightViewAxis [ 1 ] , shadowParms . or . axis [ 1 ] ) ;
VectorCopy ( shadow - > lightViewAxis [ 2 ] , shadowParms . or . axis [ 2 ] ) ;
{
tr . viewCount + + ;
tr . viewParms = shadowParms ;
tr . viewParms . frameSceneNum = tr . frameSceneNum ;
tr . viewParms . frameCount = tr . frameCount ;
firstDrawSurf = tr . refdef . numDrawSurfs ;
tr . viewCount + + ;
// set viewParms.world
R_RotateForViewer ( ) ;
{
float xmin , xmax , ymin , ymax , znear , zfar ;
viewParms_t * dest = & tr . viewParms ;
vec3_t pop ;
xmin = ymin = - shadow - > viewRadius ;
xmax = ymax = shadow - > viewRadius ;
znear = 0 ;
zfar = shadow - > lightRadius ;
dest - > projectionMatrix [ 0 ] = 2 / ( xmax - xmin ) ;
dest - > projectionMatrix [ 4 ] = 0 ;
dest - > projectionMatrix [ 8 ] = ( xmax + xmin ) / ( xmax - xmin ) ;
dest - > projectionMatrix [ 12 ] = 0 ;
dest - > projectionMatrix [ 1 ] = 0 ;
dest - > projectionMatrix [ 5 ] = 2 / ( ymax - ymin ) ;
dest - > projectionMatrix [ 9 ] = ( ymax + ymin ) / ( ymax - ymin ) ; // normally 0
dest - > projectionMatrix [ 13 ] = 0 ;
dest - > projectionMatrix [ 2 ] = 0 ;
dest - > projectionMatrix [ 6 ] = 0 ;
dest - > projectionMatrix [ 10 ] = 2 / ( zfar - znear ) ;
dest - > projectionMatrix [ 14 ] = 0 ;
dest - > projectionMatrix [ 3 ] = 0 ;
dest - > projectionMatrix [ 7 ] = 0 ;
dest - > projectionMatrix [ 11 ] = 0 ;
dest - > projectionMatrix [ 15 ] = 1 ;
VectorScale ( dest - > or . axis [ 1 ] , 1.0f , dest - > frustum [ 0 ] . normal ) ;
VectorMA ( dest - > or . origin , - shadow - > viewRadius , dest - > frustum [ 0 ] . normal , pop ) ;
dest - > frustum [ 0 ] . dist = DotProduct ( pop , dest - > frustum [ 0 ] . normal ) ;
VectorScale ( dest - > or . axis [ 1 ] , - 1.0f , dest - > frustum [ 1 ] . normal ) ;
VectorMA ( dest - > or . origin , - shadow - > viewRadius , dest - > frustum [ 1 ] . normal , pop ) ;
dest - > frustum [ 1 ] . dist = DotProduct ( pop , dest - > frustum [ 1 ] . normal ) ;
VectorScale ( dest - > or . axis [ 2 ] , 1.0f , dest - > frustum [ 2 ] . normal ) ;
VectorMA ( dest - > or . origin , - shadow - > viewRadius , dest - > frustum [ 2 ] . normal , pop ) ;
dest - > frustum [ 2 ] . dist = DotProduct ( pop , dest - > frustum [ 2 ] . normal ) ;
VectorScale ( dest - > or . axis [ 2 ] , - 1.0f , dest - > frustum [ 3 ] . normal ) ;
VectorMA ( dest - > or . origin , - shadow - > viewRadius , dest - > frustum [ 3 ] . normal , pop ) ;
dest - > frustum [ 3 ] . dist = DotProduct ( pop , dest - > frustum [ 3 ] . normal ) ;
VectorScale ( dest - > or . axis [ 0 ] , - 1.0f , dest - > frustum [ 4 ] . normal ) ;
VectorMA ( dest - > or . origin , - shadow - > lightRadius , dest - > frustum [ 4 ] . normal , pop ) ;
dest - > frustum [ 4 ] . dist = DotProduct ( pop , dest - > frustum [ 4 ] . normal ) ;
for ( j = 0 ; j < 5 ; j + + )
{
dest - > frustum [ j ] . type = PLANE_NON_AXIAL ;
SetPlaneSignbits ( & dest - > frustum [ j ] ) ;
}
2013-01-10 02:30:12 +00:00
dest - > flags | = VPF_FARPLANEFRUSTUM ;
2012-10-26 01:23:06 +00:00
}
for ( j = 0 ; j < shadow - > numEntities ; j + + )
{
R_AddEntitySurface ( shadow - > entityNums [ j ] ) ;
}
R_SortDrawSurfs ( tr . refdef . drawSurfs + firstDrawSurf , tr . refdef . numDrawSurfs - firstDrawSurf ) ;
if ( ! glRefConfig . framebufferObject )
R_AddCapShadowmapCmd ( i , - 1 ) ;
}
}
}
static float CalcSplit ( float n , float f , float i , float m )
{
return ( n * pow ( f / n , i / m ) + ( f - n ) * i / m ) / 2.0f ;
}
void R_RenderSunShadowMaps ( const refdef_t * fd , int level )
{
viewParms_t shadowParms ;
vec4_t lightDir , lightCol ;
vec3_t lightViewAxis [ 3 ] ;
vec3_t lightOrigin ;
float splitZNear , splitZFar , splitBias ;
float viewZNear , viewZFar ;
vec3_t lightviewBounds [ 2 ] ;
qboolean lightViewIndependentOfCameraView = qfalse ;
if ( r_forceSun - > integer = = 2 )
{
int scale = 32768 ;
float angle = ( fd - > time % scale ) / ( float ) scale * M_PI ;
lightDir [ 0 ] = cos ( angle ) ;
lightDir [ 1 ] = sin ( 35.0f * M_PI / 180.0f ) ;
lightDir [ 2 ] = sin ( angle ) * cos ( 35.0f * M_PI / 180.0f ) ;
lightDir [ 3 ] = 0.0f ;
if ( 1 ) //((fd->time % (scale * 2)) < scale)
{
lightCol [ 0 ] =
lightCol [ 1 ] =
lightCol [ 2 ] = CLAMP ( sin ( angle ) * 2.0f , 0.0f , 1.0f ) * 2.0f ;
lightCol [ 3 ] = 1.0f ;
}
else
{
lightCol [ 0 ] =
lightCol [ 1 ] =
lightCol [ 2 ] = CLAMP ( sin ( angle ) * 2.0f * 0.1f , 0.0f , 0.1f ) ;
lightCol [ 3 ] = 1.0f ;
}
VectorCopy4 ( lightDir , tr . refdef . sunDir ) ;
VectorCopy4 ( lightCol , tr . refdef . sunCol ) ;
VectorScale4 ( lightCol , 0.2f , tr . refdef . sunAmbCol ) ;
}
else
{
VectorCopy4 ( tr . refdef . sunDir , lightDir ) ;
}
viewZNear = r_shadowCascadeZNear - > value ;
viewZFar = r_shadowCascadeZFar - > value ;
splitBias = r_shadowCascadeZBias - > value ;
switch ( level )
{
case 0 :
default :
//splitZNear = r_znear->value;
//splitZFar = 256;
splitZNear = viewZNear ;
splitZFar = CalcSplit ( viewZNear , viewZFar , 1 , 3 ) + splitBias ;
break ;
case 1 :
splitZNear = CalcSplit ( viewZNear , viewZFar , 1 , 3 ) + splitBias ;
splitZFar = CalcSplit ( viewZNear , viewZFar , 2 , 3 ) + splitBias ;
//splitZNear = 256;
//splitZFar = 896;
break ;
case 2 :
splitZNear = CalcSplit ( viewZNear , viewZFar , 2 , 3 ) + splitBias ;
splitZFar = viewZFar ;
//splitZNear = 896;
//splitZFar = 3072;
break ;
}
VectorCopy ( fd - > vieworg , lightOrigin ) ;
// Make up a projection
VectorScale ( lightDir , - 1.0f , lightViewAxis [ 0 ] ) ;
if ( lightViewIndependentOfCameraView )
{
// Use world up as light view up
VectorSet ( lightViewAxis [ 2 ] , 0 , 0 , 1 ) ;
}
else if ( level = = 0 )
{
// Level 0 tries to use a diamond texture orientation relative to camera view
// Use halfway between camera view forward and left for light view up
VectorAdd ( fd - > viewaxis [ 0 ] , fd - > viewaxis [ 1 ] , lightViewAxis [ 2 ] ) ;
}
else
{
// Use camera view up as light view up
VectorCopy ( fd - > viewaxis [ 2 ] , lightViewAxis [ 2 ] ) ;
}
// Check if too close to parallel to light direction
if ( abs ( DotProduct ( lightViewAxis [ 2 ] , lightViewAxis [ 0 ] ) ) > 0.9f )
{
if ( lightViewIndependentOfCameraView )
{
// Use world left as light view up
VectorSet ( lightViewAxis [ 2 ] , 0 , 1 , 0 ) ;
}
else if ( level = = 0 )
{
// Level 0 tries to use a diamond texture orientation relative to camera view
// Use halfway between camera view forward and up for light view up
VectorAdd ( fd - > viewaxis [ 0 ] , fd - > viewaxis [ 2 ] , lightViewAxis [ 2 ] ) ;
}
else
{
// Use camera view left as light view up
VectorCopy ( fd - > viewaxis [ 1 ] , lightViewAxis [ 2 ] ) ;
}
}
// clean axes
CrossProduct ( lightViewAxis [ 2 ] , lightViewAxis [ 0 ] , lightViewAxis [ 1 ] ) ;
VectorNormalize ( lightViewAxis [ 1 ] ) ;
CrossProduct ( lightViewAxis [ 0 ] , lightViewAxis [ 1 ] , lightViewAxis [ 2 ] ) ;
// Create bounds for light projection using slice of view projection
{
matrix_t lightViewMatrix ;
vec4_t point , base , lightViewPoint ;
float lx , ly ;
base [ 3 ] = 1 ;
point [ 3 ] = 1 ;
lightViewPoint [ 3 ] = 1 ;
Matrix16View ( lightViewAxis , lightOrigin , lightViewMatrix ) ;
ClearBounds ( lightviewBounds [ 0 ] , lightviewBounds [ 1 ] ) ;
// add view near plane
lx = splitZNear * tan ( fd - > fov_x * M_PI / 360.0f ) ;
ly = splitZNear * tan ( fd - > fov_y * M_PI / 360.0f ) ;
VectorMA ( fd - > vieworg , splitZNear , fd - > viewaxis [ 0 ] , base ) ;
VectorMA ( base , lx , fd - > viewaxis [ 1 ] , point ) ;
VectorMA ( point , ly , fd - > viewaxis [ 2 ] , point ) ;
Matrix16Transform ( lightViewMatrix , point , lightViewPoint ) ;
AddPointToBounds ( lightViewPoint , lightviewBounds [ 0 ] , lightviewBounds [ 1 ] ) ;
VectorMA ( base , - lx , fd - > viewaxis [ 1 ] , point ) ;
VectorMA ( point , ly , fd - > viewaxis [ 2 ] , point ) ;
Matrix16Transform ( lightViewMatrix , point , lightViewPoint ) ;
AddPointToBounds ( lightViewPoint , lightviewBounds [ 0 ] , lightviewBounds [ 1 ] ) ;
VectorMA ( base , lx , fd - > viewaxis [ 1 ] , point ) ;
VectorMA ( point , - ly , fd - > viewaxis [ 2 ] , point ) ;
Matrix16Transform ( lightViewMatrix , point , lightViewPoint ) ;
AddPointToBounds ( lightViewPoint , lightviewBounds [ 0 ] , lightviewBounds [ 1 ] ) ;
VectorMA ( base , - lx , fd - > viewaxis [ 1 ] , point ) ;
VectorMA ( point , - ly , fd - > viewaxis [ 2 ] , point ) ;
Matrix16Transform ( lightViewMatrix , point , lightViewPoint ) ;
AddPointToBounds ( lightViewPoint , lightviewBounds [ 0 ] , lightviewBounds [ 1 ] ) ;
// add view far plane
lx = splitZFar * tan ( fd - > fov_x * M_PI / 360.0f ) ;
ly = splitZFar * tan ( fd - > fov_y * M_PI / 360.0f ) ;
VectorMA ( fd - > vieworg , splitZFar , fd - > viewaxis [ 0 ] , base ) ;
VectorMA ( base , lx , fd - > viewaxis [ 1 ] , point ) ;
VectorMA ( point , ly , fd - > viewaxis [ 2 ] , point ) ;
Matrix16Transform ( lightViewMatrix , point , lightViewPoint ) ;
AddPointToBounds ( lightViewPoint , lightviewBounds [ 0 ] , lightviewBounds [ 1 ] ) ;
VectorMA ( base , - lx , fd - > viewaxis [ 1 ] , point ) ;
VectorMA ( point , ly , fd - > viewaxis [ 2 ] , point ) ;
Matrix16Transform ( lightViewMatrix , point , lightViewPoint ) ;
AddPointToBounds ( lightViewPoint , lightviewBounds [ 0 ] , lightviewBounds [ 1 ] ) ;
VectorMA ( base , lx , fd - > viewaxis [ 1 ] , point ) ;
VectorMA ( point , - ly , fd - > viewaxis [ 2 ] , point ) ;
Matrix16Transform ( lightViewMatrix , point , lightViewPoint ) ;
AddPointToBounds ( lightViewPoint , lightviewBounds [ 0 ] , lightviewBounds [ 1 ] ) ;
VectorMA ( base , - lx , fd - > viewaxis [ 1 ] , point ) ;
VectorMA ( point , - ly , fd - > viewaxis [ 2 ] , point ) ;
Matrix16Transform ( lightViewMatrix , point , lightViewPoint ) ;
AddPointToBounds ( lightViewPoint , lightviewBounds [ 0 ] , lightviewBounds [ 1 ] ) ;
if ( ! glRefConfig . depthClamp )
lightviewBounds [ 0 ] [ 0 ] = lightviewBounds [ 1 ] [ 0 ] - 8192 ;
// Moving the Light in Texel-Sized Increments
// from http://msdn.microsoft.com/en-us/library/windows/desktop/ee416324%28v=vs.85%29.aspx
//
if ( lightViewIndependentOfCameraView )
{
float cascadeBound , worldUnitsPerTexel , invWorldUnitsPerTexel ;
cascadeBound = MAX ( lightviewBounds [ 1 ] [ 0 ] - lightviewBounds [ 0 ] [ 0 ] , lightviewBounds [ 1 ] [ 1 ] - lightviewBounds [ 0 ] [ 1 ] ) ;
cascadeBound = MAX ( cascadeBound , lightviewBounds [ 1 ] [ 2 ] - lightviewBounds [ 0 ] [ 2 ] ) ;
worldUnitsPerTexel = cascadeBound / tr . sunShadowFbo [ level ] - > width ;
invWorldUnitsPerTexel = 1.0f / worldUnitsPerTexel ;
VectorScale ( lightviewBounds [ 0 ] , invWorldUnitsPerTexel , lightviewBounds [ 0 ] ) ;
lightviewBounds [ 0 ] [ 0 ] = floor ( lightviewBounds [ 0 ] [ 0 ] ) ;
lightviewBounds [ 0 ] [ 1 ] = floor ( lightviewBounds [ 0 ] [ 1 ] ) ;
lightviewBounds [ 0 ] [ 2 ] = floor ( lightviewBounds [ 0 ] [ 2 ] ) ;
VectorScale ( lightviewBounds [ 0 ] , worldUnitsPerTexel , lightviewBounds [ 0 ] ) ;
VectorScale ( lightviewBounds [ 1 ] , invWorldUnitsPerTexel , lightviewBounds [ 1 ] ) ;
lightviewBounds [ 1 ] [ 0 ] = floor ( lightviewBounds [ 1 ] [ 0 ] ) ;
lightviewBounds [ 1 ] [ 1 ] = floor ( lightviewBounds [ 1 ] [ 1 ] ) ;
lightviewBounds [ 1 ] [ 2 ] = floor ( lightviewBounds [ 1 ] [ 2 ] ) ;
VectorScale ( lightviewBounds [ 1 ] , worldUnitsPerTexel , lightviewBounds [ 1 ] ) ;
}
//ri.Printf(PRINT_ALL, "znear %f zfar %f\n", lightviewBounds[0][0], lightviewBounds[1][0]);
//ri.Printf(PRINT_ALL, "fovx %f fovy %f xmin %f xmax %f ymin %f ymax %f\n", fd->fov_x, fd->fov_y, xmin, xmax, ymin, ymax);
}
{
int firstDrawSurf ;
Com_Memset ( & shadowParms , 0 , sizeof ( shadowParms ) ) ;
if ( glRefConfig . framebufferObject )
{
shadowParms . viewportX = 0 ;
shadowParms . viewportY = 0 ;
}
else
{
shadowParms . viewportX = tr . refdef . x ;
shadowParms . viewportY = glConfig . vidHeight - ( tr . refdef . y + tr . sunShadowFbo [ level ] - > height ) ;
}
shadowParms . viewportWidth = tr . sunShadowFbo [ level ] - > width ;
shadowParms . viewportHeight = tr . sunShadowFbo [ level ] - > height ;
shadowParms . isPortal = qfalse ;
shadowParms . isMirror = qfalse ;
shadowParms . fovX = 90 ;
shadowParms . fovY = 90 ;
if ( glRefConfig . framebufferObject )
shadowParms . targetFbo = tr . sunShadowFbo [ level ] ;
2013-09-16 07:54:26 +00:00
shadowParms . flags = VPF_DEPTHSHADOW | VPF_DEPTHCLAMP | VPF_ORTHOGRAPHIC | VPF_NOVIEWMODEL ;
2012-10-26 01:23:06 +00:00
shadowParms . zFar = lightviewBounds [ 1 ] [ 0 ] ;
VectorCopy ( lightOrigin , shadowParms . or . origin ) ;
VectorCopy ( lightViewAxis [ 0 ] , shadowParms . or . axis [ 0 ] ) ;
VectorCopy ( lightViewAxis [ 1 ] , shadowParms . or . axis [ 1 ] ) ;
VectorCopy ( lightViewAxis [ 2 ] , shadowParms . or . axis [ 2 ] ) ;
VectorCopy ( lightOrigin , shadowParms . pvsOrigin ) ;
{
tr . viewCount + + ;
tr . viewParms = shadowParms ;
tr . viewParms . frameSceneNum = tr . frameSceneNum ;
tr . viewParms . frameCount = tr . frameCount ;
firstDrawSurf = tr . refdef . numDrawSurfs ;
tr . viewCount + + ;
// set viewParms.world
R_RotateForViewer ( ) ;
R_SetupProjectionOrtho ( & tr . viewParms , lightviewBounds ) ;
R_AddWorldSurfaces ( ) ;
R_AddPolygonSurfaces ( ) ;
R_AddEntitySurfaces ( ) ;
R_SortDrawSurfs ( tr . refdef . drawSurfs + firstDrawSurf , tr . refdef . numDrawSurfs - firstDrawSurf ) ;
}
Matrix16Multiply ( tr . viewParms . projectionMatrix , tr . viewParms . world . modelMatrix , tr . refdef . sunShadowMvp [ level ] ) ;
}
}
2013-09-16 07:54:26 +00:00
void R_RenderCubemapSide ( int cubemapIndex , int cubemapSide , qboolean subscene )
{
refdef_t refdef ;
viewParms_t parms ;
float oldColorScale = tr . refdef . colorScale ;
memset ( & refdef , 0 , sizeof ( refdef ) ) ;
refdef . rdflags = 0 ;
VectorCopy ( tr . cubemapOrigins [ cubemapIndex ] , refdef . vieworg ) ;
switch ( cubemapSide )
{
case 0 :
// -X
VectorSet ( refdef . viewaxis [ 0 ] , - 1 , 0 , 0 ) ;
VectorSet ( refdef . viewaxis [ 1 ] , 0 , 0 , - 1 ) ;
VectorSet ( refdef . viewaxis [ 2 ] , 0 , 1 , 0 ) ;
break ;
case 1 :
// +X
VectorSet ( refdef . viewaxis [ 0 ] , 1 , 0 , 0 ) ;
VectorSet ( refdef . viewaxis [ 1 ] , 0 , 0 , 1 ) ;
VectorSet ( refdef . viewaxis [ 2 ] , 0 , 1 , 0 ) ;
break ;
case 2 :
// -Y
VectorSet ( refdef . viewaxis [ 0 ] , 0 , - 1 , 0 ) ;
VectorSet ( refdef . viewaxis [ 1 ] , 1 , 0 , 0 ) ;
VectorSet ( refdef . viewaxis [ 2 ] , 0 , 0 , - 1 ) ;
break ;
case 3 :
// +Y
VectorSet ( refdef . viewaxis [ 0 ] , 0 , 1 , 0 ) ;
VectorSet ( refdef . viewaxis [ 1 ] , 1 , 0 , 0 ) ;
VectorSet ( refdef . viewaxis [ 2 ] , 0 , 0 , 1 ) ;
break ;
case 4 :
// -Z
VectorSet ( refdef . viewaxis [ 0 ] , 0 , 0 , - 1 ) ;
VectorSet ( refdef . viewaxis [ 1 ] , 1 , 0 , 0 ) ;
VectorSet ( refdef . viewaxis [ 2 ] , 0 , 1 , 0 ) ;
break ;
case 5 :
// +Z
VectorSet ( refdef . viewaxis [ 0 ] , 0 , 0 , 1 ) ;
VectorSet ( refdef . viewaxis [ 1 ] , - 1 , 0 , 0 ) ;
VectorSet ( refdef . viewaxis [ 2 ] , 0 , 1 , 0 ) ;
break ;
}
refdef . fov_x = 90 ;
refdef . fov_y = 90 ;
refdef . x = 0 ;
refdef . y = 0 ;
refdef . width = tr . renderCubeFbo - > width ;
refdef . height = tr . renderCubeFbo - > height ;
refdef . time = 0 ;
if ( ! subscene )
{
RE_BeginScene ( & refdef ) ;
// FIXME: sun shadows aren't rendered correctly in cubemaps
// fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first
if ( 0 ) //(glRefConfig.framebufferObject && (r_forceSun->integer || tr.sunShadows))
{
R_RenderSunShadowMaps ( & refdef , 0 ) ;
R_RenderSunShadowMaps ( & refdef , 1 ) ;
R_RenderSunShadowMaps ( & refdef , 2 ) ;
}
}
{
vec3_t ambient , directed , lightDir ;
R_LightForPoint ( tr . refdef . vieworg , ambient , directed , lightDir ) ;
tr . refdef . colorScale = 766.0f / ( directed [ 0 ] + directed [ 1 ] + directed [ 2 ] + 1.0f ) ;
if ( directed [ 0 ] + directed [ 1 ] + directed [ 2 ] = = 0 )
{
ri . Printf ( PRINT_ALL , " cubemap %d (%f, %f, %f) is outside the lightgrid! \n " , cubemapIndex , tr . refdef . vieworg [ 0 ] , tr . refdef . vieworg [ 1 ] , tr . refdef . vieworg [ 2 ] ) ;
}
}
Com_Memset ( & parms , 0 , sizeof ( parms ) ) ;
parms . viewportX = 0 ;
parms . viewportY = 0 ;
parms . viewportWidth = tr . renderCubeFbo - > width ;
parms . viewportHeight = tr . renderCubeFbo - > height ;
parms . isPortal = qfalse ;
parms . isMirror = qtrue ;
parms . flags = VPF_NOVIEWMODEL | VPF_NOCUBEMAPS ;
parms . fovX = 90 ;
parms . fovY = 90 ;
VectorCopy ( refdef . vieworg , parms . or . origin ) ;
VectorCopy ( refdef . viewaxis [ 0 ] , parms . or . axis [ 0 ] ) ;
VectorCopy ( refdef . viewaxis [ 1 ] , parms . or . axis [ 1 ] ) ;
VectorCopy ( refdef . viewaxis [ 2 ] , parms . or . axis [ 2 ] ) ;
VectorCopy ( refdef . vieworg , parms . pvsOrigin ) ;
// FIXME: sun shadows aren't rendered correctly in cubemaps
// fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first
if ( 0 ) //(r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows))
{
parms . flags = VPF_USESUNLIGHT ;
}
parms . targetFbo = tr . renderCubeFbo ;
parms . targetFboLayer = cubemapSide ;
parms . targetFboCubemapIndex = cubemapIndex ;
R_RenderView ( & parms ) ;
if ( subscene )
{
tr . refdef . colorScale = oldColorScale ;
}
else
{
RE_EndScene ( ) ;
}
}