1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8
9 Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 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 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 #include "sys/platform.h"
30 #include "framework/Session.h"
31 #include "renderer/ModelManager.h"
32 #include "renderer/RenderWorld_local.h"
33 #include "ui/UserInterface.h"
34
35 #include "renderer/tr_local.h"
36
37 /*
38
39
40 Prelight models
41
42 "_prelight_<lightname>", ie "_prelight_light1"
43
44 Static surfaces available to dmap will be processed to optimized
45 shadow and lit surface geometry
46
47 Entity models are never prelighted.
48
49 Light entity can have a "noPrelight 1" key set to avoid the preprocessing
50 and carving of the world. A light that will move should usually have this
51 set.
52
53 Prelight models will usually have multiple surfaces
54
55 Shadow volume surfaces will have the material "_shadowVolume"
56
57 The exact same vertexes as the ambient surfaces will be used for the
58 non-shadow surfaces, so there is opportunity to share
59
60
61 Reference their parent surfaces?
62 Reference their parent area?
63
64
65 If we don't track parts that are in different areas, there will be huge
66 losses when an areaportal closed door has a light poking slightly
67 through it.
68
69 There is potential benefit to splitting even the shadow volumes
70 at area boundaries, but it would involve the possibility of an
71 extra plane of shadow drawing at the area boundary.
72
73
74 interaction lightName numIndexes
75
76 Shadow volume surface
77
78 Surfaces in the world cannot have "no self shadow" properties, because all
79 the surfaces are considered together for the optimized shadow volume. If
80 you want no self shadow on a static surface, you must still make it into an
81 entity so it isn't considered in the prelight.
82
83
84 r_hidePrelights
85 r_hideNonPrelights
86
87
88
89 each surface could include prelight indexes
90
91 generation procedure in dmap:
92
93 carve original surfaces into areas
94
95 for each light
96 build shadow volume and beam tree
97 cut all potentially lit surfaces into the beam tree
98 move lit fragments into a new optimize group
99
100 optimize groups
101
102 build light models
103
104
105
106
107 */
108
109 /*
110 =================================================================================
111
112 LIGHT TESTING
113
114 =================================================================================
115 */
116
117
118 /*
119 ====================
120 R_ModulateLights_f
121
122 Modifies the shaderParms on all the lights so the level
123 designers can easily test different color schemes
124 ====================
125 */
R_ModulateLights_f(const idCmdArgs & args)126 void R_ModulateLights_f( const idCmdArgs &args ) {
127 if ( !tr.primaryWorld ) {
128 return;
129 }
130 if ( args.Argc() != 4 ) {
131 common->Printf( "usage: modulateLights <redFloat> <greenFloat> <blueFloat>\n" );
132 return;
133 }
134
135 float modulate[3];
136 int i;
137 for ( i = 0 ; i < 3 ; i++ ) {
138 modulate[i] = atof( args.Argv( i+1 ) );
139 }
140
141 int count = 0;
142 for ( i = 0 ; i < tr.primaryWorld->lightDefs.Num() ; i++ ) {
143 idRenderLightLocal *light;
144
145 light = tr.primaryWorld->lightDefs[i];
146 if ( light ) {
147 count++;
148 for ( int j = 0 ; j < 3 ; j++ ) {
149 light->parms.shaderParms[j] *= modulate[j];
150 }
151 }
152 }
153 common->Printf( "modulated %i lights\n", count );
154 }
155
156
157
158 //======================================================================================
159
160
161 /*
162 ===============
163 R_CreateEntityRefs
164
165 Creates all needed model references in portal areas,
166 chaining them to both the area and the entityDef.
167
168 Bumps tr.viewCount.
169 ===============
170 */
R_CreateEntityRefs(idRenderEntityLocal * def)171 void R_CreateEntityRefs( idRenderEntityLocal *def ) {
172 int i;
173 idVec3 transformed[8];
174 idVec3 v;
175
176 if ( !def->parms.hModel ) {
177 def->parms.hModel = renderModelManager->DefaultModel();
178 }
179
180 // if the entity hasn't been fully specified due to expensive animation calcs
181 // for md5 and particles, use the provided conservative bounds.
182 if ( def->parms.callback ) {
183 def->referenceBounds = def->parms.bounds;
184 } else {
185 def->referenceBounds = def->parms.hModel->Bounds( &def->parms );
186 }
187
188 // some models, like empty particles, may not need to be added at all
189 if ( def->referenceBounds.IsCleared() ) {
190 return;
191 }
192
193 if ( r_showUpdates.GetBool() &&
194 ( def->referenceBounds[1][0] - def->referenceBounds[0][0] > 1024 ||
195 def->referenceBounds[1][1] - def->referenceBounds[0][1] > 1024 ) ) {
196 common->Printf( "big entityRef: %f,%f\n", def->referenceBounds[1][0] - def->referenceBounds[0][0],
197 def->referenceBounds[1][1] - def->referenceBounds[0][1] );
198 }
199
200 for (i = 0 ; i < 8 ; i++) {
201 v[0] = def->referenceBounds[i&1][0];
202 v[1] = def->referenceBounds[(i>>1)&1][1];
203 v[2] = def->referenceBounds[(i>>2)&1][2];
204
205 R_LocalPointToGlobal( def->modelMatrix, v, transformed[i] );
206 }
207
208 // bump the view count so we can tell if an
209 // area already has a reference
210 tr.viewCount++;
211
212 // push these points down the BSP tree into areas
213 def->world->PushVolumeIntoTree( def, NULL, 8, transformed );
214 }
215
216
217 /*
218 =================================================================================
219
220 CREATE LIGHT REFS
221
222 =================================================================================
223 */
224
225 /*
226 =====================
227 R_SetLightProject
228
229 All values are reletive to the origin
230 Assumes that right and up are not normalized
231 This is also called by dmap during map processing.
232 =====================
233 */
R_SetLightProject(idPlane lightProject[4],const idVec3 origin,const idVec3 target,const idVec3 rightVector,const idVec3 upVector,const idVec3 start,const idVec3 stop)234 void R_SetLightProject( idPlane lightProject[4], const idVec3 origin, const idVec3 target,
235 const idVec3 rightVector, const idVec3 upVector, const idVec3 start, const idVec3 stop ) {
236 float dist;
237 float scale;
238 float rLen, uLen;
239 idVec3 normal;
240 float ofs;
241 idVec3 right, up;
242 idVec3 startGlobal;
243 idVec4 targetGlobal;
244
245 right = rightVector;
246 rLen = right.Normalize();
247 up = upVector;
248 uLen = up.Normalize();
249 normal = up.Cross( right );
250 //normal = right.Cross( up );
251 normal.Normalize();
252
253 dist = target * normal; // - ( origin * normal );
254 if ( dist < 0 ) {
255 dist = -dist;
256 normal = -normal;
257 }
258
259 scale = ( 0.5f * dist ) / rLen;
260 right *= scale;
261 scale = -( 0.5f * dist ) / uLen;
262 up *= scale;
263
264 lightProject[2] = normal;
265 lightProject[2][3] = -( origin * lightProject[2].Normal() );
266
267 lightProject[0] = right;
268 lightProject[0][3] = -( origin * lightProject[0].Normal() );
269
270 lightProject[1] = up;
271 lightProject[1][3] = -( origin * lightProject[1].Normal() );
272
273 // now offset to center
274 targetGlobal.ToVec3() = target + origin;
275 targetGlobal[3] = 1;
276 ofs = 0.5f - ( targetGlobal * lightProject[0].ToVec4() ) / ( targetGlobal * lightProject[2].ToVec4() );
277 lightProject[0].ToVec4() += ofs * lightProject[2].ToVec4();
278 ofs = 0.5f - ( targetGlobal * lightProject[1].ToVec4() ) / ( targetGlobal * lightProject[2].ToVec4() );
279 lightProject[1].ToVec4() += ofs * lightProject[2].ToVec4();
280
281 // set the falloff vector
282 normal = stop - start;
283 dist = normal.Normalize();
284 if ( dist <= 0 ) {
285 dist = 1;
286 }
287 lightProject[3] = normal * ( 1.0f / dist );
288 startGlobal = start + origin;
289 lightProject[3][3] = -( startGlobal * lightProject[3].Normal() );
290 }
291
292 /*
293 ===================
294 R_SetLightFrustum
295
296 Creates plane equations from the light projection, positive sides
297 face out of the light
298 ===================
299 */
R_SetLightFrustum(const idPlane lightProject[4],idPlane frustum[6])300 void R_SetLightFrustum( const idPlane lightProject[4], idPlane frustum[6] ) {
301 int i;
302
303 // we want the planes of s=0, s=q, t=0, and t=q
304 frustum[0] = lightProject[0];
305 frustum[1] = lightProject[1];
306 frustum[2] = lightProject[2] - lightProject[0];
307 frustum[3] = lightProject[2] - lightProject[1];
308
309 // we want the planes of s=0 and s=1 for front and rear clipping planes
310 frustum[4] = lightProject[3];
311
312 frustum[5] = lightProject[3];
313 frustum[5][3] -= 1.0f;
314 frustum[5] = -frustum[5];
315
316 for ( i = 0 ; i < 6 ; i++ ) {
317 float l;
318
319 frustum[i] = -frustum[i];
320 l = frustum[i].Normalize();
321 frustum[i][3] /= l;
322 }
323 }
324
325 /*
326 ====================
327 R_FreeLightDefFrustum
328 ====================
329 */
R_FreeLightDefFrustum(idRenderLightLocal * ldef)330 void R_FreeLightDefFrustum( idRenderLightLocal *ldef ) {
331 int i;
332
333 // free the frustum tris
334 if ( ldef->frustumTris ) {
335 R_FreeStaticTriSurf( ldef->frustumTris );
336 ldef->frustumTris = NULL;
337 }
338 // free frustum windings
339 for ( i = 0; i < 6; i++ ) {
340 if ( ldef->frustumWindings[i] ) {
341 delete ldef->frustumWindings[i];
342 ldef->frustumWindings[i] = NULL;
343 }
344 }
345 }
346
347 /*
348 =================
349 R_DeriveLightData
350
351 Fills everything in based on light->parms
352 =================
353 */
R_DeriveLightData(idRenderLightLocal * light)354 void R_DeriveLightData( idRenderLightLocal *light ) {
355 int i;
356
357 // decide which light shader we are going to use
358 if ( light->parms.shader ) {
359 light->lightShader = light->parms.shader;
360 }
361 if ( !light->lightShader ) {
362 if ( light->parms.pointLight ) {
363 light->lightShader = declManager->FindMaterial( "lights/defaultPointLight" );
364 } else {
365 light->lightShader = declManager->FindMaterial( "lights/defaultProjectedLight" );
366 }
367 }
368
369 // get the falloff image
370 light->falloffImage = light->lightShader->LightFalloffImage();
371 if ( !light->falloffImage ) {
372 // use the falloff from the default shader of the correct type
373 const idMaterial *defaultShader;
374
375 if ( light->parms.pointLight ) {
376 defaultShader = declManager->FindMaterial( "lights/defaultPointLight" );
377 light->falloffImage = defaultShader->LightFalloffImage();
378 } else {
379 // projected lights by default don't diminish with distance
380 defaultShader = declManager->FindMaterial( "lights/defaultProjectedLight" );
381 light->falloffImage = defaultShader->LightFalloffImage();
382 }
383 }
384
385 // set the projection
386 if ( !light->parms.pointLight ) {
387 // projected light
388
389 R_SetLightProject( light->lightProject, vec3_origin /* light->parms.origin */, light->parms.target,
390 light->parms.right, light->parms.up, light->parms.start, light->parms.end);
391 } else {
392 // point light
393 memset( light->lightProject, 0, sizeof( light->lightProject ) );
394 light->lightProject[0][0] = 0.5f / light->parms.lightRadius[0];
395 light->lightProject[1][1] = 0.5f / light->parms.lightRadius[1];
396 light->lightProject[3][2] = 0.5f / light->parms.lightRadius[2];
397 light->lightProject[0][3] = 0.5f;
398 light->lightProject[1][3] = 0.5f;
399 light->lightProject[2][3] = 1.0f;
400 light->lightProject[3][3] = 0.5f;
401 }
402
403 // set the frustum planes
404 R_SetLightFrustum( light->lightProject, light->frustum );
405
406 // rotate the light planes and projections by the axis
407 R_AxisToModelMatrix( light->parms.axis, light->parms.origin, light->modelMatrix );
408
409 for ( i = 0 ; i < 6 ; i++ ) {
410 idPlane temp;
411 temp = light->frustum[i];
412 R_LocalPlaneToGlobal( light->modelMatrix, temp, light->frustum[i] );
413 }
414 for ( i = 0 ; i < 4 ; i++ ) {
415 idPlane temp;
416 temp = light->lightProject[i];
417 R_LocalPlaneToGlobal( light->modelMatrix, temp, light->lightProject[i] );
418 }
419
420 // adjust global light origin for off center projections and parallel projections
421 // we are just faking parallel by making it a very far off center for now
422 if ( light->parms.parallel ) {
423 idVec3 dir;
424
425 dir = light->parms.lightCenter;
426 if ( !dir.Normalize() ) {
427 // make point straight up if not specified
428 dir[2] = 1;
429 }
430 light->globalLightOrigin = light->parms.origin + dir * 100000;
431 } else {
432 light->globalLightOrigin = light->parms.origin + light->parms.axis * light->parms.lightCenter;
433 }
434
435 R_FreeLightDefFrustum( light );
436
437 light->frustumTris = R_PolytopeSurface( 6, light->frustum, light->frustumWindings );
438
439 // a projected light will have one shadowFrustum, a point light will have
440 // six unless the light center is outside the box
441 R_MakeShadowFrustums( light );
442 }
443
444 /*
445 =================
446 R_CreateLightRefs
447 =================
448 */
449 #define MAX_LIGHT_VERTS 40
R_CreateLightRefs(idRenderLightLocal * light)450 void R_CreateLightRefs( idRenderLightLocal *light ) {
451 idVec3 points[MAX_LIGHT_VERTS];
452 int i;
453 srfTriangles_t *tri;
454
455 tri = light->frustumTris;
456
457 // because a light frustum is made of only six intersecting planes,
458 // we should never be able to get a stupid number of points...
459 if ( tri->numVerts > MAX_LIGHT_VERTS ) {
460 common->Error( "R_CreateLightRefs: %i points in frustumTris!", tri->numVerts );
461 }
462 for ( i = 0 ; i < tri->numVerts ; i++ ) {
463 points[i] = tri->verts[i].xyz;
464 }
465
466 if ( r_showUpdates.GetBool() && ( tri->bounds[1][0] - tri->bounds[0][0] > 1024 ||
467 tri->bounds[1][1] - tri->bounds[0][1] > 1024 ) ) {
468 common->Printf( "big lightRef: %f,%f\n", tri->bounds[1][0] - tri->bounds[0][0]
469 ,tri->bounds[1][1] - tri->bounds[0][1] );
470 }
471
472 // determine the areaNum for the light origin, which may let us
473 // cull the light if it is behind a closed door
474 // it is debatable if we want to use the entity origin or the center offset origin,
475 // but we definitely don't want to use a parallel offset origin
476 light->areaNum = light->world->PointInArea( light->globalLightOrigin );
477 if ( light->areaNum == -1 ) {
478 light->areaNum = light->world->PointInArea( light->parms.origin );
479 }
480
481 // bump the view count so we can tell if an
482 // area already has a reference
483 tr.viewCount++;
484
485 // if we have a prelight model that includes all the shadows for the major world occluders,
486 // we can limit the area references to those visible through the portals from the light center.
487 // We can't do this in the normal case, because shadows are cast from back facing triangles, which
488 // may be in areas not directly visible to the light projection center.
489 if ( light->parms.prelightModel && r_useLightPortalFlow.GetBool() && light->lightShader->LightCastsShadows() ) {
490 light->world->FlowLightThroughPortals( light );
491 } else {
492 // push these points down the BSP tree into areas
493 light->world->PushVolumeIntoTree( NULL, light, tri->numVerts, points );
494 }
495 }
496
497 /*
498 ===============
499 R_RenderLightFrustum
500
501 Called by the editor and dmap to operate on light volumes
502 ===============
503 */
R_RenderLightFrustum(const renderLight_t & renderLight,idPlane lightFrustum[6])504 void R_RenderLightFrustum( const renderLight_t &renderLight, idPlane lightFrustum[6] ) {
505 idRenderLightLocal fakeLight;
506
507 fakeLight.parms = renderLight;
508
509 R_DeriveLightData( &fakeLight );
510
511 R_FreeStaticTriSurf( fakeLight.frustumTris );
512
513 for ( int i = 0 ; i < 6 ; i++ ) {
514 lightFrustum[i] = fakeLight.frustum[i];
515 }
516 }
517
518
519 //=================================================================================
520
521 /*
522 ===============
523 WindingCompletelyInsideLight
524 ===============
525 */
WindingCompletelyInsideLight(const idWinding * w,const idRenderLightLocal * ldef)526 bool WindingCompletelyInsideLight( const idWinding *w, const idRenderLightLocal *ldef ) {
527 int i, j;
528
529 for ( i = 0 ; i < w->GetNumPoints() ; i++ ) {
530 for ( j = 0 ; j < 6 ; j++ ) {
531 float d;
532
533 d = (*w)[i].ToVec3() * ldef->frustum[j].Normal() + ldef->frustum[j][3];
534 if ( d > 0 ) {
535 return false;
536 }
537 }
538 }
539 return true;
540 }
541
542 /*
543 ======================
544 R_CreateLightDefFogPortals
545
546 When a fog light is created or moved, see if it completely
547 encloses any portals, which may allow them to be fogged closed.
548 ======================
549 */
R_CreateLightDefFogPortals(idRenderLightLocal * ldef)550 void R_CreateLightDefFogPortals( idRenderLightLocal *ldef ) {
551 areaReference_t *lref;
552 portalArea_t *area;
553
554 ldef->foggedPortals = NULL;
555
556 if ( !ldef->lightShader->IsFogLight() ) {
557 return;
558 }
559
560 // some fog lights will explicitly disallow portal fogging
561 if ( ldef->lightShader->TestMaterialFlag( MF_NOPORTALFOG ) ) {
562 return;
563 }
564
565 for ( lref = ldef->references ; lref ; lref = lref->ownerNext ) {
566 // check all the models in this area
567 area = lref->area;
568
569 portal_t *prt;
570 doublePortal_t *dp;
571
572 for ( prt = area->portals ; prt ; prt = prt->next ) {
573 dp = prt->doublePortal;
574
575 // we only handle a single fog volume covering a portal
576 // this will never cause incorrect drawing, but it may
577 // fail to cull a portal
578 if ( dp->fogLight ) {
579 continue;
580 }
581
582 if ( WindingCompletelyInsideLight( prt->w, ldef ) ) {
583 dp->fogLight = ldef;
584 dp->nextFoggedPortal = ldef->foggedPortals;
585 ldef->foggedPortals = dp;
586 }
587 }
588 }
589 }
590
591 /*
592 ====================
593 R_FreeLightDefDerivedData
594
595 Frees all references and lit surfaces from the light
596 ====================
597 */
R_FreeLightDefDerivedData(idRenderLightLocal * ldef)598 void R_FreeLightDefDerivedData( idRenderLightLocal *ldef ) {
599 areaReference_t *lref, *nextRef;
600
601 // rmove any portal fog references
602 for ( doublePortal_t *dp = ldef->foggedPortals ; dp ; dp = dp->nextFoggedPortal ) {
603 dp->fogLight = NULL;
604 }
605
606 // free all the interactions
607 while ( ldef->firstInteraction != NULL ) {
608 ldef->firstInteraction->UnlinkAndFree();
609 }
610
611 // free all the references to the light
612 for ( lref = ldef->references ; lref ; lref = nextRef ) {
613 nextRef = lref->ownerNext;
614
615 // unlink from the area
616 lref->areaNext->areaPrev = lref->areaPrev;
617 lref->areaPrev->areaNext = lref->areaNext;
618
619 // put it back on the free list for reuse
620 ldef->world->areaReferenceAllocator.Free( lref );
621 }
622 ldef->references = NULL;
623
624 R_FreeLightDefFrustum( ldef );
625 }
626
627 /*
628 ===================
629 R_FreeEntityDefDerivedData
630
631 Used by both RE_FreeEntityDef and RE_UpdateEntityDef
632 Does not actually free the entityDef.
633 ===================
634 */
R_FreeEntityDefDerivedData(idRenderEntityLocal * def,bool keepDecals,bool keepCachedDynamicModel)635 void R_FreeEntityDefDerivedData( idRenderEntityLocal *def, bool keepDecals, bool keepCachedDynamicModel ) {
636 int i;
637 areaReference_t *ref, *next;
638
639 // demo playback needs to free the joints, while normal play
640 // leaves them in the control of the game
641 if ( session->readDemo ) {
642 if ( def->parms.joints ) {
643 Mem_Free16( def->parms.joints );
644 def->parms.joints = NULL;
645 }
646 if ( def->parms.callbackData ) {
647 Mem_Free( def->parms.callbackData );
648 def->parms.callbackData = NULL;
649 }
650 for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
651 if ( def->parms.gui[ i ] ) {
652 delete def->parms.gui[ i ];
653 def->parms.gui[ i ] = NULL;
654 }
655 }
656 }
657
658 // free all the interactions
659 while ( def->firstInteraction != NULL ) {
660 def->firstInteraction->UnlinkAndFree();
661 }
662
663 // clear the dynamic model if present
664 if ( def->dynamicModel ) {
665 def->dynamicModel = NULL;
666 }
667
668 if ( !keepDecals ) {
669 R_FreeEntityDefDecals( def );
670 R_FreeEntityDefOverlay( def );
671 }
672
673 if ( !keepCachedDynamicModel ) {
674 delete def->cachedDynamicModel;
675 def->cachedDynamicModel = NULL;
676 }
677
678 // free the entityRefs from the areas
679 for ( ref = def->entityRefs ; ref ; ref = next ) {
680 next = ref->ownerNext;
681
682 // unlink from the area
683 ref->areaNext->areaPrev = ref->areaPrev;
684 ref->areaPrev->areaNext = ref->areaNext;
685
686 // put it back on the free list for reuse
687 def->world->areaReferenceAllocator.Free( ref );
688 }
689 def->entityRefs = NULL;
690 }
691
692 /*
693 ==================
694 R_ClearEntityDefDynamicModel
695
696 If we know the reference bounds stays the same, we
697 only need to do this on entity update, not the full
698 R_FreeEntityDefDerivedData
699 ==================
700 */
R_ClearEntityDefDynamicModel(idRenderEntityLocal * def)701 void R_ClearEntityDefDynamicModel( idRenderEntityLocal *def ) {
702 // free all the interaction surfaces
703 for( idInteraction *inter = def->firstInteraction; inter != NULL && !inter->IsEmpty(); inter = inter->entityNext ) {
704 inter->FreeSurfaces();
705 }
706
707 // clear the dynamic model if present
708 if ( def->dynamicModel ) {
709 def->dynamicModel = NULL;
710 }
711 }
712
713 /*
714 ===================
715 R_FreeEntityDefDecals
716 ===================
717 */
R_FreeEntityDefDecals(idRenderEntityLocal * def)718 void R_FreeEntityDefDecals( idRenderEntityLocal *def ) {
719 while( def->decals ) {
720 idRenderModelDecal *next = def->decals->Next();
721 idRenderModelDecal::Free( def->decals );
722 def->decals = next;
723 }
724 }
725
726 /*
727 ===================
728 R_FreeEntityDefFadedDecals
729 ===================
730 */
R_FreeEntityDefFadedDecals(idRenderEntityLocal * def,int time)731 void R_FreeEntityDefFadedDecals( idRenderEntityLocal *def, int time ) {
732 def->decals = idRenderModelDecal::RemoveFadedDecals( def->decals, time );
733 }
734
735 /*
736 ===================
737 R_FreeEntityDefOverlay
738 ===================
739 */
R_FreeEntityDefOverlay(idRenderEntityLocal * def)740 void R_FreeEntityDefOverlay( idRenderEntityLocal *def ) {
741 if ( def->overlay ) {
742 idRenderModelOverlay::Free( def->overlay );
743 def->overlay = NULL;
744 }
745 }
746
747 /*
748 ===================
749 R_FreeDerivedData
750
751 ReloadModels and RegenerateWorld call this
752 // FIXME: need to do this for all worlds
753 ===================
754 */
R_FreeDerivedData(void)755 void R_FreeDerivedData( void ) {
756 int i, j;
757 idRenderWorldLocal *rw;
758 idRenderEntityLocal *def;
759 idRenderLightLocal *light;
760
761 for ( j = 0; j < tr.worlds.Num(); j++ ) {
762 rw = tr.worlds[j];
763
764 for ( i = 0; i < rw->entityDefs.Num(); i++ ) {
765 def = rw->entityDefs[i];
766 if ( !def ) {
767 continue;
768 }
769 R_FreeEntityDefDerivedData( def, false, false );
770 }
771
772 for ( i = 0; i < rw->lightDefs.Num(); i++ ) {
773 light = rw->lightDefs[i];
774 if ( !light ) {
775 continue;
776 }
777 R_FreeLightDefDerivedData( light );
778 }
779 }
780 }
781
782 /*
783 ===================
784 R_CheckForEntityDefsUsingModel
785 ===================
786 */
R_CheckForEntityDefsUsingModel(idRenderModel * model)787 void R_CheckForEntityDefsUsingModel( idRenderModel *model ) {
788 int i, j;
789 idRenderWorldLocal *rw;
790 idRenderEntityLocal *def;
791
792 for ( j = 0; j < tr.worlds.Num(); j++ ) {
793 rw = tr.worlds[j];
794
795 for ( i = 0 ; i < rw->entityDefs.Num(); i++ ) {
796 def = rw->entityDefs[i];
797 if ( !def ) {
798 continue;
799 }
800 if ( def->parms.hModel == model ) {
801 //assert( 0 );
802 // this should never happen but Radiant messes it up all the time so just free the derived data
803 R_FreeEntityDefDerivedData( def, false, false );
804 }
805 }
806 }
807 }
808
809 /*
810 ===================
811 R_ReCreateWorldReferences
812
813 ReloadModels and RegenerateWorld call this
814 // FIXME: need to do this for all worlds
815 ===================
816 */
R_ReCreateWorldReferences(void)817 void R_ReCreateWorldReferences( void ) {
818 int i, j;
819 idRenderWorldLocal *rw;
820 idRenderEntityLocal *def;
821 idRenderLightLocal *light;
822
823 // let the interaction generation code know this shouldn't be optimized for
824 // a particular view
825 tr.viewDef = NULL;
826
827 for ( j = 0; j < tr.worlds.Num(); j++ ) {
828 rw = tr.worlds[j];
829
830 for ( i = 0 ; i < rw->entityDefs.Num() ; i++ ) {
831 def = rw->entityDefs[i];
832 if ( !def ) {
833 continue;
834 }
835 // the world model entities are put specifically in a single
836 // area, instead of just pushing their bounds into the tree
837 if ( i < rw->numPortalAreas ) {
838 rw->AddEntityRefToArea( def, &rw->portalAreas[i] );
839 } else {
840 R_CreateEntityRefs( def );
841 }
842 }
843
844 for ( i = 0 ; i < rw->lightDefs.Num() ; i++ ) {
845 light = rw->lightDefs[i];
846 if ( !light ) {
847 continue;
848 }
849 renderLight_t parms = light->parms;
850
851 light->world->FreeLightDef( i );
852 rw->UpdateLightDef( i, &parms );
853 }
854 }
855 }
856
857 /*
858 ===================
859 R_RegenerateWorld_f
860
861 Frees and regenerates all references and interactions, which
862 must be done when switching between display list mode and immediate mode
863 ===================
864 */
R_RegenerateWorld_f(const idCmdArgs & args)865 void R_RegenerateWorld_f( const idCmdArgs &args ) {
866 R_FreeDerivedData();
867
868 // watch how much memory we allocate
869 tr.staticAllocCount = 0;
870
871 R_ReCreateWorldReferences();
872
873 common->Printf( "Regenerated world, staticAllocCount = %i.\n", tr.staticAllocCount );
874 }
875