tr_frontend_addmodels.cpp (46005B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 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. 23 24 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. 25 26 =========================================================================== 27 */ 28 29 #pragma hdrstop 30 #include "../idlib/precompiled.h" 31 32 #include "tr_local.h" 33 #include "Model_local.h" 34 35 idCVar r_skipStaticShadows( "r_skipStaticShadows", "0", CVAR_RENDERER | CVAR_BOOL, "skip static shadows" ); 36 idCVar r_skipDynamicShadows( "r_skipDynamicShadows", "0", CVAR_RENDERER | CVAR_BOOL, "skip dynamic shadows" ); 37 idCVar r_useParallelAddModels( "r_useParallelAddModels", "1", CVAR_RENDERER | CVAR_BOOL, "add all models in parallel with jobs" ); 38 idCVar r_useParallelAddShadows( "r_useParallelAddShadows", "1", CVAR_RENDERER | CVAR_INTEGER, "0 = off, 1 = threaded", 0, 1 ); 39 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" ); 40 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" ); 41 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" ); 42 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" ); 43 44 static const float CHECK_BOUNDS_EPSILON = 1.0f; 45 46 /* 47 ================== 48 R_SortViewEntities 49 ================== 50 */ 51 viewEntity_t * R_SortViewEntities( viewEntity_t * vEntities ) { 52 SCOPED_PROFILE_EVENT( "R_SortViewEntities" ); 53 54 // We want to avoid having a single AddModel for something complex be 55 // the last thing processed and hurt the parallel occupancy, so 56 // sort dynamic models first, _area models second, then everything else. 57 viewEntity_t * dynamics = NULL; 58 viewEntity_t * areas = NULL; 59 viewEntity_t * others = NULL; 60 for ( viewEntity_t * vEntity = vEntities; vEntity != NULL; ) { 61 viewEntity_t * next = vEntity->next; 62 const idRenderModel * model = vEntity->entityDef->parms.hModel; 63 if ( model->IsDynamicModel() != DM_STATIC ) { 64 vEntity->next = dynamics; 65 dynamics = vEntity; 66 } else if ( model->IsStaticWorldModel() ) { 67 vEntity->next = areas; 68 areas = vEntity; 69 } else { 70 vEntity->next = others; 71 others = vEntity; 72 } 73 vEntity = next; 74 } 75 76 // concatenate the lists 77 viewEntity_t * all = others; 78 79 for ( viewEntity_t * vEntity = areas; vEntity != NULL; ) { 80 viewEntity_t * next = vEntity->next; 81 vEntity->next = all; 82 all = vEntity; 83 vEntity = next; 84 } 85 86 for ( viewEntity_t * vEntity = dynamics; vEntity != NULL; ) { 87 viewEntity_t * next = vEntity->next; 88 vEntity->next = all; 89 all = vEntity; 90 vEntity = next; 91 } 92 93 return all; 94 } 95 96 /* 97 ================== 98 R_ClearEntityDefDynamicModel 99 100 If we know the reference bounds stays the same, we 101 only need to do this on entity update, not the full 102 R_FreeEntityDefDerivedData 103 ================== 104 */ 105 void R_ClearEntityDefDynamicModel( idRenderEntityLocal *def ) { 106 // free all the interaction surfaces 107 for ( idInteraction *inter = def->firstInteraction; inter != NULL && !inter->IsEmpty(); inter = inter->entityNext ) { 108 inter->FreeSurfaces(); 109 } 110 111 // clear the dynamic model if present 112 if ( def->dynamicModel ) { 113 // this is copied from cachedDynamicModel, so it doesn't need to be freed 114 def->dynamicModel = NULL; 115 } 116 def->dynamicModelFrameCount = 0; 117 } 118 119 /* 120 ================== 121 R_IssueEntityDefCallback 122 ================== 123 */ 124 bool R_IssueEntityDefCallback( idRenderEntityLocal *def ) { 125 idBounds oldBounds = def->localReferenceBounds; 126 127 def->archived = false; // will need to be written to the demo file 128 129 bool update; 130 if ( tr.viewDef != NULL ) { 131 update = def->parms.callback( &def->parms, &tr.viewDef->renderView ); 132 } else { 133 update = def->parms.callback( &def->parms, NULL ); 134 } 135 tr.pc.c_entityDefCallbacks++; 136 137 if ( def->parms.hModel == NULL ) { 138 common->Error( "R_IssueEntityDefCallback: dynamic entity callback didn't set model" ); 139 } 140 141 if ( r_checkBounds.GetBool() ) { 142 if ( oldBounds[0][0] > def->localReferenceBounds[0][0] + CHECK_BOUNDS_EPSILON || 143 oldBounds[0][1] > def->localReferenceBounds[0][1] + CHECK_BOUNDS_EPSILON || 144 oldBounds[0][2] > def->localReferenceBounds[0][2] + CHECK_BOUNDS_EPSILON || 145 oldBounds[1][0] < def->localReferenceBounds[1][0] - CHECK_BOUNDS_EPSILON || 146 oldBounds[1][1] < def->localReferenceBounds[1][1] - CHECK_BOUNDS_EPSILON || 147 oldBounds[1][2] < def->localReferenceBounds[1][2] - CHECK_BOUNDS_EPSILON ) { 148 common->Printf( "entity %i callback extended reference bounds\n", def->index ); 149 } 150 } 151 152 return update; 153 } 154 155 /* 156 =================== 157 R_EntityDefDynamicModel 158 159 This is also called by the game code for idRenderWorldLocal::ModelTrace(), and idRenderWorldLocal::Trace() which is bad for performance... 160 161 Issues a deferred entity callback if necessary. 162 If the model isn't dynamic, it returns the original. 163 Returns the cached dynamic model if present, otherwise creates it. 164 =================== 165 */ 166 idRenderModel *R_EntityDefDynamicModel( idRenderEntityLocal *def ) { 167 if ( def->dynamicModelFrameCount == tr.frameCount ) { 168 return def->dynamicModel; 169 } 170 171 // allow deferred entities to construct themselves 172 bool callbackUpdate; 173 if ( def->parms.callback != NULL ) { 174 SCOPED_PROFILE_EVENT( "R_IssueEntityDefCallback" ); 175 callbackUpdate = R_IssueEntityDefCallback( def ); 176 } else { 177 callbackUpdate = false; 178 } 179 180 idRenderModel *model = def->parms.hModel; 181 182 if ( model == NULL ) { 183 common->Error( "R_EntityDefDynamicModel: NULL model" ); 184 return NULL; 185 } 186 187 if ( model->IsDynamicModel() == DM_STATIC ) { 188 def->dynamicModel = NULL; 189 def->dynamicModelFrameCount = 0; 190 return model; 191 } 192 193 // continously animating models (particle systems, etc) will have their snapshot updated every single view 194 if ( callbackUpdate || ( model->IsDynamicModel() == DM_CONTINUOUS && def->dynamicModelFrameCount != tr.frameCount ) ) { 195 R_ClearEntityDefDynamicModel( def ); 196 } 197 198 // if we don't have a snapshot of the dynamic model, generate it now 199 if ( def->dynamicModel == NULL ) { 200 201 SCOPED_PROFILE_EVENT( "InstantiateDynamicModel" ); 202 203 // instantiate the snapshot of the dynamic model, possibly reusing memory from the cached snapshot 204 def->cachedDynamicModel = model->InstantiateDynamicModel( &def->parms, tr.viewDef, def->cachedDynamicModel ); 205 206 if ( def->cachedDynamicModel != NULL && r_checkBounds.GetBool() ) { 207 idBounds b = def->cachedDynamicModel->Bounds(); 208 if ( b[0][0] < def->localReferenceBounds[0][0] - CHECK_BOUNDS_EPSILON || 209 b[0][1] < def->localReferenceBounds[0][1] - CHECK_BOUNDS_EPSILON || 210 b[0][2] < def->localReferenceBounds[0][2] - CHECK_BOUNDS_EPSILON || 211 b[1][0] > def->localReferenceBounds[1][0] + CHECK_BOUNDS_EPSILON || 212 b[1][1] > def->localReferenceBounds[1][1] + CHECK_BOUNDS_EPSILON || 213 b[1][2] > def->localReferenceBounds[1][2] + CHECK_BOUNDS_EPSILON ) { 214 common->Printf( "entity %i dynamic model exceeded reference bounds\n", def->index ); 215 } 216 } 217 218 def->dynamicModel = def->cachedDynamicModel; 219 def->dynamicModelFrameCount = tr.frameCount; 220 } 221 222 // set model depth hack value 223 if ( def->dynamicModel != NULL && model->DepthHack() != 0.0f && tr.viewDef != NULL ) { 224 idPlane eye, clip; 225 idVec3 ndc; 226 R_TransformModelToClip( def->parms.origin, tr.viewDef->worldSpace.modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip ); 227 R_TransformClipToDevice( clip, ndc ); 228 def->parms.modelDepthHack = model->DepthHack() * ( 1.0f - ndc.z ); 229 } else { 230 def->parms.modelDepthHack = 0.0f; 231 } 232 233 return def->dynamicModel; 234 } 235 236 /* 237 =================== 238 R_SetupDrawSurfShader 239 =================== 240 */ 241 void R_SetupDrawSurfShader( drawSurf_t * drawSurf, const idMaterial * shader, const renderEntity_t * renderEntity ) { 242 drawSurf->material = shader; 243 drawSurf->sort = shader->GetSort(); 244 245 // process the shader expressions for conditionals / color / texcoords 246 const float *constRegs = shader->ConstantRegisters(); 247 if ( likely( constRegs != NULL ) ) { 248 // shader only uses constant values 249 drawSurf->shaderRegisters = constRegs; 250 } else { 251 // by default evaluate with the entityDef's shader parms 252 const float * shaderParms = renderEntity->shaderParms; 253 254 // a reference shader will take the calculated stage color value from another shader 255 // and use that for the parm0-parm3 of the current shader, which allows a stage of 256 // a light model and light flares to pick up different flashing tables from 257 // different light shaders 258 float generatedShaderParms[MAX_ENTITY_SHADER_PARMS]; 259 if ( unlikely( renderEntity->referenceShader != NULL ) ) { 260 // evaluate the reference shader to find our shader parms 261 float refRegs[MAX_EXPRESSION_REGISTERS]; 262 renderEntity->referenceShader->EvaluateRegisters( refRegs, renderEntity->shaderParms, 263 tr.viewDef->renderView.shaderParms, 264 tr.viewDef->renderView.time[renderEntity->timeGroup] * 0.001f, renderEntity->referenceSound ); 265 266 const shaderStage_t * pStage = renderEntity->referenceShader->GetStage( 0 ); 267 268 memcpy( generatedShaderParms, renderEntity->shaderParms, sizeof( generatedShaderParms ) ); 269 generatedShaderParms[0] = refRegs[ pStage->color.registers[0] ]; 270 generatedShaderParms[1] = refRegs[ pStage->color.registers[1] ]; 271 generatedShaderParms[2] = refRegs[ pStage->color.registers[2] ]; 272 273 shaderParms = generatedShaderParms; 274 } 275 276 // allocte frame memory for the shader register values 277 float * regs = (float *)R_FrameAlloc( shader->GetNumRegisters() * sizeof( float ), FRAME_ALLOC_SHADER_REGISTER ); 278 drawSurf->shaderRegisters = regs; 279 280 // process the shader expressions for conditionals / color / texcoords 281 shader->EvaluateRegisters( regs, shaderParms, tr.viewDef->renderView.shaderParms, 282 tr.viewDef->renderView.time[renderEntity->timeGroup] * 0.001f, renderEntity->referenceSound ); 283 } 284 } 285 286 /* 287 =================== 288 R_SetupDrawSurfJoints 289 =================== 290 */ 291 void R_SetupDrawSurfJoints( drawSurf_t * drawSurf, const srfTriangles_t * tri, const idMaterial * shader ) { 292 if ( tri->staticModelWithJoints == NULL || !r_useGPUSkinning.GetBool() ) { 293 drawSurf->jointCache = 0; 294 return; 295 } 296 297 idRenderModelStatic * model = tri->staticModelWithJoints; 298 assert( model->jointsInverted != NULL ); 299 300 if ( !vertexCache.CacheIsCurrent( model->jointsInvertedBuffer ) ) { 301 const int alignment = glConfig.uniformBufferOffsetAlignment; 302 model->jointsInvertedBuffer = vertexCache.AllocJoint( model->jointsInverted, ALIGN( model->numInvertedJoints * sizeof( idJointMat ), alignment ) ); 303 } 304 drawSurf->jointCache = model->jointsInvertedBuffer; 305 } 306 307 /* 308 =================== 309 R_AddSingleModel 310 311 May be run in parallel. 312 313 Here is where dynamic models actually get instantiated, and necessary 314 interaction surfaces get created. This is all done on a sort-by-model 315 basis to keep source data in cache (most likely L2) as any interactions 316 and shadows are generated, since dynamic models will typically be lit by 317 two or more lights. 318 =================== 319 */ 320 void R_AddSingleModel( viewEntity_t * vEntity ) { 321 // we will add all interaction surfs here, to be chained to the lights in later serial code 322 vEntity->drawSurfs = NULL; 323 vEntity->staticShadowVolumes = NULL; 324 vEntity->dynamicShadowVolumes = NULL; 325 326 // globals we really should pass in... 327 const viewDef_t * viewDef = tr.viewDef; 328 329 idRenderEntityLocal * entityDef = vEntity->entityDef; 330 const renderEntity_t * renderEntity = &entityDef->parms; 331 const idRenderWorldLocal * world = entityDef->world; 332 333 if ( viewDef->isXraySubview && entityDef->parms.xrayIndex == 1 ) { 334 return; 335 } else if ( !viewDef->isXraySubview && entityDef->parms.xrayIndex == 2 ) { 336 return; 337 } 338 339 SCOPED_PROFILE_EVENT( renderEntity->hModel == NULL ? "Unknown Model" : renderEntity->hModel->Name() ); 340 341 // calculate the znear for testing whether or not the view is inside a shadow projection 342 const float znear = ( viewDef->renderView.cramZNear ) ? ( r_znear.GetFloat() * 0.25f ) : r_znear.GetFloat(); 343 344 // if the entity wasn't seen through a portal chain, it was added just for light shadows 345 const bool modelIsVisible = !vEntity->scissorRect.IsEmpty(); 346 const bool addInteractions = modelIsVisible && ( !viewDef->isXraySubview || entityDef->parms.xrayIndex == 2 ); 347 const int entityIndex = entityDef->index; 348 349 //--------------------------- 350 // Find which of the visible lights contact this entity 351 // 352 // If the entity doesn't accept light or cast shadows from any surface, 353 // this can be skipped. 354 // 355 // OPTIMIZE: world areas can assume all referenced lights are used 356 //--------------------------- 357 int numContactedLights = 0; 358 static const int MAX_CONTACTED_LIGHTS = 128; 359 viewLight_t * contactedLights[MAX_CONTACTED_LIGHTS]; 360 idInteraction * staticInteractions[MAX_CONTACTED_LIGHTS]; 361 362 if ( renderEntity->hModel == NULL || 363 renderEntity->hModel->ModelHasInteractingSurfaces() || 364 renderEntity->hModel->ModelHasShadowCastingSurfaces() ) { 365 SCOPED_PROFILE_EVENT( "Find lights" ); 366 for ( viewLight_t * vLight = viewDef->viewLights; vLight != NULL; vLight = vLight->next ) { 367 if ( vLight->scissorRect.IsEmpty() ) { 368 continue; 369 } 370 if ( vLight->entityInteractionState != NULL ) { 371 // new code path, everything was done in AddLight 372 if ( vLight->entityInteractionState[entityIndex] == viewLight_t::INTERACTION_YES ) { 373 contactedLights[numContactedLights] = vLight; 374 staticInteractions[numContactedLights] = world->interactionTable[vLight->lightDef->index * world->interactionTableWidth + entityIndex]; 375 if ( ++numContactedLights == MAX_CONTACTED_LIGHTS ) { 376 break; 377 } 378 } 379 continue; 380 } 381 382 const idRenderLightLocal * lightDef = vLight->lightDef; 383 384 if ( !lightDef->globalLightBounds.IntersectsBounds( entityDef->globalReferenceBounds ) ) { 385 continue; 386 } 387 388 if ( R_CullModelBoundsToLight( lightDef, entityDef->localReferenceBounds, entityDef->modelRenderMatrix ) ) { 389 continue; 390 } 391 392 if ( !modelIsVisible ) { 393 // some lights have their center of projection outside the world 394 if ( lightDef->areaNum != -1 ) { 395 // if no part of the model is in an area that is connected to 396 // the light center (it is behind a solid, closed door), we can ignore it 397 bool areasConnected = false; 398 for ( areaReference_t *ref = entityDef->entityRefs; ref != NULL; ref = ref->ownerNext ) { 399 if ( world->AreasAreConnected( lightDef->areaNum, ref->area->areaNum, PS_BLOCK_VIEW ) ) { 400 areasConnected = true; 401 break; 402 } 403 } 404 if ( areasConnected == false ) { 405 // can't possibly be seen or shadowed 406 continue; 407 } 408 } 409 410 // check more precisely for shadow visibility 411 idBounds shadowBounds; 412 R_ShadowBounds( entityDef->globalReferenceBounds, lightDef->globalLightBounds, lightDef->globalLightOrigin, shadowBounds ); 413 414 // this doesn't say that the shadow can't effect anything, only that it can't 415 // effect anything in the view 416 if ( idRenderMatrix::CullBoundsToMVP( viewDef->worldSpace.mvp, shadowBounds ) ) { 417 continue; 418 } 419 } 420 contactedLights[numContactedLights] = vLight; 421 staticInteractions[numContactedLights] = world->interactionTable[vLight->lightDef->index * world->interactionTableWidth + entityIndex]; 422 if ( ++numContactedLights == MAX_CONTACTED_LIGHTS ) { 423 break; 424 } 425 } 426 } 427 428 // if we aren't visible and none of the shadows stretch into the view, 429 // we don't need to do anything else 430 if ( !modelIsVisible && numContactedLights == 0 ) { 431 return; 432 } 433 434 //--------------------------- 435 // create a dynamic model if the geometry isn't static 436 //--------------------------- 437 idRenderModel * model = R_EntityDefDynamicModel( entityDef ); 438 if ( model == NULL || model->NumSurfaces() <= 0 ) { 439 return; 440 } 441 442 // add the lightweight blood decal surfaces if the model is directly visible 443 if ( modelIsVisible ) { 444 assert( !vEntity->scissorRect.IsEmpty() ); 445 446 if ( entityDef->decals != NULL && !r_skipDecals.GetBool() ) { 447 entityDef->decals->CreateDeferredDecals( model ); 448 449 unsigned int numDrawSurfs = entityDef->decals->GetNumDecalDrawSurfs(); 450 for ( unsigned int i = 0; i < numDrawSurfs; i++ ) { 451 drawSurf_t * decalDrawSurf = entityDef->decals->CreateDecalDrawSurf( vEntity, i ); 452 if ( decalDrawSurf != NULL ) { 453 decalDrawSurf->linkChain = NULL; 454 decalDrawSurf->nextOnLight = vEntity->drawSurfs; 455 vEntity->drawSurfs = decalDrawSurf; 456 } 457 } 458 } 459 460 if ( entityDef->overlays != NULL && !r_skipOverlays.GetBool() ) { 461 entityDef->overlays->CreateDeferredOverlays( model ); 462 463 unsigned int numDrawSurfs = entityDef->overlays->GetNumOverlayDrawSurfs(); 464 for ( unsigned int i = 0; i < numDrawSurfs; i++ ) { 465 drawSurf_t * overlayDrawSurf = entityDef->overlays->CreateOverlayDrawSurf( vEntity, model, i ); 466 if ( overlayDrawSurf != NULL ) { 467 overlayDrawSurf->linkChain = NULL; 468 overlayDrawSurf->nextOnLight = vEntity->drawSurfs; 469 vEntity->drawSurfs = overlayDrawSurf; 470 } 471 } 472 } 473 } 474 475 //--------------------------- 476 // copy matrix related stuff for back-end use 477 // and setup a render matrix for faster culling 478 //--------------------------- 479 vEntity->modelDepthHack = renderEntity->modelDepthHack; 480 vEntity->weaponDepthHack = renderEntity->weaponDepthHack; 481 vEntity->skipMotionBlur = renderEntity->skipMotionBlur; 482 483 memcpy( vEntity->modelMatrix, entityDef->modelMatrix, sizeof( vEntity->modelMatrix ) ); 484 R_MatrixMultiply( entityDef->modelMatrix, viewDef->worldSpace.modelViewMatrix, vEntity->modelViewMatrix ); 485 486 idRenderMatrix viewMat; 487 idRenderMatrix::Transpose( *(idRenderMatrix *)vEntity->modelViewMatrix, viewMat ); 488 idRenderMatrix::Multiply( viewDef->projectionRenderMatrix, viewMat, vEntity->mvp ); 489 if ( renderEntity->weaponDepthHack ) { 490 idRenderMatrix::ApplyDepthHack( vEntity->mvp ); 491 } 492 if ( renderEntity->modelDepthHack != 0.0f ) { 493 idRenderMatrix::ApplyModelDepthHack( vEntity->mvp, renderEntity->modelDepthHack ); 494 } 495 496 // local light and view origins are used to determine if the view is definitely outside 497 // an extruded shadow volume, which means we can skip drawing the end caps 498 idVec3 localViewOrigin; 499 R_GlobalPointToLocal( vEntity->modelMatrix, viewDef->renderView.vieworg, localViewOrigin ); 500 501 //--------------------------- 502 // add all the model surfaces 503 //--------------------------- 504 for ( int surfaceNum = 0; surfaceNum < model->NumSurfaces(); surfaceNum++ ) { 505 const modelSurface_t *surf = model->Surface( surfaceNum ); 506 507 // for debugging, only show a single surface at a time 508 if ( r_singleSurface.GetInteger() >= 0 && surfaceNum != r_singleSurface.GetInteger() ) { 509 continue; 510 } 511 512 srfTriangles_t * tri = surf->geometry; 513 if ( tri == NULL ) { 514 continue; 515 } 516 if ( tri->numIndexes == NULL ) { 517 continue; // happens for particles 518 } 519 const idMaterial * shader = surf->shader; 520 if ( shader == NULL ) { 521 continue; 522 } 523 if ( !shader->IsDrawn() ) { 524 continue; // collision hulls, etc 525 } 526 527 // RemapShaderBySkin 528 if ( entityDef->parms.customShader != NULL ) { 529 // this is sort of a hack, but causes deformed surfaces to map to empty surfaces, 530 // so the item highlight overlay doesn't highlight the autosprite surface 531 if ( shader->Deform() ) { 532 continue; 533 } 534 shader = entityDef->parms.customShader; 535 } else if ( entityDef->parms.customSkin ) { 536 shader = entityDef->parms.customSkin->RemapShaderBySkin( shader ); 537 if ( shader == NULL ) { 538 continue; 539 } 540 if ( !shader->IsDrawn() ) { 541 continue; 542 } 543 } 544 545 // optionally override with the renderView->globalMaterial 546 if ( tr.primaryRenderView.globalMaterial != NULL ) { 547 shader = tr.primaryRenderView.globalMaterial; 548 } 549 550 SCOPED_PROFILE_EVENT( shader->GetName() ); 551 552 // debugging tool to make sure we have the correct pre-calculated bounds 553 if ( r_checkBounds.GetBool() ) { 554 for ( int j = 0; j < tri->numVerts; j++ ) { 555 int k; 556 for ( k = 0; k < 3; k++ ) { 557 if ( tri->verts[j].xyz[k] > tri->bounds[1][k] + CHECK_BOUNDS_EPSILON 558 || tri->verts[j].xyz[k] < tri->bounds[0][k] - CHECK_BOUNDS_EPSILON ) { 559 common->Printf( "bad tri->bounds on %s:%s\n", entityDef->parms.hModel->Name(), shader->GetName() ); 560 break; 561 } 562 if ( tri->verts[j].xyz[k] > entityDef->localReferenceBounds[1][k] + CHECK_BOUNDS_EPSILON 563 || tri->verts[j].xyz[k] < entityDef->localReferenceBounds[0][k] - CHECK_BOUNDS_EPSILON ) { 564 common->Printf( "bad referenceBounds on %s:%s\n", entityDef->parms.hModel->Name(), shader->GetName() ); 565 break; 566 } 567 } 568 if ( k != 3 ) { 569 break; 570 } 571 } 572 } 573 574 // view frustum culling for the precise surface bounds, which is tighter 575 // than the entire entity reference bounds 576 // If the entire model wasn't visible, there is no need to check the 577 // individual surfaces. 578 const bool surfaceDirectlyVisible = modelIsVisible && !idRenderMatrix::CullBoundsToMVP( vEntity->mvp, tri->bounds ); 579 const bool gpuSkinned = ( tri->staticModelWithJoints != NULL && r_useGPUSkinning.GetBool() ); 580 581 //-------------------------- 582 // base drawing surface 583 //-------------------------- 584 drawSurf_t * baseDrawSurf = NULL; 585 if ( surfaceDirectlyVisible ) { 586 // make sure we have an ambient cache and all necessary normals / tangents 587 if ( !vertexCache.CacheIsCurrent( tri->indexCache ) ) { 588 tri->indexCache = vertexCache.AllocIndex( tri->indexes, ALIGN( tri->numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) ); 589 } 590 if ( !vertexCache.CacheIsCurrent( tri->ambientCache ) ) { 591 // we are going to use it for drawing, so make sure we have the tangents and normals 592 if ( shader->ReceivesLighting() && !tri->tangentsCalculated ) { 593 assert( tri->staticModelWithJoints == NULL ); 594 R_DeriveTangents( tri ); 595 assert( false ); // this should no longer be hit 596 } 597 tri->ambientCache = vertexCache.AllocVertex( tri->verts, ALIGN( tri->numVerts * sizeof( idDrawVert ), VERTEX_CACHE_ALIGN ) ); 598 } 599 600 // add the surface for drawing 601 // we can re-use some of the values for light interaction surfaces 602 baseDrawSurf = (drawSurf_t *)R_FrameAlloc( sizeof( *baseDrawSurf ), FRAME_ALLOC_DRAW_SURFACE ); 603 baseDrawSurf->frontEndGeo = tri; 604 baseDrawSurf->space = vEntity; 605 baseDrawSurf->scissorRect = vEntity->scissorRect; 606 baseDrawSurf->extraGLState = 0; 607 baseDrawSurf->renderZFail = 0; 608 609 R_SetupDrawSurfShader( baseDrawSurf, shader, renderEntity ); 610 611 // Check for deformations (eyeballs, flares, etc) 612 const deform_t shaderDeform = shader->Deform(); 613 if ( shaderDeform != DFRM_NONE ) { 614 drawSurf_t * deformDrawSurf = R_DeformDrawSurf( baseDrawSurf ); 615 if ( deformDrawSurf != NULL ) { 616 // any deforms may have created multiple draw surfaces 617 for ( drawSurf_t * surf = deformDrawSurf, * next = NULL; surf != NULL; surf = next ) { 618 next = surf->nextOnLight; 619 620 surf->linkChain = NULL; 621 surf->nextOnLight = vEntity->drawSurfs; 622 vEntity->drawSurfs = surf; 623 } 624 } 625 } 626 627 // Most deform source surfaces do not need to be rendered. 628 // However, particles are rendered in conjunction with the source surface. 629 if ( shaderDeform == DFRM_NONE || shaderDeform == DFRM_PARTICLE || shaderDeform == DFRM_PARTICLE2 ) { 630 // copy verts and indexes to this frame's hardware memory if they aren't already there 631 if ( !vertexCache.CacheIsCurrent( tri->ambientCache ) ) { 632 tri->ambientCache = vertexCache.AllocVertex( tri->verts, ALIGN( tri->numVerts * sizeof( tri->verts[0] ), VERTEX_CACHE_ALIGN ) ); 633 } 634 if ( !vertexCache.CacheIsCurrent( tri->indexCache ) ) { 635 tri->indexCache = vertexCache.AllocIndex( tri->indexes, ALIGN( tri->numIndexes * sizeof( tri->indexes[0] ), INDEX_CACHE_ALIGN ) ); 636 } 637 638 R_SetupDrawSurfJoints( baseDrawSurf, tri, shader ); 639 640 baseDrawSurf->numIndexes = tri->numIndexes; 641 baseDrawSurf->ambientCache = tri->ambientCache; 642 baseDrawSurf->indexCache = tri->indexCache; 643 baseDrawSurf->shadowCache = 0; 644 645 baseDrawSurf->linkChain = NULL; // link to the view 646 baseDrawSurf->nextOnLight = vEntity->drawSurfs; 647 vEntity->drawSurfs = baseDrawSurf; 648 } 649 } 650 651 //---------------------------------------- 652 // add all light interactions 653 //---------------------------------------- 654 for ( int contactedLight = 0; contactedLight < numContactedLights; contactedLight++ ) { 655 viewLight_t * vLight = contactedLights[contactedLight]; 656 const idRenderLightLocal * lightDef = vLight->lightDef; 657 const idInteraction * interaction = staticInteractions[contactedLight]; 658 659 // check for a static interaction 660 surfaceInteraction_t *surfInter = NULL; 661 if ( interaction > INTERACTION_EMPTY && interaction->staticInteraction ) { 662 // we have a static interaction that was calculated accurately 663 assert( model->NumSurfaces() == interaction->numSurfaces ); 664 surfInter = &interaction->surfaces[surfaceNum]; 665 } else { 666 // try to do a more precise cull of this model surface to the light 667 if ( R_CullModelBoundsToLight( lightDef, tri->bounds, entityDef->modelRenderMatrix ) ) { 668 continue; 669 } 670 } 671 672 // "invisible ink" lights and shaders (imp spawn drawing on walls, etc) 673 if ( shader->Spectrum() != lightDef->lightShader->Spectrum() ) { 674 continue; 675 } 676 677 // Calculate the local light origin to determine if the view is inside the shadow 678 // projection and to calculate the triangle facing for dynamic shadow volumes. 679 idVec3 localLightOrigin; 680 R_GlobalPointToLocal( vEntity->modelMatrix, lightDef->globalLightOrigin, localLightOrigin ); 681 682 //-------------------------- 683 // surface light interactions 684 //-------------------------- 685 686 dynamicShadowVolumeParms_t * dynamicShadowParms = NULL; 687 688 if ( addInteractions && surfaceDirectlyVisible && shader->ReceivesLighting() ) { 689 // static interactions can commonly find that no triangles from a surface 690 // contact the light, even when the total model does 691 if ( surfInter == NULL || surfInter->lightTrisIndexCache > 0 ) { 692 // create a drawSurf for this interaction 693 drawSurf_t * lightDrawSurf = (drawSurf_t *)R_FrameAlloc( sizeof( *lightDrawSurf ), FRAME_ALLOC_DRAW_SURFACE ); 694 695 if ( surfInter != NULL ) { 696 // optimized static interaction 697 lightDrawSurf->numIndexes = surfInter->numLightTrisIndexes; 698 lightDrawSurf->indexCache = surfInter->lightTrisIndexCache; 699 } else { 700 // throw the entire source surface at it without any per-triangle culling 701 lightDrawSurf->numIndexes = tri->numIndexes; 702 lightDrawSurf->indexCache = tri->indexCache; 703 704 // optionally cull the triangles to the light volume 705 if ( r_cullDynamicLightTriangles.GetBool() ) { 706 707 vertCacheHandle_t lightIndexCache = vertexCache.AllocIndex( NULL, ALIGN( lightDrawSurf->numIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) ); 708 if ( vertexCache.CacheIsCurrent( lightIndexCache ) ) { 709 lightDrawSurf->indexCache = lightIndexCache; 710 711 dynamicShadowParms = (dynamicShadowVolumeParms_t *)R_FrameAlloc( sizeof( dynamicShadowParms[0] ), FRAME_ALLOC_SHADOW_VOLUME_PARMS ); 712 713 dynamicShadowParms->verts = tri->verts; 714 dynamicShadowParms->numVerts = tri->numVerts; 715 dynamicShadowParms->indexes = tri->indexes; 716 dynamicShadowParms->numIndexes = tri->numIndexes; 717 dynamicShadowParms->silEdges = tri->silEdges; 718 dynamicShadowParms->numSilEdges = tri->numSilEdges; 719 dynamicShadowParms->joints = gpuSkinned ? tri->staticModelWithJoints->jointsInverted : NULL; 720 dynamicShadowParms->numJoints = gpuSkinned ? tri->staticModelWithJoints->numInvertedJoints : 0; 721 dynamicShadowParms->triangleBounds = tri->bounds; 722 dynamicShadowParms->triangleMVP = vEntity->mvp; 723 dynamicShadowParms->localLightOrigin = localLightOrigin; 724 dynamicShadowParms->localViewOrigin = localViewOrigin; 725 idRenderMatrix::Multiply( vLight->lightDef->baseLightProject, entityDef->modelRenderMatrix, dynamicShadowParms->localLightProject ); 726 dynamicShadowParms->zNear = znear; 727 dynamicShadowParms->lightZMin = vLight->scissorRect.zmin; 728 dynamicShadowParms->lightZMax = vLight->scissorRect.zmax; 729 dynamicShadowParms->cullShadowTrianglesToLight = false; 730 dynamicShadowParms->forceShadowCaps = false; 731 dynamicShadowParms->useShadowPreciseInsideTest = false; 732 dynamicShadowParms->useShadowDepthBounds = false; 733 dynamicShadowParms->tempFacing = NULL; 734 dynamicShadowParms->tempCulled = NULL; 735 dynamicShadowParms->tempVerts = NULL; 736 dynamicShadowParms->indexBuffer = NULL; 737 dynamicShadowParms->shadowIndices = NULL; 738 dynamicShadowParms->maxShadowIndices = 0; 739 dynamicShadowParms->numShadowIndices = NULL; 740 dynamicShadowParms->lightIndices = (triIndex_t *)vertexCache.MappedIndexBuffer( lightIndexCache ); 741 dynamicShadowParms->maxLightIndices = lightDrawSurf->numIndexes; 742 dynamicShadowParms->numLightIndices = &lightDrawSurf->numIndexes; 743 dynamicShadowParms->renderZFail = NULL; 744 dynamicShadowParms->shadowZMin = NULL; 745 dynamicShadowParms->shadowZMax = NULL; 746 dynamicShadowParms->shadowVolumeState = & lightDrawSurf->shadowVolumeState; 747 748 lightDrawSurf->shadowVolumeState = SHADOWVOLUME_UNFINISHED; 749 750 dynamicShadowParms->next = vEntity->dynamicShadowVolumes; 751 vEntity->dynamicShadowVolumes = dynamicShadowParms; 752 } 753 } 754 } 755 lightDrawSurf->ambientCache = tri->ambientCache; 756 lightDrawSurf->shadowCache = 0; 757 lightDrawSurf->frontEndGeo = tri; 758 lightDrawSurf->space = vEntity; 759 lightDrawSurf->material = shader; 760 lightDrawSurf->extraGLState = 0; 761 lightDrawSurf->scissorRect = vLight->scissorRect; // interactionScissor; 762 lightDrawSurf->sort = 0.0f; 763 lightDrawSurf->renderZFail = 0; 764 lightDrawSurf->shaderRegisters = baseDrawSurf->shaderRegisters; 765 766 R_SetupDrawSurfJoints( lightDrawSurf, tri, shader ); 767 768 // Determine which linked list to add the light surface to. 769 // There will only be localSurfaces if the light casts shadows and 770 // there are surfaces with NOSELFSHADOW. 771 if ( shader->Coverage() == MC_TRANSLUCENT ) { 772 lightDrawSurf->linkChain = &vLight->translucentInteractions; 773 } else if ( !lightDef->parms.noShadows && shader->TestMaterialFlag( MF_NOSELFSHADOW ) ) { 774 lightDrawSurf->linkChain = &vLight->localInteractions; 775 } else { 776 lightDrawSurf->linkChain = &vLight->globalInteractions; 777 } 778 lightDrawSurf->nextOnLight = vEntity->drawSurfs; 779 vEntity->drawSurfs = lightDrawSurf; 780 } 781 } 782 783 //-------------------------- 784 // surface shadows 785 //-------------------------- 786 787 if ( !shader->SurfaceCastsShadow() ) { 788 continue; 789 } 790 if ( !lightDef->LightCastsShadows() ) { 791 continue; 792 } 793 if ( tri->silEdges == NULL ) { 794 continue; // can happen for beam models (shouldn't use a shadow casting material, though...) 795 } 796 797 // if the static shadow does not have any shadows 798 if ( surfInter != NULL && surfInter->numShadowIndexes == 0 ) { 799 continue; 800 } 801 802 // some entities, like view weapons, don't cast any shadows 803 if ( entityDef->parms.noShadow ) { 804 continue; 805 } 806 807 // No shadow if it's suppressed for this light. 808 if ( entityDef->parms.suppressShadowInLightID && entityDef->parms.suppressShadowInLightID == lightDef->parms.lightId ) { 809 continue; 810 } 811 812 if ( lightDef->parms.prelightModel && lightDef->lightHasMoved == false && 813 entityDef->parms.hModel->IsStaticWorldModel() && !r_skipPrelightShadows.GetBool() ) { 814 // static light / world model shadow interacitons 815 // are always captured in the prelight shadow volume 816 continue; 817 } 818 819 // If the shadow is drawn (or translucent), but the model isn't, we must include the shadow caps 820 // because we may be able to see into the shadow volume even though the view is outside it. 821 // This happens for the player world weapon and possibly some animations in multiplayer. 822 const bool forceShadowCaps = !addInteractions || r_forceShadowCaps.GetBool(); 823 824 drawSurf_t * shadowDrawSurf = (drawSurf_t *)R_FrameAlloc( sizeof( *shadowDrawSurf ), FRAME_ALLOC_DRAW_SURFACE ); 825 826 if ( surfInter != NULL ) { 827 shadowDrawSurf->numIndexes = 0; 828 shadowDrawSurf->indexCache = surfInter->shadowIndexCache; 829 shadowDrawSurf->shadowCache = tri->shadowCache; 830 shadowDrawSurf->scissorRect = vLight->scissorRect; // default to the light scissor and light depth bounds 831 shadowDrawSurf->shadowVolumeState = SHADOWVOLUME_DONE; // assume the shadow volume is done in case r_skipStaticShadows is set 832 833 if ( !r_skipStaticShadows.GetBool() ) { 834 staticShadowVolumeParms_t * staticShadowParms = (staticShadowVolumeParms_t *)R_FrameAlloc( sizeof( staticShadowParms[0] ), FRAME_ALLOC_SHADOW_VOLUME_PARMS ); 835 836 staticShadowParms->verts = tri->staticShadowVertexes; 837 staticShadowParms->numVerts = tri->numVerts * 2; 838 staticShadowParms->indexes = surfInter->shadowIndexes; 839 staticShadowParms->numIndexes = surfInter->numShadowIndexes; 840 staticShadowParms->numShadowIndicesWithCaps = surfInter->numShadowIndexes; 841 staticShadowParms->numShadowIndicesNoCaps = surfInter->numShadowIndexesNoCaps; 842 staticShadowParms->triangleBounds = tri->bounds; 843 staticShadowParms->triangleMVP = vEntity->mvp; 844 staticShadowParms->localLightOrigin = localLightOrigin; 845 staticShadowParms->localViewOrigin = localViewOrigin; 846 staticShadowParms->zNear = znear; 847 staticShadowParms->lightZMin = vLight->scissorRect.zmin; 848 staticShadowParms->lightZMax = vLight->scissorRect.zmax; 849 staticShadowParms->forceShadowCaps = forceShadowCaps; 850 staticShadowParms->useShadowPreciseInsideTest = r_useShadowPreciseInsideTest.GetBool(); 851 staticShadowParms->useShadowDepthBounds = r_useShadowDepthBounds.GetBool(); 852 staticShadowParms->numShadowIndices = & shadowDrawSurf->numIndexes; 853 staticShadowParms->renderZFail = & shadowDrawSurf->renderZFail; 854 staticShadowParms->shadowZMin = & shadowDrawSurf->scissorRect.zmin; 855 staticShadowParms->shadowZMax = & shadowDrawSurf->scissorRect.zmax; 856 staticShadowParms->shadowVolumeState = & shadowDrawSurf->shadowVolumeState; 857 858 shadowDrawSurf->shadowVolumeState = SHADOWVOLUME_UNFINISHED; 859 860 staticShadowParms->next = vEntity->staticShadowVolumes; 861 vEntity->staticShadowVolumes = staticShadowParms; 862 } 863 864 } else { 865 // When CPU skinning the dynamic shadow verts of a dynamic model may not have been copied to buffer memory yet. 866 if ( !vertexCache.CacheIsCurrent( tri->shadowCache ) ) { 867 assert( !gpuSkinned ); // the shadow cache should be static when using GPU skinning 868 // Extracts just the xyz values from a set of full size drawverts, and 869 // duplicates them with w set to 0 and 1 for the vertex program to project. 870 // This is constant for any number of lights, the vertex program takes care 871 // of projecting the verts to infinity for a particular light. 872 tri->shadowCache = vertexCache.AllocVertex( NULL, ALIGN( tri->numVerts * 2 * sizeof( idShadowVert ), VERTEX_CACHE_ALIGN ) ); 873 idShadowVert * shadowVerts = (idShadowVert *)vertexCache.MappedVertexBuffer( tri->shadowCache ); 874 idShadowVert::CreateShadowCache( shadowVerts, tri->verts, tri->numVerts ); 875 } 876 877 const int maxShadowVolumeIndexes = tri->numSilEdges * 6 + tri->numIndexes * 2; 878 879 shadowDrawSurf->numIndexes = 0; 880 shadowDrawSurf->indexCache = vertexCache.AllocIndex( NULL, ALIGN( maxShadowVolumeIndexes * sizeof( triIndex_t ), INDEX_CACHE_ALIGN ) ); 881 shadowDrawSurf->shadowCache = tri->shadowCache; 882 shadowDrawSurf->scissorRect = vLight->scissorRect; // default to the light scissor and light depth bounds 883 shadowDrawSurf->shadowVolumeState = SHADOWVOLUME_DONE; // assume the shadow volume is done in case the index cache allocation failed 884 885 // if the index cache was successfully allocated then setup the parms to create a shadow volume in parallel 886 if ( vertexCache.CacheIsCurrent( shadowDrawSurf->indexCache ) && !r_skipDynamicShadows.GetBool() ) { 887 888 // if the parms were not already allocated for culling interaction triangles to the light frustum 889 if ( dynamicShadowParms == NULL ) { 890 dynamicShadowParms = (dynamicShadowVolumeParms_t *)R_FrameAlloc( sizeof( dynamicShadowParms[0] ), FRAME_ALLOC_SHADOW_VOLUME_PARMS ); 891 } else { 892 // the shadow volume will be rendered first so when the interaction surface is drawn the triangles have been culled for sure 893 *dynamicShadowParms->shadowVolumeState = SHADOWVOLUME_DONE; 894 } 895 896 dynamicShadowParms->verts = tri->verts; 897 dynamicShadowParms->numVerts = tri->numVerts; 898 dynamicShadowParms->indexes = tri->indexes; 899 dynamicShadowParms->numIndexes = tri->numIndexes; 900 dynamicShadowParms->silEdges = tri->silEdges; 901 dynamicShadowParms->numSilEdges = tri->numSilEdges; 902 dynamicShadowParms->joints = gpuSkinned ? tri->staticModelWithJoints->jointsInverted : NULL; 903 dynamicShadowParms->numJoints = gpuSkinned ? tri->staticModelWithJoints->numInvertedJoints : 0; 904 dynamicShadowParms->triangleBounds = tri->bounds; 905 dynamicShadowParms->triangleMVP = vEntity->mvp; 906 dynamicShadowParms->localLightOrigin = localLightOrigin; 907 dynamicShadowParms->localViewOrigin = localViewOrigin; 908 idRenderMatrix::Multiply( vLight->lightDef->baseLightProject, entityDef->modelRenderMatrix, dynamicShadowParms->localLightProject ); 909 dynamicShadowParms->zNear = znear; 910 dynamicShadowParms->lightZMin = vLight->scissorRect.zmin; 911 dynamicShadowParms->lightZMax = vLight->scissorRect.zmax; 912 dynamicShadowParms->cullShadowTrianglesToLight = r_cullDynamicShadowTriangles.GetBool(); 913 dynamicShadowParms->forceShadowCaps = forceShadowCaps; 914 dynamicShadowParms->useShadowPreciseInsideTest = r_useShadowPreciseInsideTest.GetBool(); 915 dynamicShadowParms->useShadowDepthBounds = r_useShadowDepthBounds.GetBool(); 916 dynamicShadowParms->tempFacing = NULL; 917 dynamicShadowParms->tempCulled = NULL; 918 dynamicShadowParms->tempVerts = NULL; 919 dynamicShadowParms->indexBuffer = NULL; 920 dynamicShadowParms->shadowIndices = (triIndex_t *)vertexCache.MappedIndexBuffer( shadowDrawSurf->indexCache ); 921 dynamicShadowParms->maxShadowIndices = maxShadowVolumeIndexes; 922 dynamicShadowParms->numShadowIndices = & shadowDrawSurf->numIndexes; 923 // dynamicShadowParms->lightIndices may have already been set for the interaction surface 924 // dynamicShadowParms->maxLightIndices may have already been set for the interaction surface 925 // dynamicShadowParms->numLightIndices may have already been set for the interaction surface 926 dynamicShadowParms->renderZFail = & shadowDrawSurf->renderZFail; 927 dynamicShadowParms->shadowZMin = & shadowDrawSurf->scissorRect.zmin; 928 dynamicShadowParms->shadowZMax = & shadowDrawSurf->scissorRect.zmax; 929 dynamicShadowParms->shadowVolumeState = & shadowDrawSurf->shadowVolumeState; 930 931 shadowDrawSurf->shadowVolumeState = SHADOWVOLUME_UNFINISHED; 932 933 // if the parms we not already linked for culling interaction triangles to the light frustum 934 if ( dynamicShadowParms->lightIndices == NULL ) { 935 dynamicShadowParms->next = vEntity->dynamicShadowVolumes; 936 vEntity->dynamicShadowVolumes = dynamicShadowParms; 937 } 938 939 tr.pc.c_createShadowVolumes++; 940 } 941 } 942 943 assert( vertexCache.CacheIsCurrent( shadowDrawSurf->shadowCache ) ); 944 assert( vertexCache.CacheIsCurrent( shadowDrawSurf->indexCache ) ); 945 946 shadowDrawSurf->ambientCache = 0; 947 shadowDrawSurf->frontEndGeo = NULL; 948 shadowDrawSurf->space = vEntity; 949 shadowDrawSurf->material = NULL; 950 shadowDrawSurf->extraGLState = 0; 951 shadowDrawSurf->sort = 0.0f; 952 shadowDrawSurf->shaderRegisters = NULL; 953 954 R_SetupDrawSurfJoints( shadowDrawSurf, tri, NULL ); 955 956 // determine which linked list to add the shadow surface to 957 shadowDrawSurf->linkChain = shader->TestMaterialFlag( MF_NOSELFSHADOW ) ? &vLight->localShadows : &vLight->globalShadows; 958 shadowDrawSurf->nextOnLight = vEntity->drawSurfs; 959 vEntity->drawSurfs = shadowDrawSurf; 960 } 961 } 962 } 963 964 REGISTER_PARALLEL_JOB( R_AddSingleModel, "R_AddSingleModel" ); 965 966 /* 967 ================= 968 R_LinkDrawSurfToView 969 970 Als called directly by GuiModel 971 ================= 972 */ 973 void R_LinkDrawSurfToView( drawSurf_t * drawSurf, viewDef_t * viewDef ) { 974 // if it doesn't fit, resize the list 975 if ( viewDef->numDrawSurfs == viewDef->maxDrawSurfs ) { 976 drawSurf_t **old = viewDef->drawSurfs; 977 int count; 978 979 if ( viewDef->maxDrawSurfs == 0 ) { 980 viewDef->maxDrawSurfs = INITIAL_DRAWSURFS; 981 count = 0; 982 } else { 983 count = viewDef->maxDrawSurfs * sizeof( viewDef->drawSurfs[0] ); 984 viewDef->maxDrawSurfs *= 2; 985 } 986 viewDef->drawSurfs = (drawSurf_t **)R_FrameAlloc( viewDef->maxDrawSurfs * sizeof( viewDef->drawSurfs[0] ), FRAME_ALLOC_DRAW_SURFACE_POINTER ); 987 memcpy( viewDef->drawSurfs, old, count ); 988 } 989 990 viewDef->drawSurfs[viewDef->numDrawSurfs] = drawSurf; 991 viewDef->numDrawSurfs++; 992 } 993 994 /* 995 =================== 996 R_AddModels 997 998 The end result of running this is the addition of drawSurf_t to the 999 tr.viewDef->drawSurfs[] array and light link chains, along with 1000 frameData and vertexCache allocations to support the drawSurfs. 1001 =================== 1002 */ 1003 void R_AddModels() { 1004 SCOPED_PROFILE_EVENT( "R_AddModels" ); 1005 1006 tr.viewDef->viewEntitys = R_SortViewEntities( tr.viewDef->viewEntitys ); 1007 1008 //------------------------------------------------- 1009 // Go through each view entity that is either visible to the view, or to 1010 // any light that intersects the view (for shadows). 1011 //------------------------------------------------- 1012 1013 if ( r_useParallelAddModels.GetBool() ) { 1014 for ( viewEntity_t * vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next ) { 1015 tr.frontEndJobList->AddJob( (jobRun_t)R_AddSingleModel, vEntity ); 1016 } 1017 tr.frontEndJobList->Submit(); 1018 tr.frontEndJobList->Wait(); 1019 } else { 1020 for ( viewEntity_t * vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next ) { 1021 R_AddSingleModel( vEntity ); 1022 } 1023 } 1024 1025 //------------------------------------------------- 1026 // Kick off jobs to setup static and dynamic shadow volumes. 1027 //------------------------------------------------- 1028 1029 if ( r_useParallelAddShadows.GetInteger() == 1 ) { 1030 for ( viewEntity_t * vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next ) { 1031 for ( staticShadowVolumeParms_t * shadowParms = vEntity->staticShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next ) { 1032 tr.frontEndJobList->AddJob( (jobRun_t)StaticShadowVolumeJob, shadowParms ); 1033 } 1034 for ( dynamicShadowVolumeParms_t * shadowParms = vEntity->dynamicShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next ) { 1035 tr.frontEndJobList->AddJob( (jobRun_t)DynamicShadowVolumeJob, shadowParms ); 1036 } 1037 vEntity->staticShadowVolumes = NULL; 1038 vEntity->dynamicShadowVolumes = NULL; 1039 } 1040 tr.frontEndJobList->Submit(); 1041 // wait here otherwise the shadow volume index buffer may be unmapped before all shadow volumes have been constructed 1042 tr.frontEndJobList->Wait(); 1043 } else { 1044 int start = Sys_Microseconds(); 1045 1046 for ( viewEntity_t * vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next ) { 1047 for ( staticShadowVolumeParms_t * shadowParms = vEntity->staticShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next ) { 1048 StaticShadowVolumeJob( shadowParms ); 1049 } 1050 for ( dynamicShadowVolumeParms_t * shadowParms = vEntity->dynamicShadowVolumes; shadowParms != NULL; shadowParms = shadowParms->next ) { 1051 DynamicShadowVolumeJob( shadowParms ); 1052 } 1053 vEntity->staticShadowVolumes = NULL; 1054 vEntity->dynamicShadowVolumes = NULL; 1055 } 1056 1057 int end = Sys_Microseconds(); 1058 backEnd.pc.shadowMicroSec += end - start; 1059 } 1060 1061 //------------------------------------------------- 1062 // Move the draw surfs to the view. 1063 //------------------------------------------------- 1064 1065 tr.viewDef->numDrawSurfs = 0; // clear the ambient surface list 1066 tr.viewDef->maxDrawSurfs = 0; // will be set to INITIAL_DRAWSURFS on R_LinkDrawSurfToView 1067 1068 for ( viewEntity_t * vEntity = tr.viewDef->viewEntitys; vEntity != NULL; vEntity = vEntity->next ) { 1069 for ( drawSurf_t * ds = vEntity->drawSurfs; ds != NULL; ) { 1070 drawSurf_t * next = ds->nextOnLight; 1071 if ( ds->linkChain == NULL ) { 1072 R_LinkDrawSurfToView( ds, tr.viewDef ); 1073 } else { 1074 ds->nextOnLight = *ds->linkChain; 1075 *ds->linkChain = ds; 1076 } 1077 ds = next; 1078 } 1079 vEntity->drawSurfs = NULL; 1080 } 1081 }