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 "framework/DeclSkin.h"
32 #include "renderer/GuiModel.h"
33 #include "renderer/RenderWorld_local.h"
34 
35 #include "renderer/tr_local.h"
36 
37 /*
38 ===================
39 R_ListRenderLightDefs_f
40 ===================
41 */
R_ListRenderLightDefs_f(const idCmdArgs & args)42 void R_ListRenderLightDefs_f( const idCmdArgs &args ) {
43 	int			i;
44 	idRenderLightLocal	*ldef;
45 
46 	if ( !tr.primaryWorld ) {
47 		return;
48 	}
49 	int active = 0;
50 	int	totalRef = 0;
51 	int	totalIntr = 0;
52 
53 	for ( i = 0 ; i < tr.primaryWorld->lightDefs.Num() ; i++ ) {
54 		ldef = tr.primaryWorld->lightDefs[i];
55 		if ( !ldef ) {
56 			common->Printf( "%4i: FREED\n", i );
57 			continue;
58 		}
59 
60 		// count up the interactions
61 		int	iCount = 0;
62 		for ( idInteraction *inter = ldef->firstInteraction; inter != NULL; inter = inter->lightNext ) {
63 			iCount++;
64 		}
65 		totalIntr += iCount;
66 
67 		// count up the references
68 		int	rCount = 0;
69 		for ( areaReference_t *ref = ldef->references ; ref ; ref = ref->ownerNext ) {
70 			rCount++;
71 		}
72 		totalRef += rCount;
73 
74 		common->Printf( "%4i: %3i intr %2i refs %s\n", i, iCount, rCount, ldef->lightShader->GetName());
75 		active++;
76 	}
77 
78 	common->Printf( "%i lightDefs, %i interactions, %i areaRefs\n", active, totalIntr, totalRef );
79 }
80 
81 /*
82 ===================
83 R_ListRenderEntityDefs_f
84 ===================
85 */
R_ListRenderEntityDefs_f(const idCmdArgs & args)86 void R_ListRenderEntityDefs_f( const idCmdArgs &args ) {
87 	int			i;
88 	idRenderEntityLocal	*mdef;
89 
90 	if ( !tr.primaryWorld ) {
91 		return;
92 	}
93 	int active = 0;
94 	int	totalRef = 0;
95 	int	totalIntr = 0;
96 
97 	for ( i = 0 ; i < tr.primaryWorld->entityDefs.Num() ; i++ ) {
98 		mdef = tr.primaryWorld->entityDefs[i];
99 		if ( !mdef ) {
100 			common->Printf( "%4i: FREED\n", i );
101 			continue;
102 		}
103 
104 		// count up the interactions
105 		int	iCount = 0;
106 		for ( idInteraction *inter = mdef->firstInteraction; inter != NULL; inter = inter->entityNext ) {
107 			iCount++;
108 		}
109 		totalIntr += iCount;
110 
111 		// count up the references
112 		int	rCount = 0;
113 		for ( areaReference_t *ref = mdef->entityRefs ; ref ; ref = ref->ownerNext ) {
114 			rCount++;
115 		}
116 		totalRef += rCount;
117 
118 		common->Printf( "%4i: %3i intr %2i refs %s\n", i, iCount, rCount, mdef->parms.hModel->Name());
119 		active++;
120 	}
121 
122 	common->Printf( "total active: %i\n", active );
123 }
124 
125 /*
126 ===================
127 idRenderWorldLocal::idRenderWorldLocal
128 ===================
129 */
idRenderWorldLocal()130 idRenderWorldLocal::idRenderWorldLocal() {
131 	mapName.Clear();
132 	mapTimeStamp = FILE_NOT_FOUND_TIMESTAMP;
133 
134 	generateAllInteractionsCalled = false;
135 
136 	areaNodes = NULL;
137 	numAreaNodes = 0;
138 
139 	portalAreas = NULL;
140 	numPortalAreas = 0;
141 
142 	doublePortals = NULL;
143 	numInterAreaPortals = 0;
144 
145 	interactionTable = 0;
146 	interactionTableWidth = 0;
147 	interactionTableHeight = 0;
148 }
149 
150 /*
151 ===================
152 idRenderWorldLocal::~idRenderWorldLocal
153 ===================
154 */
~idRenderWorldLocal()155 idRenderWorldLocal::~idRenderWorldLocal() {
156 	// free all the entityDefs, lightDefs, portals, etc
157 	FreeWorld();
158 
159 	// free up the debug lines, polys, and text
160 	RB_ClearDebugPolygons( 0 );
161 	RB_ClearDebugLines( 0 );
162 	RB_ClearDebugText( 0 );
163 }
164 
165 /*
166 ===================
167 ResizeInteractionTable
168 ===================
169 */
ResizeInteractionTable()170 void idRenderWorldLocal::ResizeInteractionTable() {
171 	// we overflowed the interaction table, so dump it
172 	// we may want to resize this in the future if it turns out to be common
173 	common->Printf( "idRenderWorldLocal::ResizeInteractionTable: overflowed interactionTableWidth, dumping\n" );
174 	R_StaticFree( interactionTable );
175 	interactionTable = NULL;
176 }
177 
178 /*
179 ===================
180 AddEntityDef
181 ===================
182 */
AddEntityDef(const renderEntity_t * re)183 qhandle_t idRenderWorldLocal::AddEntityDef( const renderEntity_t *re ){
184 	// try and reuse a free spot
185 	int entityHandle = entityDefs.FindNull();
186 	if ( entityHandle == -1 ) {
187 		entityHandle = entityDefs.Append( NULL );
188 		if ( interactionTable && entityDefs.Num() > interactionTableWidth ) {
189 			ResizeInteractionTable();
190 		}
191 	}
192 
193 	UpdateEntityDef( entityHandle, re );
194 
195 	return entityHandle;
196 }
197 
198 /*
199 ==============
200 UpdateEntityDef
201 
202 Does not write to the demo file, which will only be updated for
203 visible entities
204 ==============
205 */
206 int c_callbackUpdate;
207 
UpdateEntityDef(qhandle_t entityHandle,const renderEntity_t * re)208 void idRenderWorldLocal::UpdateEntityDef( qhandle_t entityHandle, const renderEntity_t *re ) {
209 	if ( r_skipUpdates.GetBool() ) {
210 		return;
211 	}
212 
213 	tr.pc.c_entityUpdates++;
214 
215 	if ( !re->hModel && !re->callback ) {
216 		common->Error( "idRenderWorld::UpdateEntityDef: NULL hModel" );
217 	}
218 
219 	// create new slots if needed
220 	if ( entityHandle < 0 || entityHandle > LUDICROUS_INDEX ) {
221 		common->Error( "idRenderWorld::UpdateEntityDef: index = %i", entityHandle );
222 	}
223 	while ( entityHandle >= entityDefs.Num() ) {
224 		entityDefs.Append( NULL );
225 	}
226 
227 	idRenderEntityLocal	*def = entityDefs[entityHandle];
228 	if ( def ) {
229 
230 		if ( !re->forceUpdate ) {
231 
232 			// check for exact match (OPTIMIZE: check through pointers more)
233 			if ( !re->joints && !re->callbackData && !def->dynamicModel && !memcmp( re, &def->parms, sizeof( *re ) ) ) {
234 				return;
235 			}
236 
237 			// if the only thing that changed was shaderparms, we can just leave things as they are
238 			// after updating parms
239 
240 			// if we have a callback function and the bounds, origin, axis and model match,
241 			// then we can leave the references as they are
242 			if ( re->callback ) {
243 
244 				bool axisMatch = ( re->axis == def->parms.axis );
245 				bool originMatch = ( re->origin == def->parms.origin );
246 				bool boundsMatch = ( re->bounds == def->referenceBounds );
247 				bool modelMatch = ( re->hModel == def->parms.hModel );
248 
249 				if ( boundsMatch && originMatch && axisMatch && modelMatch ) {
250 					// only clear the dynamic model and interaction surfaces if they exist
251 					c_callbackUpdate++;
252 					R_ClearEntityDefDynamicModel( def );
253 					def->parms = *re;
254 					return;
255 				}
256 			}
257 		}
258 
259 		// save any decals if the model is the same, allowing marks to move with entities
260 		if ( def->parms.hModel == re->hModel ) {
261 			R_FreeEntityDefDerivedData( def, true, true );
262 		} else {
263 			R_FreeEntityDefDerivedData( def, false, false );
264 		}
265 	} else {
266 		// creating a new one
267 		def = new idRenderEntityLocal;
268 		entityDefs[entityHandle] = def;
269 
270 		def->world = this;
271 		def->index = entityHandle;
272 	}
273 
274 	def->parms = *re;
275 
276 	R_AxisToModelMatrix( def->parms.axis, def->parms.origin, def->modelMatrix );
277 
278 	def->lastModifiedFrameNum = tr.frameCount;
279 	if ( session->writeDemo && def->archived ) {
280 		WriteFreeEntity( entityHandle );
281 		def->archived = false;
282 	}
283 
284 	// optionally immediately issue any callbacks
285 	if ( !r_useEntityCallbacks.GetBool() && def->parms.callback ) {
286 		R_IssueEntityDefCallback( def );
287 	}
288 
289 	// based on the model bounds, add references in each area
290 	// that may contain the updated surface
291 	R_CreateEntityRefs( def );
292 }
293 
294 /*
295 ===================
296 FreeEntityDef
297 
298 Frees all references and lit surfaces from the model, and
299 NULL's out it's entry in the world list
300 ===================
301 */
FreeEntityDef(qhandle_t entityHandle)302 void idRenderWorldLocal::FreeEntityDef( qhandle_t entityHandle ) {
303 	idRenderEntityLocal	*def;
304 
305 	if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
306 		common->Printf( "idRenderWorld::FreeEntityDef: handle %i > %i\n", entityHandle, entityDefs.Num() );
307 		return;
308 	}
309 
310 	def = entityDefs[entityHandle];
311 	if ( !def ) {
312 		common->Printf( "idRenderWorld::FreeEntityDef: handle %i is NULL\n", entityHandle );
313 		return;
314 	}
315 
316 	R_FreeEntityDefDerivedData( def, false, false );
317 
318 	if ( session->writeDemo && def->archived ) {
319 		WriteFreeEntity( entityHandle );
320 	}
321 
322 	// if we are playing a demo, these will have been freed
323 	// in R_FreeEntityDefDerivedData(), otherwise the gui
324 	// object still exists in the game
325 
326 	def->parms.gui[ 0 ] = NULL;
327 	def->parms.gui[ 1 ] = NULL;
328 	def->parms.gui[ 2 ] = NULL;
329 
330 	delete def;
331 	entityDefs[ entityHandle ] = NULL;
332 }
333 
334 /*
335 ==================
336 GetRenderEntity
337 ==================
338 */
GetRenderEntity(qhandle_t entityHandle) const339 const renderEntity_t *idRenderWorldLocal::GetRenderEntity( qhandle_t entityHandle ) const {
340 	idRenderEntityLocal	*def;
341 
342 	if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
343 		common->Printf( "idRenderWorld::GetRenderEntity: invalid handle %i [0, %i]\n", entityHandle, entityDefs.Num() );
344 		return NULL;
345 	}
346 
347 	def = entityDefs[entityHandle];
348 	if ( !def ) {
349 		common->Printf( "idRenderWorld::GetRenderEntity: handle %i is NULL\n", entityHandle );
350 		return NULL;
351 	}
352 
353 	return &def->parms;
354 }
355 
356 /*
357 ==================
358 AddLightDef
359 ==================
360 */
AddLightDef(const renderLight_t * rlight)361 qhandle_t idRenderWorldLocal::AddLightDef( const renderLight_t *rlight ) {
362 	// try and reuse a free spot
363 	int lightHandle = lightDefs.FindNull();
364 
365 	if ( lightHandle == -1 ) {
366 		lightHandle = lightDefs.Append( NULL );
367 		if ( interactionTable && lightDefs.Num() > interactionTableHeight ) {
368 			ResizeInteractionTable();
369 		}
370 	}
371 	UpdateLightDef( lightHandle, rlight );
372 
373 	return lightHandle;
374 }
375 
376 /*
377 =================
378 UpdateLightDef
379 
380 The generation of all the derived interaction data will
381 usually be deferred until it is visible in a scene
382 
383 Does not write to the demo file, which will only be done for visible lights
384 =================
385 */
UpdateLightDef(qhandle_t lightHandle,const renderLight_t * rlight)386 void idRenderWorldLocal::UpdateLightDef( qhandle_t lightHandle, const renderLight_t *rlight ) {
387 	if ( r_skipUpdates.GetBool() ) {
388 		return;
389 	}
390 
391 	tr.pc.c_lightUpdates++;
392 
393 	// create new slots if needed
394 	if ( lightHandle < 0 || lightHandle > LUDICROUS_INDEX ) {
395 		common->Error( "idRenderWorld::UpdateLightDef: index = %i", lightHandle );
396 	}
397 	while ( lightHandle >= lightDefs.Num() ) {
398 		lightDefs.Append( NULL );
399 	}
400 
401 	bool justUpdate = false;
402 	idRenderLightLocal *light = lightDefs[lightHandle];
403 	if ( light ) {
404 		// if the shape of the light stays the same, we don't need to dump
405 		// any of our derived data, because shader parms are calculated every frame
406 		if ( rlight->axis == light->parms.axis && rlight->end == light->parms.end &&
407 			 rlight->lightCenter == light->parms.lightCenter && rlight->lightRadius == light->parms.lightRadius &&
408 			 rlight->noShadows == light->parms.noShadows && rlight->origin == light->parms.origin &&
409 			 rlight->parallel == light->parms.parallel && rlight->pointLight == light->parms.pointLight &&
410 			 rlight->right == light->parms.right && rlight->start == light->parms.start &&
411 			 rlight->target == light->parms.target && rlight->up == light->parms.up &&
412 			 rlight->shader == light->lightShader && rlight->prelightModel == light->parms.prelightModel ) {
413 			justUpdate = true;
414 		} else {
415 			// if we are updating shadows, the prelight model is no longer valid
416 			light->lightHasMoved = true;
417 			R_FreeLightDefDerivedData( light );
418 		}
419 	} else {
420 		// create a new one
421 		light = new idRenderLightLocal;
422 		lightDefs[lightHandle] = light;
423 
424 		light->world = this;
425 		light->index = lightHandle;
426 	}
427 
428 	light->parms = *rlight;
429 	light->lastModifiedFrameNum = tr.frameCount;
430 	if ( session->writeDemo && light->archived ) {
431 		WriteFreeLight( lightHandle );
432 		light->archived = false;
433 	}
434 
435 	if ( light->lightHasMoved ) {
436 		light->parms.prelightModel = NULL;
437 	}
438 
439 	if (!justUpdate) {
440 		R_DeriveLightData( light );
441 		R_CreateLightRefs( light );
442 		R_CreateLightDefFogPortals( light );
443 	}
444 }
445 
446 /*
447 ====================
448 FreeLightDef
449 
450 Frees all references and lit surfaces from the light, and
451 NULL's out it's entry in the world list
452 ====================
453 */
FreeLightDef(qhandle_t lightHandle)454 void idRenderWorldLocal::FreeLightDef( qhandle_t lightHandle ) {
455 	idRenderLightLocal	*light;
456 
457 	if ( lightHandle < 0 || lightHandle >= lightDefs.Num() ) {
458 		common->Printf( "idRenderWorld::FreeLightDef: invalid handle %i [0, %i]\n", lightHandle, lightDefs.Num() );
459 		return;
460 	}
461 
462 	light = lightDefs[lightHandle];
463 	if ( !light ) {
464 		common->Printf( "idRenderWorld::FreeLightDef: handle %i is NULL\n", lightHandle );
465 		return;
466 	}
467 
468 	R_FreeLightDefDerivedData( light );
469 
470 	if ( session->writeDemo && light->archived ) {
471 		WriteFreeLight( lightHandle );
472 	}
473 
474 	delete light;
475 	lightDefs[lightHandle] = NULL;
476 }
477 
478 /*
479 ==================
480 GetRenderLight
481 ==================
482 */
GetRenderLight(qhandle_t lightHandle) const483 const renderLight_t *idRenderWorldLocal::GetRenderLight( qhandle_t lightHandle ) const {
484 	idRenderLightLocal *def;
485 
486 	if ( lightHandle < 0 || lightHandle >= lightDefs.Num() ) {
487 		common->Printf( "idRenderWorld::GetRenderLight: handle %i > %i\n", lightHandle, lightDefs.Num() );
488 		return NULL;
489 	}
490 
491 	def = lightDefs[lightHandle];
492 	if ( !def ) {
493 		common->Printf( "idRenderWorld::GetRenderLight: handle %i is NULL\n", lightHandle );
494 		return NULL;
495 	}
496 
497 	return &def->parms;
498 }
499 
500 /*
501 ================
502 idRenderWorldLocal::ProjectDecalOntoWorld
503 ================
504 */
ProjectDecalOntoWorld(const idFixedWinding & winding,const idVec3 & projectionOrigin,const bool parallel,const float fadeDepth,const idMaterial * material,const int startTime)505 void idRenderWorldLocal::ProjectDecalOntoWorld( const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime ) {
506 	int i, areas[10], numAreas;
507 	const areaReference_t *ref;
508 	const portalArea_t *area;
509 	const idRenderModel *model;
510 	idRenderEntityLocal *def;
511 	decalProjectionInfo_t info, localInfo;
512 
513 	if ( !idRenderModelDecal::CreateProjectionInfo( info, winding, projectionOrigin, parallel, fadeDepth, material, startTime ) ) {
514 		return;
515 	}
516 
517 	// get the world areas touched by the projection volume
518 	numAreas = BoundsInAreas( info.projectionBounds, areas, 10 );
519 
520 	// check all areas for models
521 	for ( i = 0; i < numAreas; i++ ) {
522 
523 		area = &portalAreas[ areas[i] ];
524 
525 		// check all models in this area
526 		for ( ref = area->entityRefs.areaNext; ref != &area->entityRefs; ref = ref->areaNext ) {
527 			def = ref->entity;
528 
529 			// completely ignore any dynamic or callback models
530 			model = def->parms.hModel;
531 			if ( model == NULL || model->IsDynamicModel() != DM_STATIC || def->parms.callback ) {
532 				continue;
533 			}
534 
535 			if ( def->parms.customShader != NULL && !def->parms.customShader->AllowOverlays() ) {
536 				continue;
537 			}
538 
539 			idBounds bounds;
540 			bounds.FromTransformedBounds( model->Bounds( &def->parms ), def->parms.origin, def->parms.axis );
541 
542 			// if the model bounds do not overlap with the projection bounds
543 			if ( !info.projectionBounds.IntersectsBounds( bounds ) ) {
544 				continue;
545 			}
546 
547 			// transform the bounding planes, fade planes and texture axis into local space
548 			idRenderModelDecal::GlobalProjectionInfoToLocal( localInfo, info, def->parms.origin, def->parms.axis );
549 			localInfo.force = ( def->parms.customShader != NULL );
550 
551 			if ( !def->decals ) {
552 				def->decals = idRenderModelDecal::Alloc();
553 			}
554 			def->decals->CreateDecal( model, localInfo );
555 		}
556 	}
557 }
558 
559 /*
560 ====================
561 idRenderWorldLocal::ProjectDecal
562 ====================
563 */
ProjectDecal(qhandle_t entityHandle,const idFixedWinding & winding,const idVec3 & projectionOrigin,const bool parallel,const float fadeDepth,const idMaterial * material,const int startTime)564 void idRenderWorldLocal::ProjectDecal( qhandle_t entityHandle, const idFixedWinding &winding, const idVec3 &projectionOrigin, const bool parallel, const float fadeDepth, const idMaterial *material, const int startTime ) {
565 	decalProjectionInfo_t info, localInfo;
566 
567 	if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
568 		common->Error( "idRenderWorld::ProjectOverlay: index = %i", entityHandle );
569 		return;
570 	}
571 
572 	idRenderEntityLocal	*def = entityDefs[ entityHandle ];
573 	if ( !def ) {
574 		return;
575 	}
576 
577 	const idRenderModel *model = def->parms.hModel;
578 
579 	if ( model == NULL || model->IsDynamicModel() != DM_STATIC || def->parms.callback ) {
580 		return;
581 	}
582 
583 	if ( !idRenderModelDecal::CreateProjectionInfo( info, winding, projectionOrigin, parallel, fadeDepth, material, startTime ) ) {
584 		return;
585 	}
586 
587 	idBounds bounds;
588 	bounds.FromTransformedBounds( model->Bounds( &def->parms ), def->parms.origin, def->parms.axis );
589 
590 	// if the model bounds do not overlap with the projection bounds
591 	if ( !info.projectionBounds.IntersectsBounds( bounds ) ) {
592 		return;
593 	}
594 
595 	// transform the bounding planes, fade planes and texture axis into local space
596 	idRenderModelDecal::GlobalProjectionInfoToLocal( localInfo, info, def->parms.origin, def->parms.axis );
597 	localInfo.force = ( def->parms.customShader != NULL );
598 
599 	if ( def->decals == NULL ) {
600 		def->decals = idRenderModelDecal::Alloc();
601 	}
602 	def->decals->CreateDecal( model, localInfo );
603 }
604 
605 /*
606 ====================
607 idRenderWorldLocal::ProjectOverlay
608 ====================
609 */
ProjectOverlay(qhandle_t entityHandle,const idPlane localTextureAxis[2],const idMaterial * material)610 void idRenderWorldLocal::ProjectOverlay( qhandle_t entityHandle, const idPlane localTextureAxis[2], const idMaterial *material ) {
611 
612 	if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
613 		common->Error( "idRenderWorld::ProjectOverlay: index = %i", entityHandle );
614 		return;
615 	}
616 
617 	idRenderEntityLocal	*def = entityDefs[ entityHandle ];
618 	if ( !def ) {
619 		return;
620 	}
621 
622 	const renderEntity_t *refEnt = &def->parms;
623 
624 	idRenderModel *model = refEnt->hModel;
625 	if ( model->IsDynamicModel() != DM_CACHED ) {	// FIXME: probably should be MD5 only
626 		return;
627 	}
628 	model = R_EntityDefDynamicModel( def );
629 
630 	if ( def->overlay == NULL ) {
631 		def->overlay = idRenderModelOverlay::Alloc();
632 	}
633 	def->overlay->CreateOverlay( model, localTextureAxis, material );
634 }
635 
636 /*
637 ====================
638 idRenderWorldLocal::RemoveDecals
639 ====================
640 */
RemoveDecals(qhandle_t entityHandle)641 void idRenderWorldLocal::RemoveDecals( qhandle_t entityHandle ) {
642 	if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
643 		common->Error( "idRenderWorld::ProjectOverlay: index = %i", entityHandle );
644 		return;
645 	}
646 
647 	idRenderEntityLocal	*def = entityDefs[ entityHandle ];
648 	if ( !def ) {
649 		return;
650 	}
651 
652 	R_FreeEntityDefDecals( def );
653 	R_FreeEntityDefOverlay( def );
654 }
655 
656 /*
657 ====================
658 SetRenderView
659 
660 Sets the current view so any calls to the render world will use the correct parms.
661 ====================
662 */
SetRenderView(const renderView_t * renderView)663 void idRenderWorldLocal::SetRenderView( const renderView_t *renderView ) {
664 	tr.primaryRenderView = *renderView;
665 }
666 
667 /*
668 ====================
669 RenderScene
670 
671 Draw a 3D view into a part of the window, then return
672 to 2D drawing.
673 
674 Rendering a scene may require multiple views to be rendered
675 to handle mirrors,
676 ====================
677 */
RenderScene(const renderView_t * renderView)678 void idRenderWorldLocal::RenderScene( const renderView_t *renderView ) {
679 #ifndef	ID_DEDICATED
680 	renderView_t	copy;
681 
682 	if ( !glConfig.isInitialized ) {
683 		return;
684 	}
685 
686 	copy = *renderView;
687 
688 	// skip front end rendering work, which will result
689 	// in only gui drawing
690 	if ( r_skipFrontEnd.GetBool() ) {
691 		return;
692 	}
693 
694 	if ( renderView->fov_x <= 0 || renderView->fov_y <= 0 ) {
695 		common->Error( "idRenderWorld::RenderScene: bad FOVs: %f, %f", renderView->fov_x, renderView->fov_y );
696 	}
697 
698 	// close any gui drawing
699 	tr.guiModel->EmitFullScreen();
700 	tr.guiModel->Clear();
701 
702 	int startTime = Sys_Milliseconds();
703 
704 	// setup view parms for the initial view
705 	//
706 	viewDef_t		*parms = (viewDef_t *)R_ClearedFrameAlloc( sizeof( *parms ) );
707 	parms->renderView = *renderView;
708 
709 	if ( tr.takingScreenshot ) {
710 		parms->renderView.forceUpdate = true;
711 	}
712 
713 	// set up viewport, adjusted for resolution and OpenGL style 0 at the bottom
714 	tr.RenderViewToViewport( &parms->renderView, &parms->viewport );
715 
716 	// the scissor bounds may be shrunk in subviews even if
717 	// the viewport stays the same
718 	// this scissor range is local inside the viewport
719 	parms->scissor.x1 = 0;
720 	parms->scissor.y1 = 0;
721 	parms->scissor.x2 = parms->viewport.x2 - parms->viewport.x1;
722 	parms->scissor.y2 = parms->viewport.y2 - parms->viewport.y1;
723 
724 
725 	parms->isSubview = false;
726 	parms->initialViewAreaOrigin = renderView->vieworg;
727 	parms->floatTime = parms->renderView.time * 0.001f;
728 	parms->renderWorld = this;
729 
730 	// use this time for any subsequent 2D rendering, so damage blobs/etc
731 	// can use level time
732 	tr.frameShaderTime = parms->floatTime;
733 
734 	// see if the view needs to reverse the culling sense in mirrors
735 	// or environment cube sides
736 	idVec3	cross;
737 	cross = parms->renderView.viewaxis[1].Cross( parms->renderView.viewaxis[2] );
738 	if ( cross * parms->renderView.viewaxis[0] > 0 ) {
739 		parms->isMirror = false;
740 	} else {
741 		parms->isMirror = true;
742 	}
743 
744 	if ( r_lockSurfaces.GetBool() ) {
745 		R_LockSurfaceScene( parms );
746 		return;
747 	}
748 
749 	// save this world for use by some console commands
750 	tr.primaryWorld = this;
751 	tr.primaryRenderView = *renderView;
752 	tr.primaryView = parms;
753 
754 	// rendering this view may cause other views to be rendered
755 	// for mirrors / portals / shadows / environment maps
756 	// this will also cause any necessary entities and lights to be
757 	// updated to the demo file
758 	R_RenderView( parms );
759 
760 	// now write delete commands for any modified-but-not-visible entities, and
761 	// add the renderView command to the demo
762 	if ( session->writeDemo ) {
763 		WriteRenderView( renderView );
764 	}
765 
766 #if 0
767 	for ( int i = 0 ; i < entityDefs.Num() ; i++ ) {
768 		idRenderEntityLocal	*def = entityDefs[i];
769 		if ( !def ) {
770 			continue;
771 		}
772 		if ( def->parms.callback ) {
773 			continue;
774 		}
775 		if ( def->parms.hModel->IsDynamicModel() == DM_CONTINUOUS ) {
776 		}
777 	}
778 #endif
779 
780 	int endTime = Sys_Milliseconds();
781 
782 	tr.pc.frontEndMsec += endTime - startTime;
783 
784 	// prepare for any 2D drawing after this
785 	tr.guiModel->Clear();
786 #endif
787 }
788 
789 /*
790 ===================
791 NumAreas
792 ===================
793 */
NumAreas(void) const794 int idRenderWorldLocal::NumAreas( void ) const {
795 	return numPortalAreas;
796 }
797 
798 /*
799 ===================
800 NumPortalsInArea
801 ===================
802 */
NumPortalsInArea(int areaNum)803 int idRenderWorldLocal::NumPortalsInArea( int areaNum ) {
804 	portalArea_t	*area;
805 	int				count;
806 	portal_t		*portal;
807 
808 	if ( areaNum >= numPortalAreas || areaNum < 0 ) {
809 		common->Error( "idRenderWorld::NumPortalsInArea: bad areanum %i", areaNum );
810 	}
811 	area = &portalAreas[areaNum];
812 
813 	count = 0;
814 	for ( portal = area->portals ; portal ; portal = portal->next ) {
815 		count++;
816 	}
817 	return count;
818 }
819 
820 /*
821 ===================
822 GetPortal
823 ===================
824 */
GetPortal(int areaNum,int portalNum)825 exitPortal_t idRenderWorldLocal::GetPortal( int areaNum, int portalNum ) {
826 	portalArea_t	*area;
827 	int				count;
828 	portal_t		*portal;
829 	exitPortal_t	ret;
830 
831 	if ( areaNum > numPortalAreas ) {
832 		common->Error( "idRenderWorld::GetPortal: areaNum > numAreas" );
833 	}
834 	area = &portalAreas[areaNum];
835 
836 	count = 0;
837 	for ( portal = area->portals ; portal ; portal = portal->next ) {
838 		if ( count == portalNum ) {
839 			ret.areas[0] = areaNum;
840 			ret.areas[1] = portal->intoArea;
841 			ret.w = portal->w;
842 			ret.blockingBits = portal->doublePortal->blockingBits;
843 			ret.portalHandle = portal->doublePortal - doublePortals + 1;
844 			return ret;
845 		}
846 		count++;
847 	}
848 
849 	common->Error( "idRenderWorld::GetPortal: portalNum > numPortals" );
850 
851 	memset( &ret, 0, sizeof( ret ) );
852 	return ret;
853 }
854 
855 /*
856 ===============
857 PointInAreaNum
858 
859 Will return -1 if the point is not in an area, otherwise
860 it will return 0 <= value < tr.world->numPortalAreas
861 ===============
862 */
PointInArea(const idVec3 & point) const863 int idRenderWorldLocal::PointInArea( const idVec3 &point ) const {
864 	areaNode_t	*node;
865 	int			nodeNum;
866 	float		d;
867 
868 	node = areaNodes;
869 	if ( !node ) {
870 		return -1;
871 	}
872 	while( 1 ) {
873 		d = point * node->plane.Normal() + node->plane[3];
874 		if (d > 0) {
875 			nodeNum = node->children[0];
876 		} else {
877 			nodeNum = node->children[1];
878 		}
879 		if ( nodeNum == 0 ) {
880 			return -1;		// in solid
881 		}
882 		if ( nodeNum < 0 ) {
883 			nodeNum = -1 - nodeNum;
884 			if ( nodeNum >= numPortalAreas ) {
885 				common->Error( "idRenderWorld::PointInArea: area out of range" );
886 			}
887 			return nodeNum;
888 		}
889 		node = areaNodes + nodeNum;
890 	}
891 
892 	return -1;
893 }
894 
895 /*
896 ===================
897 BoundsInAreas_r
898 ===================
899 */
BoundsInAreas_r(int nodeNum,const idBounds & bounds,int * areas,int * numAreas,int maxAreas) const900 void idRenderWorldLocal::BoundsInAreas_r( int nodeNum, const idBounds &bounds, int *areas, int *numAreas, int maxAreas ) const {
901 	int side, i;
902 	areaNode_t *node;
903 
904 	do {
905 		if ( nodeNum < 0 ) {
906 			nodeNum = -1 - nodeNum;
907 
908 			for ( i = 0; i < (*numAreas); i++ ) {
909 				if ( areas[i] == nodeNum ) {
910 					break;
911 				}
912 			}
913 			if ( i >= (*numAreas) && (*numAreas) < maxAreas ) {
914 				areas[(*numAreas)++] = nodeNum;
915 			}
916 			return;
917 		}
918 
919 		node = areaNodes + nodeNum;
920 
921 		side = bounds.PlaneSide( node->plane );
922 		if ( side == PLANESIDE_FRONT ) {
923 			nodeNum = node->children[0];
924 		}
925 		else if ( side == PLANESIDE_BACK ) {
926 			nodeNum = node->children[1];
927 		}
928 		else {
929 			if ( node->children[1] != 0 ) {
930 				BoundsInAreas_r( node->children[1], bounds, areas, numAreas, maxAreas );
931 				if ( (*numAreas) >= maxAreas ) {
932 					return;
933 				}
934 			}
935 			nodeNum = node->children[0];
936 		}
937 	} while( nodeNum != 0 );
938 
939 	return;
940 }
941 
942 /*
943 ===================
944 BoundsInAreas
945 
946   fills the *areas array with the number of the areas the bounds are in
947   returns the total number of areas the bounds are in
948 ===================
949 */
BoundsInAreas(const idBounds & bounds,int * areas,int maxAreas) const950 int idRenderWorldLocal::BoundsInAreas( const idBounds &bounds, int *areas, int maxAreas ) const {
951 	int numAreas = 0;
952 
953 	assert( areas );
954 	assert( bounds[0][0] <= bounds[1][0] && bounds[0][1] <= bounds[1][1] && bounds[0][2] <= bounds[1][2] );
955 	assert( bounds[1][0] - bounds[0][0] < 1e4f && bounds[1][1] - bounds[0][1] < 1e4f && bounds[1][2] - bounds[0][2] < 1e4f );
956 
957 	if ( !areaNodes ) {
958 		return numAreas;
959 	}
960 	BoundsInAreas_r( 0, bounds, areas, &numAreas, maxAreas );
961 	return numAreas;
962 }
963 
964 /*
965 ================
966 GuiTrace
967 
968 checks a ray trace against any gui surfaces in an entity, returning the
969 fraction location of the trace on the gui surface, or -1,-1 if no hit.
970 this doesn't do any occlusion testing, simply ignoring non-gui surfaces.
971 start / end are in global world coordinates.
972 ================
973 */
GuiTrace(qhandle_t entityHandle,const idVec3 start,const idVec3 end) const974 guiPoint_t	idRenderWorldLocal::GuiTrace( qhandle_t entityHandle, const idVec3 start, const idVec3 end ) const {
975 	localTrace_t	local;
976 	idVec3			localStart, localEnd, bestPoint;
977 	int				j;
978 	idRenderModel	*model;
979 	srfTriangles_t	*tri;
980 	const idMaterial *shader;
981 	guiPoint_t	pt;
982 
983 	pt.x = pt.y = -1;
984 	pt.guiId = 0;
985 
986 	if ( ( entityHandle < 0 ) || ( entityHandle >= entityDefs.Num() ) ) {
987 		common->Printf( "idRenderWorld::GuiTrace: invalid handle %i\n", entityHandle );
988 		return pt;
989 	}
990 
991 	idRenderEntityLocal *def = entityDefs[entityHandle];
992 	if ( !def ) {
993 		common->Printf( "idRenderWorld::GuiTrace: handle %i is NULL\n", entityHandle );
994 		return pt;
995 	}
996 
997 	model = def->parms.hModel;
998 	if ( def->parms.callback || !def->parms.hModel || def->parms.hModel->IsDynamicModel() != DM_STATIC ) {
999 		return pt;
1000 	}
1001 
1002 	// transform the points into local space
1003 	R_GlobalPointToLocal( def->modelMatrix, start, localStart );
1004 	R_GlobalPointToLocal( def->modelMatrix, end, localEnd );
1005 
1006 	for ( j = 0 ; j < model->NumSurfaces() ; j++ ) {
1007 		const modelSurface_t *surf = model->Surface( j );
1008 
1009 		tri = surf->geometry;
1010 		if ( !tri ) {
1011 			continue;
1012 		}
1013 
1014 		shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
1015 		if ( !shader ) {
1016 			continue;
1017 		}
1018 		// only trace against gui surfaces
1019 		if (!shader->HasGui()) {
1020 			continue;
1021 		}
1022 
1023 		local = R_LocalTrace( localStart, localEnd, 0.0f, tri );
1024 		if ( local.fraction < 1.0 ) {
1025 			idVec3				origin, axis[3];
1026 			idVec3				cursor;
1027 			float				axisLen[2];
1028 
1029 			R_SurfaceToTextureAxis( tri, origin, axis );
1030 			cursor = local.point - origin;
1031 
1032 			axisLen[0] = axis[0].Length();
1033 			axisLen[1] = axis[1].Length();
1034 
1035 			pt.x = ( cursor * axis[0] ) / ( axisLen[0] * axisLen[0] );
1036 			pt.y = ( cursor * axis[1] ) / ( axisLen[1] * axisLen[1] );
1037 			pt.guiId = shader->GetEntityGui();
1038 
1039 			return pt;
1040 		}
1041 	}
1042 
1043 	return pt;
1044 }
1045 
1046 /*
1047 ===================
1048 idRenderWorldLocal::ModelTrace
1049 ===================
1050 */
ModelTrace(modelTrace_t & trace,qhandle_t entityHandle,const idVec3 & start,const idVec3 & end,const float radius) const1051 bool idRenderWorldLocal::ModelTrace( modelTrace_t &trace, qhandle_t entityHandle, const idVec3 &start, const idVec3 &end, const float radius ) const {
1052 	int i;
1053 	bool collisionSurface;
1054 	const modelSurface_t *surf;
1055 	localTrace_t localTrace;
1056 	idRenderModel *model;
1057 	float modelMatrix[16];
1058 	idVec3 localStart, localEnd;
1059 	const idMaterial *shader;
1060 
1061 	trace.fraction = 1.0f;
1062 
1063 	if ( entityHandle < 0 || entityHandle >= entityDefs.Num() ) {
1064 //		common->Error( "idRenderWorld::ModelTrace: index = %i", entityHandle );
1065 		return false;
1066 	}
1067 
1068 	idRenderEntityLocal	*def = entityDefs[entityHandle];
1069 	if ( !def ) {
1070 		return false;
1071 	}
1072 
1073 	renderEntity_t *refEnt = &def->parms;
1074 
1075 	model = R_EntityDefDynamicModel( def );
1076 	if ( !model ) {
1077 		return false;
1078 	}
1079 
1080 	// transform the points into local space
1081 	R_AxisToModelMatrix( refEnt->axis, refEnt->origin, modelMatrix );
1082 	R_GlobalPointToLocal( modelMatrix, start, localStart );
1083 	R_GlobalPointToLocal( modelMatrix, end, localEnd );
1084 
1085 	// if we have explicit collision surfaces, only collide against them
1086 	// (FIXME, should probably have a parm to control this)
1087 	collisionSurface = false;
1088 	for ( i = 0; i < model->NumBaseSurfaces(); i++ ) {
1089 		surf = model->Surface( i );
1090 
1091 		shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
1092 
1093 		if ( shader->GetSurfaceFlags() & SURF_COLLISION ) {
1094 			collisionSurface = true;
1095 			break;
1096 		}
1097 	}
1098 
1099 	// only use baseSurfaces, not any overlays
1100 	for ( i = 0; i < model->NumBaseSurfaces(); i++ ) {
1101 		surf = model->Surface( i );
1102 
1103 		shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
1104 
1105 		if ( !surf->geometry || !shader ) {
1106 			continue;
1107 		}
1108 
1109 		if ( collisionSurface ) {
1110 			// only trace vs collision surfaces
1111 			if ( !( shader->GetSurfaceFlags() & SURF_COLLISION ) ) {
1112 				continue;
1113 			}
1114 		} else {
1115 			// skip if not drawn or translucent
1116 			if ( !shader->IsDrawn() || ( shader->Coverage() != MC_OPAQUE && shader->Coverage() != MC_PERFORATED ) ) {
1117 				continue;
1118 			}
1119 		}
1120 
1121 		localTrace = R_LocalTrace( localStart, localEnd, radius, surf->geometry );
1122 
1123 		if ( localTrace.fraction < trace.fraction ) {
1124 			trace.fraction = localTrace.fraction;
1125 			R_LocalPointToGlobal( modelMatrix, localTrace.point, trace.point );
1126 			trace.normal = localTrace.normal * refEnt->axis;
1127 			trace.material = shader;
1128 			trace.entity = &def->parms;
1129 			trace.jointNumber = refEnt->hModel->NearestJoint( i, localTrace.indexes[0], localTrace.indexes[1], localTrace.indexes[2] );
1130 		}
1131 	}
1132 
1133 	return ( trace.fraction < 1.0f );
1134 }
1135 
1136 /*
1137 ===================
1138 idRenderWorldLocal::Trace
1139 ===================
1140 */
1141 // FIXME: _D3XP added those.
1142 const char* playerModelExcludeList[] = {
1143 	"models/md5/characters/player/d3xp_spplayer.md5mesh",
1144 	"models/md5/characters/player/head/d3xp_head.md5mesh",
1145 	"models/md5/weapons/pistol_world/worldpistol.md5mesh",
1146 	NULL
1147 };
1148 
1149 const char* playerMaterialExcludeList[] = {
1150 	"muzzlesmokepuff",
1151 	NULL
1152 };
1153 
Trace(modelTrace_t & trace,const idVec3 & start,const idVec3 & end,const float radius,bool skipDynamic,bool skipPlayer) const1154 bool idRenderWorldLocal::Trace( modelTrace_t &trace, const idVec3 &start, const idVec3 &end, const float radius, bool skipDynamic, bool skipPlayer /*_D3XP*/ ) const {
1155 	areaReference_t * ref;
1156 	idRenderEntityLocal *def;
1157 	portalArea_t * area;
1158 	idRenderModel * model;
1159 	srfTriangles_t * tri;
1160 	localTrace_t localTrace;
1161 	int areas[128], numAreas, i, j, numSurfaces;
1162 	idBounds traceBounds, bounds;
1163 	float modelMatrix[16];
1164 	idVec3 localStart, localEnd;
1165 	const idMaterial *shader;
1166 
1167 	trace.fraction = 1.0f;
1168 	trace.point = end;
1169 
1170 	// bounds for the whole trace
1171 	traceBounds.Clear();
1172 	traceBounds.AddPoint( start );
1173 	traceBounds.AddPoint( end );
1174 
1175 	// get the world areas the trace is in
1176 	numAreas = BoundsInAreas( traceBounds, areas, 128 );
1177 
1178 	numSurfaces = 0;
1179 
1180 	// check all areas for models
1181 	for ( i = 0; i < numAreas; i++ ) {
1182 
1183 		area = &portalAreas[ areas[i] ];
1184 
1185 		// check all models in this area
1186 		for ( ref = area->entityRefs.areaNext; ref != &area->entityRefs; ref = ref->areaNext ) {
1187 			def = ref->entity;
1188 
1189 			model = def->parms.hModel;
1190 			if ( !model ) {
1191 				continue;
1192 			}
1193 
1194 			if ( model->IsDynamicModel() != DM_STATIC ) {
1195 				if ( skipDynamic ) {
1196 					continue;
1197 				}
1198 
1199 #if 1	/* _D3XP addition. could use a cleaner approach */
1200 				if ( skipPlayer ) {
1201 					idStr name = model->Name();
1202 					const char *exclude;
1203 					int k;
1204 
1205 					for ( k = 0; playerModelExcludeList[k]; k++ ) {
1206 						exclude = playerModelExcludeList[k];
1207 						if ( name == exclude ) {
1208 							break;
1209 						}
1210 					}
1211 
1212 					if ( playerModelExcludeList[k] ) {
1213 						continue;
1214 					}
1215 				}
1216 #endif
1217 
1218 				model = R_EntityDefDynamicModel( def );
1219 				if ( !model ) {
1220 					continue;	// can happen with particle systems, which don't instantiate without a valid view
1221 				}
1222 			}
1223 
1224 			bounds.FromTransformedBounds( model->Bounds( &def->parms ), def->parms.origin, def->parms.axis );
1225 
1226 			// if the model bounds do not overlap with the trace bounds
1227 			if ( !traceBounds.IntersectsBounds( bounds ) || !bounds.LineIntersection( start, trace.point ) ) {
1228 				continue;
1229 			}
1230 
1231 			// check all model surfaces
1232 			for ( j = 0; j < model->NumSurfaces(); j++ ) {
1233 				const modelSurface_t *surf = model->Surface( j );
1234 
1235 				shader = R_RemapShaderBySkin( surf->shader, def->parms.customSkin, def->parms.customShader );
1236 
1237 				// if no geometry or no shader
1238 				if ( !surf->geometry || !shader ) {
1239 					continue;
1240 				}
1241 
1242 #if 1 /* _D3XP addition. could use a cleaner approach */
1243 				if ( skipPlayer ) {
1244 					idStr name = shader->GetName();
1245 					const char *exclude;
1246 					int k;
1247 
1248 					for ( k = 0; playerMaterialExcludeList[k]; k++ ) {
1249 						exclude = playerMaterialExcludeList[k];
1250 						if ( name == exclude ) {
1251 							break;
1252 						}
1253 					}
1254 
1255 					if ( playerMaterialExcludeList[k] ) {
1256 						continue;
1257 					}
1258 				}
1259 #endif
1260 
1261 				tri = surf->geometry;
1262 
1263 				bounds.FromTransformedBounds( tri->bounds, def->parms.origin, def->parms.axis );
1264 
1265 				// if triangle bounds do not overlap with the trace bounds
1266 				if ( !traceBounds.IntersectsBounds( bounds ) || !bounds.LineIntersection( start, trace.point ) ) {
1267 					continue;
1268 				}
1269 
1270 				numSurfaces++;
1271 
1272 				// transform the points into local space
1273 				R_AxisToModelMatrix( def->parms.axis, def->parms.origin, modelMatrix );
1274 				R_GlobalPointToLocal( modelMatrix, start, localStart );
1275 				R_GlobalPointToLocal( modelMatrix, end, localEnd );
1276 
1277 				localTrace = R_LocalTrace( localStart, localEnd, radius, surf->geometry );
1278 
1279 				if ( localTrace.fraction < trace.fraction ) {
1280 					trace.fraction = localTrace.fraction;
1281 					R_LocalPointToGlobal( modelMatrix, localTrace.point, trace.point );
1282 					trace.normal = localTrace.normal * def->parms.axis;
1283 					trace.material = shader;
1284 					trace.entity = &def->parms;
1285 					trace.jointNumber = model->NearestJoint( j, localTrace.indexes[0], localTrace.indexes[1], localTrace.indexes[2] );
1286 
1287 					traceBounds.Clear();
1288 					traceBounds.AddPoint( start );
1289 					traceBounds.AddPoint( start + trace.fraction * (end - start) );
1290 				}
1291 			}
1292 		}
1293 	}
1294 	return ( trace.fraction < 1.0f );
1295 }
1296 
1297 /*
1298 ==================
1299 idRenderWorldLocal::RecurseProcBSP
1300 ==================
1301 */
RecurseProcBSP_r(modelTrace_t * results,int parentNodeNum,int nodeNum,float p1f,float p2f,const idVec3 & p1,const idVec3 & p2) const1302 void idRenderWorldLocal::RecurseProcBSP_r( modelTrace_t *results, int parentNodeNum, int nodeNum, float p1f, float p2f, const idVec3 &p1, const idVec3 &p2 ) const {
1303 	float		t1, t2;
1304 	float		frac;
1305 	idVec3		mid;
1306 	int			side;
1307 	float		midf;
1308 	areaNode_t *node;
1309 
1310 	if ( results->fraction <= p1f) {
1311 		return;		// already hit something nearer
1312 	}
1313 	// empty leaf
1314 	if ( nodeNum < 0 ) {
1315 		return;
1316 	}
1317 	// if solid leaf node
1318 	if ( nodeNum == 0 ) {
1319 		if ( parentNodeNum != -1 ) {
1320 
1321 			results->fraction = p1f;
1322 			results->point = p1;
1323 			node = &areaNodes[parentNodeNum];
1324 			results->normal = node->plane.Normal();
1325 			return;
1326 		}
1327 	}
1328 	node = &areaNodes[nodeNum];
1329 
1330 	// distance from plane for trace start and end
1331 	t1 = node->plane.Normal() * p1 + node->plane[3];
1332 	t2 = node->plane.Normal() * p2 + node->plane[3];
1333 
1334 	if ( t1 >= 0.0f && t2 >= 0.0f ) {
1335 		RecurseProcBSP_r( results, nodeNum, node->children[0], p1f, p2f, p1, p2 );
1336 		return;
1337 	}
1338 	if ( t1 < 0.0f && t2 < 0.0f ) {
1339 		RecurseProcBSP_r( results, nodeNum, node->children[1], p1f, p2f, p1, p2 );
1340 		return;
1341 	}
1342 	side = t1 < t2;
1343 	frac = t1 / (t1 - t2);
1344 	midf = p1f + frac*(p2f - p1f);
1345 	mid[0] = p1[0] + frac*(p2[0] - p1[0]);
1346 	mid[1] = p1[1] + frac*(p2[1] - p1[1]);
1347 	mid[2] = p1[2] + frac*(p2[2] - p1[2]);
1348 	RecurseProcBSP_r( results, nodeNum, node->children[side], p1f, midf, p1, mid );
1349 	RecurseProcBSP_r( results, nodeNum, node->children[side^1], midf, p2f, mid, p2 );
1350 }
1351 
1352 /*
1353 ==================
1354 idRenderWorldLocal::FastWorldTrace
1355 ==================
1356 */
FastWorldTrace(modelTrace_t & results,const idVec3 & start,const idVec3 & end) const1357 bool idRenderWorldLocal::FastWorldTrace( modelTrace_t &results, const idVec3 &start, const idVec3 &end ) const {
1358 	memset( &results, 0, sizeof( modelTrace_t ) );
1359 	results.fraction = 1.0f;
1360 	if ( areaNodes != NULL ) {
1361 		RecurseProcBSP_r( &results, -1, 0, 0.0f, 1.0f, start, end );
1362 		return ( results.fraction < 1.0f );
1363 	}
1364 	return false;
1365 }
1366 
1367 /*
1368 =================================================================================
1369 
1370 CREATE MODEL REFS
1371 
1372 =================================================================================
1373 */
1374 
1375 /*
1376 =================
1377 AddEntityRefToArea
1378 
1379 This is called by R_PushVolumeIntoTree and also directly
1380 for the world model references that are precalculated.
1381 =================
1382 */
AddEntityRefToArea(idRenderEntityLocal * def,portalArea_t * area)1383 void idRenderWorldLocal::AddEntityRefToArea( idRenderEntityLocal *def, portalArea_t *area ) {
1384 	areaReference_t	*ref;
1385 
1386 	if ( !def ) {
1387 		common->Error( "idRenderWorldLocal::AddEntityRefToArea: NULL def" );
1388 	}
1389 
1390 	ref = areaReferenceAllocator.Alloc();
1391 
1392 	tr.pc.c_entityReferences++;
1393 
1394 	ref->entity = def;
1395 
1396 	// link to entityDef
1397 	ref->ownerNext = def->entityRefs;
1398 	def->entityRefs = ref;
1399 
1400 	// link to end of area list
1401 	ref->area = area;
1402 	ref->areaNext = &area->entityRefs;
1403 	ref->areaPrev = area->entityRefs.areaPrev;
1404 	ref->areaNext->areaPrev = ref;
1405 	ref->areaPrev->areaNext = ref;
1406 }
1407 
1408 /*
1409 ===================
1410 AddLightRefToArea
1411 
1412 ===================
1413 */
AddLightRefToArea(idRenderLightLocal * light,portalArea_t * area)1414 void idRenderWorldLocal::AddLightRefToArea( idRenderLightLocal *light, portalArea_t *area ) {
1415 	areaReference_t	*lref;
1416 
1417 	// add a lightref to this area
1418 	lref = areaReferenceAllocator.Alloc();
1419 	lref->light = light;
1420 	lref->area = area;
1421 	lref->ownerNext = light->references;
1422 	light->references = lref;
1423 	tr.pc.c_lightReferences++;
1424 
1425 	// doubly linked list so we can free them easily later
1426 	area->lightRefs.areaNext->areaPrev = lref;
1427 	lref->areaNext = area->lightRefs.areaNext;
1428 	lref->areaPrev = &area->lightRefs;
1429 	area->lightRefs.areaNext = lref;
1430 }
1431 
1432 /*
1433 ===================
1434 GenerateAllInteractions
1435 
1436 Force the generation of all light / surface interactions at the start of a level
1437 If this isn't called, they will all be dynamically generated
1438 
1439 This really isn't all that helpful anymore, because the calculation of shadows
1440 and light interactions is deferred from idRenderWorldLocal::CreateLightDefInteractions(), but we
1441 use it as an oportunity to size the interactionTable
1442 ===================
1443 */
GenerateAllInteractions()1444 void idRenderWorldLocal::GenerateAllInteractions() {
1445 	if ( !glConfig.isInitialized ) {
1446 		return;
1447 	}
1448 
1449 	int start = Sys_Milliseconds();
1450 
1451 	generateAllInteractionsCalled = false;
1452 
1453 	// watch how much memory we allocate
1454 	tr.staticAllocCount = 0;
1455 
1456 	// let idRenderWorldLocal::CreateLightDefInteractions() know that it shouldn't
1457 	// try and do any view specific optimizations
1458 	tr.viewDef = NULL;
1459 
1460 	for ( int i = 0 ; i < this->lightDefs.Num() ; i++ ) {
1461 		idRenderLightLocal	*ldef = this->lightDefs[i];
1462 		if ( !ldef ) {
1463 			continue;
1464 		}
1465 		this->CreateLightDefInteractions( ldef );
1466 	}
1467 
1468 	int end = Sys_Milliseconds();
1469 	int	msec = end - start;
1470 
1471 	common->Printf( "idRenderWorld::GenerateAllInteractions, msec = %i, staticAllocCount = %i.\n", msec, tr.staticAllocCount );
1472 
1473 
1474 	// build the interaction table
1475 	if ( r_useInteractionTable.GetBool() ) {
1476 		interactionTableWidth = entityDefs.Num() + 100;
1477 		interactionTableHeight = lightDefs.Num() + 100;
1478 		int	size =  interactionTableWidth * interactionTableHeight * sizeof( *interactionTable );
1479 		interactionTable = (idInteraction **)R_ClearedStaticAlloc( size );
1480 
1481 		int	count = 0;
1482 		for ( int i = 0 ; i < this->lightDefs.Num() ; i++ ) {
1483 			idRenderLightLocal	*ldef = this->lightDefs[i];
1484 			if ( !ldef ) {
1485 				continue;
1486 			}
1487 			idInteraction	*inter;
1488 			for ( inter = ldef->firstInteraction; inter != NULL; inter = inter->lightNext ) {
1489 				idRenderEntityLocal	*edef = inter->entityDef;
1490 				int index = ldef->index * interactionTableWidth + edef->index;
1491 
1492 				interactionTable[ index ] = inter;
1493 				count++;
1494 			}
1495 		}
1496 
1497 		common->Printf( "interactionTable size: %i bytes\n", size );
1498 		common->Printf( "%d interaction take %zd bytes\n", count, count * sizeof( idInteraction ) );
1499 	}
1500 
1501 	// entities flagged as noDynamicInteractions will no longer make any
1502 	generateAllInteractionsCalled = true;
1503 }
1504 
1505 /*
1506 ===================
1507 idRenderWorldLocal::FreeInteractions
1508 ===================
1509 */
FreeInteractions()1510 void idRenderWorldLocal::FreeInteractions() {
1511 	int			i;
1512 	idRenderEntityLocal	*def;
1513 
1514 	for ( i = 0 ; i < entityDefs.Num(); i++ ) {
1515 		def = entityDefs[i];
1516 		if ( !def ) {
1517 			continue;
1518 		}
1519 		// free all the interactions
1520 		while ( def->firstInteraction != NULL ) {
1521 			def->firstInteraction->UnlinkAndFree();
1522 		}
1523 	}
1524 }
1525 
1526 /*
1527 ==================
1528 PushVolumeIntoTree
1529 
1530 Used for both light volumes and model volumes.
1531 
1532 This does not clip the points by the planes, so some slop
1533 occurs.
1534 
1535 tr.viewCount should be bumped before calling, allowing it
1536 to prevent double checking areas.
1537 
1538 We might alternatively choose to do this with an area flow.
1539 ==================
1540 */
PushVolumeIntoTree_r(idRenderEntityLocal * def,idRenderLightLocal * light,const idSphere * sphere,int numPoints,const idVec3 (* points),int nodeNum)1541 void idRenderWorldLocal::PushVolumeIntoTree_r( idRenderEntityLocal *def, idRenderLightLocal *light, const idSphere *sphere, int numPoints, const idVec3 (*points),
1542 								 int nodeNum ) {
1543 	int			i;
1544 	areaNode_t	*node;
1545 	bool	front, back;
1546 
1547 	if ( nodeNum < 0 ) {
1548 		portalArea_t	*area;
1549 		int		areaNum = -1 - nodeNum;
1550 
1551 		area = &portalAreas[ areaNum ];
1552 		if ( area->viewCount == tr.viewCount ) {
1553 			return;	// already added a reference here
1554 		}
1555 		area->viewCount = tr.viewCount;
1556 
1557 		if ( def ) {
1558 			AddEntityRefToArea( def, area );
1559 		}
1560 		if ( light ) {
1561 			AddLightRefToArea( light, area );
1562 		}
1563 
1564 		return;
1565 	}
1566 
1567 	node = areaNodes + nodeNum;
1568 
1569 	// if we know that all possible children nodes only touch an area
1570 	// we have already marked, we can early out
1571 	if ( r_useNodeCommonChildren.GetBool() &&
1572 		node->commonChildrenArea != CHILDREN_HAVE_MULTIPLE_AREAS ) {
1573 		// note that we do NOT try to set a reference in this area
1574 		// yet, because the test volume may yet wind up being in the
1575 		// solid part, which would cause bounds slightly poked into
1576 		// a wall to show up in the next room
1577 		if ( portalAreas[ node->commonChildrenArea ].viewCount == tr.viewCount ) {
1578 			return;
1579 		}
1580 	}
1581 
1582 	// if the bounding sphere is completely on one side, don't
1583 	// bother checking the individual points
1584 	float sd = node->plane.Distance( sphere->GetOrigin() );
1585 	if ( sd >= sphere->GetRadius() ) {
1586 		nodeNum = node->children[0];
1587 		if ( nodeNum ) {	// 0 = solid
1588 			PushVolumeIntoTree_r( def, light, sphere, numPoints, points, nodeNum );
1589 		}
1590 		return;
1591 	}
1592 	if ( sd <= -sphere->GetRadius() ) {
1593 		nodeNum = node->children[1];
1594 		if ( nodeNum ) {	// 0 = solid
1595 			PushVolumeIntoTree_r( def, light, sphere, numPoints, points, nodeNum );
1596 		}
1597 		return;
1598 	}
1599 
1600 	// exact check all the points against the node plane
1601 	front = back = false;
1602 #ifdef MACOS_X	//loop unrolling & pre-fetching for performance
1603 	const idVec3 norm = node->plane.Normal();
1604 	const float plane3 = node->plane[3];
1605 	float D0, D1, D2, D3;
1606 
1607 	for ( i = 0 ; i < numPoints - 4; i+=4 ) {
1608 		D0 = points[i+0] * norm + plane3;
1609 		D1 = points[i+1] * norm + plane3;
1610 		if ( !front && D0 >= 0.0f ) {
1611 			front = true;
1612 		} else if ( !back && D0 <= 0.0f ) {
1613 			back = true;
1614 		}
1615 		D2 = points[i+1] * norm + plane3;
1616 		if ( !front && D1 >= 0.0f ) {
1617 			front = true;
1618 		} else if ( !back && D1 <= 0.0f ) {
1619 			back = true;
1620 		}
1621 		D3 = points[i+1] * norm + plane3;
1622 		if ( !front && D2 >= 0.0f ) {
1623 			front = true;
1624 		} else if ( !back && D2 <= 0.0f ) {
1625 			back = true;
1626 		}
1627 
1628 		if ( !front && D3 >= 0.0f ) {
1629 			front = true;
1630 		} else if ( !back && D3 <= 0.0f ) {
1631 			back = true;
1632 		}
1633 		if ( back && front ) {
1634 			break;
1635 		}
1636 	}
1637 	if(!(back && front)) {
1638 		for (; i < numPoints ; i++ ) {
1639 			float d;
1640 			d = points[i] * node->plane.Normal() + node->plane[3];
1641 			if ( d >= 0.0f ) {
1642 				front = true;
1643 			} else if ( d <= 0.0f ) {
1644 				back = true;
1645 			}
1646 			if ( back && front ) {
1647 				break;
1648 			}
1649 		}
1650 	}
1651 #else
1652 	for ( i = 0 ; i < numPoints ; i++ ) {
1653 		float d;
1654 
1655 		d = points[i] * node->plane.Normal() + node->plane[3];
1656 		if ( d >= 0.0f ) {
1657 			front = true;
1658 		} else if ( d <= 0.0f ) {
1659 			back = true;
1660 		}
1661 		if ( back && front ) {
1662 			break;
1663 		}
1664 	}
1665 #endif
1666 	if ( front ) {
1667 		nodeNum = node->children[0];
1668 		if ( nodeNum ) {	// 0 = solid
1669 			PushVolumeIntoTree_r( def, light, sphere, numPoints, points, nodeNum );
1670 		}
1671 	}
1672 	if ( back ) {
1673 		nodeNum = node->children[1];
1674 		if ( nodeNum ) {	// 0 = solid
1675 			PushVolumeIntoTree_r( def, light, sphere, numPoints, points, nodeNum );
1676 		}
1677 	}
1678 }
1679 
1680 /*
1681 ==============
1682 PushVolumeIntoTree
1683 ==============
1684 */
PushVolumeIntoTree(idRenderEntityLocal * def,idRenderLightLocal * light,int numPoints,const idVec3 (* points))1685 void idRenderWorldLocal::PushVolumeIntoTree( idRenderEntityLocal *def, idRenderLightLocal *light, int numPoints, const idVec3 (*points) ) {
1686 	int i;
1687 	float radSquared, lr;
1688 	idVec3 mid, dir;
1689 
1690 	if ( areaNodes == NULL ) {
1691 		return;
1692 	}
1693 
1694 	// calculate a bounding sphere for the points
1695 	mid.Zero();
1696 	for ( i = 0; i < numPoints; i++ ) {
1697 		mid += points[i];
1698 	}
1699 	mid *= ( 1.0f / numPoints );
1700 
1701 	radSquared = 0;
1702 
1703 	for ( i = 0; i < numPoints; i++ ) {
1704 		dir = points[i] - mid;
1705 		lr = dir * dir;
1706 		if ( lr > radSquared ) {
1707 			radSquared = lr;
1708 		}
1709 	}
1710 
1711 	idSphere sphere( mid, sqrt( radSquared ) );
1712 
1713 	PushVolumeIntoTree_r( def, light, &sphere, numPoints, points, 0 );
1714 }
1715 
1716 //===================================================================
1717 
1718 /*
1719 ====================
1720 idRenderWorldLocal::DebugClearLines
1721 ====================
1722 */
DebugClearLines(int time)1723 void idRenderWorldLocal::DebugClearLines( int time ) {
1724 	RB_ClearDebugLines( time );
1725 	RB_ClearDebugText( time );
1726 }
1727 
1728 /*
1729 ====================
1730 idRenderWorldLocal::DebugLine
1731 ====================
1732 */
DebugLine(const idVec4 & color,const idVec3 & start,const idVec3 & end,const int lifetime,const bool depthTest)1733 void idRenderWorldLocal::DebugLine( const idVec4 &color, const idVec3 &start, const idVec3 &end, const int lifetime, const bool depthTest ) {
1734 	RB_AddDebugLine( color, start, end, lifetime, depthTest );
1735 }
1736 
1737 /*
1738 ================
1739 idRenderWorldLocal::DebugArrow
1740 ================
1741 */
DebugArrow(const idVec4 & color,const idVec3 & start,const idVec3 & end,int size,const int lifetime)1742 void idRenderWorldLocal::DebugArrow( const idVec4 &color, const idVec3 &start, const idVec3 &end, int size, const int lifetime ) {
1743 	idVec3 forward, right, up, v1, v2;
1744 	float a, s;
1745 	int i;
1746 	static float arrowCos[40];
1747 	static float arrowSin[40];
1748 	static int arrowStep;
1749 
1750 	DebugLine( color, start, end, lifetime );
1751 
1752 	if ( r_debugArrowStep.GetInteger() <= 10 ) {
1753 		return;
1754 	}
1755 	// calculate sine and cosine when step size changes
1756 	if ( arrowStep != r_debugArrowStep.GetInteger() ) {
1757 		arrowStep = r_debugArrowStep.GetInteger();
1758 		for (i = 0, a = 0; a < 360.0f; a += arrowStep, i++) {
1759 			arrowCos[i] = idMath::Cos16( DEG2RAD( a ) );
1760 			arrowSin[i] = idMath::Sin16( DEG2RAD( a ) );
1761 		}
1762 		arrowCos[i] = arrowCos[0];
1763 		arrowSin[i] = arrowSin[0];
1764 	}
1765 	// draw a nice arrow
1766 	forward = end - start;
1767 	forward.Normalize();
1768 	forward.NormalVectors( right, up);
1769 	for (i = 0, a = 0; a < 360.0f; a += arrowStep, i++) {
1770 		s = 0.5f * size * arrowCos[i];
1771 		v1 = end - size * forward;
1772 		v1 = v1 + s * right;
1773 		s = 0.5f * size * arrowSin[i];
1774 		v1 = v1 + s * up;
1775 
1776 		s = 0.5f * size * arrowCos[i+1];
1777 		v2 = end - size * forward;
1778 		v2 = v2 + s * right;
1779 		s = 0.5f * size * arrowSin[i+1];
1780 		v2 = v2 + s * up;
1781 
1782 		DebugLine( color, v1, end, lifetime );
1783 		DebugLine( color, v1, v2, lifetime );
1784 	}
1785 }
1786 
1787 /*
1788 ====================
1789 idRenderWorldLocal::DebugWinding
1790 ====================
1791 */
DebugWinding(const idVec4 & color,const idWinding & w,const idVec3 & origin,const idMat3 & axis,const int lifetime,const bool depthTest)1792 void idRenderWorldLocal::DebugWinding( const idVec4 &color, const idWinding &w, const idVec3 &origin, const idMat3 &axis, const int lifetime, const bool depthTest ) {
1793 	int i;
1794 	idVec3 point, lastPoint;
1795 
1796 	if ( w.GetNumPoints() < 2 ) {
1797 		return;
1798 	}
1799 
1800 	lastPoint = origin + w[w.GetNumPoints()-1].ToVec3() * axis;
1801 	for ( i = 0; i < w.GetNumPoints(); i++ ) {
1802 		point = origin + w[i].ToVec3() * axis;
1803 		DebugLine( color, lastPoint, point, lifetime, depthTest );
1804 		lastPoint = point;
1805 	}
1806 }
1807 
1808 /*
1809 ====================
1810 idRenderWorldLocal::DebugCircle
1811 ====================
1812 */
DebugCircle(const idVec4 & color,const idVec3 & origin,const idVec3 & dir,const float radius,const int numSteps,const int lifetime,const bool depthTest)1813 void idRenderWorldLocal::DebugCircle( const idVec4 &color, const idVec3 &origin, const idVec3 &dir, const float radius, const int numSteps, const int lifetime, const bool depthTest ) {
1814 	int i;
1815 	float a;
1816 	idVec3 left, up, point, lastPoint;
1817 
1818 	dir.OrthogonalBasis( left, up );
1819 	left *= radius;
1820 	up *= radius;
1821 	lastPoint = origin + up;
1822 	for ( i = 1; i <= numSteps; i++ ) {
1823 		a = idMath::TWO_PI * i / numSteps;
1824 		point = origin + idMath::Sin16( a ) * left + idMath::Cos16( a ) * up;
1825 		DebugLine( color, lastPoint, point, lifetime, depthTest );
1826 		lastPoint = point;
1827 	}
1828 }
1829 
1830 /*
1831 ============
1832 idRenderWorldLocal::DebugSphere
1833 ============
1834 */
DebugSphere(const idVec4 & color,const idSphere & sphere,const int lifetime,const bool depthTest)1835 void idRenderWorldLocal::DebugSphere( const idVec4 &color, const idSphere &sphere, const int lifetime, const bool depthTest /*_D3XP*/ ) {
1836 	int i, j, n, num;
1837 	float s, c;
1838 	idVec3 p, lastp, *lastArray;
1839 
1840 	num = 360 / 15;
1841 	lastArray = (idVec3 *) _alloca16( num * sizeof( idVec3 ) );
1842 	lastArray[0] = sphere.GetOrigin() + idVec3( 0, 0, sphere.GetRadius() );
1843 	for ( n = 1; n < num; n++ ) {
1844 		lastArray[n] = lastArray[0];
1845 	}
1846 
1847 	for ( i = 15; i <= 360; i += 15 ) {
1848 		s = idMath::Sin16( DEG2RAD(i) );
1849 		c = idMath::Cos16( DEG2RAD(i) );
1850 		lastp[0] = sphere.GetOrigin()[0];
1851 		lastp[1] = sphere.GetOrigin()[1] + sphere.GetRadius() * s;
1852 		lastp[2] = sphere.GetOrigin()[2] + sphere.GetRadius() * c;
1853 		for ( n = 0, j = 15; j <= 360; j += 15, n++ ) {
1854 			p[0] = sphere.GetOrigin()[0] + idMath::Sin16( DEG2RAD(j) ) * sphere.GetRadius() * s;
1855 			p[1] = sphere.GetOrigin()[1] + idMath::Cos16( DEG2RAD(j) ) * sphere.GetRadius() * s;
1856 			p[2] = lastp[2];
1857 
1858 			DebugLine( color, lastp, p, lifetime,depthTest );
1859 			DebugLine( color, lastp, lastArray[n], lifetime, depthTest );
1860 
1861 			lastArray[n] = lastp;
1862 			lastp = p;
1863 		}
1864 	}
1865 }
1866 
1867 /*
1868 ====================
1869 idRenderWorldLocal::DebugBounds
1870 ====================
1871 */
DebugBounds(const idVec4 & color,const idBounds & bounds,const idVec3 & org,const int lifetime)1872 void idRenderWorldLocal::DebugBounds( const idVec4 &color, const idBounds &bounds, const idVec3 &org, const int lifetime ) {
1873 	int i;
1874 	idVec3 v[8];
1875 
1876 	if ( bounds.IsCleared() ) {
1877 		return;
1878 	}
1879 
1880 	for ( i = 0; i < 8; i++ ) {
1881 		v[i][0] = org[0] + bounds[(i^(i>>1))&1][0];
1882 		v[i][1] = org[1] + bounds[(i>>1)&1][1];
1883 		v[i][2] = org[2] + bounds[(i>>2)&1][2];
1884 	}
1885 	for ( i = 0; i < 4; i++ ) {
1886 		DebugLine( color, v[i], v[(i+1)&3], lifetime );
1887 		DebugLine( color, v[4+i], v[4+((i+1)&3)], lifetime );
1888 		DebugLine( color, v[i], v[4+i], lifetime );
1889 	}
1890 }
1891 
1892 /*
1893 ====================
1894 idRenderWorldLocal::DebugBox
1895 ====================
1896 */
DebugBox(const idVec4 & color,const idBox & box,const int lifetime)1897 void idRenderWorldLocal::DebugBox( const idVec4 &color, const idBox &box, const int lifetime ) {
1898 	int i;
1899 	idVec3 v[8];
1900 
1901 	box.ToPoints( v );
1902 	for ( i = 0; i < 4; i++ ) {
1903 		DebugLine( color, v[i], v[(i+1)&3], lifetime );
1904 		DebugLine( color, v[4+i], v[4+((i+1)&3)], lifetime );
1905 		DebugLine( color, v[i], v[4+i], lifetime );
1906 	}
1907 }
1908 
1909 /*
1910 ================
1911 idRenderWorldLocal::DebugFrustum
1912 ================
1913 */
DebugFrustum(const idVec4 & color,const idFrustum & frustum,const bool showFromOrigin,const int lifetime)1914 void idRenderWorldLocal::DebugFrustum( const idVec4 &color, const idFrustum &frustum, const bool showFromOrigin, const int lifetime ) {
1915 	int i;
1916 	idVec3 v[8];
1917 
1918 	frustum.ToPoints( v );
1919 
1920 	if ( frustum.GetNearDistance() > 0.0f ) {
1921 		for ( i = 0; i < 4; i++ ) {
1922 			DebugLine( color, v[i], v[(i+1)&3], lifetime );
1923 		}
1924 		if ( showFromOrigin ) {
1925 			for ( i = 0; i < 4; i++ ) {
1926 				DebugLine( color, frustum.GetOrigin(), v[i], lifetime );
1927 			}
1928 		}
1929 	}
1930 	for ( i = 0; i < 4; i++ ) {
1931 		DebugLine( color, v[4+i], v[4+((i+1)&3)], lifetime );
1932 		DebugLine( color, v[i], v[4+i], lifetime );
1933 	}
1934 }
1935 
1936 /*
1937 ============
1938 idRenderWorldLocal::DebugCone
1939 
1940   dir is the cone axis
1941   radius1 is the radius at the apex
1942   radius2 is the radius at apex+dir
1943 ============
1944 */
DebugCone(const idVec4 & color,const idVec3 & apex,const idVec3 & dir,float radius1,float radius2,const int lifetime)1945 void idRenderWorldLocal::DebugCone( const idVec4 &color, const idVec3 &apex, const idVec3 &dir, float radius1, float radius2, const int lifetime ) {
1946 	int i;
1947 	idMat3 axis;
1948 	idVec3 top, p1, p2, lastp1, lastp2, d;
1949 
1950 	axis[2] = dir;
1951 	axis[2].Normalize();
1952 	axis[2].NormalVectors( axis[0], axis[1] );
1953 	axis[1] = -axis[1];
1954 
1955 	top = apex + dir;
1956 	lastp2 = top + radius2 * axis[1];
1957 
1958 	if ( radius1 == 0.0f ) {
1959 		for ( i = 20; i <= 360; i += 20 ) {
1960 			d = idMath::Sin16( DEG2RAD(i) ) * axis[0] + idMath::Cos16( DEG2RAD(i) ) * axis[1];
1961 			p2 = top + d * radius2;
1962 			DebugLine( color, lastp2, p2, lifetime );
1963 			DebugLine( color, p2, apex, lifetime );
1964 			lastp2 = p2;
1965 		}
1966 	} else {
1967 		lastp1 = apex + radius1 * axis[1];
1968 		for ( i = 20; i <= 360; i += 20 ) {
1969 			d = idMath::Sin16( DEG2RAD(i) ) * axis[0] + idMath::Cos16( DEG2RAD(i) ) * axis[1];
1970 			p1 = apex + d * radius1;
1971 			p2 = top + d * radius2;
1972 			DebugLine( color, lastp1, p1, lifetime );
1973 			DebugLine( color, lastp2, p2, lifetime );
1974 			DebugLine( color, p1, p2, lifetime );
1975 			lastp1 = p1;
1976 			lastp2 = p2;
1977 		}
1978 	}
1979 }
1980 
1981 /*
1982 ================
1983 idRenderWorldLocal::DebugAxis
1984 ================
1985 */
DebugAxis(const idVec3 & origin,const idMat3 & axis)1986 void idRenderWorldLocal::DebugAxis( const idVec3 &origin, const idMat3 &axis ) {
1987 	idVec3 start = origin;
1988 	idVec3 end = start + axis[0] * 20.0f;
1989 	DebugArrow( colorWhite, start, end, 2 );
1990 	end = start + axis[0] * -20.0f;
1991 	DebugArrow( colorWhite, start, end, 2 );
1992 	end = start + axis[1] * +20.0f;
1993 	DebugArrow( colorGreen, start, end, 2 );
1994 	end = start + axis[1] * -20.0f;
1995 	DebugArrow( colorGreen, start, end, 2 );
1996 	end = start + axis[2] * +20.0f;
1997 	DebugArrow( colorBlue, start, end, 2 );
1998 	end = start + axis[2] * -20.0f;
1999 	DebugArrow( colorBlue, start, end, 2 );
2000 }
2001 
2002 /*
2003 ====================
2004 idRenderWorldLocal::DebugClearPolygons
2005 ====================
2006 */
DebugClearPolygons(int time)2007 void idRenderWorldLocal::DebugClearPolygons( int time ) {
2008 	RB_ClearDebugPolygons( time );
2009 }
2010 
2011 /*
2012 ====================
2013 idRenderWorldLocal::DebugPolygon
2014 ====================
2015 */
DebugPolygon(const idVec4 & color,const idWinding & winding,const int lifeTime,const bool depthTest)2016 void idRenderWorldLocal::DebugPolygon( const idVec4 &color, const idWinding &winding, const int lifeTime, const bool depthTest ) {
2017 	RB_AddDebugPolygon( color, winding, lifeTime, depthTest );
2018 }
2019 
2020 /*
2021 ================
2022 idRenderWorldLocal::DebugScreenRect
2023 ================
2024 */
DebugScreenRect(const idVec4 & color,const idScreenRect & rect,const viewDef_t * viewDef,const int lifetime)2025 void idRenderWorldLocal::DebugScreenRect( const idVec4 &color, const idScreenRect &rect, const viewDef_t *viewDef, const int lifetime ) {
2026 	int i;
2027 	float centerx, centery, dScale, hScale, vScale;
2028 	idBounds bounds;
2029 	idVec3 p[4];
2030 
2031 	centerx = ( viewDef->viewport.x2 - viewDef->viewport.x1 ) * 0.5f;
2032 	centery = ( viewDef->viewport.y2 - viewDef->viewport.y1 ) * 0.5f;
2033 
2034 	dScale = r_znear.GetFloat() + 1.0f;
2035 	hScale = dScale * idMath::Tan16( DEG2RAD( viewDef->renderView.fov_x * 0.5f ) );
2036 	vScale = dScale * idMath::Tan16( DEG2RAD( viewDef->renderView.fov_y * 0.5f ) );
2037 
2038 	bounds[0][0] = bounds[1][0] = dScale;
2039 	bounds[0][1] = -( rect.x1 - centerx ) / centerx * hScale;
2040 	bounds[1][1] = -( rect.x2 - centerx ) / centerx * hScale;
2041 	bounds[0][2] = ( rect.y1 - centery ) / centery * vScale;
2042 	bounds[1][2] = ( rect.y2 - centery ) / centery * vScale;
2043 
2044 	for ( i = 0; i < 4; i++ ) {
2045 		p[i].x = bounds[0][0];
2046 		p[i].y = bounds[(i^(i>>1))&1].y;
2047 		p[i].z = bounds[(i>>1)&1].z;
2048 		p[i] = viewDef->renderView.vieworg + p[i] * viewDef->renderView.viewaxis;
2049 	}
2050 	for ( i = 0; i < 4; i++ ) {
2051 		DebugLine( color, p[i], p[(i+1)&3], false );
2052 	}
2053 }
2054 
2055 /*
2056 ================
2057 idRenderWorldLocal::DrawTextLength
2058 
2059   returns the length of the given text
2060 ================
2061 */
DrawTextLength(const char * text,float scale,int len)2062 float idRenderWorldLocal::DrawTextLength( const char *text, float scale, int len ) {
2063 	return RB_DrawTextLength( text, scale, len );
2064 }
2065 
2066 /*
2067 ================
2068 idRenderWorldLocal::DrawText
2069 
2070   oriented on the viewaxis
2071   align can be 0-left, 1-center (default), 2-right
2072 ================
2073 */
DrawText(const char * text,const idVec3 & origin,float scale,const idVec4 & color,const idMat3 & viewAxis,const int align,const int lifetime,const bool depthTest)2074 void idRenderWorldLocal::DrawText( const char *text, const idVec3 &origin, float scale, const idVec4 &color, const idMat3 &viewAxis, const int align, const int lifetime, const bool depthTest ) {
2075 	RB_AddDebugText( text, origin, scale, color, viewAxis, align, lifetime, depthTest );
2076 }
2077 
2078 /*
2079 ===============
2080 idRenderWorldLocal::RegenerateWorld
2081 ===============
2082 */
RegenerateWorld()2083 void idRenderWorldLocal::RegenerateWorld() {
2084 	R_RegenerateWorld_f( idCmdArgs() );
2085 }
2086 
2087 /*
2088 ===============
2089 R_GlobalShaderOverride
2090 ===============
2091 */
R_GlobalShaderOverride(const idMaterial ** shader)2092 bool R_GlobalShaderOverride( const idMaterial **shader ) {
2093 
2094 	if ( !(*shader)->IsDrawn() ) {
2095 		return false;
2096 	}
2097 
2098 	if ( tr.primaryRenderView.globalMaterial ) {
2099 		*shader = tr.primaryRenderView.globalMaterial;
2100 		return true;
2101 	}
2102 
2103 	if ( r_materialOverride.GetString()[0] != '\0' ) {
2104 		*shader = declManager->FindMaterial( r_materialOverride.GetString() );
2105 		return true;
2106 	}
2107 
2108 	return false;
2109 }
2110 
2111 /*
2112 ===============
2113 R_RemapShaderBySkin
2114 ===============
2115 */
R_RemapShaderBySkin(const idMaterial * shader,const idDeclSkin * skin,const idMaterial * customShader)2116 const idMaterial *R_RemapShaderBySkin( const idMaterial *shader, const idDeclSkin *skin, const idMaterial *customShader ) {
2117 
2118 	if ( !shader ) {
2119 		return NULL;
2120 	}
2121 
2122 	// never remap surfaces that were originally nodraw, like collision hulls
2123 	if ( !shader->IsDrawn() ) {
2124 		return shader;
2125 	}
2126 
2127 	if ( customShader ) {
2128 		// this is sort of a hack, but cause deformed surfaces to map to empty surfaces,
2129 		// so the item highlight overlay doesn't highlight the autosprite surface
2130 		if ( shader->Deform() ) {
2131 			return NULL;
2132 		}
2133 		return const_cast<idMaterial *>(customShader);
2134 	}
2135 
2136 	if ( !skin || !shader ) {
2137 		return const_cast<idMaterial *>(shader);
2138 	}
2139 
2140 	return skin->RemapShaderBySkin( shader );
2141 }
2142