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