2012-11-26 18:58:24 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
Doom 3 BFG Edition GPL Source Code
2012-11-28 15:47:07 +00:00
Copyright ( C ) 1993 - 2012 id Software LLC , a ZeniMax Media company .
2012-11-26 18:58:24 +00:00
2012-11-28 15:47:07 +00:00
This file is part of the Doom 3 BFG Edition GPL Source Code ( " Doom 3 BFG Edition Source Code " ) .
2012-11-26 18:58:24 +00:00
Doom 3 BFG Edition 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 3 of the License , or
( at your option ) any later version .
Doom 3 BFG Edition 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 Doom 3 BFG Edition Source Code . If not , see < http : //www.gnu.org/licenses/>.
In addition , the Doom 3 BFG Edition Source Code is also subject to certain additional terms . You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code . If not , please request a copy in writing from id Software at the address below .
If you have questions concerning this license or the applicable additional terms , you may contact in writing id Software LLC , c / o ZeniMax Media Inc . , Suite 120 , Rockville , Maryland 20850 USA .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# pragma hdrstop
2012-12-22 15:18:19 +00:00
# include "precompiled.h"
2012-11-26 18:58:24 +00:00
# include "tr_local.h"
# include "Model_local.h"
idCVar r_skipStaticShadows ( " r_skipStaticShadows " , " 0 " , CVAR_RENDERER | CVAR_BOOL , " skip static shadows " ) ;
idCVar r_skipDynamicShadows ( " r_skipDynamicShadows " , " 0 " , CVAR_RENDERER | CVAR_BOOL , " skip dynamic shadows " ) ;
idCVar r_useParallelAddModels ( " r_useParallelAddModels " , " 1 " , CVAR_RENDERER | CVAR_BOOL , " add all models in parallel with jobs " ) ;
idCVar r_useParallelAddShadows ( " r_useParallelAddShadows " , " 1 " , CVAR_RENDERER | CVAR_INTEGER , " 0 = off, 1 = threaded " , 0 , 1 ) ;
idCVar r_useShadowPreciseInsideTest ( " r_useShadowPreciseInsideTest " , " 1 " , CVAR_RENDERER | CVAR_BOOL , " use a precise and more expensive test to determine whether the view is inside a shadow volume " ) ;
idCVar r_cullDynamicShadowTriangles ( " r_cullDynamicShadowTriangles " , " 1 " , CVAR_RENDERER | CVAR_BOOL , " cull occluder triangles that are outside the light frustum so they do not contribute to the dynamic shadow volume " ) ;
idCVar r_cullDynamicLightTriangles ( " r_cullDynamicLightTriangles " , " 1 " , CVAR_RENDERER | CVAR_BOOL , " cull surface triangles that are outside the light frustum so they do not get rendered for interactions " ) ;
idCVar r_forceShadowCaps ( " r_forceShadowCaps " , " 0 " , CVAR_RENDERER | CVAR_BOOL , " 0 = skip rendering shadow caps if view is outside shadow volume, 1 = always render shadow caps " ) ;
static const float CHECK_BOUNDS_EPSILON = 1.0f ;
/*
= = = = = = = = = = = = = = = = = =
R_SortViewEntities
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
viewEntity_t * R_SortViewEntities ( viewEntity_t * vEntities )
{
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( " R_SortViewEntities " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// We want to avoid having a single AddModel for something complex be
// the last thing processed and hurt the parallel occupancy, so
// sort dynamic models first, _area models second, then everything else.
2012-11-28 15:47:07 +00:00
viewEntity_t * dynamics = NULL ;
viewEntity_t * areas = NULL ;
viewEntity_t * others = NULL ;
for ( viewEntity_t * vEntity = vEntities ; vEntity ! = NULL ; )
{
viewEntity_t * next = vEntity - > next ;
const idRenderModel * model = vEntity - > entityDef - > parms . hModel ;
if ( model - > IsDynamicModel ( ) ! = DM_STATIC )
{
2012-11-26 18:58:24 +00:00
vEntity - > next = dynamics ;
dynamics = vEntity ;
2012-11-28 15:47:07 +00:00
}
else if ( model - > IsStaticWorldModel ( ) )
{
2012-11-26 18:58:24 +00:00
vEntity - > next = areas ;
areas = vEntity ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
vEntity - > next = others ;
others = vEntity ;
}
vEntity = next ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// concatenate the lists
2012-11-28 15:47:07 +00:00
viewEntity_t * all = others ;
for ( viewEntity_t * vEntity = areas ; vEntity ! = NULL ; )
{
viewEntity_t * next = vEntity - > next ;
2012-11-26 18:58:24 +00:00
vEntity - > next = all ;
all = vEntity ;
vEntity = next ;
}
2012-11-28 15:47:07 +00:00
for ( viewEntity_t * vEntity = dynamics ; vEntity ! = NULL ; )
{
viewEntity_t * next = vEntity - > next ;
2012-11-26 18:58:24 +00:00
vEntity - > next = all ;
all = vEntity ;
vEntity = next ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return all ;
}
/*
= = = = = = = = = = = = = = = = = =
R_ClearEntityDefDynamicModel
If we know the reference bounds stays the same , we
only need to do this on entity update , not the full
R_FreeEntityDefDerivedData
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_ClearEntityDefDynamicModel ( idRenderEntityLocal * def )
{
2012-11-26 18:58:24 +00:00
// free all the interaction surfaces
2012-11-28 15:47:07 +00:00
for ( idInteraction * inter = def - > firstInteraction ; inter ! = NULL & & ! inter - > IsEmpty ( ) ; inter = inter - > entityNext )
{
2012-11-26 18:58:24 +00:00
inter - > FreeSurfaces ( ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// clear the dynamic model if present
2012-11-28 15:47:07 +00:00
if ( def - > dynamicModel )
{
2012-11-26 18:58:24 +00:00
// this is copied from cachedDynamicModel, so it doesn't need to be freed
def - > dynamicModel = NULL ;
}
def - > dynamicModelFrameCount = 0 ;
}
/*
= = = = = = = = = = = = = = = = = =
R_IssueEntityDefCallback
= = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
bool R_IssueEntityDefCallback ( idRenderEntityLocal * def )
{
2012-11-26 18:58:24 +00:00
idBounds oldBounds = def - > localReferenceBounds ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
def - > archived = false ; // will need to be written to the demo file
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
bool update ;
2012-11-28 15:47:07 +00:00
if ( tr . viewDef ! = NULL )
{
2012-11-26 18:58:24 +00:00
update = def - > parms . callback ( & def - > parms , & tr . viewDef - > renderView ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
update = def - > parms . callback ( & def - > parms , NULL ) ;
}
tr . pc . c_entityDefCallbacks + + ;
2012-11-28 15:47:07 +00:00
if ( def - > parms . hModel = = NULL )
{
2012-11-26 18:58:24 +00:00
common - > Error ( " R_IssueEntityDefCallback: dynamic entity callback didn't set model " ) ;
}
2012-11-28 15:47:07 +00:00
if ( r_checkBounds . GetBool ( ) )
{
if ( oldBounds [ 0 ] [ 0 ] > def - > localReferenceBounds [ 0 ] [ 0 ] + CHECK_BOUNDS_EPSILON | |
2012-11-26 18:58:24 +00:00
oldBounds [ 0 ] [ 1 ] > def - > localReferenceBounds [ 0 ] [ 1 ] + CHECK_BOUNDS_EPSILON | |
oldBounds [ 0 ] [ 2 ] > def - > localReferenceBounds [ 0 ] [ 2 ] + CHECK_BOUNDS_EPSILON | |
oldBounds [ 1 ] [ 0 ] < def - > localReferenceBounds [ 1 ] [ 0 ] - CHECK_BOUNDS_EPSILON | |
oldBounds [ 1 ] [ 1 ] < def - > localReferenceBounds [ 1 ] [ 1 ] - CHECK_BOUNDS_EPSILON | |
2012-11-28 15:47:07 +00:00
oldBounds [ 1 ] [ 2 ] < def - > localReferenceBounds [ 1 ] [ 2 ] - CHECK_BOUNDS_EPSILON )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " entity %i callback extended reference bounds \n " , def - > index ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return update ;
}
/*
= = = = = = = = = = = = = = = = = = =
R_EntityDefDynamicModel
This is also called by the game code for idRenderWorldLocal : : ModelTrace ( ) , and idRenderWorldLocal : : Trace ( ) which is bad for performance . . .
Issues a deferred entity callback if necessary .
If the model isn ' t dynamic , it returns the original .
Returns the cached dynamic model if present , otherwise creates it .
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
idRenderModel * R_EntityDefDynamicModel ( idRenderEntityLocal * def )
{
if ( def - > dynamicModelFrameCount = = tr . frameCount )
{
2012-11-26 18:58:24 +00:00
return def - > dynamicModel ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// allow deferred entities to construct themselves
bool callbackUpdate ;
2012-11-28 15:47:07 +00:00
if ( def - > parms . callback ! = NULL )
{
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( " R_IssueEntityDefCallback " ) ;
callbackUpdate = R_IssueEntityDefCallback ( def ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
callbackUpdate = false ;
}
2012-11-28 15:47:07 +00:00
idRenderModel * model = def - > parms . hModel ;
if ( model = = NULL )
{
2012-11-26 18:58:24 +00:00
common - > Error ( " R_EntityDefDynamicModel: NULL model " ) ;
return NULL ;
}
2012-11-28 15:47:07 +00:00
if ( model - > IsDynamicModel ( ) = = DM_STATIC )
{
2012-11-26 18:58:24 +00:00
def - > dynamicModel = NULL ;
def - > dynamicModelFrameCount = 0 ;
return model ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// continously animating models (particle systems, etc) will have their snapshot updated every single view
2012-11-28 15:47:07 +00:00
if ( callbackUpdate | | ( model - > IsDynamicModel ( ) = = DM_CONTINUOUS & & def - > dynamicModelFrameCount ! = tr . frameCount ) )
{
2012-11-26 18:58:24 +00:00
R_ClearEntityDefDynamicModel ( def ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if we don't have a snapshot of the dynamic model, generate it now
2012-11-28 15:47:07 +00:00
if ( def - > dynamicModel = = NULL )
{
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( " InstantiateDynamicModel " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// instantiate the snapshot of the dynamic model, possibly reusing memory from the cached snapshot
def - > cachedDynamicModel = model - > InstantiateDynamicModel ( & def - > parms , tr . viewDef , def - > cachedDynamicModel ) ;
2012-11-28 15:47:07 +00:00
if ( def - > cachedDynamicModel ! = NULL & & r_checkBounds . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
idBounds b = def - > cachedDynamicModel - > Bounds ( ) ;
2012-11-28 15:47:07 +00:00
if ( b [ 0 ] [ 0 ] < def - > localReferenceBounds [ 0 ] [ 0 ] - CHECK_BOUNDS_EPSILON | |
2012-11-26 18:58:24 +00:00
b [ 0 ] [ 1 ] < def - > localReferenceBounds [ 0 ] [ 1 ] - CHECK_BOUNDS_EPSILON | |
b [ 0 ] [ 2 ] < def - > localReferenceBounds [ 0 ] [ 2 ] - CHECK_BOUNDS_EPSILON | |
b [ 1 ] [ 0 ] > def - > localReferenceBounds [ 1 ] [ 0 ] + CHECK_BOUNDS_EPSILON | |
b [ 1 ] [ 1 ] > def - > localReferenceBounds [ 1 ] [ 1 ] + CHECK_BOUNDS_EPSILON | |
2012-11-28 15:47:07 +00:00
b [ 1 ] [ 2 ] > def - > localReferenceBounds [ 1 ] [ 2 ] + CHECK_BOUNDS_EPSILON )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " entity %i dynamic model exceeded reference bounds \n " , def - > index ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
def - > dynamicModel = def - > cachedDynamicModel ;
def - > dynamicModelFrameCount = tr . frameCount ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// set model depth hack value
2012-11-28 15:47:07 +00:00
if ( def - > dynamicModel ! = NULL & & model - > DepthHack ( ) ! = 0.0f & & tr . viewDef ! = NULL )
{
2012-11-26 18:58:24 +00:00
idPlane eye , clip ;
idVec3 ndc ;
R_TransformModelToClip ( def - > parms . origin , tr . viewDef - > worldSpace . modelViewMatrix , tr . viewDef - > projectionMatrix , eye , clip ) ;
R_TransformClipToDevice ( clip , ndc ) ;
def - > parms . modelDepthHack = model - > DepthHack ( ) * ( 1.0f - ndc . z ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
def - > parms . modelDepthHack = 0.0f ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
return def - > dynamicModel ;
}
/*
= = = = = = = = = = = = = = = = = = =
R_SetupDrawSurfShader
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_SetupDrawSurfShader ( drawSurf_t * drawSurf , const idMaterial * shader , const renderEntity_t * renderEntity )
{
2012-11-26 18:58:24 +00:00
drawSurf - > material = shader ;
drawSurf - > sort = shader - > GetSort ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// process the shader expressions for conditionals / color / texcoords
2012-11-28 15:47:07 +00:00
const float * constRegs = shader - > ConstantRegisters ( ) ;
if ( likely ( constRegs ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
// shader only uses constant values
drawSurf - > shaderRegisters = constRegs ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// by default evaluate with the entityDef's shader parms
2012-11-28 15:47:07 +00:00
const float * shaderParms = renderEntity - > shaderParms ;
2012-11-26 18:58:24 +00:00
// a reference shader will take the calculated stage color value from another shader
// and use that for the parm0-parm3 of the current shader, which allows a stage of
// a light model and light flares to pick up different flashing tables from
// different light shaders
float generatedShaderParms [ MAX_ENTITY_SHADER_PARMS ] ;
2012-11-28 15:47:07 +00:00
if ( unlikely ( renderEntity - > referenceShader ! = NULL ) )
{
2012-11-26 18:58:24 +00:00
// evaluate the reference shader to find our shader parms
float refRegs [ MAX_EXPRESSION_REGISTERS ] ;
renderEntity - > referenceShader - > EvaluateRegisters ( refRegs , renderEntity - > shaderParms ,
2012-11-28 15:47:07 +00:00
tr . viewDef - > renderView . shaderParms ,
tr . viewDef - > renderView . time [ renderEntity - > timeGroup ] * 0.001f , renderEntity - > referenceSound ) ;
const shaderStage_t * pStage = renderEntity - > referenceShader - > GetStage ( 0 ) ;
2012-11-26 18:58:24 +00:00
memcpy ( generatedShaderParms , renderEntity - > shaderParms , sizeof ( generatedShaderParms ) ) ;
generatedShaderParms [ 0 ] = refRegs [ pStage - > color . registers [ 0 ] ] ;
generatedShaderParms [ 1 ] = refRegs [ pStage - > color . registers [ 1 ] ] ;
generatedShaderParms [ 2 ] = refRegs [ pStage - > color . registers [ 2 ] ] ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
shaderParms = generatedShaderParms ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// allocte frame memory for the shader register values
2012-11-28 15:47:07 +00:00
float * regs = ( float * ) R_FrameAlloc ( shader - > GetNumRegisters ( ) * sizeof ( float ) , FRAME_ALLOC_SHADER_REGISTER ) ;
2012-11-26 18:58:24 +00:00
drawSurf - > shaderRegisters = regs ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// process the shader expressions for conditionals / color / texcoords
shader - > EvaluateRegisters ( regs , shaderParms , tr . viewDef - > renderView . shaderParms ,
2012-11-28 15:47:07 +00:00
tr . viewDef - > renderView . time [ renderEntity - > timeGroup ] * 0.001f , renderEntity - > referenceSound ) ;
2012-11-26 18:58:24 +00:00
}
}
/*
= = = = = = = = = = = = = = = = = = =
R_SetupDrawSurfJoints
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_SetupDrawSurfJoints ( drawSurf_t * drawSurf , const srfTriangles_t * tri , const idMaterial * shader )
{
if ( tri - > staticModelWithJoints = = NULL | | ! r_useGPUSkinning . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
drawSurf - > jointCache = 0 ;
return ;
}
2012-11-28 15:47:07 +00:00
idRenderModelStatic * model = tri - > staticModelWithJoints ;
2012-11-26 18:58:24 +00:00
assert ( model - > jointsInverted ! = NULL ) ;
2012-11-28 15:47:07 +00:00
if ( ! vertexCache . CacheIsCurrent ( model - > jointsInvertedBuffer ) )
{
2012-11-26 18:58:24 +00:00
const int alignment = glConfig . uniformBufferOffsetAlignment ;
model - > jointsInvertedBuffer = vertexCache . AllocJoint ( model - > jointsInverted , ALIGN ( model - > numInvertedJoints * sizeof ( idJointMat ) , alignment ) ) ;
}
drawSurf - > jointCache = model - > jointsInvertedBuffer ;
}
/*
= = = = = = = = = = = = = = = = = = =
R_AddSingleModel
May be run in parallel .
Here is where dynamic models actually get instantiated , and necessary
interaction surfaces get created . This is all done on a sort - by - model
basis to keep source data in cache ( most likely L2 ) as any interactions
and shadows are generated , since dynamic models will typically be lit by
two or more lights .
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_AddSingleModel ( viewEntity_t * vEntity )
{
2012-11-26 18:58:24 +00:00
// we will add all interaction surfs here, to be chained to the lights in later serial code
vEntity - > drawSurfs = NULL ;
vEntity - > staticShadowVolumes = NULL ;
vEntity - > dynamicShadowVolumes = NULL ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// globals we really should pass in...
2012-11-28 15:47:07 +00:00
const viewDef_t * viewDef = tr . viewDef ;
idRenderEntityLocal * entityDef = vEntity - > entityDef ;
const renderEntity_t * renderEntity = & entityDef - > parms ;
const idRenderWorldLocal * world = entityDef - > world ;
if ( viewDef - > isXraySubview & & entityDef - > parms . xrayIndex = = 1 )
{
2012-11-26 18:58:24 +00:00
return ;
2012-11-28 15:47:07 +00:00
}
else if ( ! viewDef - > isXraySubview & & entityDef - > parms . xrayIndex = = 2 )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( renderEntity - > hModel = = NULL ? " Unknown Model " : renderEntity - > hModel - > Name ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// calculate the znear for testing whether or not the view is inside a shadow projection
const float znear = ( viewDef - > renderView . cramZNear ) ? ( r_znear . GetFloat ( ) * 0.25f ) : r_znear . GetFloat ( ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if the entity wasn't seen through a portal chain, it was added just for light shadows
const bool modelIsVisible = ! vEntity - > scissorRect . IsEmpty ( ) ;
const bool addInteractions = modelIsVisible & & ( ! viewDef - > isXraySubview | | entityDef - > parms . xrayIndex = = 2 ) ;
const int entityIndex = entityDef - > index ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//---------------------------
// Find which of the visible lights contact this entity
//
// If the entity doesn't accept light or cast shadows from any surface,
// this can be skipped.
//
// OPTIMIZE: world areas can assume all referenced lights are used
//---------------------------
int numContactedLights = 0 ;
static const int MAX_CONTACTED_LIGHTS = 128 ;
2012-11-28 15:47:07 +00:00
viewLight_t * contactedLights [ MAX_CONTACTED_LIGHTS ] ;
idInteraction * staticInteractions [ MAX_CONTACTED_LIGHTS ] ;
if ( renderEntity - > hModel = = NULL | |
2012-11-26 18:58:24 +00:00
renderEntity - > hModel - > ModelHasInteractingSurfaces ( ) | |
2012-11-28 15:47:07 +00:00
renderEntity - > hModel - > ModelHasShadowCastingSurfaces ( ) )
{
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( " Find lights " ) ;
2012-11-28 15:47:07 +00:00
for ( viewLight_t * vLight = viewDef - > viewLights ; vLight ! = NULL ; vLight = vLight - > next )
{
if ( vLight - > scissorRect . IsEmpty ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( vLight - > entityInteractionState ! = NULL )
{
2012-11-26 18:58:24 +00:00
// new code path, everything was done in AddLight
2012-11-28 15:47:07 +00:00
if ( vLight - > entityInteractionState [ entityIndex ] = = viewLight_t : : INTERACTION_YES )
{
2012-11-26 18:58:24 +00:00
contactedLights [ numContactedLights ] = vLight ;
staticInteractions [ numContactedLights ] = world - > interactionTable [ vLight - > lightDef - > index * world - > interactionTableWidth + entityIndex ] ;
2012-11-28 15:47:07 +00:00
if ( + + numContactedLights = = MAX_CONTACTED_LIGHTS )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
continue ;
}
2012-11-28 15:47:07 +00:00
const idRenderLightLocal * lightDef = vLight - > lightDef ;
if ( ! lightDef - > globalLightBounds . IntersectsBounds ( entityDef - > globalReferenceBounds ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( R_CullModelBoundsToLight ( lightDef , entityDef - > localReferenceBounds , entityDef - > modelRenderMatrix ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ! modelIsVisible )
{
2012-11-26 18:58:24 +00:00
// some lights have their center of projection outside the world
2012-11-28 15:47:07 +00:00
if ( lightDef - > areaNum ! = - 1 )
{
2012-11-26 18:58:24 +00:00
// if no part of the model is in an area that is connected to
// the light center (it is behind a solid, closed door), we can ignore it
bool areasConnected = false ;
2012-11-28 15:47:07 +00:00
for ( areaReference_t * ref = entityDef - > entityRefs ; ref ! = NULL ; ref = ref - > ownerNext )
{
if ( world - > AreasAreConnected ( lightDef - > areaNum , ref - > area - > areaNum , PS_BLOCK_VIEW ) )
{
2012-11-26 18:58:24 +00:00
areasConnected = true ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( areasConnected = = false )
{
2012-11-26 18:58:24 +00:00
// can't possibly be seen or shadowed
continue ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// check more precisely for shadow visibility
idBounds shadowBounds ;
R_ShadowBounds ( entityDef - > globalReferenceBounds , lightDef - > globalLightBounds , lightDef - > globalLightOrigin , shadowBounds ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// this doesn't say that the shadow can't effect anything, only that it can't
// effect anything in the view
2012-11-28 15:47:07 +00:00
if ( idRenderMatrix : : CullBoundsToMVP ( viewDef - > worldSpace . mvp , shadowBounds ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
}
contactedLights [ numContactedLights ] = vLight ;
staticInteractions [ numContactedLights ] = world - > interactionTable [ vLight - > lightDef - > index * world - > interactionTableWidth + entityIndex ] ;
2012-11-28 15:47:07 +00:00
if ( + + numContactedLights = = MAX_CONTACTED_LIGHTS )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if we aren't visible and none of the shadows stretch into the view,
// we don't need to do anything else
2012-11-28 15:47:07 +00:00
if ( ! modelIsVisible & & numContactedLights = = 0 )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//---------------------------
// create a dynamic model if the geometry isn't static
//---------------------------
2012-11-28 15:47:07 +00:00
idRenderModel * model = R_EntityDefDynamicModel ( entityDef ) ;
if ( model = = NULL | | model - > NumSurfaces ( ) < = 0 )
{
2012-11-26 18:58:24 +00:00
return ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// add the lightweight blood decal surfaces if the model is directly visible
2012-11-28 15:47:07 +00:00
if ( modelIsVisible )
{
2012-11-26 18:58:24 +00:00
assert ( ! vEntity - > scissorRect . IsEmpty ( ) ) ;
2012-11-28 15:47:07 +00:00
if ( entityDef - > decals ! = NULL & & ! r_skipDecals . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
entityDef - > decals - > CreateDeferredDecals ( model ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
unsigned int numDrawSurfs = entityDef - > decals - > GetNumDecalDrawSurfs ( ) ;
2012-11-28 15:47:07 +00:00
for ( unsigned int i = 0 ; i < numDrawSurfs ; i + + )
{
drawSurf_t * decalDrawSurf = entityDef - > decals - > CreateDecalDrawSurf ( vEntity , i ) ;
if ( decalDrawSurf ! = NULL )
{
2012-11-26 18:58:24 +00:00
decalDrawSurf - > linkChain = NULL ;
decalDrawSurf - > nextOnLight = vEntity - > drawSurfs ;
vEntity - > drawSurfs = decalDrawSurf ;
}
}
}
2012-11-28 15:47:07 +00:00
if ( entityDef - > overlays ! = NULL & & ! r_skipOverlays . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
entityDef - > overlays - > CreateDeferredOverlays ( model ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
unsigned int numDrawSurfs = entityDef - > overlays - > GetNumOverlayDrawSurfs ( ) ;
2012-11-28 15:47:07 +00:00
for ( unsigned int i = 0 ; i < numDrawSurfs ; i + + )
{
drawSurf_t * overlayDrawSurf = entityDef - > overlays - > CreateOverlayDrawSurf ( vEntity , model , i ) ;
if ( overlayDrawSurf ! = NULL )
{
2012-11-26 18:58:24 +00:00
overlayDrawSurf - > linkChain = NULL ;
overlayDrawSurf - > nextOnLight = vEntity - > drawSurfs ;
vEntity - > drawSurfs = overlayDrawSurf ;
}
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//---------------------------
// copy matrix related stuff for back-end use
// and setup a render matrix for faster culling
//---------------------------
vEntity - > modelDepthHack = renderEntity - > modelDepthHack ;
vEntity - > weaponDepthHack = renderEntity - > weaponDepthHack ;
vEntity - > skipMotionBlur = renderEntity - > skipMotionBlur ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
memcpy ( vEntity - > modelMatrix , entityDef - > modelMatrix , sizeof ( vEntity - > modelMatrix ) ) ;
R_MatrixMultiply ( entityDef - > modelMatrix , viewDef - > worldSpace . modelViewMatrix , vEntity - > modelViewMatrix ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
idRenderMatrix viewMat ;
2012-11-28 15:47:07 +00:00
idRenderMatrix : : Transpose ( * ( idRenderMatrix * ) vEntity - > modelViewMatrix , viewMat ) ;
2012-11-26 18:58:24 +00:00
idRenderMatrix : : Multiply ( viewDef - > projectionRenderMatrix , viewMat , vEntity - > mvp ) ;
2012-11-28 15:47:07 +00:00
if ( renderEntity - > weaponDepthHack )
{
2012-11-26 18:58:24 +00:00
idRenderMatrix : : ApplyDepthHack ( vEntity - > mvp ) ;
}
2012-11-28 15:47:07 +00:00
if ( renderEntity - > modelDepthHack ! = 0.0f )
{
2012-11-26 18:58:24 +00:00
idRenderMatrix : : ApplyModelDepthHack ( vEntity - > mvp , renderEntity - > modelDepthHack ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// local light and view origins are used to determine if the view is definitely outside
// an extruded shadow volume, which means we can skip drawing the end caps
idVec3 localViewOrigin ;
R_GlobalPointToLocal ( vEntity - > modelMatrix , viewDef - > renderView . vieworg , localViewOrigin ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//---------------------------
// add all the model surfaces
//---------------------------
2012-11-28 15:47:07 +00:00
for ( int surfaceNum = 0 ; surfaceNum < model - > NumSurfaces ( ) ; surfaceNum + + )
{
const modelSurface_t * surf = model - > Surface ( surfaceNum ) ;
2012-11-26 18:58:24 +00:00
// for debugging, only show a single surface at a time
2012-11-28 15:47:07 +00:00
if ( r_singleSurface . GetInteger ( ) > = 0 & & surfaceNum ! = r_singleSurface . GetInteger ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
srfTriangles_t * tri = surf - > geometry ;
if ( tri = = NULL )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-12-11 22:48:55 +00:00
if ( tri - > numIndexes = = 0 )
2012-11-28 15:47:07 +00:00
{
2012-11-26 18:58:24 +00:00
continue ; // happens for particles
}
2012-11-28 15:47:07 +00:00
const idMaterial * shader = surf - > shader ;
if ( shader = = NULL )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ! shader - > IsDrawn ( ) )
{
2012-11-26 18:58:24 +00:00
continue ; // collision hulls, etc
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// RemapShaderBySkin
2012-11-28 15:47:07 +00:00
if ( entityDef - > parms . customShader ! = NULL )
{
2012-11-26 18:58:24 +00:00
// this is sort of a hack, but causes deformed surfaces to map to empty surfaces,
// so the item highlight overlay doesn't highlight the autosprite surface
2012-11-28 15:47:07 +00:00
if ( shader - > Deform ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
shader = entityDef - > parms . customShader ;
2012-11-28 15:47:07 +00:00
}
else if ( entityDef - > parms . customSkin )
{
2012-11-26 18:58:24 +00:00
shader = entityDef - > parms . customSkin - > RemapShaderBySkin ( shader ) ;
2012-11-28 15:47:07 +00:00
if ( shader = = NULL )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ! shader - > IsDrawn ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// optionally override with the renderView->globalMaterial
2012-11-28 15:47:07 +00:00
if ( tr . primaryRenderView . globalMaterial ! = NULL )
{
2012-11-26 18:58:24 +00:00
shader = tr . primaryRenderView . globalMaterial ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( shader - > GetName ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// debugging tool to make sure we have the correct pre-calculated bounds
2012-11-28 15:47:07 +00:00
if ( r_checkBounds . GetBool ( ) )
{
for ( int j = 0 ; j < tri - > numVerts ; j + + )
{
2012-11-26 18:58:24 +00:00
int k ;
2012-11-28 15:47:07 +00:00
for ( k = 0 ; k < 3 ; k + + )
{
if ( tri - > verts [ j ] . xyz [ k ] > tri - > bounds [ 1 ] [ k ] + CHECK_BOUNDS_EPSILON
| | tri - > verts [ j ] . xyz [ k ] < tri - > bounds [ 0 ] [ k ] - CHECK_BOUNDS_EPSILON )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " bad tri->bounds on %s:%s \n " , entityDef - > parms . hModel - > Name ( ) , shader - > GetName ( ) ) ;
break ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > verts [ j ] . xyz [ k ] > entityDef - > localReferenceBounds [ 1 ] [ k ] + CHECK_BOUNDS_EPSILON
| | tri - > verts [ j ] . xyz [ k ] < entityDef - > localReferenceBounds [ 0 ] [ k ] - CHECK_BOUNDS_EPSILON )
{
2012-11-26 18:58:24 +00:00
common - > Printf ( " bad referenceBounds on %s:%s \n " , entityDef - > parms . hModel - > Name ( ) , shader - > GetName ( ) ) ;
break ;
}
}
2012-11-28 15:47:07 +00:00
if ( k ! = 3 )
{
2012-11-26 18:58:24 +00:00
break ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// view frustum culling for the precise surface bounds, which is tighter
// than the entire entity reference bounds
// If the entire model wasn't visible, there is no need to check the
// individual surfaces.
const bool surfaceDirectlyVisible = modelIsVisible & & ! idRenderMatrix : : CullBoundsToMVP ( vEntity - > mvp , tri - > bounds ) ;
const bool gpuSkinned = ( tri - > staticModelWithJoints ! = NULL & & r_useGPUSkinning . GetBool ( ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//--------------------------
// base drawing surface
//--------------------------
2012-11-28 15:47:07 +00:00
drawSurf_t * baseDrawSurf = NULL ;
if ( surfaceDirectlyVisible )
{
2012-11-26 18:58:24 +00:00
// make sure we have an ambient cache and all necessary normals / tangents
2012-11-28 15:47:07 +00:00
if ( ! vertexCache . CacheIsCurrent ( tri - > indexCache ) )
{
2012-11-26 18:58:24 +00:00
tri - > indexCache = vertexCache . AllocIndex ( tri - > indexes , ALIGN ( tri - > numIndexes * sizeof ( triIndex_t ) , INDEX_CACHE_ALIGN ) ) ;
}
2012-11-28 15:47:07 +00:00
if ( ! vertexCache . CacheIsCurrent ( tri - > ambientCache ) )
{
2012-11-26 18:58:24 +00:00
// we are going to use it for drawing, so make sure we have the tangents and normals
2012-11-28 15:47:07 +00:00
if ( shader - > ReceivesLighting ( ) & & ! tri - > tangentsCalculated )
{
2012-11-26 18:58:24 +00:00
assert ( tri - > staticModelWithJoints = = NULL ) ;
R_DeriveTangents ( tri ) ;
2012-12-08 17:20:13 +00:00
2012-12-07 20:24:45 +00:00
// RB: this was hit by parametric particle models ..
//assert( false ); // this should no longer be hit
// RB end
2012-11-26 18:58:24 +00:00
}
tri - > ambientCache = vertexCache . AllocVertex ( tri - > verts , ALIGN ( tri - > numVerts * sizeof ( idDrawVert ) , VERTEX_CACHE_ALIGN ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// add the surface for drawing
2012-11-28 15:47:07 +00:00
// we can re-use some of the values for light interaction surfaces
baseDrawSurf = ( drawSurf_t * ) R_FrameAlloc ( sizeof ( * baseDrawSurf ) , FRAME_ALLOC_DRAW_SURFACE ) ;
2012-11-26 18:58:24 +00:00
baseDrawSurf - > frontEndGeo = tri ;
baseDrawSurf - > space = vEntity ;
baseDrawSurf - > scissorRect = vEntity - > scissorRect ;
baseDrawSurf - > extraGLState = 0 ;
baseDrawSurf - > renderZFail = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_SetupDrawSurfShader ( baseDrawSurf , shader , renderEntity ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Check for deformations (eyeballs, flares, etc)
const deform_t shaderDeform = shader - > Deform ( ) ;
2012-11-28 15:47:07 +00:00
if ( shaderDeform ! = DFRM_NONE )
{
drawSurf_t * deformDrawSurf = R_DeformDrawSurf ( baseDrawSurf ) ;
if ( deformDrawSurf ! = NULL )
{
2012-11-26 18:58:24 +00:00
// any deforms may have created multiple draw surfaces
2012-11-28 15:47:07 +00:00
for ( drawSurf_t * surf = deformDrawSurf , * next = NULL ; surf ! = NULL ; surf = next )
{
2012-11-26 18:58:24 +00:00
next = surf - > nextOnLight ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
surf - > linkChain = NULL ;
surf - > nextOnLight = vEntity - > drawSurfs ;
vEntity - > drawSurfs = surf ;
}
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Most deform source surfaces do not need to be rendered.
// However, particles are rendered in conjunction with the source surface.
2012-11-28 15:47:07 +00:00
if ( shaderDeform = = DFRM_NONE | | shaderDeform = = DFRM_PARTICLE | | shaderDeform = = DFRM_PARTICLE2 )
{
2012-11-26 18:58:24 +00:00
// copy verts and indexes to this frame's hardware memory if they aren't already there
2012-11-28 15:47:07 +00:00
if ( ! vertexCache . CacheIsCurrent ( tri - > ambientCache ) )
{
2012-11-26 18:58:24 +00:00
tri - > ambientCache = vertexCache . AllocVertex ( tri - > verts , ALIGN ( tri - > numVerts * sizeof ( tri - > verts [ 0 ] ) , VERTEX_CACHE_ALIGN ) ) ;
}
2012-11-28 15:47:07 +00:00
if ( ! vertexCache . CacheIsCurrent ( tri - > indexCache ) )
{
2012-11-26 18:58:24 +00:00
tri - > indexCache = vertexCache . AllocIndex ( tri - > indexes , ALIGN ( tri - > numIndexes * sizeof ( tri - > indexes [ 0 ] ) , INDEX_CACHE_ALIGN ) ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_SetupDrawSurfJoints ( baseDrawSurf , tri , shader ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
baseDrawSurf - > numIndexes = tri - > numIndexes ;
baseDrawSurf - > ambientCache = tri - > ambientCache ;
baseDrawSurf - > indexCache = tri - > indexCache ;
baseDrawSurf - > shadowCache = 0 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
baseDrawSurf - > linkChain = NULL ; // link to the view
baseDrawSurf - > nextOnLight = vEntity - > drawSurfs ;
vEntity - > drawSurfs = baseDrawSurf ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//----------------------------------------
// add all light interactions
//----------------------------------------
2012-11-28 15:47:07 +00:00
for ( int contactedLight = 0 ; contactedLight < numContactedLights ; contactedLight + + )
{
viewLight_t * vLight = contactedLights [ contactedLight ] ;
const idRenderLightLocal * lightDef = vLight - > lightDef ;
const idInteraction * interaction = staticInteractions [ contactedLight ] ;
2012-11-26 18:58:24 +00:00
// check for a static interaction
2012-11-28 15:47:07 +00:00
surfaceInteraction_t * surfInter = NULL ;
if ( interaction > INTERACTION_EMPTY & & interaction - > staticInteraction )
{
2012-11-26 18:58:24 +00:00
// we have a static interaction that was calculated accurately
assert ( model - > NumSurfaces ( ) = = interaction - > numSurfaces ) ;
surfInter = & interaction - > surfaces [ surfaceNum ] ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// try to do a more precise cull of this model surface to the light
2012-11-28 15:47:07 +00:00
if ( R_CullModelBoundsToLight ( lightDef , tri - > bounds , entityDef - > modelRenderMatrix ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
}
// "invisible ink" lights and shaders (imp spawn drawing on walls, etc)
2012-11-28 15:47:07 +00:00
if ( shader - > Spectrum ( ) ! = lightDef - > lightShader - > Spectrum ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Calculate the local light origin to determine if the view is inside the shadow
// projection and to calculate the triangle facing for dynamic shadow volumes.
idVec3 localLightOrigin ;
R_GlobalPointToLocal ( vEntity - > modelMatrix , lightDef - > globalLightOrigin , localLightOrigin ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//--------------------------
// surface light interactions
//--------------------------
2012-11-28 15:47:07 +00:00
dynamicShadowVolumeParms_t * dynamicShadowParms = NULL ;
if ( addInteractions & & surfaceDirectlyVisible & & shader - > ReceivesLighting ( ) )
{
2012-11-26 18:58:24 +00:00
// static interactions can commonly find that no triangles from a surface
// contact the light, even when the total model does
2012-11-28 15:47:07 +00:00
if ( surfInter = = NULL | | surfInter - > lightTrisIndexCache > 0 )
{
2012-11-26 18:58:24 +00:00
// create a drawSurf for this interaction
2012-11-28 15:47:07 +00:00
drawSurf_t * lightDrawSurf = ( drawSurf_t * ) R_FrameAlloc ( sizeof ( * lightDrawSurf ) , FRAME_ALLOC_DRAW_SURFACE ) ;
if ( surfInter ! = NULL )
{
2012-11-26 18:58:24 +00:00
// optimized static interaction
lightDrawSurf - > numIndexes = surfInter - > numLightTrisIndexes ;
lightDrawSurf - > indexCache = surfInter - > lightTrisIndexCache ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// throw the entire source surface at it without any per-triangle culling
lightDrawSurf - > numIndexes = tri - > numIndexes ;
lightDrawSurf - > indexCache = tri - > indexCache ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// optionally cull the triangles to the light volume
2012-11-28 15:47:07 +00:00
if ( r_cullDynamicLightTriangles . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
vertCacheHandle_t lightIndexCache = vertexCache . AllocIndex ( NULL , ALIGN ( lightDrawSurf - > numIndexes * sizeof ( triIndex_t ) , INDEX_CACHE_ALIGN ) ) ;
2012-11-28 15:47:07 +00:00
if ( vertexCache . CacheIsCurrent ( lightIndexCache ) )
{
2012-11-26 18:58:24 +00:00
lightDrawSurf - > indexCache = lightIndexCache ;
2012-11-28 15:47:07 +00:00
dynamicShadowParms = ( dynamicShadowVolumeParms_t * ) R_FrameAlloc ( sizeof ( dynamicShadowParms [ 0 ] ) , FRAME_ALLOC_SHADOW_VOLUME_PARMS ) ;
2012-11-26 18:58:24 +00:00
dynamicShadowParms - > verts = tri - > verts ;
dynamicShadowParms - > numVerts = tri - > numVerts ;
dynamicShadowParms - > indexes = tri - > indexes ;
dynamicShadowParms - > numIndexes = tri - > numIndexes ;
dynamicShadowParms - > silEdges = tri - > silEdges ;
dynamicShadowParms - > numSilEdges = tri - > numSilEdges ;
dynamicShadowParms - > joints = gpuSkinned ? tri - > staticModelWithJoints - > jointsInverted : NULL ;
dynamicShadowParms - > numJoints = gpuSkinned ? tri - > staticModelWithJoints - > numInvertedJoints : 0 ;
dynamicShadowParms - > triangleBounds = tri - > bounds ;
dynamicShadowParms - > triangleMVP = vEntity - > mvp ;
dynamicShadowParms - > localLightOrigin = localLightOrigin ;
dynamicShadowParms - > localViewOrigin = localViewOrigin ;
idRenderMatrix : : Multiply ( vLight - > lightDef - > baseLightProject , entityDef - > modelRenderMatrix , dynamicShadowParms - > localLightProject ) ;
dynamicShadowParms - > zNear = znear ;
dynamicShadowParms - > lightZMin = vLight - > scissorRect . zmin ;
dynamicShadowParms - > lightZMax = vLight - > scissorRect . zmax ;
dynamicShadowParms - > cullShadowTrianglesToLight = false ;
dynamicShadowParms - > forceShadowCaps = false ;
dynamicShadowParms - > useShadowPreciseInsideTest = false ;
dynamicShadowParms - > useShadowDepthBounds = false ;
dynamicShadowParms - > tempFacing = NULL ;
dynamicShadowParms - > tempCulled = NULL ;
dynamicShadowParms - > tempVerts = NULL ;
dynamicShadowParms - > indexBuffer = NULL ;
dynamicShadowParms - > shadowIndices = NULL ;
dynamicShadowParms - > maxShadowIndices = 0 ;
dynamicShadowParms - > numShadowIndices = NULL ;
2012-11-28 15:47:07 +00:00
dynamicShadowParms - > lightIndices = ( triIndex_t * ) vertexCache . MappedIndexBuffer ( lightIndexCache ) ;
2012-11-26 18:58:24 +00:00
dynamicShadowParms - > maxLightIndices = lightDrawSurf - > numIndexes ;
dynamicShadowParms - > numLightIndices = & lightDrawSurf - > numIndexes ;
dynamicShadowParms - > renderZFail = NULL ;
dynamicShadowParms - > shadowZMin = NULL ;
dynamicShadowParms - > shadowZMax = NULL ;
dynamicShadowParms - > shadowVolumeState = & lightDrawSurf - > shadowVolumeState ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
lightDrawSurf - > shadowVolumeState = SHADOWVOLUME_UNFINISHED ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
dynamicShadowParms - > next = vEntity - > dynamicShadowVolumes ;
vEntity - > dynamicShadowVolumes = dynamicShadowParms ;
}
}
}
lightDrawSurf - > ambientCache = tri - > ambientCache ;
lightDrawSurf - > shadowCache = 0 ;
lightDrawSurf - > frontEndGeo = tri ;
lightDrawSurf - > space = vEntity ;
lightDrawSurf - > material = shader ;
lightDrawSurf - > extraGLState = 0 ;
lightDrawSurf - > scissorRect = vLight - > scissorRect ; // interactionScissor;
lightDrawSurf - > sort = 0.0f ;
lightDrawSurf - > renderZFail = 0 ;
lightDrawSurf - > shaderRegisters = baseDrawSurf - > shaderRegisters ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_SetupDrawSurfJoints ( lightDrawSurf , tri , shader ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// Determine which linked list to add the light surface to.
// There will only be localSurfaces if the light casts shadows and
// there are surfaces with NOSELFSHADOW.
2012-11-28 15:47:07 +00:00
if ( shader - > Coverage ( ) = = MC_TRANSLUCENT )
{
2012-11-26 18:58:24 +00:00
lightDrawSurf - > linkChain = & vLight - > translucentInteractions ;
2012-11-28 15:47:07 +00:00
}
else if ( ! lightDef - > parms . noShadows & & shader - > TestMaterialFlag ( MF_NOSELFSHADOW ) )
{
2012-11-26 18:58:24 +00:00
lightDrawSurf - > linkChain = & vLight - > localInteractions ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
lightDrawSurf - > linkChain = & vLight - > globalInteractions ;
}
lightDrawSurf - > nextOnLight = vEntity - > drawSurfs ;
vEntity - > drawSurfs = lightDrawSurf ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//--------------------------
// surface shadows
//--------------------------
2012-11-28 15:47:07 +00:00
if ( ! shader - > SurfaceCastsShadow ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( ! lightDef - > LightCastsShadows ( ) )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( tri - > silEdges = = NULL )
{
2012-11-26 18:58:24 +00:00
continue ; // can happen for beam models (shouldn't use a shadow casting material, though...)
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if the static shadow does not have any shadows
2012-11-28 15:47:07 +00:00
if ( surfInter ! = NULL & & surfInter - > numShadowIndexes = = 0 )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// some entities, like view weapons, don't cast any shadows
2012-11-28 15:47:07 +00:00
if ( entityDef - > parms . noShadow )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// No shadow if it's suppressed for this light.
2012-11-28 15:47:07 +00:00
if ( entityDef - > parms . suppressShadowInLightID & & entityDef - > parms . suppressShadowInLightID = = lightDef - > parms . lightId )
{
2012-11-26 18:58:24 +00:00
continue ;
}
2012-11-28 15:47:07 +00:00
if ( lightDef - > parms . prelightModel & & lightDef - > lightHasMoved = = false & &
entityDef - > parms . hModel - > IsStaticWorldModel ( ) & & ! r_skipPrelightShadows . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
// static light / world model shadow interacitons
// are always captured in the prelight shadow volume
continue ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// If the shadow is drawn (or translucent), but the model isn't, we must include the shadow caps
// because we may be able to see into the shadow volume even though the view is outside it.
// This happens for the player world weapon and possibly some animations in multiplayer.
const bool forceShadowCaps = ! addInteractions | | r_forceShadowCaps . GetBool ( ) ;
2012-11-28 15:47:07 +00:00
drawSurf_t * shadowDrawSurf = ( drawSurf_t * ) R_FrameAlloc ( sizeof ( * shadowDrawSurf ) , FRAME_ALLOC_DRAW_SURFACE ) ;
if ( surfInter ! = NULL )
{
2012-11-26 18:58:24 +00:00
shadowDrawSurf - > numIndexes = 0 ;
shadowDrawSurf - > indexCache = surfInter - > shadowIndexCache ;
shadowDrawSurf - > shadowCache = tri - > shadowCache ;
shadowDrawSurf - > scissorRect = vLight - > scissorRect ; // default to the light scissor and light depth bounds
shadowDrawSurf - > shadowVolumeState = SHADOWVOLUME_DONE ; // assume the shadow volume is done in case r_skipStaticShadows is set
2012-11-28 15:47:07 +00:00
if ( ! r_skipStaticShadows . GetBool ( ) )
{
staticShadowVolumeParms_t * staticShadowParms = ( staticShadowVolumeParms_t * ) R_FrameAlloc ( sizeof ( staticShadowParms [ 0 ] ) , FRAME_ALLOC_SHADOW_VOLUME_PARMS ) ;
2012-11-26 18:58:24 +00:00
staticShadowParms - > verts = tri - > staticShadowVertexes ;
staticShadowParms - > numVerts = tri - > numVerts * 2 ;
staticShadowParms - > indexes = surfInter - > shadowIndexes ;
staticShadowParms - > numIndexes = surfInter - > numShadowIndexes ;
staticShadowParms - > numShadowIndicesWithCaps = surfInter - > numShadowIndexes ;
staticShadowParms - > numShadowIndicesNoCaps = surfInter - > numShadowIndexesNoCaps ;
staticShadowParms - > triangleBounds = tri - > bounds ;
staticShadowParms - > triangleMVP = vEntity - > mvp ;
staticShadowParms - > localLightOrigin = localLightOrigin ;
staticShadowParms - > localViewOrigin = localViewOrigin ;
staticShadowParms - > zNear = znear ;
staticShadowParms - > lightZMin = vLight - > scissorRect . zmin ;
staticShadowParms - > lightZMax = vLight - > scissorRect . zmax ;
staticShadowParms - > forceShadowCaps = forceShadowCaps ;
staticShadowParms - > useShadowPreciseInsideTest = r_useShadowPreciseInsideTest . GetBool ( ) ;
staticShadowParms - > useShadowDepthBounds = r_useShadowDepthBounds . GetBool ( ) ;
staticShadowParms - > numShadowIndices = & shadowDrawSurf - > numIndexes ;
staticShadowParms - > renderZFail = & shadowDrawSurf - > renderZFail ;
staticShadowParms - > shadowZMin = & shadowDrawSurf - > scissorRect . zmin ;
staticShadowParms - > shadowZMax = & shadowDrawSurf - > scissorRect . zmax ;
staticShadowParms - > shadowVolumeState = & shadowDrawSurf - > shadowVolumeState ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
shadowDrawSurf - > shadowVolumeState = SHADOWVOLUME_UNFINISHED ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
staticShadowParms - > next = vEntity - > staticShadowVolumes ;
vEntity - > staticShadowVolumes = staticShadowParms ;
}
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
// When CPU skinning the dynamic shadow verts of a dynamic model may not have been copied to buffer memory yet.
2012-11-28 15:47:07 +00:00
if ( ! vertexCache . CacheIsCurrent ( tri - > shadowCache ) )
{
2012-11-26 18:58:24 +00:00
assert ( ! gpuSkinned ) ; // the shadow cache should be static when using GPU skinning
// Extracts just the xyz values from a set of full size drawverts, and
// duplicates them with w set to 0 and 1 for the vertex program to project.
// This is constant for any number of lights, the vertex program takes care
// of projecting the verts to infinity for a particular light.
tri - > shadowCache = vertexCache . AllocVertex ( NULL , ALIGN ( tri - > numVerts * 2 * sizeof ( idShadowVert ) , VERTEX_CACHE_ALIGN ) ) ;
2012-11-28 15:47:07 +00:00
idShadowVert * shadowVerts = ( idShadowVert * ) vertexCache . MappedVertexBuffer ( tri - > shadowCache ) ;
2012-11-26 18:58:24 +00:00
idShadowVert : : CreateShadowCache ( shadowVerts , tri - > verts , tri - > numVerts ) ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
const int maxShadowVolumeIndexes = tri - > numSilEdges * 6 + tri - > numIndexes * 2 ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
shadowDrawSurf - > numIndexes = 0 ;
shadowDrawSurf - > indexCache = vertexCache . AllocIndex ( NULL , ALIGN ( maxShadowVolumeIndexes * sizeof ( triIndex_t ) , INDEX_CACHE_ALIGN ) ) ;
shadowDrawSurf - > shadowCache = tri - > shadowCache ;
shadowDrawSurf - > scissorRect = vLight - > scissorRect ; // default to the light scissor and light depth bounds
shadowDrawSurf - > shadowVolumeState = SHADOWVOLUME_DONE ; // assume the shadow volume is done in case the index cache allocation failed
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if the index cache was successfully allocated then setup the parms to create a shadow volume in parallel
2012-11-28 15:47:07 +00:00
if ( vertexCache . CacheIsCurrent ( shadowDrawSurf - > indexCache ) & & ! r_skipDynamicShadows . GetBool ( ) )
{
2012-11-26 18:58:24 +00:00
// if the parms were not already allocated for culling interaction triangles to the light frustum
2012-11-28 15:47:07 +00:00
if ( dynamicShadowParms = = NULL )
{
dynamicShadowParms = ( dynamicShadowVolumeParms_t * ) R_FrameAlloc ( sizeof ( dynamicShadowParms [ 0 ] ) , FRAME_ALLOC_SHADOW_VOLUME_PARMS ) ;
}
else
{
2012-11-26 18:58:24 +00:00
// the shadow volume will be rendered first so when the interaction surface is drawn the triangles have been culled for sure
* dynamicShadowParms - > shadowVolumeState = SHADOWVOLUME_DONE ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
dynamicShadowParms - > verts = tri - > verts ;
dynamicShadowParms - > numVerts = tri - > numVerts ;
dynamicShadowParms - > indexes = tri - > indexes ;
dynamicShadowParms - > numIndexes = tri - > numIndexes ;
dynamicShadowParms - > silEdges = tri - > silEdges ;
dynamicShadowParms - > numSilEdges = tri - > numSilEdges ;
dynamicShadowParms - > joints = gpuSkinned ? tri - > staticModelWithJoints - > jointsInverted : NULL ;
dynamicShadowParms - > numJoints = gpuSkinned ? tri - > staticModelWithJoints - > numInvertedJoints : 0 ;
dynamicShadowParms - > triangleBounds = tri - > bounds ;
dynamicShadowParms - > triangleMVP = vEntity - > mvp ;
dynamicShadowParms - > localLightOrigin = localLightOrigin ;
dynamicShadowParms - > localViewOrigin = localViewOrigin ;
idRenderMatrix : : Multiply ( vLight - > lightDef - > baseLightProject , entityDef - > modelRenderMatrix , dynamicShadowParms - > localLightProject ) ;
dynamicShadowParms - > zNear = znear ;
dynamicShadowParms - > lightZMin = vLight - > scissorRect . zmin ;
dynamicShadowParms - > lightZMax = vLight - > scissorRect . zmax ;
dynamicShadowParms - > cullShadowTrianglesToLight = r_cullDynamicShadowTriangles . GetBool ( ) ;
dynamicShadowParms - > forceShadowCaps = forceShadowCaps ;
dynamicShadowParms - > useShadowPreciseInsideTest = r_useShadowPreciseInsideTest . GetBool ( ) ;
dynamicShadowParms - > useShadowDepthBounds = r_useShadowDepthBounds . GetBool ( ) ;
dynamicShadowParms - > tempFacing = NULL ;
dynamicShadowParms - > tempCulled = NULL ;
dynamicShadowParms - > tempVerts = NULL ;
dynamicShadowParms - > indexBuffer = NULL ;
2012-11-28 15:47:07 +00:00
dynamicShadowParms - > shadowIndices = ( triIndex_t * ) vertexCache . MappedIndexBuffer ( shadowDrawSurf - > indexCache ) ;
2012-11-26 18:58:24 +00:00
dynamicShadowParms - > maxShadowIndices = maxShadowVolumeIndexes ;
dynamicShadowParms - > numShadowIndices = & shadowDrawSurf - > numIndexes ;
// dynamicShadowParms->lightIndices may have already been set for the interaction surface
// dynamicShadowParms->maxLightIndices may have already been set for the interaction surface
// dynamicShadowParms->numLightIndices may have already been set for the interaction surface
dynamicShadowParms - > renderZFail = & shadowDrawSurf - > renderZFail ;
dynamicShadowParms - > shadowZMin = & shadowDrawSurf - > scissorRect . zmin ;
dynamicShadowParms - > shadowZMax = & shadowDrawSurf - > scissorRect . zmax ;
dynamicShadowParms - > shadowVolumeState = & shadowDrawSurf - > shadowVolumeState ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
shadowDrawSurf - > shadowVolumeState = SHADOWVOLUME_UNFINISHED ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// if the parms we not already linked for culling interaction triangles to the light frustum
2012-11-28 15:47:07 +00:00
if ( dynamicShadowParms - > lightIndices = = NULL )
{
2012-11-26 18:58:24 +00:00
dynamicShadowParms - > next = vEntity - > dynamicShadowVolumes ;
vEntity - > dynamicShadowVolumes = dynamicShadowParms ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tr . pc . c_createShadowVolumes + + ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
assert ( vertexCache . CacheIsCurrent ( shadowDrawSurf - > shadowCache ) ) ;
assert ( vertexCache . CacheIsCurrent ( shadowDrawSurf - > indexCache ) ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
shadowDrawSurf - > ambientCache = 0 ;
shadowDrawSurf - > frontEndGeo = NULL ;
shadowDrawSurf - > space = vEntity ;
shadowDrawSurf - > material = NULL ;
shadowDrawSurf - > extraGLState = 0 ;
shadowDrawSurf - > sort = 0.0f ;
shadowDrawSurf - > shaderRegisters = NULL ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
R_SetupDrawSurfJoints ( shadowDrawSurf , tri , NULL ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
// determine which linked list to add the shadow surface to
shadowDrawSurf - > linkChain = shader - > TestMaterialFlag ( MF_NOSELFSHADOW ) ? & vLight - > localShadows : & vLight - > globalShadows ;
shadowDrawSurf - > nextOnLight = vEntity - > drawSurfs ;
vEntity - > drawSurfs = shadowDrawSurf ;
}
}
}
REGISTER_PARALLEL_JOB ( R_AddSingleModel , " R_AddSingleModel " ) ;
/*
= = = = = = = = = = = = = = = = =
R_LinkDrawSurfToView
Als called directly by GuiModel
= = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_LinkDrawSurfToView ( drawSurf_t * drawSurf , viewDef_t * viewDef )
{
2012-11-26 18:58:24 +00:00
// if it doesn't fit, resize the list
2012-11-28 15:47:07 +00:00
if ( viewDef - > numDrawSurfs = = viewDef - > maxDrawSurfs )
{
drawSurf_t * * old = viewDef - > drawSurfs ;
2012-11-26 18:58:24 +00:00
int count ;
2012-11-28 15:47:07 +00:00
if ( viewDef - > maxDrawSurfs = = 0 )
{
2012-11-26 18:58:24 +00:00
viewDef - > maxDrawSurfs = INITIAL_DRAWSURFS ;
count = 0 ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
count = viewDef - > maxDrawSurfs * sizeof ( viewDef - > drawSurfs [ 0 ] ) ;
viewDef - > maxDrawSurfs * = 2 ;
}
2012-11-28 15:47:07 +00:00
viewDef - > drawSurfs = ( drawSurf_t * * ) R_FrameAlloc ( viewDef - > maxDrawSurfs * sizeof ( viewDef - > drawSurfs [ 0 ] ) , FRAME_ALLOC_DRAW_SURFACE_POINTER ) ;
2012-11-26 18:58:24 +00:00
memcpy ( viewDef - > drawSurfs , old , count ) ;
}
viewDef - > drawSurfs [ viewDef - > numDrawSurfs ] = drawSurf ;
viewDef - > numDrawSurfs + + ;
}
/*
= = = = = = = = = = = = = = = = = = =
R_AddModels
The end result of running this is the addition of drawSurf_t to the
tr . viewDef - > drawSurfs [ ] array and light link chains , along with
frameData and vertexCache allocations to support the drawSurfs .
= = = = = = = = = = = = = = = = = = =
*/
2012-11-28 15:47:07 +00:00
void R_AddModels ( )
{
2012-11-26 18:58:24 +00:00
SCOPED_PROFILE_EVENT ( " R_AddModels " ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tr . viewDef - > viewEntitys = R_SortViewEntities ( tr . viewDef - > viewEntitys ) ;
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// Go through each view entity that is either visible to the view, or to
// any light that intersects the view (for shadows).
//-------------------------------------------------
2012-11-28 15:47:07 +00:00
if ( r_useParallelAddModels . GetBool ( ) )
{
for ( viewEntity_t * vEntity = tr . viewDef - > viewEntitys ; vEntity ! = NULL ; vEntity = vEntity - > next )
{
tr . frontEndJobList - > AddJob ( ( jobRun_t ) R_AddSingleModel , vEntity ) ;
2012-11-26 18:58:24 +00:00
}
tr . frontEndJobList - > Submit ( ) ;
tr . frontEndJobList - > Wait ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
for ( viewEntity_t * vEntity = tr . viewDef - > viewEntitys ; vEntity ! = NULL ; vEntity = vEntity - > next )
{
2012-11-26 18:58:24 +00:00
R_AddSingleModel ( vEntity ) ;
}
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// Kick off jobs to setup static and dynamic shadow volumes.
//-------------------------------------------------
2012-11-28 15:47:07 +00:00
if ( r_useParallelAddShadows . GetInteger ( ) = = 1 )
{
for ( viewEntity_t * vEntity = tr . viewDef - > viewEntitys ; vEntity ! = NULL ; vEntity = vEntity - > next )
{
for ( staticShadowVolumeParms_t * shadowParms = vEntity - > staticShadowVolumes ; shadowParms ! = NULL ; shadowParms = shadowParms - > next )
{
tr . frontEndJobList - > AddJob ( ( jobRun_t ) StaticShadowVolumeJob , shadowParms ) ;
2012-11-26 18:58:24 +00:00
}
2012-11-28 15:47:07 +00:00
for ( dynamicShadowVolumeParms_t * shadowParms = vEntity - > dynamicShadowVolumes ; shadowParms ! = NULL ; shadowParms = shadowParms - > next )
{
tr . frontEndJobList - > AddJob ( ( jobRun_t ) DynamicShadowVolumeJob , shadowParms ) ;
2012-11-26 18:58:24 +00:00
}
vEntity - > staticShadowVolumes = NULL ;
vEntity - > dynamicShadowVolumes = NULL ;
}
tr . frontEndJobList - > Submit ( ) ;
// wait here otherwise the shadow volume index buffer may be unmapped before all shadow volumes have been constructed
tr . frontEndJobList - > Wait ( ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
int start = Sys_Microseconds ( ) ;
2012-11-28 15:47:07 +00:00
for ( viewEntity_t * vEntity = tr . viewDef - > viewEntitys ; vEntity ! = NULL ; vEntity = vEntity - > next )
{
for ( staticShadowVolumeParms_t * shadowParms = vEntity - > staticShadowVolumes ; shadowParms ! = NULL ; shadowParms = shadowParms - > next )
{
2012-11-26 18:58:24 +00:00
StaticShadowVolumeJob ( shadowParms ) ;
}
2012-11-28 15:47:07 +00:00
for ( dynamicShadowVolumeParms_t * shadowParms = vEntity - > dynamicShadowVolumes ; shadowParms ! = NULL ; shadowParms = shadowParms - > next )
{
2012-11-26 18:58:24 +00:00
DynamicShadowVolumeJob ( shadowParms ) ;
}
vEntity - > staticShadowVolumes = NULL ;
vEntity - > dynamicShadowVolumes = NULL ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
int end = Sys_Microseconds ( ) ;
backEnd . pc . shadowMicroSec + = end - start ;
}
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
//-------------------------------------------------
// Move the draw surfs to the view.
//-------------------------------------------------
2012-11-28 15:47:07 +00:00
2012-11-26 18:58:24 +00:00
tr . viewDef - > numDrawSurfs = 0 ; // clear the ambient surface list
tr . viewDef - > maxDrawSurfs = 0 ; // will be set to INITIAL_DRAWSURFS on R_LinkDrawSurfToView
2012-11-28 15:47:07 +00:00
for ( viewEntity_t * vEntity = tr . viewDef - > viewEntitys ; vEntity ! = NULL ; vEntity = vEntity - > next )
{
for ( drawSurf_t * ds = vEntity - > drawSurfs ; ds ! = NULL ; )
{
drawSurf_t * next = ds - > nextOnLight ;
if ( ds - > linkChain = = NULL )
{
2012-11-26 18:58:24 +00:00
R_LinkDrawSurfToView ( ds , tr . viewDef ) ;
2012-11-28 15:47:07 +00:00
}
else
{
2012-11-26 18:58:24 +00:00
ds - > nextOnLight = * ds - > linkChain ;
* ds - > linkChain = ds ;
}
ds = next ;
}
vEntity - > drawSurfs = NULL ;
}
}