This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/render/r_surface.c

470 lines
11 KiB
C

//=======================================================================
// Copyright XashXT Group 2007 ©
// r_surface.c - surface-related refresh code
//=======================================================================
#include "r_local.h"
#include "mathlib.h"
#include "matrixlib.h"
#include "const.h"
#define BACKFACE_EPSILON 0.01
rmodel_t *r_worldModel;
ref_entity_t *r_worldEntity;
vec3_t r_worldMins, r_worldMaxs;
int r_frameCount;
int r_visFrameCount;
int r_areabitsChanged;
int r_viewCluster;
int numRadarEnts = 0;
radar_ent_t RadarEnts[MAX_RADAR_ENTS];
/*
=================
R_DrawSurface
=================
*/
void R_DrawSurface( void )
{
surface_t *surf = m_pRenderMesh->mesh;
surfPoly_t *p;
surfPolyVert_t *v;
int i;
for( p = surf->poly; p; p = p->next )
{
RB_CheckMeshOverflow( p->numIndices, p->numVertices );
for( i = 0; i < p->numIndices; i += 3 )
{
indexArray[numIndex++] = numVertex + p->indices[i+0];
indexArray[numIndex++] = numVertex + p->indices[i+1];
indexArray[numIndex++] = numVertex + p->indices[i+2];
}
for( i = 0, v = p->vertices; i < p->numVertices; i++, v++ )
{
vertexArray[numVertex][0] = v->xyz[0];
vertexArray[numVertex][1] = v->xyz[1];
vertexArray[numVertex][2] = v->xyz[2];
tangentArray[numVertex][0] = surf->tangent[0];
tangentArray[numVertex][1] = surf->tangent[1];
tangentArray[numVertex][2] = surf->tangent[2];
binormalArray[numVertex][0] = surf->binormal[0];
binormalArray[numVertex][1] = surf->binormal[1];
binormalArray[numVertex][2] = surf->binormal[2];
normalArray[numVertex][0] = surf->normal[0];
normalArray[numVertex][1] = surf->normal[1];
normalArray[numVertex][2] = surf->normal[2];
inTexCoordArray[numVertex][0] = v->st[0];
inTexCoordArray[numVertex][1] = v->st[1];
inTexCoordArray[numVertex][2] = v->lightmap[0];
inTexCoordArray[numVertex][3] = v->lightmap[1];
Vector4Copy(v->color, inColorArray[numVertex]);
numVertex++;
}
}
}
/*
=================
R_CullSurface
=================
*/
static bool R_CullSurface( surface_t *surf, const vec3_t origin, int clipFlags )
{
cplane_t *plane;
float dist;
if( r_nocull->integer ) return false;
// find which side of the node we are on
plane = surf->plane;
if( plane->type < 3 ) dist = origin[plane->type] - plane->dist;
else dist = DotProduct( origin, plane->normal ) - plane->dist;
if(!(surf->flags & SURF_PLANEBACK))
{
if( dist <= BACKFACE_EPSILON )
return true; // wrong side
}
else
{
if( dist >= -BACKFACE_EPSILON )
return true; // wrong side
}
// cull
if( clipFlags )
{
if( R_CullBox( surf->mins, surf->maxs, clipFlags ))
return true;
}
return false;
}
/*
=================
R_AddSurfaceToList
=================
*/
static void R_AddSurfaceToList( surface_t *surf, ref_entity_t *entity )
{
mipTex_t *tex = surf->texInfo;
ref_shader_t *shader = tex->shader;
int map, lmNum;
if( tex->flags & SURF_NODRAW )
return;
// select lightmap
lmNum = surf->lmNum;
// check for lightmap modification
if( r_dynamiclights->integer && (shader->flags & SHADER_HASLIGHTMAP))
{
if( surf->dlightFrame == r_frameCount ) lmNum = 255;
else
{
for( map = 0; map < surf->numStyles; map++ )
{
if( surf->cachedLight[map] != r_lightStyles[surf->styles[map]].white )
{
lmNum = 255;
break;
}
}
}
}
// add it
R_AddMeshToList( MESH_SURFACE, surf, shader, entity, lmNum );
// Also add caustics
if( r_caustics->integer )
{
if( surf->flags & SURF_WATERCAUSTICS )
R_AddMeshToList( MESH_SURFACE, surf, r_waterCausticsShader, entity, 0 );
if( surf->flags & SURF_SLIMECAUSTICS )
R_AddMeshToList( MESH_SURFACE, surf, r_slimeCausticsShader, entity, 0 );
if( surf->flags & SURF_LAVACAUSTICS )
R_AddMeshToList( MESH_SURFACE, surf, r_lavaCausticsShader, entity, 0 );
}
}
/*
=======================================================================
BRUSH MODELS
=======================================================================
*/
/*
=================
R_AddBrushModelToList
=================
*/
void R_AddBrushModelToList( ref_entity_t *entity )
{
rmodel_t *model = entity->model;
surface_t *surf;
dlight_t *dl;
vec3_t origin, tmp;
vec3_t mins, maxs;
int i, l;
if( !model->numModelSurfaces )
return;
// cull
if( !AxisCompare( entity->axis, axisDefault ))
{
for( i = 0; i < 3; i++ )
{
mins[i] = entity->origin[i] - model->radius;
maxs[i] = entity->origin[i] + model->radius;
}
if( R_CullSphere( entity->origin, model->radius, MAX_CLIPFLAGS ))
return;
VectorSubtract( r_origin, entity->origin, tmp );
VectorRotate( tmp, entity->axis, origin );
}
else
{
VectorAdd( entity->origin, model->mins, mins );
VectorAdd( entity->origin, model->maxs, maxs );
if( R_CullBox( mins, maxs, MAX_CLIPFLAGS ))
return;
VectorSubtract( r_refdef.vieworg, entity->origin, origin );
}
// Calculate dynamic lighting
if( r_dynamiclights->integer )
{
for( l = 0, dl = r_dlights; l < r_numDLights; l++, dl++ )
{
if( !BoundsAndSphereIntersect( mins, maxs, dl->origin, dl->intensity ))
continue;
surf = model->surfaces + model->firstModelSurface;
for( i = 0; i < model->numModelSurfaces; i++, surf++ )
{
if( surf->dlightFrame != r_frameCount )
{
surf->dlightFrame = r_frameCount;
surf->dlightBits = (1<<l);
}
else surf->dlightBits |= (1<<l);
}
}
}
// add all the surfaces
surf = model->surfaces + model->firstModelSurface;
for( i = 0; i < model->numModelSurfaces; i++, surf++ )
{
// cull
if( R_CullSurface( surf, origin, 0 ))
continue;
// add the surface
R_AddSurfaceToList( surf, entity );
}
}
/*
=======================================================================
WORLD MODEL
=======================================================================
*/
/*
=================
R_MarkLeaves
Mark the leaves and nodes that are in the PVS for the current cluster
=================
*/
static void R_MarkLeaves( void )
{
byte *vis;
int i, cluster;
node_t *leaf, *parent;
// lockpvs lets designers walk around to determine the
// extent of the current pvs
if( r_lockpvs->integer ) return;
// Current view cluster
leaf = R_PointInLeaf( r_refdef.vieworg );
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( r_viewCluster == cluster && !r_areabitsChanged && !r_showcluster->modified )
return;
if( r_showcluster->modified || r_showcluster->integer )
{
r_showcluster->modified = false;
if( r_showcluster->integer )
Msg( "cluster:%i area:%i\n", cluster, leaf->area );
}
r_visFrameCount++;
r_viewCluster = cluster;
if( r_novis->integer || r_viewCluster == -1 )
{
for( i = 0; i < r_worldModel->numNodes; i++ )
{
if( r_worldModel->nodes[i].contents != CONTENTS_SOLID )
r_worldModel->nodes[i].visFrame = r_visFrameCount;
}
return;
}
vis = R_ClusterPVS( r_viewCluster );
for( i = 0, leaf = r_worldModel->nodes; i < r_worldModel->numNodes; i++, leaf++ )
{
cluster = leaf->cluster;
if( cluster < 0 || cluster >= r_worldModel->numClusters )
continue;
// check general pvs
if(!(vis[cluster>>3] & (1<<(cluster&7))))
continue;
// check for door connection
if((r_refdef.areabits[leaf->area>>3] & (1<<(leaf->area & 7 ))))
continue; // not visible
parent = (node_t *)leaf;
do {
if( parent->visFrame == r_visFrameCount )
break;
parent->visFrame = r_visFrameCount;
parent = parent->parent;
} while( parent );
}
}
/*
=================
R_RecursiveWorldNode
=================
*/
static void R_RecursiveWorldNode( node_t *node, int planeBits, int dlightBits )
{
cplane_t *plane;
surface_t *surf, **mark;
int i, clipped;
while( 1 )
{
int newDlights[2];
if( node->contents == CONTENTS_SOLID )
return; // solid
if( node->visFrame != r_visFrameCount )
return;
// if the bounding volume is outside the frustum, nothing
// inside can be visible OPTIMIZE: don't do this all the way to leafs?
// g-cont. because we throw node->firstface and node->numfaces !!!!
if( planeBits )
{
for( i = 0, plane = r_frustum; i < 4; i++, plane++ )
{
if(!(planeBits & (1<<i))) continue;
clipped = BoxOnPlaneSide( node->mins, node->maxs, plane );
if( clipped == 2 ) return;
if( clipped == 1 ) planeBits &= ~(1<<i);
}
}
if( node->contents != CONTENTS_NODE ) 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
newDlights[0] = 0;
newDlights[1] = 0;
if( dlightBits )
{
for( i = 0; i < r_numDLights; i++ )
{
dlight_t *dl;
float dist;
if( dlightBits & (1<<i ))
{
dl = &r_dlights[i];
dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist;
if( dist > -dl->intensity ) newDlights[0] |= (1<<i);
if( dist < dl->intensity ) newDlights[1] |= (1<<i);
}
}
}
// recurse down the children, front side first
R_RecursiveWorldNode( node->children[0], planeBits, newDlights[0] );
// tail recurse
node = node->children[1];
dlightBits = newDlights[1];
}
// add to world mins/maxs
AddPointToBounds( node->mins, r_worldMins, r_worldMaxs );
AddPointToBounds( node->maxs, r_worldMins, r_worldMaxs );
r_stats.numLeafs++;
// add the individual surfaces
for( i = 0, mark = node->firstMarkSurface; i < node->numMarkSurfaces; i++, mark++ )
{
surf = *mark;
if( surf->visFrame == r_frameCount )
continue; // already added this surface from another leaf
surf->visFrame = r_frameCount;
if( surf->dlightFrame != r_frameCount )
{
surf->dlightFrame = r_frameCount;
surf->dlightBits = dlightBits;
}
else surf->dlightBits |= dlightBits;
// cull
if( R_CullSurface( surf, r_refdef.vieworg, planeBits ))
continue;
// clip sky surfaces
if( surf->texInfo->flags & SURF_SKY )
{
R_ClipSkySurface( surf );
continue;
}
// add the surface
R_AddSurfaceToList( surf, r_worldEntity );
}
}
/*
=================
R_AddWorldToList
=================
*/
void R_AddWorldToList( void )
{
int planeBits;
int dlightBits;
if( r_refdef.rdflags & RDF_NOWORLDMODEL )
return;
if( !r_drawworld->integer )
return;
if( r_nocull->integer ) planeBits = 0;
else planeBits = MAX_CLIPFLAGS;
if( !r_dynamiclights->integer ) dlightBits = 0;
else dlightBits = (1<<r_numDLights ) - 1;
// bump frame count
r_frameCount++;
// auto cycle the world frame for texture animation
r_worldEntity->frame = (int)(r_refdef.time * 2);
r_stats.numDLights += r_numDLights;
// clear world mins/maxs
ClearBounds( r_worldMins, r_worldMaxs );
R_MarkLeaves();
R_ClearSky(); // S.T.A.L.K.E.R ClearSky
R_RecursiveWorldNode( r_worldModel->nodes, planeBits, dlightBits );
R_AddSkyToList();
}