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