2013-04-19 02:52:48 +00:00
//Anything above this #include will be ignored by the compiler
# include "../qcommon/exe_headers.h"
# include "tr_local.h"
# ifdef VV_LIGHTING
# include "tr_lightmanager.h"
# endif
# ifdef _XBOX
# include "../qcommon/sparc.h"
static bool lookingForWorstLeaf = false ;
# endif
# ifndef _XBOX
inline void Q_CastShort2Float ( float * f , const short * s )
{
* f = ( ( float ) * s ) ;
}
# endif
# ifdef _XBOX
static bool GetCoordsForLeaf ( int leafNum , vec3_t coords )
{
srfSurfaceFace_t * face ;
msurface_t * surf ;
int i ;
for ( i = 0 ; i < tr . world - > leafs [ leafNum ] . nummarksurfaces ; i + + ) {
surf = * ( tr . world - > marksurfaces +
tr . world - > leafs [ leafNum ] . firstMarkSurfNum + i ) ;
if ( ! surf - > data | | * surf - > data ! = SF_FACE ) {
continue ;
}
face = ( srfSurfaceFace_t * ) surf - > data ;
Q_CastShort2Float ( & coords [ 0 ] , ( short * ) ( face - > srfPoints + 0 ) ) ;
Q_CastShort2Float ( & coords [ 1 ] , ( short * ) ( face - > srfPoints + 1 ) ) ;
Q_CastShort2Float ( & coords [ 2 ] , ( short * ) ( face - > srfPoints + 2 ) ) ;
return true ;
}
return false ;
}
# endif
/*
= = = = = = = = = = = = = = = = =
R_CullTriSurf
Returns true if the grid is completely culled away .
Also sets the clipped hint bit in tess
= = = = = = = = = = = = = = = = =
*/
static qboolean R_CullTriSurf ( srfTriangles_t * cv ) {
int boxCull ;
boxCull = R_CullLocalBox ( cv - > bounds ) ;
if ( boxCull = = CULL_OUT ) {
return qtrue ;
}
return qfalse ;
}
/*
= = = = = = = = = = = = = = = = =
R_CullGrid
Returns true if the grid is completely culled away .
Also sets the clipped hint bit in tess
= = = = = = = = = = = = = = = = =
*/
static qboolean R_CullGrid ( srfGridMesh_t * cv ) {
int boxCull ;
int sphereCull ;
if ( r_nocurves - > integer ) {
return qtrue ;
}
if ( tr . currentEntityNum ! = TR_WORLDENT ) {
sphereCull = R_CullLocalPointAndRadius ( cv - > localOrigin , cv - > meshRadius ) ;
} else {
sphereCull = R_CullPointAndRadius ( cv - > localOrigin , cv - > meshRadius ) ;
}
boxCull = CULL_OUT ;
// check for trivial reject
if ( sphereCull = = CULL_OUT )
{
tr . pc . c_sphere_cull_patch_out + + ;
return qtrue ;
}
// check bounding box if necessary
else if ( sphereCull = = CULL_CLIP )
{
tr . pc . c_sphere_cull_patch_clip + + ;
boxCull = R_CullLocalBox ( cv - > meshBounds ) ;
if ( boxCull = = CULL_OUT )
{
tr . pc . c_box_cull_patch_out + + ;
return qtrue ;
}
else if ( boxCull = = CULL_IN )
{
tr . pc . c_box_cull_patch_in + + ;
}
else
{
tr . pc . c_box_cull_patch_clip + + ;
}
}
else
{
tr . pc . c_sphere_cull_patch_in + + ;
}
return qfalse ;
}
/*
= = = = = = = = = = = = = = = =
R_CullSurface
Tries to back face cull surfaces before they are lighted or
added to the sorting list .
This will also allow mirrors on both sides of a model without recursion .
= = = = = = = = = = = = = = = =
*/
static qboolean R_CullSurface ( surfaceType_t * surface , shader_t * shader ) {
srfSurfaceFace_t * sface ;
float d ;
if ( r_nocull - > integer ) {
return qfalse ;
}
if ( * surface = = SF_GRID ) {
return R_CullGrid ( ( srfGridMesh_t * ) surface ) ;
}
if ( * surface = = SF_TRIANGLES ) {
return R_CullTriSurf ( ( srfTriangles_t * ) surface ) ;
}
if ( * surface ! = SF_FACE ) {
return qfalse ;
}
if ( shader - > cullType = = CT_TWO_SIDED ) {
return qfalse ;
}
// face culling
if ( ! r_facePlaneCull - > integer ) {
return qfalse ;
}
sface = ( srfSurfaceFace_t * ) surface ;
if ( r_cullRoofFaces - > integer )
{ //Very slow, but this is only intended for taking shots for automap images.
if ( sface - > plane . normal [ 2 ] > 0.0f & &
sface - > numPoints > 0 )
{ //it's facing up I guess
static int i ;
static trace_t tr ;
static vec3_t basePoint ;
static vec3_t endPoint ;
static vec3_t nNormal ;
static vec3_t v ;
//The fact that this point is in the middle of the array has no relation to the
//orientation in the surface outline.
# ifdef _XBOX
Q_CastShort2Float ( & basePoint [ 0 ] , ( short * ) ( sface - > srfPoints + ( sface - > numPoints / 2 ) + 0 ) ) ;
Q_CastShort2Float ( & basePoint [ 1 ] , ( short * ) ( sface - > srfPoints + ( sface - > numPoints / 2 ) + 1 ) ) ;
Q_CastShort2Float ( & basePoint [ 2 ] , ( short * ) ( sface - > srfPoints + ( sface - > numPoints / 2 ) + 2 ) ) ;
# else
basePoint [ 0 ] = sface - > points [ sface - > numPoints / 2 ] [ 0 ] ;
basePoint [ 1 ] = sface - > points [ sface - > numPoints / 2 ] [ 1 ] ;
basePoint [ 2 ] = sface - > points [ sface - > numPoints / 2 ] [ 2 ] ;
# endif
basePoint [ 2 ] + = 2.0f ;
//the endpoint will be 8192 units from the chosen point
//in the direction of the surface normal
//just go straight up I guess, for now (slight hack)
VectorSet ( nNormal , 0.0f , 0.0f , 1.0f ) ;
VectorMA ( basePoint , 8192.0f , nNormal , endPoint ) ;
CM_BoxTrace ( & tr , basePoint , endPoint , NULL , NULL , 0 , ( CONTENTS_SOLID | CONTENTS_TERRAIN ) , qfalse ) ;
if ( ! tr . startsolid & &
! tr . allsolid & &
( tr . fraction = = 1.0f | | ( tr . surfaceFlags & SURF_NOIMPACT ) ) )
{ //either hit nothing or sky, so this surface is near the top of the level I guess. Or the floor of a really tall room, but if that's the case we're just screwed.
VectorSubtract ( basePoint , tr . endpos , v ) ;
if ( tr . fraction = = 1.0f | | VectorLength ( v ) < r_roofCullCeilDist - > value )
{ //ignore it if it's not close to the top, unless it just hit nothing
//Let's try to dig back into the brush based on the negative direction of the plane,
//and if we pop out on the other side we'll see if it's ground or not.
i = 4 ;
VectorCopy ( sface - > plane . normal , nNormal ) ;
VectorInverse ( nNormal ) ;
while ( i < 4096 )
{
VectorMA ( basePoint , i , nNormal , endPoint ) ;
CM_BoxTrace ( & tr , endPoint , endPoint , NULL , NULL , 0 , ( CONTENTS_SOLID | CONTENTS_TERRAIN ) , qfalse ) ;
if ( ! tr . startsolid & &
! tr . allsolid & &
tr . fraction = = 1.0f )
{ //in the clear
break ;
}
i + + ;
}
if ( i < 4096 )
{ //Make sure we got into clearance
VectorCopy ( endPoint , basePoint ) ;
basePoint [ 2 ] - = 2.0f ;
//just go straight down I guess, for now (slight hack)
VectorSet ( nNormal , 0.0f , 0.0f , - 1.0f ) ;
VectorMA ( basePoint , 4096.0f , nNormal , endPoint ) ;
//trace a second time from the clear point in the inverse normal direction of the surface.
//If we hit something within a set amount of units, we will assume it's a bridge type object
//and leave it to be drawn. Otherwise we will assume it is a roof or other obstruction and
//cull it out.
CM_BoxTrace ( & tr , basePoint , endPoint , NULL , NULL , 0 , ( CONTENTS_SOLID | CONTENTS_TERRAIN ) , qfalse ) ;
if ( ! tr . startsolid & &
! tr . allsolid & &
( tr . fraction ! = 1.0f & & ! ( tr . surfaceFlags & SURF_NOIMPACT ) ) )
{ //if we hit nothing or a noimpact going down then this is probably "ground".
VectorSubtract ( basePoint , tr . endpos , endPoint ) ;
if ( VectorLength ( endPoint ) > r_roofCullCeilDist - > value )
{ //128 (by default) is our maximum tolerance, above that will be removed
return qtrue ;
}
}
}
}
}
}
}
d = DotProduct ( tr . ori . viewOrigin , sface - > plane . normal ) ;
// don't cull exactly on the plane, because there are levels of rounding
// through the BSP, ICD, and hardware that may cause pixel gaps if an
// epsilon isn't allowed here
if ( shader - > cullType = = CT_FRONT_SIDED ) {
if ( d < sface - > plane . dist - 8 ) {
return qtrue ;
}
} else {
if ( d > sface - > plane . dist + 8 ) {
return qtrue ;
}
}
return qfalse ;
}
# ifndef VV_LIGHTING
static int R_DlightFace ( srfSurfaceFace_t * face , int dlightBits ) {
float d ;
int i ;
dlight_t * dl ;
for ( i = 0 ; i < tr . refdef . num_dlights ; i + + ) {
if ( ! ( dlightBits & ( 1 < < i ) ) ) {
continue ;
}
dl = & tr . refdef . dlights [ i ] ;
d = DotProduct ( dl - > origin , face - > plane . normal ) - face - > plane . dist ;
if ( ! VectorCompare ( face - > plane . normal , vec3_origin ) & & ( d < - dl - > radius | | d > dl - > radius ) ) {
// dlight doesn't reach the plane
dlightBits & = ~ ( 1 < < i ) ;
}
}
if ( ! dlightBits ) {
tr . pc . c_dlightSurfacesCulled + + ;
}
face - > dlightBits = dlightBits ;
return dlightBits ;
}
static int R_DlightGrid ( srfGridMesh_t * grid , int dlightBits ) {
int i ;
dlight_t * dl ;
for ( i = 0 ; i < tr . refdef . num_dlights ; i + + ) {
if ( ! ( dlightBits & ( 1 < < i ) ) ) {
continue ;
}
dl = & tr . refdef . dlights [ i ] ;
if ( dl - > origin [ 0 ] - dl - > radius > grid - > meshBounds [ 1 ] [ 0 ]
| | dl - > origin [ 0 ] + dl - > radius < grid - > meshBounds [ 0 ] [ 0 ]
| | dl - > origin [ 1 ] - dl - > radius > grid - > meshBounds [ 1 ] [ 1 ]
| | dl - > origin [ 1 ] + dl - > radius < grid - > meshBounds [ 0 ] [ 1 ]
| | dl - > origin [ 2 ] - dl - > radius > grid - > meshBounds [ 1 ] [ 2 ]
| | dl - > origin [ 2 ] + dl - > radius < grid - > meshBounds [ 0 ] [ 2 ] ) {
// dlight doesn't reach the bounds
dlightBits & = ~ ( 1 < < i ) ;
}
}
if ( ! dlightBits ) {
tr . pc . c_dlightSurfacesCulled + + ;
}
grid - > dlightBits = dlightBits ;
return dlightBits ;
}
static int R_DlightTrisurf ( srfTriangles_t * surf , int dlightBits ) {
// FIXME: more dlight culling to trisurfs...
surf - > dlightBits = dlightBits ;
return dlightBits ;
#if 0
int i ;
dlight_t * dl ;
for ( i = 0 ; i < tr . refdef . num_dlights ; i + + ) {
if ( ! ( dlightBits & ( 1 < < i ) ) ) {
continue ;
}
dl = & tr . refdef . dlights [ i ] ;
if ( dl - > origin [ 0 ] - dl - > radius > grid - > meshBounds [ 1 ] [ 0 ]
| | dl - > origin [ 0 ] + dl - > radius < grid - > meshBounds [ 0 ] [ 0 ]
| | dl - > origin [ 1 ] - dl - > radius > grid - > meshBounds [ 1 ] [ 1 ]
| | dl - > origin [ 1 ] + dl - > radius < grid - > meshBounds [ 0 ] [ 1 ]
| | dl - > origin [ 2 ] - dl - > radius > grid - > meshBounds [ 1 ] [ 2 ]
| | dl - > origin [ 2 ] + dl - > radius < grid - > meshBounds [ 0 ] [ 2 ] ) {
// dlight doesn't reach the bounds
dlightBits & = ~ ( 1 < < i ) ;
}
}
if ( ! dlightBits ) {
tr . pc . c_dlightSurfacesCulled + + ;
}
grid - > dlightBits = dlightBits ;
return dlightBits ;
# endif
}
/*
= = = = = = = = = = = = = = = = = = = =
R_DlightSurface
The given surface is going to be drawn , and it touches a leaf
that is touched by one or more dlights , so try to throw out
more dlights if possible .
= = = = = = = = = = = = = = = = = = = =
*/
static int R_DlightSurface ( msurface_t * surf , int dlightBits ) {
if ( * surf - > data = = SF_FACE ) {
dlightBits = R_DlightFace ( ( srfSurfaceFace_t * ) surf - > data , dlightBits ) ;
} else if ( * surf - > data = = SF_GRID ) {
dlightBits = R_DlightGrid ( ( srfGridMesh_t * ) surf - > data , dlightBits ) ;
} else if ( * surf - > data = = SF_TRIANGLES ) {
dlightBits = R_DlightTrisurf ( ( srfTriangles_t * ) surf - > data , dlightBits ) ;
} else {
dlightBits = 0 ;
}
if ( dlightBits ) {
tr . pc . c_dlightSurfaces + + ;
}
return dlightBits ;
}
# endif // VV_LIGHTING
# ifdef _ALT_AUTOMAP_METHOD
static bool tr_drawingAutoMap = false ;
# endif
static float g_playerHeight = 0.0f ;
/*
= = = = = = = = = = = = = = = = = = = = = =
R_AddWorldSurface
= = = = = = = = = = = = = = = = = = = = = =
*/
# ifdef VV_LIGHTING
void R_AddWorldSurface ( msurface_t * surf , int dlightBits , qboolean noViewCount )
# else
static void R_AddWorldSurface ( msurface_t * surf , int dlightBits , qboolean noViewCount = qfalse )
# endif
{
if ( ! noViewCount )
{
if ( surf - > viewCount = = tr . viewCount )
{
// already in this view, but lets make sure all the dlight bits are set
if ( * surf - > data = = SF_FACE )
{
( ( srfSurfaceFace_t * ) surf - > data ) - > dlightBits | = dlightBits ;
}
else if ( * surf - > data = = SF_GRID )
{
( ( srfGridMesh_t * ) surf - > data ) - > dlightBits | = dlightBits ;
}
else if ( * surf - > data = = SF_TRIANGLES )
{
( ( srfTriangles_t * ) surf - > data ) - > dlightBits | = dlightBits ;
}
return ;
}
surf - > viewCount = tr . viewCount ;
// FIXME: bmodel fog?
}
/*
if ( r_shadows - > integer = = 2 )
{
dlightBits = R_DlightSurface ( surf , dlightBits ) ;
//dlightBits = ( dlightBits != 0 );
R_AddDrawSurf ( surf - > data , tr . shadowShader , surf - > fogIndex , dlightBits ) ;
}
*/
//world shadows?
// try to cull before dlighting or adding
# ifdef _ALT_AUTOMAP_METHOD
if ( ! tr_drawingAutoMap & & R_CullSurface ( surf - > data , surf - > shader ) )
# else
if ( R_CullSurface ( surf - > data , surf - > shader ) )
# endif
{
return ;
}
// check for dlighting
if ( dlightBits ) {
# ifdef VV_LIGHTING
dlightBits = VVLightMan . R_DlightSurface ( surf , dlightBits ) ;
# else
dlightBits = R_DlightSurface ( surf , dlightBits ) ;
# endif
dlightBits = ( dlightBits ! = 0 ) ;
}
# ifdef _ALT_AUTOMAP_METHOD
if ( tr_drawingAutoMap )
{
// if (g_playerHeight != g_lastHeight ||
// !g_lastHeightValid)
if ( * surf - > data = = SF_FACE )
{ //only do this if we need to
bool completelyTransparent = true ;
int i = 0 ;
srfSurfaceFace_t * face = ( srfSurfaceFace_t * ) surf - > data ;
byte * indices = ( byte * ) ( face + face - > ofsIndices ) ;
float * point ;
vec3_t color ;
float alpha ;
float e ;
bool polyStarted = false ;
while ( i < face - > numIndices )
{
point = & face - > points [ indices [ i ] ] [ 0 ] ;
//base the color on the elevation... for now, just check the first point height
if ( point [ 2 ] < g_playerHeight )
{
e = point [ 2 ] - g_playerHeight ;
}
else
{
e = g_playerHeight - point [ 2 ] ;
}
if ( e < 0.0f )
{
e = - e ;
}
//set alpha and color based on relative height of point
alpha = e / 256.0f ;
e / = 512.0f ;
//cap color
if ( e > 1.0f )
{
e = 1.0f ;
}
else if ( e < 0.0f )
{
e = 0.0f ;
}
VectorSet ( color , e , 1.0f - e , 0.0f ) ;
//cap alpha
if ( alpha > 1.0f )
{
alpha = 1.0f ;
}
else if ( alpha < 0.0f )
{
alpha = 0.0f ;
}
if ( alpha ! = 1.0f )
{ //this point is not entirely alpha'd out, so still draw the surface
completelyTransparent = false ;
}
if ( ! completelyTransparent )
{
if ( ! polyStarted )
{
qglBegin ( GL_POLYGON ) ;
polyStarted = true ;
}
qglColor4f ( color [ 0 ] , color [ 1 ] , color [ 2 ] , 1.0f - alpha ) ;
qglVertex3f ( point [ i ] , point [ i ] , point [ 2 ] ) ;
}
i + + ;
}
if ( polyStarted )
{
qglEnd ( ) ;
}
}
}
else
# endif
{
R_AddDrawSurf ( surf - > data , surf - > shader , surf - > fogIndex , dlightBits ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
BRUSH MODELS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = =
R_AddBrushModelSurfaces
= = = = = = = = = = = = = = = = =
*/
void R_AddBrushModelSurfaces ( trRefEntity_t * ent ) {
bmodel_t * bmodel ;
int clip ;
model_t * pModel ;
int i ;
pModel = R_GetModelByHandle ( ent - > e . hModel ) ;
bmodel = pModel - > bmodel ;
clip = R_CullLocalBox ( bmodel - > bounds ) ;
if ( clip = = CULL_OUT ) {
return ;
}
if ( pModel - > bspInstance )
{ //rwwRMG - added
# ifdef VV_LIGHTING
VVLightMan . R_SetupEntityLighting ( & tr . refdef , ent ) ;
# else
R_SetupEntityLighting ( & tr . refdef , ent ) ;
# endif
}
//rww - Take this into account later?
// if (!com_RMG || !com_RMG->integer)
// { // don't dlight bmodels on rmg, as multiple copies of the same instance will light up
# ifdef VV_LIGHTING
VVLightMan . R_DlightBmodel ( bmodel , false ) ;
# else
R_DlightBmodel ( bmodel , false ) ;
# endif
// }
// else
// {
// R_DlightBmodel( bmodel, true );
// }
for ( i = 0 ; i < bmodel - > numSurfaces ; i + + ) {
R_AddWorldSurface ( bmodel - > firstSurface + i , tr . currentEntity - > dlightBits , qtrue ) ;
}
}
float GetQuadArea ( vec3_t v1 , vec3_t v2 , vec3_t v3 , vec3_t v4 )
{
vec3_t vec1 , vec2 , dis1 , dis2 ;
// Get area of tri1
VectorSubtract ( v1 , v2 , vec1 ) ;
VectorSubtract ( v1 , v4 , vec2 ) ;
CrossProduct ( vec1 , vec2 , dis1 ) ;
VectorScale ( dis1 , 0.25f , dis1 ) ;
// Get area of tri2
VectorSubtract ( v3 , v2 , vec1 ) ;
VectorSubtract ( v3 , v4 , vec2 ) ;
CrossProduct ( vec1 , vec2 , dis2 ) ;
VectorScale ( dis2 , 0.25f , dis2 ) ;
// Return addition of disSqr of each tri area
return ( dis1 [ 0 ] * dis1 [ 0 ] + dis1 [ 1 ] * dis1 [ 1 ] + dis1 [ 2 ] * dis1 [ 2 ] +
dis2 [ 0 ] * dis2 [ 0 ] + dis2 [ 1 ] * dis2 [ 1 ] + dis2 [ 2 ] * dis2 [ 2 ] ) ;
}
# ifdef _XBOX
float GetQuadArea ( unsigned short v1 [ 3 ] , unsigned short v2 [ 3 ] , unsigned short v3 [ 3 ] , unsigned short v4 [ 3 ] )
{
vec3_t fv1 ;
vec3_t fv2 ;
vec3_t fv3 ;
vec3_t fv4 ;
for ( int i = 0 ; i < 3 ; i + + ) {
Q_CastShort2Float ( & fv1 [ i ] , ( short * ) & v1 [ i ] ) ;
Q_CastShort2Float ( & fv2 [ i ] , ( short * ) & v2 [ i ] ) ;
Q_CastShort2Float ( & fv3 [ i ] , ( short * ) & v3 [ i ] ) ;
Q_CastShort2Float ( & fv4 [ i ] , ( short * ) & v4 [ i ] ) ;
}
return GetQuadArea ( fv1 , fv2 , fv3 , fv4 ) ;
}
# endif
void RE_GetBModelVerts ( int bmodelIndex , vec3_t * verts , vec3_t normal )
{
msurface_t * surfs ;
srfSurfaceFace_t * face ;
bmodel_t * bmodel ;
model_t * pModel ;
int i ;
// Not sure if we really need to track the best two candidates
int maxDist [ 2 ] = { 0 , 0 } ;
int maxIndx [ 2 ] = { 0 , 0 } ;
int dist = 0 ;
float dot1 , dot2 ;
pModel = R_GetModelByHandle ( bmodelIndex ) ;
bmodel = pModel - > bmodel ;
// Loop through all surfaces on the brush and find the best two candidates
for ( i = 0 ; i < bmodel - > numSurfaces ; i + + )
{
surfs = bmodel - > firstSurface + i ;
face = ( srfSurfaceFace_t * ) surfs - > data ;
// It seems that the safest way to handle this is by finding the area of the faces
# ifdef _XBOX
int nextSurfPoint = NEXT_SURFPOINT ( face - > flags ) ;
dist = GetQuadArea ( face - > srfPoints , face - > srfPoints + nextSurfPoint ,
face - > srfPoints + nextSurfPoint * 2 , face - > srfPoints +
nextSurfPoint * 3 ) ;
# else
dist = GetQuadArea ( face - > points [ 0 ] , face - > points [ 1 ] , face - > points [ 2 ] , face - > points [ 3 ] ) ;
# endif
// Check against the highest max
if ( dist > maxDist [ 0 ] )
{
// Shuffle our current maxes down
maxDist [ 1 ] = maxDist [ 0 ] ;
maxIndx [ 1 ] = maxIndx [ 0 ] ;
maxDist [ 0 ] = dist ;
maxIndx [ 0 ] = i ;
}
// Check against the second highest max
else if ( dist > = maxDist [ 1 ] )
{
// just stomp the old
maxDist [ 1 ] = dist ;
maxIndx [ 1 ] = i ;
}
}
// Hopefully we've found two best case candidates. Now we should see which of these faces the viewer
surfs = bmodel - > firstSurface + maxIndx [ 0 ] ;
face = ( srfSurfaceFace_t * ) surfs - > data ;
dot1 = DotProduct ( face - > plane . normal , tr . refdef . viewaxis [ 0 ] ) ;
surfs = bmodel - > firstSurface + maxIndx [ 1 ] ;
face = ( srfSurfaceFace_t * ) surfs - > data ;
dot2 = DotProduct ( face - > plane . normal , tr . refdef . viewaxis [ 0 ] ) ;
if ( dot2 < dot1 & & dot2 < 0.0f )
{
i = maxIndx [ 1 ] ; // use the second face
}
else if ( dot1 < dot2 & & dot1 < 0.0f )
{
i = maxIndx [ 0 ] ; // use the first face
}
else
{ // Possibly only have one face, so may as well use the first face, which also should be the best one
//i = rand() & 1; // ugh, we don't know which to use. I'd hope this would never happen
i = maxIndx [ 0 ] ; // use the first face
}
surfs = bmodel - > firstSurface + i ;
face = ( srfSurfaceFace_t * ) surfs - > data ;
# ifdef _XBOX
int nextSurfPoint = NEXT_SURFPOINT ( face - > flags ) ;
for ( int t = 0 ; t < 4 ; t + + )
{
Q_CastShort2Float ( & verts [ t ] [ 0 ] , ( short * ) ( face - > srfPoints + nextSurfPoint * t + 0 ) ) ;
Q_CastShort2Float ( & verts [ t ] [ 1 ] , ( short * ) ( face - > srfPoints + nextSurfPoint * t + 1 ) ) ;
Q_CastShort2Float ( & verts [ t ] [ 2 ] , ( short * ) ( face - > srfPoints + nextSurfPoint * t + 2 ) ) ;
}
# else
for ( int t = 0 ; t < 4 ; t + + )
{
VectorCopy ( face - > points [ t ] , verts [ t ] ) ;
}
# endif
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
WORLD MODEL
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
WIREFRAME AUTOMAP GENERATION SYSTEM - BEGIN
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# ifndef _ALT_AUTOMAP_METHOD
typedef struct wireframeSurfPoint_s
{
vec3_t xyz ;
float alpha ;
vec3_t color ;
} wireframeSurfPoint_t ;
typedef struct wireframeMapSurf_s
{
bool completelyTransparent ;
int numPoints ;
wireframeSurfPoint_t * points ;
wireframeMapSurf_s * next ;
} wireframeMapSurf_t ;
typedef struct wireframeMap_s
{
wireframeMapSurf_t * surfs ;
} wireframeMap_t ;
static wireframeMap_t g_autoMapFrame ;
static wireframeMapSurf_t * * g_autoMapNextFree = NULL ;
static bool g_autoMapValid = false ; //set to true of g_autoMapFrame is valid.
//get the next available wireframe automap surface. -rww
static inline wireframeMapSurf_t * R_GetNewWireframeMapSurf ( void )
{
wireframeMapSurf_t * * next = & g_autoMapFrame . surfs ;
if ( g_autoMapNextFree )
{ //save us the time of going through the entire linked list from root
next = g_autoMapNextFree ;
}
while ( * next )
{ //iterate through until we find the next unused one
next = & ( * next ) - > next ;
}
//allocate memory for it and pass it back
( * next ) = ( wireframeMapSurf_t * ) Z_Malloc ( sizeof ( wireframeMapSurf_t ) , TAG_ALL , qtrue ) ;
g_autoMapNextFree = & ( * next ) - > next ;
return ( * next ) ;
}
//evaluate a surface, see if it is valid for being part of the
//wireframe map render. -rww
# ifdef _XBOX
static inline void R_EvaluateWireframeSurf ( msurface_t * surf )
{
if ( * surf - > data = = SF_FACE )
{
srfSurfaceFace_t * face = ( srfSurfaceFace_t * ) surf - > data ;
int numPoints = face - > numPoints ;
unsigned char * indices = ( unsigned char * ) ( ( ( char * ) face ) + face - > ofsIndices ) ;
if ( numPoints > 0 )
{ //we can add it
int i = 0 ;
wireframeMapSurf_t * nextSurf = R_GetNewWireframeMapSurf ( ) ;
//now go through the indices and add a point for each
nextSurf - > points = ( wireframeSurfPoint_t * ) Z_Malloc ( sizeof ( wireframeSurfPoint_t ) * face - > numIndices , TAG_ALL , qtrue ) ;
nextSurf - > numPoints = face - > numIndices ;
while ( i < face - > numIndices )
{
vec3_t point ;
Q_CastShort2Float ( & point [ 0 ] , ( short * ) face - > srfPoints + indices [ i ] + 0 ) ;
Q_CastShort2Float ( & point [ 1 ] , ( short * ) face - > srfPoints + indices [ i ] + 1 ) ;
Q_CastShort2Float ( & point [ 2 ] , ( short * ) face - > srfPoints + indices [ i ] + 2 ) ;
VectorCopy ( point , nextSurf - > points [ i ] . xyz ) ;
i + + ;
}
}
}
else if ( * surf - > data = = SF_TRIANGLES )
{
//srfTriangles_t *surfTri = (srfTriangles_t *)surf->data;
return ; //not handled
}
else if ( * surf - > data = = SF_GRID )
{
//srfGridMesh_t *gridMesh = (srfGridMesh_t *)surf->data;
return ; //not handled
}
else
{ //...unknown type?
return ;
}
}
# else // _XBOX
static inline void R_EvaluateWireframeSurf ( msurface_t * surf )
{
if ( * surf - > data = = SF_FACE )
{
srfSurfaceFace_t * face = ( srfSurfaceFace_t * ) surf - > data ;
float * points = & face - > points [ 0 ] [ 0 ] ;
int numPoints = face - > numIndices ;
int * indices = ( int * ) ( ( byte * ) face + face - > ofsIndices ) ;
//byte *indices = (byte *)(face + face->ofsIndices);
if ( points & & numPoints > 0 )
{ //we can add it
int i = 0 ;
wireframeMapSurf_t * nextSurf = R_GetNewWireframeMapSurf ( ) ;
#if 0 //doing in realtime now
float e ;
//base the color on the elevation... for now, just check the first point height
if ( points [ 2 ] < 0.0f )
{
e = - points [ 2 ] ;
}
else
{
e = points [ 2 ] ;
}
e / = 2048.0f ;
if ( e > 1.0f )
{
e = 1.0f ;
}
else if ( e < 0.0f )
{
e = 0.0f ;
}
VectorSet ( color , e , 1.0f - e , 0.0f ) ;
# endif
//now go through the indices and add a point for each
nextSurf - > points = ( wireframeSurfPoint_t * ) Z_Malloc ( sizeof ( wireframeSurfPoint_t ) * face - > numIndices , TAG_ALL , qtrue ) ;
nextSurf - > numPoints = face - > numIndices ;
while ( i < face - > numIndices )
{
points = & face - > points [ indices [ i ] ] [ 0 ] ;
VectorCopy ( points , nextSurf - > points [ i ] . xyz ) ;
i + + ;
}
}
}
else if ( * surf - > data = = SF_TRIANGLES )
{
//srfTriangles_t *surfTri = (srfTriangles_t *)surf->data;
return ; //not handled
}
else if ( * surf - > data = = SF_GRID )
{
//srfGridMesh_t *gridMesh = (srfGridMesh_t *)surf->data;
return ; //not handled
}
else
{ //...unknown type?
return ;
}
}
# endif // _XBOX
//see if any surfaces on the node are facing opposite directions
//using plane normals. -rww
static inline bool R_NodeHasOppositeFaces ( mnode_t * node )
{
int c , d ;
msurface_t * surf , * surf2 , * * mark , * * mark2 ;
srfSurfaceFace_t * face , * face2 ;
vec3_t normalDif ;
# ifdef _XBOX
mleaf_s * leaf ;
leaf = ( mleaf_s * ) node ;
mark = tr . world - > marksurfaces + leaf - > firstMarkSurfNum ;
c = leaf - > nummarksurfaces ;
# else
mark = node - > firstmarksurface ;
c = node - > nummarksurfaces ;
# endif
while ( c - - )
{
surf = * mark ;
if ( * surf - > data ! = SF_FACE )
{ //if this node is not entirely comprised of faces, I guess we shouldn't check it?
return false ;
}
face = ( srfSurfaceFace_t * ) surf - > data ;
//go through other surfs and compare against this surf
# ifdef _XBOX
leaf = ( mleaf_s * ) node ;
d = leaf - > nummarksurfaces ;
mark2 = tr . world - > marksurfaces + leaf - > firstMarkSurfNum ;
# else
d = node - > nummarksurfaces ;
mark2 = node - > firstmarksurface ;
# endif
while ( d - - )
{
surf2 = * mark2 ;
if ( * surf2 - > data ! = SF_FACE )
{
return false ;
}
face2 = ( srfSurfaceFace_t * ) surf2 - > data ;
//see if this normal has a drastic angular change
VectorSubtract ( face - > plane . normal , face2 - > plane . normal , normalDif ) ;
if ( VectorLength ( normalDif ) > = 1.8f )
{
return true ;
}
mark2 + + ;
}
mark + + ;
}
return false ;
}
//recursively called for each node to go through the surfaces on that
//node and generate the wireframe map. -rww
static inline void R_RecursiveWireframeSurf ( mnode_t * node )
{
int c ;
msurface_t * surf , * * mark ;
if ( ! node )
{
return ;
}
while ( 1 )
{
if ( ! node | |
node - > visframe ! = tr . visCount )
{ //not valid, stop this chain of recursion
return ;
}
if ( node - > contents ! = - 1 )
{
break ;
}
R_RecursiveWireframeSurf ( node - > children [ 0 ] ) ;
node = node - > children [ 1 ] ;
}
// add the individual surfaces
# ifdef _XBOX
mleaf_s * leaf ;
leaf = ( mleaf_s * ) node ;
mark = tr . world - > marksurfaces + leaf - > firstMarkSurfNum ;
c = leaf - > nummarksurfaces ;
# else
mark = node - > firstmarksurface ;
c = node - > nummarksurfaces ;
# endif
while ( c - - )
{
// the surface may have already been added if it
// spans multiple leafs
surf = * mark ;
R_EvaluateWireframeSurf ( surf ) ;
mark + + ;
}
}
//generates a wireframe model of the map for the automap view -rww
static void R_GenerateWireframeMap ( mnode_t * baseNode )
{
int i ;
//initialize data to all 0
memset ( & g_autoMapFrame , 0 , sizeof ( g_autoMapFrame ) ) ;
//take the hit for this frame, mark all of these things as visible
//so we know which are valid for automap generation, but only the
//ones that are facing outside the world! (well, ideally.)
for ( i = 0 ; i < tr . world - > numnodes ; i + + )
{
if ( tr . world - > nodes [ i ] . contents ! = CONTENTS_SOLID )
{
#if 0 //doesn't work, I take it surfs on nodes are not related to surfs on brushes
if ( ! R_NodeHasOppositeFaces ( & tr . world - > nodes [ i ] ) )
# endif
{
tr . world - > nodes [ i ] . visframe = tr . visCount ;
}
}
}
//now start the recursive evaluation
R_RecursiveWireframeSurf ( baseNode ) ;
}
//clear out the wireframe map data -rww
void R_DestroyWireframeMap ( void )
{
wireframeMapSurf_t * next ;
wireframeMapSurf_t * last ;
if ( ! g_autoMapValid )
{ //not valid to begin with
return ;
}
next = g_autoMapFrame . surfs ;
while ( next )
{
//free memory allocated for points on this surface
Z_Free ( next - > points ) ;
//get the next surface
last = next ;
next = next - > next ;
//free memory for this surface
Z_Free ( last ) ;
}
//invalidate everything
memset ( & g_autoMapFrame , 0 , sizeof ( g_autoMapFrame ) ) ;
g_autoMapValid = false ;
g_autoMapNextFree = NULL ;
}
//save 3d automap data to file -rww
qboolean R_WriteWireframeMapToFile ( void )
{
fileHandle_t f ;
int requiredSize = 0 ;
wireframeMapSurf_t * surf = g_autoMapFrame . surfs ;
byte * out , * rOut ;
//let's go through and see how much space we're going to need to stuff all this
//data into
while ( surf )
{
//memory for each point
requiredSize + = sizeof ( wireframeSurfPoint_t ) * surf - > numPoints ;
//memory for numPoints
requiredSize + = sizeof ( int ) ;
surf = surf - > next ;
}
if ( requiredSize < = 0 )
{ //nothing to do..?
return qfalse ;
}
f = FS_FOpenFileWrite ( " blahblah.bla " ) ;
if ( ! f )
{ //can't create?
return qfalse ;
}
//allocate the memory we will need
out = ( byte * ) Z_Malloc ( requiredSize , TAG_ALL , qtrue ) ;
rOut = out ;
//now go through and put the data into the memory
surf = g_autoMapFrame . surfs ;
while ( surf )
{
memcpy ( out , surf , ( sizeof ( wireframeSurfPoint_t ) * surf - > numPoints ) + sizeof ( int ) ) ;
//memory for each point
out + = sizeof ( wireframeSurfPoint_t ) * surf - > numPoints ;
//memory for numPoints
out + = sizeof ( int ) ;
surf = surf - > next ;
}
//now write the buffer, and close
FS_Write ( rOut , requiredSize , f ) ;
Z_Free ( rOut ) ;
FS_FCloseFile ( f ) ;
return qtrue ;
}
//load 3d automap data from file -rww
qboolean R_GetWireframeMapFromFile ( void )
{
wireframeMapSurf_t * surfs , * rSurfs ;
wireframeMapSurf_t * newSurf ;
fileHandle_t f ;
int i = 0 ;
int len ;
int stepBytes ;
len = FS_FOpenFileRead ( " blahblah.bla " , & f , qfalse ) ;
if ( ! f | | len < = 0 )
{ //it doesn't exist
return qfalse ;
}
surfs = ( wireframeMapSurf_t * ) Z_Malloc ( len , TAG_ALL , qtrue ) ;
rSurfs = surfs ;
FS_Read ( surfs , len , f ) ;
while ( i < len )
{
newSurf = R_GetNewWireframeMapSurf ( ) ;
newSurf - > points = ( wireframeSurfPoint_t * ) Z_Malloc ( sizeof ( wireframeSurfPoint_t ) * surfs - > numPoints , TAG_ALL , qtrue ) ;
//copy the surf data into the new surf
//note - the surfs->points pointer is NOT pointing to valid memory, a pointer to that
//pointer is actually what we want to use as the location of the point offsets.
memcpy ( newSurf - > points , & surfs - > points , sizeof ( wireframeSurfPoint_t ) * surfs - > numPoints ) ;
newSurf - > numPoints = surfs - > numPoints ;
//the size of the point data, plus an int (the number of points)
stepBytes = ( sizeof ( wireframeSurfPoint_t ) * surfs - > numPoints ) + sizeof ( int ) ;
i + = stepBytes ;
//increment the pointer to the start of the next surface
surfs = ( wireframeMapSurf_t * ) ( ( byte * ) surfs + stepBytes ) ;
}
//it should end up being equal, if not something was wrong with this file.
assert ( i = = len ) ;
FS_FCloseFile ( f ) ;
Z_Free ( rSurfs ) ;
return qtrue ;
}
//create everything, after destroying any existing data -rww
qboolean R_InitializeWireframeAutomap ( void )
{
if ( r_autoMapDisable & & r_autoMapDisable - > integer )
{
return qfalse ;
}
if ( tr . world & &
tr . world - > nodes )
{
R_DestroyWireframeMap ( ) ;
#if 0 //file load-save
if ( ! R_GetWireframeMapFromFile ( ) )
{ //first try loading the data from a file. If there is none, generate it.
R_GenerateWireframeMap ( tr . world - > nodes ) ;
//now write it to file, since we have generated it successfully.
R_WriteWireframeMapToFile ( ) ;
}
# else //always generate
R_GenerateWireframeMap ( tr . world - > nodes ) ;
# endif
g_autoMapValid = true ;
}
return ( qboolean ) g_autoMapValid ;
}
# endif //0
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
WIREFRAME AUTOMAP GENERATION SYSTEM - END
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
void R_AutomapElevationAdjustment ( float newHeight )
{
g_playerHeight = newHeight ;
}
# ifdef _ALT_AUTOMAP_METHOD
//adjust the player height for gradient elevation colors -rww
qboolean R_InitializeWireframeAutomap ( void )
{ //yoink
return qtrue ;
}
# endif
//draw the automap with the given transformation matrix -rww
# define QUADINFINITY 16777216
static float g_lastHeight = 0.0f ;
static bool g_lastHeightValid = false ;
static void R_RecursiveWorldNode ( mnode_t * node , int planeBits , int dlightBits ) ;
const void * R_DrawWireframeAutomap ( const void * data )
{
const drawBufferCommand_t * cmd = ( const drawBufferCommand_t * ) data ;
float e = 0.0f ;
float alpha ;
wireframeMapSurf_t * s = g_autoMapFrame . surfs ;
# ifndef _ALT_AUTOMAP_METHOD
int i ;
# endif
if ( ! r_autoMap | | ! r_autoMap - > integer )
{
return ( const void * ) ( cmd + 1 ) ;
}
# ifndef _ALT_AUTOMAP_METHOD
if ( ! g_autoMapValid )
{ //data is not valid, don't draw
return ( const void * ) ( cmd + 1 ) ;
}
# endif
#if 0 //instead of this method, just do the automap as a new "scene"
//projection matrix mode
qglMatrixMode ( GL_PROJECTION ) ;
//store the current matrix
qglPushMatrix ( ) ;
//translate to our proper pos/angles from identity
qglLoadIdentity ( ) ;
qglTranslatef ( pos [ 0 ] , pos [ 1 ] , pos [ 2 ] ) ;
//presumeably this is correct for compensating for quake's
//crazy angle system.
qglRotatef ( angles [ 1 ] , 0.0f , 0.0f , 1.0f ) ;
qglRotatef ( - angles [ 0 ] , 0.0f , 1.0f , 0.0f ) ;
qglRotatef ( angles [ 2 ] , 1.0f , 0.0f , 0.0f ) ;
# endif
//disable 2d texturing
qglDisable ( GL_TEXTURE_2D ) ;
//now draw the backdrop
#if 0 //this does no good sadly, because of the issue of having to clear with a second scene
//in order for global fog clearing to work.
if ( r_autoMapBackAlpha & & r_autoMapBackAlpha - > value )
{ //specify the automap background alpha
alpha = r_autoMapBackAlpha - > value ;
//cap it reasonably
if ( alpha < 0.0f )
{
alpha = 0.0f ;
}
else if ( alpha > 1.0f )
{
alpha = 1.0f ;
}
GL_State ( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_SRC_ALPHA ) ;
}
else
# endif
{
alpha = 1.0f ;
GL_State ( 0 ) ;
}
//black
qglColor4f ( 0.0f , 0.0f , 0.0f , alpha ) ;
//draw a black backdrop
qglPushMatrix ( ) ;
qglLoadIdentity ( ) ; //get the ident matrix
qglBegin ( GL_QUADS ) ;
qglVertex3f ( - QUADINFINITY , QUADINFINITY , - ( backEnd . viewParms . zFar - 1 ) ) ;
qglVertex3f ( QUADINFINITY , QUADINFINITY , - ( backEnd . viewParms . zFar - 1 ) ) ;
qglVertex3f ( QUADINFINITY , - QUADINFINITY , - ( backEnd . viewParms . zFar - 1 ) ) ;
qglVertex3f ( - QUADINFINITY , - QUADINFINITY , - ( backEnd . viewParms . zFar - 1 ) ) ;
qglEnd ( ) ;
//pop back the viewmatrix
qglPopMatrix ( ) ;
//set the mode to line draw
if ( r_autoMap - > integer = = 2 )
{ //line mode
GL_State ( GLS_POLYMODE_LINE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_SRC_COLOR | GLS_DEPTHMASK_TRUE ) ;
}
else
{ //fill mode
//GL_State(GLS_SRCBLEND_SRC_ALPHA|GLS_DSTBLEND_SRC_COLOR|GLS_DEPTHMASK_TRUE);
GL_State ( GLS_DEPTHMASK_TRUE ) ;
}
//set culling
GL_Cull ( CT_TWO_SIDED ) ;
# ifndef _ALT_AUTOMAP_METHOD
//Draw the triangles
while ( s )
{
//first, loop through and set the alpha on every point for this surf.
//if the alpha ends up being completely transparent for every point, we don't even
//need to draw it
if ( g_playerHeight ! = g_lastHeight | |
! g_lastHeightValid )
{ //only do this if we need to
i = 0 ;
s - > completelyTransparent = true ;
while ( i < s - > numPoints )
{
//base the color on the elevation... for now, just check the first point height
if ( s - > points [ i ] . xyz [ 2 ] < g_playerHeight )
{
e = s - > points [ i ] . xyz [ 2 ] - g_playerHeight ;
}
else
{
e = g_playerHeight - s - > points [ i ] . xyz [ 2 ] ;
}
if ( e < 0.0f )
{
e = - e ;
}
if ( r_autoMap - > integer ! = 2 )
{ //fill mode
if ( s - > points [ i ] . xyz [ 2 ] > ( g_playerHeight + 64.0f ) )
{
s - > points [ i ] . alpha = 1.0f ;
}
else
{
s - > points [ i ] . alpha = e / 256.0f ;
}
}
else
{
//set alpha and color based on relative height of point
s - > points [ i ] . alpha = e / 256.0f ;
}
e / = 512.0f ;
//cap color
if ( e > 1.0f )
{
e = 1.0f ;
}
else if ( e < 0.0f )
{
e = 0.0f ;
}
VectorSet ( s - > points [ i ] . color , e , 1.0f - e , 0.0f ) ;
//cap alpha
if ( s - > points [ i ] . alpha > 1.0f )
{
s - > points [ i ] . alpha = 1.0f ;
}
else if ( s - > points [ i ] . alpha < 0.0f )
{
s - > points [ i ] . alpha = 0.0f ;
}
if ( s - > points [ i ] . alpha ! = 1.0f )
{ //this point is not entirely alpha'd out, so still draw the surface
s - > completelyTransparent = false ;
}
i + + ;
}
}
if ( s - > completelyTransparent )
{
s = s - > next ;
continue ;
}
i = 0 ;
qglBegin ( GL_TRIANGLES ) ;
while ( i < s - > numPoints )
{
if ( r_autoMap - > integer = = 2 | | s - > numPoints < 3 )
{ //line mode or not enough verts on surface
qglColor4f ( s - > points [ i ] . color [ 0 ] , s - > points [ i ] . color [ 1 ] , s - > points [ i ] . color [ 2 ] , s - > points [ i ] . alpha ) ;
}
else
{ //fill mode
vec3_t planeNormal ;
float fAlpha = s - > points [ i ] . alpha ;
planeNormal [ 0 ] = s - > points [ 0 ] . xyz [ 1 ] * ( s - > points [ 1 ] . xyz [ 2 ] - s - > points [ 2 ] . xyz [ 2 ] ) + s - > points [ 1 ] . xyz [ 1 ] * ( s - > points [ 2 ] . xyz [ 2 ] - s - > points [ 0 ] . xyz [ 2 ] ) + s - > points [ 2 ] . xyz [ 1 ] * ( s - > points [ 0 ] . xyz [ 2 ] - s - > points [ 1 ] . xyz [ 2 ] ) ;
planeNormal [ 1 ] = s - > points [ 0 ] . xyz [ 2 ] * ( s - > points [ 1 ] . xyz [ 0 ] - s - > points [ 2 ] . xyz [ 0 ] ) + s - > points [ 1 ] . xyz [ 2 ] * ( s - > points [ 2 ] . xyz [ 0 ] - s - > points [ 0 ] . xyz [ 0 ] ) + s - > points [ 2 ] . xyz [ 2 ] * ( s - > points [ 0 ] . xyz [ 0 ] - s - > points [ 1 ] . xyz [ 0 ] ) ;
planeNormal [ 2 ] = s - > points [ 0 ] . xyz [ 0 ] * ( s - > points [ 1 ] . xyz [ 1 ] - s - > points [ 2 ] . xyz [ 1 ] ) + s - > points [ 1 ] . xyz [ 0 ] * ( s - > points [ 2 ] . xyz [ 1 ] - s - > points [ 0 ] . xyz [ 1 ] ) + s - > points [ 2 ] . xyz [ 0 ] * ( s - > points [ 0 ] . xyz [ 1 ] - s - > points [ 1 ] . xyz [ 1 ] ) ;
if ( planeNormal [ 0 ] < 0.0f ) planeNormal [ 0 ] = - planeNormal [ 0 ] ;
if ( planeNormal [ 1 ] < 0.0f ) planeNormal [ 1 ] = - planeNormal [ 1 ] ;
if ( planeNormal [ 2 ] < 0.0f ) planeNormal [ 2 ] = - planeNormal [ 2 ] ;
/*
if ( s - > points [ i ] . xyz [ 2 ] > g_playerHeight + 64.0f & &
planeNormal [ 2 ] > 0.7f )
{ //surface above player facing up/down directly
fAlpha = 1.0f - planeNormal [ 2 ] ;
}
*/
//qglColor4f(planeNormal[0], planeNormal[1], planeNormal[2], fAlpha);
qglColor4f ( s - > points [ i ] . color [ 0 ] , s - > points [ i ] . color [ 1 ] , 1.0f - planeNormal [ 2 ] , fAlpha ) ;
}
qglVertex3f ( s - > points [ i ] . xyz [ 0 ] , s - > points [ i ] . xyz [ 1 ] , s - > points [ i ] . xyz [ 2 ] ) ;
i + + ;
}
qglEnd ( ) ;
s = s - > next ;
}
# else
tr_drawingAutoMap = true ;
R_RecursiveWorldNode ( tr . world - > nodes , 15 , 0 ) ;
tr_drawingAutoMap = false ;
# endif
g_lastHeight = g_playerHeight ;
g_lastHeightValid = true ;
#if 0 //instead of this method, just do the automap as a new "scene"
//pop back the view matrix
qglPopMatrix ( ) ;
# endif
//reenable 2d texturing
qglEnable ( GL_TEXTURE_2D ) ;
//white color/full alpha
qglColor4f ( 1.0f , 1.0f , 1.0f , 1.0f ) ;
return ( const void * ) ( cmd + 1 ) ;
}
/*
= = = = = = = = = = = = = = = =
R_RecursiveWorldNode
= = = = = = = = = = = = = = = =
*/
# ifndef VV_LIGHTING
static void R_RecursiveWorldNode ( mnode_t * node , int planeBits , int dlightBits ) {
do
{
int newDlights [ 2 ] ;
# ifdef _ALT_AUTOMAP_METHOD
if ( tr_drawingAutoMap )
{
node - > visframe = tr . visCount ;
}
# endif
// if the node wasn't marked as potentially visible, exit
if ( node - > visframe ! = tr . visCount )
{
return ;
}
// if the bounding volume is outside the frustum, nothing
// inside can be visible OPTIMIZE: don't do this all the way to leafs?
# ifdef _ALT_AUTOMAP_METHOD
if ( r_nocull - > integer ! = 1 & & ! tr_drawingAutoMap )
# else
if ( r_nocull - > integer ! = 1 )
# endif
{
int r ;
if ( planeBits & 1 ) {
r = BoxOnPlaneSide ( node - > mins , node - > maxs , & tr . viewParms . frustum [ 0 ] ) ;
if ( r = = 2 ) {
return ; // culled
}
if ( r = = 1 ) {
planeBits & = ~ 1 ; // all descendants will also be in front
}
}
if ( planeBits & 2 ) {
r = BoxOnPlaneSide ( node - > mins , node - > maxs , & tr . viewParms . frustum [ 1 ] ) ;
if ( r = = 2 ) {
return ; // culled
}
if ( r = = 1 ) {
planeBits & = ~ 2 ; // all descendants will also be in front
}
}
if ( planeBits & 4 ) {
r = BoxOnPlaneSide ( node - > mins , node - > maxs , & tr . viewParms . frustum [ 2 ] ) ;
if ( r = = 2 ) {
return ; // culled
}
if ( r = = 1 ) {
planeBits & = ~ 4 ; // all descendants will also be in front
}
}
if ( planeBits & 8 ) {
r = BoxOnPlaneSide ( node - > mins , node - > maxs , & tr . viewParms . frustum [ 3 ] ) ;
if ( r = = 2 ) {
return ; // culled
}
if ( r = = 1 ) {
planeBits & = ~ 8 ; // all descendants will also be in front
}
}
}
if ( node - > contents ! = - 1 ) {
break ;
}
// node is just a decision point, so go down both sides
// since we don't care about sort orders, just go positive to negative
// determine which dlights are needed
if ( r_nocull - > integer ! = 2 )
{
newDlights [ 0 ] = 0 ;
newDlights [ 1 ] = 0 ;
if ( dlightBits )
{
int i ;
for ( i = 0 ; i < tr . refdef . num_dlights ; i + + )
{
dlight_t * dl ;
float dist ;
if ( dlightBits & ( 1 < < i ) ) {
dl = & tr . refdef . dlights [ i ] ;
dist = DotProduct ( dl - > origin , node - > plane - > normal ) - node - > plane - > dist ;
if ( dist > - dl - > radius ) {
newDlights [ 0 ] | = ( 1 < < i ) ;
}
if ( dist < dl - > radius ) {
newDlights [ 1 ] | = ( 1 < < i ) ;
}
}
}
}
}
else
{
newDlights [ 0 ] = dlightBits ;
newDlights [ 1 ] = dlightBits ;
}
// recurse down the children, front side first
R_RecursiveWorldNode ( node - > children [ 0 ] , planeBits , newDlights [ 0 ] ) ;
// tail recurse
node = node - > children [ 1 ] ;
dlightBits = newDlights [ 1 ] ;
} while ( 1 ) ;
{
// leaf node, so add mark surfaces
int c ;
msurface_t * surf , * * mark ;
tr . pc . c_leafs + + ;
// add to z buffer bounds
if ( node - > mins [ 0 ] < tr . viewParms . visBounds [ 0 ] [ 0 ] ) {
tr . viewParms . visBounds [ 0 ] [ 0 ] = node - > mins [ 0 ] ;
}
if ( node - > mins [ 1 ] < tr . viewParms . visBounds [ 0 ] [ 1 ] ) {
tr . viewParms . visBounds [ 0 ] [ 1 ] = node - > mins [ 1 ] ;
}
if ( node - > mins [ 2 ] < tr . viewParms . visBounds [ 0 ] [ 2 ] ) {
tr . viewParms . visBounds [ 0 ] [ 2 ] = node - > mins [ 2 ] ;
}
if ( node - > maxs [ 0 ] > tr . viewParms . visBounds [ 1 ] [ 0 ] ) {
tr . viewParms . visBounds [ 1 ] [ 0 ] = node - > maxs [ 0 ] ;
}
if ( node - > maxs [ 1 ] > tr . viewParms . visBounds [ 1 ] [ 1 ] ) {
tr . viewParms . visBounds [ 1 ] [ 1 ] = node - > maxs [ 1 ] ;
}
if ( node - > maxs [ 2 ] > tr . viewParms . visBounds [ 1 ] [ 2 ] ) {
tr . viewParms . visBounds [ 1 ] [ 2 ] = node - > maxs [ 2 ] ;
}
// add the individual surfaces
mark = node - > firstmarksurface ;
c = node - > nummarksurfaces ;
while ( c - - ) {
// the surface may have already been added if it
// spans multiple leafs
surf = * mark ;
R_AddWorldSurface ( surf , dlightBits ) ;
mark + + ;
}
}
}
# endif // VV_LIGHTING
/*
= = = = = = = = = = = = = = =
R_PointInLeaf
= = = = = = = = = = = = = = =
*/
static mnode_t * R_PointInLeaf ( const vec3_t p ) {
mnode_t * node ;
float d ;
cplane_t * plane ;
if ( ! tr . world ) {
Com_Error ( ERR_DROP , " R_PointInLeaf: bad model " ) ;
}
node = tr . world - > nodes ;
while ( 1 ) {
if ( node - > contents ! = - 1 ) {
break ;
}
# ifdef _XBOX
plane = tr . world - > planes + node - > planeNum ;
# else
plane = node - > plane ;
# endif
d = DotProduct ( p , plane - > normal ) - plane - > dist ;
if ( d > 0 ) {
node = node - > children [ 0 ] ;
} else {
node = node - > children [ 1 ] ;
}
}
return node ;
}
/*
= = = = = = = = = = = = = =
R_ClusterPVS
= = = = = = = = = = = = = =
*/
static const byte * R_ClusterPVS ( int cluster ) {
if ( ! tr . world | | ! tr . world - > vis | | cluster < 0 | | cluster > = tr . world - > numClusters ) {
return tr . world - > novis ;
}
# ifdef _XBOX
return tr . world - > vis - > Decompress ( cluster * tr . world - > clusterBytes ,
tr . world - > numClusters ) ;
# else
return tr . world - > vis + cluster * tr . world - > clusterBytes ;
# endif
}
/*
= = = = = = = = = = = = = = = = =
R_inPVS
= = = = = = = = = = = = = = = = =
*/
qboolean R_inPVS ( const vec3_t p1 , const vec3_t p2 , byte * mask ) {
int leafnum ;
int cluster ;
int area1 , area2 ;
leafnum = CM_PointLeafnum ( p1 ) ;
cluster = CM_LeafCluster ( leafnum ) ;
area1 = CM_LeafArea ( leafnum ) ;
//agh, the damn snapshot mask doesn't work for this
mask = ( byte * ) CM_ClusterPVS ( cluster ) ;
leafnum = CM_PointLeafnum ( p2 ) ;
cluster = CM_LeafCluster ( leafnum ) ;
area2 = CM_LeafArea ( leafnum ) ;
if ( mask & & ( ! ( mask [ cluster > > 3 ] & ( 1 < < ( cluster & 7 ) ) ) ) )
return qfalse ;
//this doesn't freakin work
// if (!CM_AreasConnected (area1, area2))
// return qfalse; // a door blocks sight
return qtrue ;
}
/*
= = = = = = = = = = = = = = =
R_MarkLeaves
Mark the leaves and nodes that are in the PVS for the current
cluster
= = = = = = = = = = = = = = =
*/
# ifdef _XBOX
void R_MarkLeaves ( mleaf_s * leafOverride ) {
const byte * vis ;
mleaf_s * leaf ;
mnode_s * parent ;
int i ;
int cluster ;
// lockpvs lets designers walk around to determine the
// extent of the current pvs
if ( r_lockpvs - > integer ) {
return ;
}
// current viewcluster
if ( ! leafOverride ) {
leaf = ( mleaf_s * ) R_PointInLeaf ( tr . viewParms . pvsOrigin ) ;
} else {
leaf = leafOverride ;
}
cluster = leaf - > cluster ;
assert ( leaf - > contents ! = - 1 ) ;
// if the cluster is the same and the area visibility matrix
// hasn't changed, we don't need to mark everything again
if ( tr . viewCluster = = cluster & & ! tr . refdef . areamaskModified ) {
return ;
}
tr . visCount + + ;
tr . viewCluster = cluster ;
if ( r_novis - > integer | | tr . viewCluster = = - 1 ) {
for ( i = 0 ; i < tr . world - > numnodes ; i + + ) {
if ( tr . world - > nodes [ i ] . contents ! = CONTENTS_SOLID ) {
tr . world - > nodes [ i ] . visframe = tr . visCount ;
}
}
return ;
}
vis = R_ClusterPVS ( tr . viewCluster ) ;
for ( i = 0 , leaf = tr . world - > leafs ; i < tr . world - > numleafs ; i + + , leaf + + ) {
cluster = leaf - > cluster ;
if ( cluster < 0 | | cluster > = tr . world - > numClusters ) {
continue ;
}
// check general pvs
if ( ! ( vis [ cluster > > 3 ] & ( 1 < < ( cluster & 7 ) ) ) ) {
continue ;
}
// check for door connection
if ( ! lookingForWorstLeaf & &
( tr . refdef . areamask [ leaf - > area > > 3 ] & ( 1 < < ( leaf - > area & 7 ) ) ) ) {
continue ; // not visible
}
parent = ( mnode_t * ) leaf ;
assert ( leaf - > contents ! = - 1 ) ;
do {
if ( parent - > visframe = = tr . visCount )
break ;
parent - > visframe = tr . visCount ;
parent = parent - > parent ;
} while ( parent ) ;
}
}
# else // _XBOX
static void R_MarkLeaves ( void ) {
const byte * vis ;
mnode_t * leaf , * parent ;
int i ;
int cluster ;
// lockpvs lets designers walk around to determine the
// extent of the current pvs
if ( r_lockpvs - > integer ) {
return ;
}
// current viewcluster
leaf = R_PointInLeaf ( tr . viewParms . pvsOrigin ) ;
cluster = leaf - > cluster ;
// if the cluster is the same and the area visibility matrix
// hasn't changed, we don't need to mark everything again
// if r_showcluster was just turned on, remark everything
if ( tr . viewCluster = = cluster & & ! tr . refdef . areamaskModified
& & ! r_showcluster - > modified ) {
return ;
}
if ( r_showcluster - > modified | | r_showcluster - > integer ) {
r_showcluster - > modified = qfalse ;
if ( r_showcluster - > integer ) {
Com_Printf ( " cluster:%i area:%i \n " , cluster , leaf - > area ) ;
}
}
tr . visCount + + ;
tr . viewCluster = cluster ;
if ( r_novis - > integer | | tr . viewCluster = = - 1 ) {
for ( i = 0 ; i < tr . world - > numnodes ; i + + ) {
if ( tr . world - > nodes [ i ] . contents ! = CONTENTS_SOLID ) {
tr . world - > nodes [ i ] . visframe = tr . visCount ;
}
}
return ;
}
vis = R_ClusterPVS ( tr . viewCluster ) ;
for ( i = 0 , leaf = tr . world - > nodes ; i < tr . world - > numnodes ; i + + , leaf + + ) {
cluster = leaf - > cluster ;
if ( cluster < 0 | | cluster > = tr . world - > numClusters ) {
continue ;
}
// check general pvs
if ( ! ( vis [ cluster > > 3 ] & ( 1 < < ( cluster & 7 ) ) ) ) {
continue ;
}
// check for door connection
if ( ( tr . refdef . areamask [ leaf - > area > > 3 ] & ( 1 < < ( leaf - > area & 7 ) ) ) ) {
continue ; // not visible
}
parent = leaf ;
do {
if ( parent - > visframe = = tr . visCount )
break ;
parent - > visframe = tr . visCount ;
parent = parent - > parent ;
} while ( parent ) ;
}
}
# endif // _XBOX
/*
= = = = = = = = = = = = =
R_AddWorldSurfaces
= = = = = = = = = = = = =
*/
# ifdef _XBOX
void R_AddWorldSurfaces ( void ) {
if ( ! r_drawworld - > integer ) {
return ;
}
if ( tr . refdef . rdflags & RDF_NOWORLDMODEL ) {
return ;
}
tr . currentEntityNum = TR_WORLDENT ; //ENTITYNUM_WORLD;
tr . shiftedEntityNum = tr . currentEntityNum < < QSORT_ENTITYNUM_SHIFT ;
// clear out the visible min/max
ClearBounds ( tr . viewParms . visBounds [ 0 ] , tr . viewParms . visBounds [ 1 ] ) ;
// perform frustum culling and add all the potentially visible surfaces
if ( VVLightMan . num_dlights > MAX_DLIGHTS ) {
VVLightMan . num_dlights = MAX_DLIGHTS ;
}
VVLightMan . R_RecursiveWorldNode ( tr . world - > nodes , 15 , ( 1 < < VVLightMan . num_dlights ) - 1 ) ;
}
# else // _XBOX
void R_AddWorldSurfaces ( void ) {
if ( ! r_drawworld - > integer ) {
return ;
}
if ( tr . refdef . rdflags & RDF_NOWORLDMODEL ) {
return ;
}
tr . currentEntityNum = TR_WORLDENT ;
tr . shiftedEntityNum = tr . currentEntityNum < < QSORT_ENTITYNUM_SHIFT ;
// determine which leaves are in the PVS / areamask
R_MarkLeaves ( ) ;
// clear out the visible min/max
ClearBounds ( tr . viewParms . visBounds [ 0 ] , tr . viewParms . visBounds [ 1 ] ) ;
// perform frustum culling and add all the potentially visible surfaces
if ( tr . refdef . num_dlights > 32 ) {
tr . refdef . num_dlights = 32 ;
}
R_RecursiveWorldNode ( tr . world - > nodes , 15 , ( 1 < < tr . refdef . num_dlights ) - 1 ) ;
}
# endif // _XBOX