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 "idlib/math/Interpolate.h"
31 #include "framework/Game.h"
32 #include "renderer/VertexCache.h"
33 #include "renderer/RenderWorld_local.h"
34 #include "ui/Window.h"
35 
36 #include "renderer/tr_local.h"
37 
38 static const float CHECK_BOUNDS_EPSILON = 1.0f;
39 
40 /*
41 ===========================================================================================
42 
43 VERTEX CACHE GENERATORS
44 
45 ===========================================================================================
46 */
47 
48 /*
49 ==================
50 R_CreateAmbientCache
51 
52 Create it if needed
53 ==================
54 */
R_CreateAmbientCache(srfTriangles_t * tri,bool needsLighting)55 bool R_CreateAmbientCache( srfTriangles_t *tri, bool needsLighting ) {
56 	if ( tri->ambientCache ) {
57 		return true;
58 	}
59 	// we are going to use it for drawing, so make sure we have the tangents and normals
60 	if ( needsLighting && !tri->tangentsCalculated ) {
61 		R_DeriveTangents( tri );
62 	}
63 
64 	vertexCache.Alloc( tri->verts, tri->numVerts * sizeof( tri->verts[0] ), &tri->ambientCache );
65 	if ( !tri->ambientCache ) {
66 		return false;
67 	}
68 	return true;
69 }
70 
71 /*
72 ==================
73 R_CreateLightingCache
74 
75 Returns false if the cache couldn't be allocated, in which case the surface should be skipped.
76 ==================
77 */
R_CreateLightingCache(const idRenderEntityLocal * ent,const idRenderLightLocal * light,srfTriangles_t * tri)78 bool R_CreateLightingCache( const idRenderEntityLocal *ent, const idRenderLightLocal *light, srfTriangles_t *tri ) {
79 	idVec3		localLightOrigin;
80 
81 	// fogs and blends don't need light vectors
82 	if ( light->lightShader->IsFogLight() || light->lightShader->IsBlendLight() ) {
83 		return true;
84 	}
85 
86 	// not needed if we have vertex programs
87 	if ( tr.backEndRendererHasVertexPrograms ) {
88 		return true;
89 	}
90 
91 	R_GlobalPointToLocal( ent->modelMatrix, light->globalLightOrigin, localLightOrigin );
92 
93 	int	size = tri->ambientSurface->numVerts * sizeof( lightingCache_t );
94 	lightingCache_t *cache = (lightingCache_t *)_alloca16( size );
95 
96 #if 1
97 
98 	SIMDProcessor->CreateTextureSpaceLightVectors( &cache[0].localLightVector, localLightOrigin,
99 												tri->ambientSurface->verts, tri->ambientSurface->numVerts, tri->indexes, tri->numIndexes );
100 
101 #else
102 
103 	bool *used = (bool *)_alloca16( tri->ambientSurface->numVerts * sizeof( used[0] ) );
104 	memset( used, 0, tri->ambientSurface->numVerts * sizeof( used[0] ) );
105 
106 	// because the interaction may be a very small subset of the full surface,
107 	// it makes sense to only deal with the verts used
108 	for ( int j = 0; j < tri->numIndexes; j++ ) {
109 		int i = tri->indexes[j];
110 		if ( used[i] ) {
111 			continue;
112 		}
113 		used[i] = true;
114 
115 		idVec3 lightDir;
116 		const idDrawVert *v;
117 
118 		v = &tri->ambientSurface->verts[i];
119 
120 		lightDir = localLightOrigin - v->xyz;
121 
122 		cache[i].localLightVector[0] = lightDir * v->tangents[0];
123 		cache[i].localLightVector[1] = lightDir * v->tangents[1];
124 		cache[i].localLightVector[2] = lightDir * v->normal;
125 	}
126 
127 #endif
128 
129 	vertexCache.Alloc( cache, size, &tri->lightingCache );
130 	if ( !tri->lightingCache ) {
131 		return false;
132 	}
133 	return true;
134 }
135 
136 /*
137 ==================
138 R_CreatePrivateShadowCache
139 
140 This is used only for a specific light
141 ==================
142 */
R_CreatePrivateShadowCache(srfTriangles_t * tri)143 void R_CreatePrivateShadowCache( srfTriangles_t *tri ) {
144 	if ( !tri->shadowVertexes ) {
145 		return;
146 	}
147 
148 	vertexCache.Alloc( tri->shadowVertexes, tri->numVerts * sizeof( *tri->shadowVertexes ), &tri->shadowCache );
149 }
150 
151 /*
152 ==================
153 R_CreateVertexProgramShadowCache
154 
155 This is constant for any number of lights, the vertex program
156 takes care of projecting the verts to infinity.
157 ==================
158 */
R_CreateVertexProgramShadowCache(srfTriangles_t * tri)159 void R_CreateVertexProgramShadowCache( srfTriangles_t *tri ) {
160 	if ( tri->verts == NULL ) {
161 		return;
162 	}
163 
164 	shadowCache_t *temp = (shadowCache_t *)_alloca16( tri->numVerts * 2 * sizeof( shadowCache_t ) );
165 
166 #if 1
167 
168 	SIMDProcessor->CreateVertexProgramShadowCache( &temp->xyz, tri->verts, tri->numVerts );
169 
170 #else
171 
172 	int numVerts = tri->numVerts;
173 	const idDrawVert *verts = tri->verts;
174 	for ( int i = 0; i < numVerts; i++ ) {
175 		const float *v = verts[i].xyz.ToFloatPtr();
176 		temp[i*2+0].xyz[0] = v[0];
177 		temp[i*2+1].xyz[0] = v[0];
178 		temp[i*2+0].xyz[1] = v[1];
179 		temp[i*2+1].xyz[1] = v[1];
180 		temp[i*2+0].xyz[2] = v[2];
181 		temp[i*2+1].xyz[2] = v[2];
182 		temp[i*2+0].xyz[3] = 1.0f;		// on the model surface
183 		temp[i*2+1].xyz[3] = 0.0f;		// will be projected to infinity
184 	}
185 
186 #endif
187 
188 	vertexCache.Alloc( temp, tri->numVerts * 2 * sizeof( shadowCache_t ), &tri->shadowCache );
189 }
190 
191 /*
192 ==================
193 R_SkyboxTexGen
194 ==================
195 */
R_SkyboxTexGen(drawSurf_t * surf,const idVec3 & viewOrg)196 void R_SkyboxTexGen( drawSurf_t *surf, const idVec3 &viewOrg ) {
197 	int		i;
198 	idVec3	localViewOrigin;
199 
200 	R_GlobalPointToLocal( surf->space->modelMatrix, viewOrg, localViewOrigin );
201 
202 	int numVerts = surf->geo->numVerts;
203 	int size = numVerts * sizeof( idVec3 );
204 	idVec3 *texCoords = (idVec3 *) _alloca16( size );
205 
206 	const idDrawVert *verts = surf->geo->verts;
207 	for ( i = 0; i < numVerts; i++ ) {
208 		texCoords[i][0] = verts[i].xyz[0] - localViewOrigin[0];
209 		texCoords[i][1] = verts[i].xyz[1] - localViewOrigin[1];
210 		texCoords[i][2] = verts[i].xyz[2] - localViewOrigin[2];
211 	}
212 
213 	surf->dynamicTexCoords = vertexCache.AllocFrameTemp( texCoords, size );
214 }
215 
216 /*
217 ==================
218 R_WobbleskyTexGen
219 ==================
220 */
R_WobbleskyTexGen(drawSurf_t * surf,const idVec3 & viewOrg)221 void R_WobbleskyTexGen( drawSurf_t *surf, const idVec3 &viewOrg ) {
222 	int		i;
223 	idVec3	localViewOrigin;
224 
225 	const int *parms = surf->material->GetTexGenRegisters();
226 
227 	float	wobbleDegrees = surf->shaderRegisters[ parms[0] ];
228 	float	wobbleSpeed = surf->shaderRegisters[ parms[1] ];
229 	float	rotateSpeed = surf->shaderRegisters[ parms[2] ];
230 
231 	wobbleDegrees = wobbleDegrees * idMath::PI / 180;
232 	wobbleSpeed = wobbleSpeed * 2 * idMath::PI / 60;
233 	rotateSpeed = rotateSpeed * 2 * idMath::PI / 60;
234 
235 	// very ad-hoc "wobble" transform
236 	float	transform[16];
237 	float	a = tr.viewDef->floatTime * wobbleSpeed;
238 	float	s = sin( a ) * sin( wobbleDegrees );
239 	float	c = cos( a ) * sin( wobbleDegrees );
240 	float	z = cos( wobbleDegrees );
241 
242 	idVec3	axis[3];
243 
244 	axis[2][0] = c;
245 	axis[2][1] = s;
246 	axis[2][2] = z;
247 
248 	axis[1][0] = -sin( a * 2 ) * sin( wobbleDegrees );
249 	axis[1][2] = -s * sin( wobbleDegrees );
250 	axis[1][1] = sqrt( 1.0f - ( axis[1][0] * axis[1][0] + axis[1][2] * axis[1][2] ) );
251 
252 	// make the second vector exactly perpendicular to the first
253 	axis[1] -= ( axis[2] * axis[1] ) * axis[2];
254 	axis[1].Normalize();
255 
256 	// construct the third with a cross
257 	axis[0].Cross( axis[1], axis[2] );
258 
259 	// add the rotate
260 	s = sin( rotateSpeed * tr.viewDef->floatTime );
261 	c = cos( rotateSpeed * tr.viewDef->floatTime );
262 
263 	transform[0] = axis[0][0] * c + axis[1][0] * s;
264 	transform[4] = axis[0][1] * c + axis[1][1] * s;
265 	transform[8] = axis[0][2] * c + axis[1][2] * s;
266 
267 	transform[1] = axis[1][0] * c - axis[0][0] * s;
268 	transform[5] = axis[1][1] * c - axis[0][1] * s;
269 	transform[9] = axis[1][2] * c - axis[0][2] * s;
270 
271 	transform[2] = axis[2][0];
272 	transform[6] = axis[2][1];
273 	transform[10] = axis[2][2];
274 
275 	transform[3] = transform[7] = transform[11] = 0.0f;
276 	transform[12] = transform[13] = transform[14] = 0.0f;
277 
278 	R_GlobalPointToLocal( surf->space->modelMatrix, viewOrg, localViewOrigin );
279 
280 	int numVerts = surf->geo->numVerts;
281 	int size = numVerts * sizeof( idVec3 );
282 	idVec3 *texCoords = (idVec3 *) _alloca16( size );
283 
284 	const idDrawVert *verts = surf->geo->verts;
285 	for ( i = 0; i < numVerts; i++ ) {
286 		idVec3 v;
287 
288 		v[0] = verts[i].xyz[0] - localViewOrigin[0];
289 		v[1] = verts[i].xyz[1] - localViewOrigin[1];
290 		v[2] = verts[i].xyz[2] - localViewOrigin[2];
291 
292 		R_LocalPointToGlobal( transform, v, texCoords[i] );
293 	}
294 
295 	surf->dynamicTexCoords = vertexCache.AllocFrameTemp( texCoords, size );
296 }
297 
298 /*
299 =================
300 R_SpecularTexGen
301 
302 Calculates the specular coordinates for cards without vertex programs.
303 =================
304 */
R_SpecularTexGen(drawSurf_t * surf,const idVec3 & globalLightOrigin,const idVec3 & viewOrg)305 static void R_SpecularTexGen( drawSurf_t *surf, const idVec3 &globalLightOrigin, const idVec3 &viewOrg ) {
306 	const srfTriangles_t *tri;
307 	idVec3	localLightOrigin;
308 	idVec3	localViewOrigin;
309 
310 	R_GlobalPointToLocal( surf->space->modelMatrix, globalLightOrigin, localLightOrigin );
311 	R_GlobalPointToLocal( surf->space->modelMatrix, viewOrg, localViewOrigin );
312 
313 	tri = surf->geo;
314 
315 	// FIXME: change to 3 component?
316 	int	size = tri->numVerts * sizeof( idVec4 );
317 	idVec4 *texCoords = (idVec4 *) _alloca16( size );
318 
319 #if 1
320 
321 	SIMDProcessor->CreateSpecularTextureCoords( texCoords, localLightOrigin, localViewOrigin,
322 											tri->verts, tri->numVerts, tri->indexes, tri->numIndexes );
323 
324 #else
325 
326 	bool *used = (bool *)_alloca16( tri->numVerts * sizeof( used[0] ) );
327 	memset( used, 0, tri->numVerts * sizeof( used[0] ) );
328 
329 	// because the interaction may be a very small subset of the full surface,
330 	// it makes sense to only deal with the verts used
331 	for ( int j = 0; j < tri->numIndexes; j++ ) {
332 		int i = tri->indexes[j];
333 		if ( used[i] ) {
334 			continue;
335 		}
336 		used[i] = true;
337 
338 		float ilength;
339 
340 		const idDrawVert *v = &tri->verts[i];
341 
342 		idVec3 lightDir = localLightOrigin - v->xyz;
343 		idVec3 viewDir = localViewOrigin - v->xyz;
344 
345 		ilength = idMath::RSqrt( lightDir * lightDir );
346 		lightDir[0] *= ilength;
347 		lightDir[1] *= ilength;
348 		lightDir[2] *= ilength;
349 
350 		ilength = idMath::RSqrt( viewDir * viewDir );
351 		viewDir[0] *= ilength;
352 		viewDir[1] *= ilength;
353 		viewDir[2] *= ilength;
354 
355 		lightDir += viewDir;
356 
357 		texCoords[i][0] = lightDir * v->tangents[0];
358 		texCoords[i][1] = lightDir * v->tangents[1];
359 		texCoords[i][2] = lightDir * v->normal;
360 		texCoords[i][3] = 1;
361 	}
362 
363 #endif
364 
365 	surf->dynamicTexCoords = vertexCache.AllocFrameTemp( texCoords, size );
366 }
367 
368 
369 //=======================================================================================================
370 
371 /*
372 =============
373 R_SetEntityDefViewEntity
374 
375 If the entityDef isn't already on the viewEntity list, create
376 a viewEntity and add it to the list with an empty scissor rect.
377 
378 This does not instantiate dynamic models for the entity yet.
379 =============
380 */
R_SetEntityDefViewEntity(idRenderEntityLocal * def)381 viewEntity_t *R_SetEntityDefViewEntity( idRenderEntityLocal *def ) {
382 	viewEntity_t		*vModel;
383 
384 	if ( def->viewCount == tr.viewCount ) {
385 		return def->viewEntity;
386 	}
387 	def->viewCount = tr.viewCount;
388 
389 	// set the model and modelview matricies
390 	vModel = (viewEntity_t *)R_ClearedFrameAlloc( sizeof( *vModel ) );
391 	vModel->entityDef = def;
392 
393 	// the scissorRect will be expanded as the model bounds is accepted into visible portal chains
394 	vModel->scissorRect.Clear();
395 
396 	// copy the model and weapon depth hack for back-end use
397 	vModel->modelDepthHack = def->parms.modelDepthHack;
398 	vModel->weaponDepthHack = def->parms.weaponDepthHack;
399 
400 	R_AxisToModelMatrix( def->parms.axis, def->parms.origin, vModel->modelMatrix );
401 
402 	// we may not have a viewDef if we are just creating shadows at entity creation time
403 	if ( tr.viewDef ) {
404 		myGlMultMatrix( vModel->modelMatrix, tr.viewDef->worldSpace.modelViewMatrix, vModel->modelViewMatrix );
405 
406 		vModel->next = tr.viewDef->viewEntitys;
407 		tr.viewDef->viewEntitys = vModel;
408 	}
409 
410 	def->viewEntity = vModel;
411 
412 	return vModel;
413 }
414 
415 /*
416 ====================
417 R_TestPointInViewLight
418 ====================
419 */
420 static const float INSIDE_LIGHT_FRUSTUM_SLOP = 32;
421 // this needs to be greater than the dist from origin to corner of near clip plane
R_TestPointInViewLight(const idVec3 & org,const idRenderLightLocal * light)422 static bool R_TestPointInViewLight( const idVec3 &org, const idRenderLightLocal *light ) {
423 	int		i;
424 	idVec3	local;
425 
426 	for ( i = 0 ; i < 6 ; i++ ) {
427 		float d = light->frustum[i].Distance( org );
428 		if ( d > INSIDE_LIGHT_FRUSTUM_SLOP ) {
429 			return false;
430 		}
431 	}
432 
433 	return true;
434 }
435 
436 /*
437 ===================
438 R_PointInFrustum
439 
440 Assumes positive sides face outward
441 ===================
442 */
R_PointInFrustum(idVec3 & p,idPlane * planes,int numPlanes)443 static bool R_PointInFrustum( idVec3 &p, idPlane *planes, int numPlanes ) {
444 	for ( int i = 0 ; i < numPlanes ; i++ ) {
445 		float d = planes[i].Distance( p );
446 		if ( d > 0 ) {
447 			return false;
448 		}
449 	}
450 	return true;
451 }
452 
453 /*
454 =============
455 R_SetLightDefViewLight
456 
457 If the lightDef isn't already on the viewLight list, create
458 a viewLight and add it to the list with an empty scissor rect.
459 =============
460 */
R_SetLightDefViewLight(idRenderLightLocal * light)461 viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *light ) {
462 	viewLight_t *vLight;
463 
464 	if ( light->viewCount == tr.viewCount ) {
465 		return light->viewLight;
466 	}
467 	light->viewCount = tr.viewCount;
468 
469 	// add to the view light chain
470 	vLight = (viewLight_t *)R_ClearedFrameAlloc( sizeof( *vLight ) );
471 	vLight->lightDef = light;
472 
473 	// the scissorRect will be expanded as the light bounds is accepted into visible portal chains
474 	vLight->scissorRect.Clear();
475 
476 	// calculate the shadow cap optimization states
477 	vLight->viewInsideLight = R_TestPointInViewLight( tr.viewDef->renderView.vieworg, light );
478 	if ( !vLight->viewInsideLight ) {
479 		vLight->viewSeesShadowPlaneBits = 0;
480 		for ( int i = 0 ; i < light->numShadowFrustums ; i++ ) {
481 			float d = light->shadowFrustums[i].planes[5].Distance( tr.viewDef->renderView.vieworg );
482 			if ( d < INSIDE_LIGHT_FRUSTUM_SLOP ) {
483 				vLight->viewSeesShadowPlaneBits|= 1 << i;
484 			}
485 		}
486 	} else {
487 		// this should not be referenced in this case
488 		vLight->viewSeesShadowPlaneBits = 63;
489 	}
490 
491 	// see if the light center is in view, which will allow us to cull invisible shadows
492 	vLight->viewSeesGlobalLightOrigin = R_PointInFrustum( light->globalLightOrigin, tr.viewDef->frustum, 4 );
493 
494 	// copy data used by backend
495 	vLight->globalLightOrigin = light->globalLightOrigin;
496 	vLight->lightProject[0] = light->lightProject[0];
497 	vLight->lightProject[1] = light->lightProject[1];
498 	vLight->lightProject[2] = light->lightProject[2];
499 	vLight->lightProject[3] = light->lightProject[3];
500 	vLight->fogPlane = light->frustum[5];
501 	vLight->frustumTris = light->frustumTris;
502 	vLight->falloffImage = light->falloffImage;
503 	vLight->lightShader = light->lightShader;
504 	vLight->shaderRegisters = NULL;		// allocated and evaluated in R_AddLightSurfaces
505 
506 	// link the view light
507 	vLight->next = tr.viewDef->viewLights;
508 	tr.viewDef->viewLights = vLight;
509 
510 	light->viewLight = vLight;
511 
512 	return vLight;
513 }
514 
515 /*
516 =================
517 idRenderWorldLocal::CreateLightDefInteractions
518 
519 When a lightDef is determined to effect the view (contact the frustum and non-0 light), it will check to
520 make sure that it has interactions for all the entityDefs that it might possibly contact.
521 
522 This does not guarantee that all possible interactions for this light are generated, only that
523 the ones that may effect the current view are generated. so it does need to be called every view.
524 
525 This does not cause entityDefs to create dynamic models, all work is done on the referenceBounds.
526 
527 All entities that have non-empty interactions with viewLights will
528 have viewEntities made for them and be put on the viewEntity list,
529 even if their surfaces aren't visible, because they may need to cast shadows.
530 
531 Interactions are usually removed when a entityDef or lightDef is modified, unless the change
532 is known to not effect them, so there is no danger of getting a stale interaction, we just need to
533 check that needed ones are created.
534 
535 An interaction can be at several levels:
536 
537 Don't interact (but share an area) (numSurfaces = 0)
538 Entity reference bounds touches light frustum, but surfaces haven't been generated (numSurfaces = -1)
539 Shadow surfaces have been generated, but light surfaces have not.  The shadow surface may still be empty due to bounds being conservative.
540 Both shadow and light surfaces have been generated.  Either or both surfaces may still be empty due to conservative bounds.
541 
542 =================
543 */
CreateLightDefInteractions(idRenderLightLocal * ldef)544 void idRenderWorldLocal::CreateLightDefInteractions( idRenderLightLocal *ldef ) {
545 	areaReference_t		*eref;
546 	areaReference_t		*lref;
547 	idRenderEntityLocal		*edef;
548 	portalArea_t	*area;
549 	idInteraction	*inter;
550 
551 	for ( lref = ldef->references ; lref ; lref = lref->ownerNext ) {
552 		area = lref->area;
553 
554 		// check all the models in this area
555 		for ( eref = area->entityRefs.areaNext ; eref != &area->entityRefs ; eref = eref->areaNext ) {
556 			edef = eref->entity;
557 
558 			// if the entity doesn't have any light-interacting surfaces, we could skip this,
559 			// but we don't want to instantiate dynamic models yet, so we can't check that on
560 			// most things
561 
562 			// if the entity isn't viewed
563 			if ( tr.viewDef && edef->viewCount != tr.viewCount ) {
564 				// if the light doesn't cast shadows, skip
565 				if ( !ldef->lightShader->LightCastsShadows() ) {
566 					continue;
567 				}
568 				// if we are suppressing its shadow in this view, skip
569 				if ( !r_skipSuppress.GetBool() ) {
570 					if ( edef->parms.suppressShadowInViewID && edef->parms.suppressShadowInViewID == tr.viewDef->renderView.viewID ) {
571 						continue;
572 					}
573 					if ( edef->parms.suppressShadowInLightID && edef->parms.suppressShadowInLightID == ldef->parms.lightId ) {
574 						continue;
575 					}
576 				}
577 			}
578 
579 			// some big outdoor meshes are flagged to not create any dynamic interactions
580 			// when the level designer knows that nearby moving lights shouldn't actually hit them
581 			if ( edef->parms.noDynamicInteractions && edef->world->generateAllInteractionsCalled ) {
582 				continue;
583 			}
584 
585 			// if any of the edef's interaction match this light, we don't
586 			// need to consider it.
587 			if ( r_useInteractionTable.GetBool() && this->interactionTable ) {
588 				// allocating these tables may take several megs on big maps, but it saves 3% to 5% of
589 				// the CPU time.  The table is updated at interaction::AllocAndLink() and interaction::UnlinkAndFree()
590 				int index = ldef->index * this->interactionTableWidth + edef->index;
591 				inter = this->interactionTable[ index ];
592 				if ( inter ) {
593 					// if this entity wasn't in view already, the scissor rect will be empty,
594 					// so it will only be used for shadow casting
595 					if ( !inter->IsEmpty() ) {
596 						R_SetEntityDefViewEntity( edef );
597 					}
598 					continue;
599 				}
600 			} else {
601 				// scan the doubly linked lists, which may have several dozen entries
602 
603 				// we could check either model refs or light refs for matches, but it is
604 				// assumed that there will be less lights in an area than models
605 				// so the entity chains should be somewhat shorter (they tend to be fairly close).
606 				for ( inter = edef->firstInteraction; inter != NULL; inter = inter->entityNext ) {
607 					if ( inter->lightDef == ldef ) {
608 						break;
609 					}
610 				}
611 
612 				// if we already have an interaction, we don't need to do anything
613 				if ( inter != NULL ) {
614 					// if this entity wasn't in view already, the scissor rect will be empty,
615 					// so it will only be used for shadow casting
616 					if ( !inter->IsEmpty() ) {
617 						R_SetEntityDefViewEntity( edef );
618 					}
619 					continue;
620 				}
621 			}
622 
623 			//
624 			// create a new interaction, but don't do any work other than bbox to frustum culling
625 			//
626 			idInteraction *inter = idInteraction::AllocAndLink( edef, ldef );
627 
628 			// do a check of the entity reference bounds against the light frustum,
629 			// trying to avoid creating a viewEntity if it hasn't been already
630 			float	modelMatrix[16];
631 			float	*m;
632 
633 			if ( edef->viewCount == tr.viewCount ) {
634 				m = edef->viewEntity->modelMatrix;
635 			} else {
636 				R_AxisToModelMatrix( edef->parms.axis, edef->parms.origin, modelMatrix );
637 				m = modelMatrix;
638 			}
639 
640 			if ( R_CullLocalBox( edef->referenceBounds, m, 6, ldef->frustum ) ) {
641 				inter->MakeEmpty();
642 				continue;
643 			}
644 
645 			// we will do a more precise per-surface check when we are checking the entity
646 
647 			// if this entity wasn't in view already, the scissor rect will be empty,
648 			// so it will only be used for shadow casting
649 			R_SetEntityDefViewEntity( edef );
650 		}
651 	}
652 }
653 
654 //===============================================================================================================
655 
656 /*
657 =================
658 R_LinkLightSurf
659 =================
660 */
R_LinkLightSurf(const drawSurf_t ** link,const srfTriangles_t * tri,const viewEntity_t * space,const idRenderLightLocal * light,const idMaterial * shader,const idScreenRect & scissor,bool viewInsideShadow)661 void R_LinkLightSurf( const drawSurf_t **link, const srfTriangles_t *tri, const viewEntity_t *space,
662 				   const idRenderLightLocal *light, const idMaterial *shader, const idScreenRect &scissor, bool viewInsideShadow ) {
663 	drawSurf_t		*drawSurf;
664 
665 	if ( !space ) {
666 		space = &tr.viewDef->worldSpace;
667 	}
668 
669 	drawSurf = (drawSurf_t *)R_FrameAlloc( sizeof( *drawSurf ) );
670 
671 	drawSurf->geo = tri;
672 	drawSurf->space = space;
673 	drawSurf->material = shader;
674 	drawSurf->scissorRect = scissor;
675 	drawSurf->dsFlags = 0;
676 	if ( viewInsideShadow ) {
677 		drawSurf->dsFlags |= DSF_VIEW_INSIDE_SHADOW;
678 	}
679 
680 	if ( !shader ) {
681 		// shadows won't have a shader
682 		drawSurf->shaderRegisters = NULL;
683 	} else {
684 		// process the shader expressions for conditionals / color / texcoords
685 		const float *constRegs = shader->ConstantRegisters();
686 		if ( constRegs ) {
687 			// this shader has only constants for parameters
688 			drawSurf->shaderRegisters = constRegs;
689 		} else {
690 			// FIXME: share with the ambient surface?
691 			float *regs = (float *)R_FrameAlloc( shader->GetNumRegisters() * sizeof( float ) );
692 			drawSurf->shaderRegisters = regs;
693 			shader->EvaluateRegisters( regs, space->entityDef->parms.shaderParms, tr.viewDef, space->entityDef->parms.referenceSound );
694 		}
695 
696 		// calculate the specular coordinates if we aren't using vertex programs
697 		if ( !tr.backEndRendererHasVertexPrograms && !r_skipSpecular.GetBool() ) {
698 			R_SpecularTexGen( drawSurf, light->globalLightOrigin, tr.viewDef->renderView.vieworg );
699 			// if we failed to allocate space for the specular calculations, drop the surface
700 			if ( !drawSurf->dynamicTexCoords ) {
701 				return;
702 			}
703 		}
704 	}
705 
706 	// actually link it in
707 	drawSurf->nextOnLight = *link;
708 	*link = drawSurf;
709 }
710 
711 /*
712 ======================
713 R_ClippedLightScissorRectangle
714 ======================
715 */
R_ClippedLightScissorRectangle(viewLight_t * vLight)716 idScreenRect R_ClippedLightScissorRectangle( viewLight_t *vLight ) {
717 	int i, j;
718 	const idRenderLightLocal *light = vLight->lightDef;
719 	idScreenRect r;
720 	idFixedWinding w;
721 
722 	r.Clear();
723 
724 	for ( i = 0 ; i < 6 ; i++ ) {
725 		const idWinding *ow = light->frustumWindings[i];
726 
727 		// projected lights may have one of the frustums degenerated
728 		if ( !ow ) {
729 			continue;
730 		}
731 
732 		// the light frustum planes face out from the light,
733 		// so the planes that have the view origin on the negative
734 		// side will be the "back" faces of the light, which must have
735 		// some fragment inside the portalStack to be visible
736 		if ( light->frustum[i].Distance( tr.viewDef->renderView.vieworg ) >= 0 ) {
737 			continue;
738 		}
739 
740 		w = *ow;
741 
742 		// now check the winding against each of the frustum planes
743 		for ( j = 0; j < 5; j++ ) {
744 			if ( !w.ClipInPlace( -tr.viewDef->frustum[j] ) ) {
745 				break;
746 			}
747 		}
748 
749 		// project these points to the screen and add to bounds
750 		for ( j = 0; j < w.GetNumPoints(); j++ ) {
751 			idPlane		eye, clip;
752 			idVec3		ndc;
753 
754 			R_TransformModelToClip( w[j].ToVec3(), tr.viewDef->worldSpace.modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip );
755 
756 			if ( clip[3] <= 0.01f ) {
757 				clip[3] = 0.01f;
758 			}
759 
760 			R_TransformClipToDevice( clip, tr.viewDef, ndc );
761 
762 			float windowX = 0.5f * ( 1.0f + ndc[0] ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 );
763 			float windowY = 0.5f * ( 1.0f + ndc[1] ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 );
764 
765 			if ( windowX > tr.viewDef->scissor.x2 ) {
766 				windowX = tr.viewDef->scissor.x2;
767 			} else if ( windowX < tr.viewDef->scissor.x1 ) {
768 				windowX = tr.viewDef->scissor.x1;
769 			}
770 			if ( windowY > tr.viewDef->scissor.y2 ) {
771 				windowY = tr.viewDef->scissor.y2;
772 			} else if ( windowY < tr.viewDef->scissor.y1 ) {
773 				windowY = tr.viewDef->scissor.y1;
774 			}
775 
776 			r.AddPoint( windowX, windowY );
777 		}
778 	}
779 
780 	// add the fudge boundary
781 	r.Expand();
782 
783 	return r;
784 }
785 
786 /*
787 ==================
788 R_CalcLightScissorRectangle
789 
790 The light screen bounds will be used to crop the scissor rect during
791 stencil clears and interaction drawing
792 ==================
793 */
794 int	c_clippedLight, c_unclippedLight;
795 
R_CalcLightScissorRectangle(viewLight_t * vLight)796 idScreenRect	R_CalcLightScissorRectangle( viewLight_t *vLight ) {
797 	idScreenRect	r;
798 	srfTriangles_t *tri;
799 	idPlane			eye, clip;
800 	idVec3			ndc;
801 
802 	if ( vLight->lightDef->parms.pointLight ) {
803 		idBounds bounds;
804 		idRenderLightLocal *lightDef = vLight->lightDef;
805 		tr.viewDef->viewFrustum.ProjectionBounds( idBox( lightDef->parms.origin, lightDef->parms.lightRadius, lightDef->parms.axis ), bounds );
806 		return R_ScreenRectFromViewFrustumBounds( bounds );
807 	}
808 
809 	if ( r_useClippedLightScissors.GetInteger() == 2 ) {
810 		return R_ClippedLightScissorRectangle( vLight );
811 	}
812 
813 	r.Clear();
814 
815 	tri = vLight->lightDef->frustumTris;
816 	for ( int i = 0 ; i < tri->numVerts ; i++ ) {
817 		R_TransformModelToClip( tri->verts[i].xyz, tr.viewDef->worldSpace.modelViewMatrix,
818 			tr.viewDef->projectionMatrix, eye, clip );
819 
820 		// if it is near clipped, clip the winding polygons to the view frustum
821 		if ( clip[3] <= 1 ) {
822 			c_clippedLight++;
823 			if ( r_useClippedLightScissors.GetInteger() ) {
824 				return R_ClippedLightScissorRectangle( vLight );
825 			} else {
826 				r.x1 = r.y1 = 0;
827 				r.x2 = ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 ) - 1;
828 				r.y2 = ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 ) - 1;
829 				return r;
830 			}
831 		}
832 
833 		R_TransformClipToDevice( clip, tr.viewDef, ndc );
834 
835 		float windowX = 0.5f * ( 1.0f + ndc[0] ) * ( tr.viewDef->viewport.x2 - tr.viewDef->viewport.x1 );
836 		float windowY = 0.5f * ( 1.0f + ndc[1] ) * ( tr.viewDef->viewport.y2 - tr.viewDef->viewport.y1 );
837 
838 		if ( windowX > tr.viewDef->scissor.x2 ) {
839 			windowX = tr.viewDef->scissor.x2;
840 		} else if ( windowX < tr.viewDef->scissor.x1 ) {
841 			windowX = tr.viewDef->scissor.x1;
842 		}
843 		if ( windowY > tr.viewDef->scissor.y2 ) {
844 			windowY = tr.viewDef->scissor.y2;
845 		} else if ( windowY < tr.viewDef->scissor.y1 ) {
846 			windowY = tr.viewDef->scissor.y1;
847 		}
848 
849 		r.AddPoint( windowX, windowY );
850 	}
851 
852 	// add the fudge boundary
853 	r.Expand();
854 
855 	c_unclippedLight++;
856 
857 	return r;
858 }
859 
860 /*
861 =================
862 R_AddLightSurfaces
863 
864 Calc the light shader values, removing any light from the viewLight list
865 if it is determined to not have any visible effect due to being flashed off or turned off.
866 
867 Adds entities to the viewEntity list if they are needed for shadow casting.
868 
869 Add any precomputed shadow volumes.
870 
871 Removes lights from the viewLights list if they are completely
872 turned off, or completely off screen.
873 
874 Create any new interactions needed between the viewLights
875 and the viewEntitys due to game movement
876 =================
877 */
R_AddLightSurfaces(void)878 void R_AddLightSurfaces( void ) {
879 	viewLight_t		*vLight;
880 	idRenderLightLocal *light;
881 	viewLight_t		**ptr;
882 
883 	// go through each visible light, possibly removing some from the list
884 	ptr = &tr.viewDef->viewLights;
885 	while ( *ptr ) {
886 		vLight = *ptr;
887 		light = vLight->lightDef;
888 
889 		const idMaterial	*lightShader = light->lightShader;
890 		if ( !lightShader ) {
891 			common->Error( "R_AddLightSurfaces: NULL lightShader" );
892 		}
893 
894 		// see if we are suppressing the light in this view
895 		if ( !r_skipSuppress.GetBool() ) {
896 			if ( light->parms.suppressLightInViewID
897 			&& light->parms.suppressLightInViewID == tr.viewDef->renderView.viewID ) {
898 				*ptr = vLight->next;
899 				light->viewCount = -1;
900 				continue;
901 			}
902 			if ( light->parms.allowLightInViewID
903 			&& light->parms.allowLightInViewID != tr.viewDef->renderView.viewID ) {
904 				*ptr = vLight->next;
905 				light->viewCount = -1;
906 				continue;
907 			}
908 		}
909 
910 		// evaluate the light shader registers
911 		float *lightRegs =(float *)R_FrameAlloc( lightShader->GetNumRegisters() * sizeof( float ) );
912 		vLight->shaderRegisters = lightRegs;
913 		lightShader->EvaluateRegisters( lightRegs, light->parms.shaderParms, tr.viewDef, light->parms.referenceSound );
914 
915 		// if this is a purely additive light and no stage in the light shader evaluates
916 		// to a positive light value, we can completely skip the light
917 		if ( !lightShader->IsFogLight() && !lightShader->IsBlendLight() ) {
918 			int lightStageNum;
919 			for ( lightStageNum = 0 ; lightStageNum < lightShader->GetNumStages() ; lightStageNum++ ) {
920 				const shaderStage_t	*lightStage = lightShader->GetStage( lightStageNum );
921 
922 				// ignore stages that fail the condition
923 				if ( !lightRegs[ lightStage->conditionRegister ] ) {
924 					continue;
925 				}
926 
927 				const int *registers = lightStage->color.registers;
928 
929 				// snap tiny values to zero to avoid lights showing up with the wrong color
930 				if ( lightRegs[ registers[0] ] < 0.001f ) {
931 					lightRegs[ registers[0] ] = 0.0f;
932 				}
933 				if ( lightRegs[ registers[1] ] < 0.001f ) {
934 					lightRegs[ registers[1] ] = 0.0f;
935 				}
936 				if ( lightRegs[ registers[2] ] < 0.001f ) {
937 					lightRegs[ registers[2] ] = 0.0f;
938 				}
939 
940 				// FIXME:	when using the following values the light shows up bright red when using nvidia drivers/hardware
941 				//			this seems to have been fixed ?
942 				//lightRegs[ registers[0] ] = 1.5143074e-005f;
943 				//lightRegs[ registers[1] ] = 1.5483369e-005f;
944 				//lightRegs[ registers[2] ] = 1.7014690e-005f;
945 
946 				if ( lightRegs[ registers[0] ] > 0.0f ||
947 						lightRegs[ registers[1] ] > 0.0f ||
948 							lightRegs[ registers[2] ] > 0.0f ) {
949 					break;
950 				}
951 			}
952 			if ( lightStageNum == lightShader->GetNumStages() ) {
953 				// we went through all the stages and didn't find one that adds anything
954 				// remove the light from the viewLights list, and change its frame marker
955 				// so interaction generation doesn't think the light is visible and
956 				// create a shadow for it
957 				*ptr = vLight->next;
958 				light->viewCount = -1;
959 				continue;
960 			}
961 		}
962 
963 		if ( r_useLightScissors.GetBool() ) {
964 			// calculate the screen area covered by the light frustum
965 			// which will be used to crop the stencil cull
966 			idScreenRect scissorRect = R_CalcLightScissorRectangle( vLight );
967 			// intersect with the portal crossing scissor rectangle
968 			vLight->scissorRect.Intersect( scissorRect );
969 
970 			if ( r_showLightScissors.GetBool() ) {
971 				R_ShowColoredScreenRect( vLight->scissorRect, light->index );
972 			}
973 		}
974 
975 #if 0
976 		// this never happens, because CullLightByPortals() does a more precise job
977 		if ( vLight->scissorRect.IsEmpty() ) {
978 			// this light doesn't touch anything on screen, so remove it from the list
979 			*ptr = vLight->next;
980 			continue;
981 		}
982 #endif
983 
984 		// this one stays on the list
985 		ptr = &vLight->next;
986 
987 		// if we are doing a soft-shadow novelty test, regenerate the light with
988 		// a random offset every time
989 		if ( r_lightSourceRadius.GetFloat() != 0.0f ) {
990 			for ( int i = 0 ; i < 3 ; i++ ) {
991 				light->globalLightOrigin[i] += r_lightSourceRadius.GetFloat() * ( -1 + 2 * (rand()&0xfff)/(float)0xfff );
992 			}
993 		}
994 
995 		// create interactions with all entities the light may touch, and add viewEntities
996 		// that may cast shadows, even if they aren't directly visible.  Any real work
997 		// will be deferred until we walk through the viewEntities
998 		tr.viewDef->renderWorld->CreateLightDefInteractions( light );
999 		tr.pc.c_viewLights++;
1000 
1001 		// fog lights will need to draw the light frustum triangles, so make sure they
1002 		// are in the vertex cache
1003 		if ( lightShader->IsFogLight() ) {
1004 			if ( !light->frustumTris->ambientCache ) {
1005 				if ( !R_CreateAmbientCache( light->frustumTris, false ) ) {
1006 					// skip if we are out of vertex memory
1007 					continue;
1008 				}
1009 			}
1010 			// touch the surface so it won't get purged
1011 			vertexCache.Touch( light->frustumTris->ambientCache );
1012 		}
1013 
1014 		// add the prelight shadows for the static world geometry
1015 		if ( light->parms.prelightModel && r_useOptimizedShadows.GetBool() ) {
1016 
1017 			if ( !light->parms.prelightModel->NumSurfaces() ) {
1018 				common->Error( "no surfs in prelight model '%s'", light->parms.prelightModel->Name() );
1019 			}
1020 
1021 			srfTriangles_t	*tri = light->parms.prelightModel->Surface( 0 )->geometry;
1022 			if ( !tri->shadowVertexes ) {
1023 				common->Error( "R_AddLightSurfaces: prelight model '%s' without shadowVertexes", light->parms.prelightModel->Name() );
1024 			}
1025 
1026 			// these shadows will all have valid bounds, and can be culled normally
1027 			if ( r_useShadowCulling.GetBool() ) {
1028 				if ( R_CullLocalBox( tri->bounds, tr.viewDef->worldSpace.modelMatrix, 5, tr.viewDef->frustum ) ) {
1029 					continue;
1030 				}
1031 			}
1032 
1033 			// if we have been purged, re-upload the shadowVertexes
1034 			if ( !tri->shadowCache ) {
1035 				R_CreatePrivateShadowCache( tri );
1036 				if ( !tri->shadowCache ) {
1037 					continue;
1038 				}
1039 			}
1040 
1041 			// touch the shadow surface so it won't get purged
1042 			vertexCache.Touch( tri->shadowCache );
1043 
1044 			if ( !tri->indexCache && r_useIndexBuffers.GetBool() ) {
1045 				vertexCache.Alloc( tri->indexes, tri->numIndexes * sizeof( tri->indexes[0] ), &tri->indexCache, true );
1046 			}
1047 			if ( tri->indexCache ) {
1048 				vertexCache.Touch( tri->indexCache );
1049 			}
1050 
1051 			R_LinkLightSurf( &vLight->globalShadows, tri, NULL, light, NULL, vLight->scissorRect, true /* FIXME? */ );
1052 		}
1053 	}
1054 }
1055 
1056 //===============================================================================================================
1057 
1058 /*
1059 ==================
1060 R_IssueEntityDefCallback
1061 ==================
1062 */
R_IssueEntityDefCallback(idRenderEntityLocal * def)1063 bool R_IssueEntityDefCallback( idRenderEntityLocal *def ) {
1064 	bool update;
1065 	idBounds	oldBounds;
1066 	const bool checkBounds = r_checkBounds.GetBool();
1067 
1068 	if ( checkBounds ) {
1069 		oldBounds = def->referenceBounds;
1070 	}
1071 
1072 	def->archived = false;		// will need to be written to the demo file
1073 	tr.pc.c_entityDefCallbacks++;
1074 	if ( tr.viewDef ) {
1075 		update = def->parms.callback( &def->parms, &tr.viewDef->renderView );
1076 	} else {
1077 		update = def->parms.callback( &def->parms, NULL );
1078 	}
1079 
1080 	if ( !def->parms.hModel ) {
1081 		common->Error( "R_IssueEntityDefCallback: dynamic entity callback didn't set model" );
1082 		return false;
1083 	}
1084 
1085 	if ( checkBounds ) {
1086 		if (	oldBounds[0][0] > def->referenceBounds[0][0] + CHECK_BOUNDS_EPSILON ||
1087 				oldBounds[0][1] > def->referenceBounds[0][1] + CHECK_BOUNDS_EPSILON ||
1088 				oldBounds[0][2] > def->referenceBounds[0][2] + CHECK_BOUNDS_EPSILON ||
1089 				oldBounds[1][0] < def->referenceBounds[1][0] - CHECK_BOUNDS_EPSILON ||
1090 				oldBounds[1][1] < def->referenceBounds[1][1] - CHECK_BOUNDS_EPSILON ||
1091 				oldBounds[1][2] < def->referenceBounds[1][2] - CHECK_BOUNDS_EPSILON ) {
1092 			common->Printf( "entity %i callback extended reference bounds\n", def->index );
1093 		}
1094 	}
1095 
1096 	return update;
1097 }
1098 
1099 /*
1100 ===================
1101 R_EntityDefDynamicModel
1102 
1103 Issues a deferred entity callback if necessary.
1104 If the model isn't dynamic, it returns the original.
1105 Returns the cached dynamic model if present, otherwise creates
1106 it and any necessary overlays
1107 ===================
1108 */
R_EntityDefDynamicModel(idRenderEntityLocal * def)1109 idRenderModel *R_EntityDefDynamicModel( idRenderEntityLocal *def ) {
1110 	bool callbackUpdate;
1111 
1112 	// allow deferred entities to construct themselves
1113 	if ( def->parms.callback ) {
1114 		callbackUpdate = R_IssueEntityDefCallback( def );
1115 	} else {
1116 		callbackUpdate = false;
1117 	}
1118 
1119 	idRenderModel *model = def->parms.hModel;
1120 
1121 	if ( !model ) {
1122 		common->Error( "R_EntityDefDynamicModel: NULL model" );
1123 	}
1124 
1125 	if ( model->IsDynamicModel() == DM_STATIC ) {
1126 		def->dynamicModel = NULL;
1127 		def->dynamicModelFrameCount = 0;
1128 		return model;
1129 	}
1130 
1131 	// continously animating models (particle systems, etc) will have their snapshot updated every single view
1132 	if ( callbackUpdate || ( model->IsDynamicModel() == DM_CONTINUOUS && def->dynamicModelFrameCount != tr.frameCount ) ) {
1133 		R_ClearEntityDefDynamicModel( def );
1134 	}
1135 
1136 	// if we don't have a snapshot of the dynamic model, generate it now
1137 	if ( !def->dynamicModel ) {
1138 
1139 		// instantiate the snapshot of the dynamic model, possibly reusing memory from the cached snapshot
1140 		def->cachedDynamicModel = model->InstantiateDynamicModel( &def->parms, tr.viewDef, def->cachedDynamicModel );
1141 
1142 		if ( def->cachedDynamicModel ) {
1143 
1144 			// add any overlays to the snapshot of the dynamic model
1145 			if ( def->overlay && !r_skipOverlays.GetBool() ) {
1146 				def->overlay->AddOverlaySurfacesToModel( def->cachedDynamicModel );
1147 			} else {
1148 				idRenderModelOverlay::RemoveOverlaySurfacesFromModel( def->cachedDynamicModel );
1149 			}
1150 
1151 			if ( r_checkBounds.GetBool() ) {
1152 				idBounds b = def->cachedDynamicModel->Bounds();
1153 				if (	b[0][0] < def->referenceBounds[0][0] - CHECK_BOUNDS_EPSILON ||
1154 						b[0][1] < def->referenceBounds[0][1] - CHECK_BOUNDS_EPSILON ||
1155 						b[0][2] < def->referenceBounds[0][2] - CHECK_BOUNDS_EPSILON ||
1156 						b[1][0] > def->referenceBounds[1][0] + CHECK_BOUNDS_EPSILON ||
1157 						b[1][1] > def->referenceBounds[1][1] + CHECK_BOUNDS_EPSILON ||
1158 						b[1][2] > def->referenceBounds[1][2] + CHECK_BOUNDS_EPSILON ) {
1159 					common->Printf( "entity %i dynamic model exceeded reference bounds\n", def->index );
1160 				}
1161 			}
1162 		}
1163 
1164 		def->dynamicModel = def->cachedDynamicModel;
1165 		def->dynamicModelFrameCount = tr.frameCount;
1166 	}
1167 
1168 	// set model depth hack value
1169 	if ( def->dynamicModel && model->DepthHack() != 0.0f && tr.viewDef ) {
1170 		idPlane eye, clip;
1171 		idVec3 ndc;
1172 		R_TransformModelToClip( def->parms.origin, tr.viewDef->worldSpace.modelViewMatrix, tr.viewDef->projectionMatrix, eye, clip );
1173 		R_TransformClipToDevice( clip, tr.viewDef, ndc );
1174 		def->parms.modelDepthHack = model->DepthHack() * ( 1.0f - ndc.z );
1175 	}
1176 
1177 	// FIXME: if any of the surfaces have deforms, create a frame-temporary model with references to the
1178 	// undeformed surfaces.  This would allow deforms to be light interacting.
1179 
1180 	return def->dynamicModel;
1181 }
1182 
1183 /*
1184 =================
1185 R_AddDrawSurf
1186 =================
1187 */
R_AddDrawSurf(const srfTriangles_t * tri,const viewEntity_t * space,const renderEntity_t * renderEntity,const idMaterial * shader,const idScreenRect & scissor)1188 void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity,
1189 					const idMaterial *shader, const idScreenRect &scissor ) {
1190 	drawSurf_t		*drawSurf;
1191 	const float		*shaderParms;
1192 	static float	refRegs[MAX_EXPRESSION_REGISTERS];	// don't put on stack, or VC++ will do a page touch
1193 	float			generatedShaderParms[MAX_ENTITY_SHADER_PARMS];
1194 
1195 	drawSurf = (drawSurf_t *)R_FrameAlloc( sizeof( *drawSurf ) );
1196 	drawSurf->geo = tri;
1197 	drawSurf->space = space;
1198 	drawSurf->material = shader;
1199 	drawSurf->scissorRect = scissor;
1200 	drawSurf->sort = shader->GetSort() + tr.sortOffset;
1201 	drawSurf->dsFlags = 0;
1202 
1203 	// bumping this offset each time causes surfaces with equal sort orders to still
1204 	// deterministically draw in the order they are added
1205 	tr.sortOffset += 0.000001f;
1206 
1207 	// if it doesn't fit, resize the list
1208 	if ( tr.viewDef->numDrawSurfs == tr.viewDef->maxDrawSurfs ) {
1209 		drawSurf_t	**old = tr.viewDef->drawSurfs;
1210 		int			count;
1211 
1212 		if ( tr.viewDef->maxDrawSurfs == 0 ) {
1213 			tr.viewDef->maxDrawSurfs = INITIAL_DRAWSURFS;
1214 			count = 0;
1215 		} else {
1216 			count = tr.viewDef->maxDrawSurfs * sizeof( tr.viewDef->drawSurfs[0] );
1217 			tr.viewDef->maxDrawSurfs *= 2;
1218 		}
1219 		tr.viewDef->drawSurfs = (drawSurf_t **)R_FrameAlloc( tr.viewDef->maxDrawSurfs * sizeof( tr.viewDef->drawSurfs[0] ) );
1220 		memcpy( tr.viewDef->drawSurfs, old, count );
1221 	}
1222 	tr.viewDef->drawSurfs[tr.viewDef->numDrawSurfs] = drawSurf;
1223 	tr.viewDef->numDrawSurfs++;
1224 
1225 	// process the shader expressions for conditionals / color / texcoords
1226 	const float	*constRegs = shader->ConstantRegisters();
1227 	if ( constRegs ) {
1228 		// shader only uses constant values
1229 		drawSurf->shaderRegisters = constRegs;
1230 	} else {
1231 		float *regs = (float *)R_FrameAlloc( shader->GetNumRegisters() * sizeof( float ) );
1232 		drawSurf->shaderRegisters = regs;
1233 
1234 		// a reference shader will take the calculated stage color value from another shader
1235 		// and use that for the parm0-parm3 of the current shader, which allows a stage of
1236 		// a light model and light flares to pick up different flashing tables from
1237 		// different light shaders
1238 		if ( renderEntity->referenceShader ) {
1239 			// evaluate the reference shader to find our shader parms
1240 			const shaderStage_t *pStage;
1241 
1242 			renderEntity->referenceShader->EvaluateRegisters( refRegs, renderEntity->shaderParms, tr.viewDef, renderEntity->referenceSound );
1243 			pStage = renderEntity->referenceShader->GetStage(0);
1244 
1245 			memcpy( generatedShaderParms, renderEntity->shaderParms, sizeof( generatedShaderParms ) );
1246 			generatedShaderParms[0] = refRegs[ pStage->color.registers[0] ];
1247 			generatedShaderParms[1] = refRegs[ pStage->color.registers[1] ];
1248 			generatedShaderParms[2] = refRegs[ pStage->color.registers[2] ];
1249 
1250 			shaderParms = generatedShaderParms;
1251 		} else {
1252 			// evaluate with the entityDef's shader parms
1253 			shaderParms = renderEntity->shaderParms;
1254 		}
1255 
1256 		float oldFloatTime = 0.0f;
1257 		int oldTime = 0;
1258 
1259 		if ( space->entityDef && space->entityDef->parms.timeGroup ) {
1260 			oldFloatTime = tr.viewDef->floatTime;
1261 			oldTime = tr.viewDef->renderView.time;
1262 
1263 			tr.viewDef->floatTime = game->GetTimeGroupTime( space->entityDef->parms.timeGroup ) * 0.001;
1264 			tr.viewDef->renderView.time = game->GetTimeGroupTime( space->entityDef->parms.timeGroup );
1265 		}
1266 
1267 		shader->EvaluateRegisters( regs, shaderParms, tr.viewDef, renderEntity->referenceSound );
1268 
1269 		if ( space->entityDef && space->entityDef->parms.timeGroup ) {
1270 			tr.viewDef->floatTime = oldFloatTime;
1271 			tr.viewDef->renderView.time = oldTime;
1272 		}
1273 	}
1274 
1275 	// check for deformations
1276 	R_DeformDrawSurf( drawSurf );
1277 
1278 	// skybox surfaces need a dynamic texgen
1279 	switch( shader->Texgen() ) {
1280 		case TG_SKYBOX_CUBE:
1281 			R_SkyboxTexGen( drawSurf, tr.viewDef->renderView.vieworg );
1282 			break;
1283 		case TG_WOBBLESKY_CUBE:
1284 			R_WobbleskyTexGen( drawSurf, tr.viewDef->renderView.vieworg );
1285 			break;
1286 	}
1287 
1288 	// check for gui surfaces
1289 	idUserInterface	*gui = NULL;
1290 
1291 	if ( !space->entityDef ) {
1292 		gui = shader->GlobalGui();
1293 	} else {
1294 		int guiNum = shader->GetEntityGui() - 1;
1295 		if ( guiNum >= 0 && guiNum < MAX_RENDERENTITY_GUI ) {
1296 			gui = renderEntity->gui[ guiNum ];
1297 		}
1298 		if ( gui == NULL ) {
1299 			gui = shader->GlobalGui();
1300 		}
1301 	}
1302 
1303 	if ( gui ) {
1304 		// force guis on the fast time
1305 		float oldFloatTime;
1306 		int oldTime;
1307 
1308 		oldFloatTime = tr.viewDef->floatTime;
1309 		oldTime = tr.viewDef->renderView.time;
1310 
1311 		tr.viewDef->floatTime = game->GetTimeGroupTime( 1 ) * 0.001;
1312 		tr.viewDef->renderView.time = game->GetTimeGroupTime( 1 );
1313 
1314 		idBounds ndcBounds;
1315 
1316 		if ( !R_PreciseCullSurface( drawSurf, ndcBounds ) ) {
1317 			// did we ever use this to forward an entity color to a gui that didn't set color?
1318 //			memcpy( tr.guiShaderParms, shaderParms, sizeof( tr.guiShaderParms ) );
1319 			R_RenderGuiSurf( gui, drawSurf );
1320 		}
1321 
1322 		tr.viewDef->floatTime = oldFloatTime;
1323 		tr.viewDef->renderView.time = oldTime;
1324 	}
1325 
1326 	// we can't add subviews at this point, because that would
1327 	// increment tr.viewCount, messing up the rest of the surface
1328 	// adds for this view
1329 }
1330 
1331 /*
1332 ===============
1333 R_AddAmbientDrawsurfs
1334 
1335 Adds surfaces for the given viewEntity
1336 Walks through the viewEntitys list and creates drawSurf_t for each surface of
1337 each viewEntity that has a non-empty scissorRect
1338 ===============
1339 */
R_AddAmbientDrawsurfs(viewEntity_t * vEntity)1340 static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) {
1341 	int					i, total;
1342 	idRenderEntityLocal	*def;
1343 	srfTriangles_t		*tri;
1344 	idRenderModel		*model;
1345 	const idMaterial	*shader;
1346 
1347 	def = vEntity->entityDef;
1348 
1349 	if ( def->dynamicModel ) {
1350 		model = def->dynamicModel;
1351 	} else {
1352 		model = def->parms.hModel;
1353 	}
1354 
1355 	// add all the surfaces
1356 	total = model->NumSurfaces();
1357 	for ( i = 0 ; i < total ; i++ ) {
1358 		const modelSurface_t	*surf = model->Surface( i );
1359 
1360 		// for debugging, only show a single surface at a time
1361 		if ( r_singleSurface.GetInteger() >= 0 && i != r_singleSurface.GetInteger() ) {
1362 			continue;
1363 		}
1364 
1365 		tri = surf->geometry;
1366 		if ( !tri ) {
1367 			continue;
1368 		}
1369 		if ( !tri->numIndexes ) {
1370 			continue;
1371 		}
1372 		shader = surf->shader;
1373 		shader = R_RemapShaderBySkin( shader, def->parms.customSkin, def->parms.customShader );
1374 
1375 		R_GlobalShaderOverride( &shader );
1376 
1377 		if ( !shader ) {
1378 			continue;
1379 		}
1380 		if ( !shader->IsDrawn() ) {
1381 			continue;
1382 		}
1383 
1384 		// debugging tool to make sure we are have the correct pre-calculated bounds
1385 		if ( r_checkBounds.GetBool() ) {
1386 			int j, k;
1387 			for ( j = 0 ; j < tri->numVerts ; j++ ) {
1388 				for ( k = 0 ; k < 3 ; k++ ) {
1389 					if ( tri->verts[j].xyz[k] > tri->bounds[1][k] + CHECK_BOUNDS_EPSILON
1390 						|| tri->verts[j].xyz[k] < tri->bounds[0][k] - CHECK_BOUNDS_EPSILON ) {
1391 						common->Printf( "bad tri->bounds on %s:%s\n", def->parms.hModel->Name(), shader->GetName() );
1392 						break;
1393 					}
1394 					if ( tri->verts[j].xyz[k] > def->referenceBounds[1][k] + CHECK_BOUNDS_EPSILON
1395 						|| tri->verts[j].xyz[k] < def->referenceBounds[0][k] - CHECK_BOUNDS_EPSILON ) {
1396 						common->Printf( "bad referenceBounds on %s:%s\n", def->parms.hModel->Name(), shader->GetName() );
1397 						break;
1398 					}
1399 				}
1400 				if ( k != 3 ) {
1401 					break;
1402 				}
1403 			}
1404 		}
1405 
1406 		if ( !R_CullLocalBox( tri->bounds, vEntity->modelMatrix, 5, tr.viewDef->frustum ) ) {
1407 
1408 			def->visibleCount = tr.viewCount;
1409 
1410 			// make sure we have an ambient cache
1411 			if ( !R_CreateAmbientCache( tri, shader->ReceivesLighting() ) ) {
1412 				// don't add anything if the vertex cache was too full to give us an ambient cache
1413 				return;
1414 			}
1415 			// touch it so it won't get purged
1416 			vertexCache.Touch( tri->ambientCache );
1417 
1418 			if ( r_useIndexBuffers.GetBool() && !tri->indexCache ) {
1419 				vertexCache.Alloc( tri->indexes, tri->numIndexes * sizeof( tri->indexes[0] ), &tri->indexCache, true );
1420 			}
1421 			if ( tri->indexCache ) {
1422 				vertexCache.Touch( tri->indexCache );
1423 			}
1424 
1425 			// add the surface for drawing
1426 			R_AddDrawSurf( tri, vEntity, &vEntity->entityDef->parms, shader, vEntity->scissorRect );
1427 
1428 			// ambientViewCount is used to allow light interactions to be rejected
1429 			// if the ambient surface isn't visible at all
1430 			tri->ambientViewCount = tr.viewCount;
1431 		}
1432 	}
1433 
1434 	// add the lightweight decal surfaces
1435 	for ( idRenderModelDecal *decal = def->decals; decal; decal = decal->Next() ) {
1436 		decal->AddDecalDrawSurf( vEntity );
1437 	}
1438 }
1439 
1440 /*
1441 ==================
1442 R_CalcEntityScissorRectangle
1443 ==================
1444 */
R_CalcEntityScissorRectangle(viewEntity_t * vEntity)1445 idScreenRect R_CalcEntityScissorRectangle( viewEntity_t *vEntity ) {
1446 	idBounds bounds;
1447 	idRenderEntityLocal *def = vEntity->entityDef;
1448 
1449 	tr.viewDef->viewFrustum.ProjectionBounds( idBox( def->referenceBounds, def->parms.origin, def->parms.axis ), bounds );
1450 
1451 	return R_ScreenRectFromViewFrustumBounds( bounds );
1452 }
1453 
1454 /*
1455 ===================
1456 R_AddModelSurfaces
1457 
1458 Here is where dynamic models actually get instantiated, and necessary
1459 interactions get created.  This is all done on a sort-by-model basis
1460 to keep source data in cache (most likely L2) as any interactions and
1461 shadows are generated, since dynamic models will typically be lit by
1462 two or more lights.
1463 ===================
1464 */
R_AddModelSurfaces(void)1465 void R_AddModelSurfaces( void ) {
1466 	viewEntity_t		*vEntity;
1467 	idInteraction		*inter, *next;
1468 	idRenderModel		*model;
1469 
1470 	// clear the ambient surface list
1471 	tr.viewDef->numDrawSurfs = 0;
1472 	tr.viewDef->maxDrawSurfs = 0;	// will be set to INITIAL_DRAWSURFS on R_AddDrawSurf
1473 
1474 	// go through each entity that is either visible to the view, or to
1475 	// any light that intersects the view (for shadows)
1476 	for ( vEntity = tr.viewDef->viewEntitys; vEntity; vEntity = vEntity->next ) {
1477 
1478 		if ( r_useEntityScissors.GetBool() ) {
1479 			// calculate the screen area covered by the entity
1480 			idScreenRect scissorRect = R_CalcEntityScissorRectangle( vEntity );
1481 			// intersect with the portal crossing scissor rectangle
1482 			vEntity->scissorRect.Intersect( scissorRect );
1483 
1484 			if ( r_showEntityScissors.GetBool() ) {
1485 				R_ShowColoredScreenRect( vEntity->scissorRect, vEntity->entityDef->index );
1486 			}
1487 		}
1488 
1489 		float oldFloatTime = 0.0f;
1490 		int oldTime = 0;
1491 
1492 		game->SelectTimeGroup( vEntity->entityDef->parms.timeGroup );
1493 
1494 		if ( vEntity->entityDef->parms.timeGroup ) {
1495 			oldFloatTime = tr.viewDef->floatTime;
1496 			oldTime = tr.viewDef->renderView.time;
1497 
1498 			tr.viewDef->floatTime = game->GetTimeGroupTime( vEntity->entityDef->parms.timeGroup ) * 0.001;
1499 			tr.viewDef->renderView.time = game->GetTimeGroupTime( vEntity->entityDef->parms.timeGroup );
1500 		}
1501 
1502 		if ( tr.viewDef->isXraySubview && vEntity->entityDef->parms.xrayIndex == 1 ) {
1503 			if ( vEntity->entityDef->parms.timeGroup ) {
1504 				tr.viewDef->floatTime = oldFloatTime;
1505 				tr.viewDef->renderView.time = oldTime;
1506 			}
1507 			continue;
1508 		} else if ( !tr.viewDef->isXraySubview && vEntity->entityDef->parms.xrayIndex == 2 ) {
1509 			if ( vEntity->entityDef->parms.timeGroup ) {
1510 				tr.viewDef->floatTime = oldFloatTime;
1511 				tr.viewDef->renderView.time = oldTime;
1512 			}
1513 			continue;
1514 		}
1515 
1516 		// add the ambient surface if it has a visible rectangle
1517 		if ( !vEntity->scissorRect.IsEmpty() ) {
1518 			model = R_EntityDefDynamicModel( vEntity->entityDef );
1519 			if ( model == NULL || model->NumSurfaces() <= 0 ) {
1520 				if ( vEntity->entityDef->parms.timeGroup ) {
1521 					tr.viewDef->floatTime = oldFloatTime;
1522 					tr.viewDef->renderView.time = oldTime;
1523 				}
1524 				continue;
1525 			}
1526 
1527 			R_AddAmbientDrawsurfs( vEntity );
1528 			tr.pc.c_visibleViewEntities++;
1529 		} else {
1530 			tr.pc.c_shadowViewEntities++;
1531 		}
1532 
1533 		//
1534 		// for all the entity / light interactions on this entity, add them to the view
1535 		//
1536 		if ( tr.viewDef->isXraySubview ) {
1537 			if ( vEntity->entityDef->parms.xrayIndex == 2 ) {
1538 				for ( inter = vEntity->entityDef->firstInteraction; inter != NULL && !inter->IsEmpty(); inter = next ) {
1539 					next = inter->entityNext;
1540 					if ( inter->lightDef->viewCount != tr.viewCount ) {
1541 						continue;
1542 					}
1543 					inter->AddActiveInteraction();
1544 				}
1545 			}
1546 		} else {
1547 			// all empty interactions are at the end of the list so once the
1548 			// first is encountered all the remaining interactions are empty
1549 			for ( inter = vEntity->entityDef->firstInteraction; inter != NULL && !inter->IsEmpty(); inter = next ) {
1550 				next = inter->entityNext;
1551 
1552 				// skip any lights that aren't currently visible
1553 				// this is run after any lights that are turned off have already
1554 				// been removed from the viewLights list, and had their viewCount cleared
1555 				if ( inter->lightDef->viewCount != tr.viewCount ) {
1556 					continue;
1557 				}
1558 				inter->AddActiveInteraction();
1559 			}
1560 		}
1561 
1562 		if ( vEntity->entityDef->parms.timeGroup ) {
1563 			tr.viewDef->floatTime = oldFloatTime;
1564 			tr.viewDef->renderView.time = oldTime;
1565 		}
1566 
1567 	}
1568 }
1569 
1570 /*
1571 =====================
1572 R_RemoveUnecessaryViewLights
1573 =====================
1574 */
R_RemoveUnecessaryViewLights(void)1575 void R_RemoveUnecessaryViewLights( void ) {
1576 	viewLight_t		*vLight;
1577 
1578 	// go through each visible light
1579 	for ( vLight = tr.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
1580 		// if the light didn't have any lit surfaces visible, there is no need to
1581 		// draw any of the shadows.  We still keep the vLight for debugging
1582 		// draws
1583 		if ( !vLight->localInteractions && !vLight->globalInteractions && !vLight->translucentInteractions ) {
1584 			vLight->localShadows = NULL;
1585 			vLight->globalShadows = NULL;
1586 		}
1587 	}
1588 
1589 	if ( r_useShadowSurfaceScissor.GetBool() ) {
1590 		// shrink the light scissor rect to only intersect the surfaces that will actually be drawn.
1591 		// This doesn't seem to actually help, perhaps because the surface scissor
1592 		// rects aren't actually the surface, but only the portal clippings.
1593 		for ( vLight = tr.viewDef->viewLights ; vLight ; vLight = vLight->next ) {
1594 			const drawSurf_t	*surf;
1595 			idScreenRect	surfRect;
1596 
1597 			if ( !vLight->lightShader->LightCastsShadows() ) {
1598 				continue;
1599 			}
1600 
1601 			surfRect.Clear();
1602 
1603 			for ( surf = vLight->globalInteractions ; surf ; surf = surf->nextOnLight ) {
1604 				surfRect.Union( surf->scissorRect );
1605 			}
1606 			for ( surf = vLight->localShadows ; surf ; surf = surf->nextOnLight ) {
1607 				const_cast<drawSurf_t *>(surf)->scissorRect.Intersect( surfRect );
1608 			}
1609 
1610 			for ( surf = vLight->localInteractions ; surf ; surf = surf->nextOnLight ) {
1611 				surfRect.Union( surf->scissorRect );
1612 			}
1613 			for ( surf = vLight->globalShadows ; surf ; surf = surf->nextOnLight ) {
1614 				const_cast<drawSurf_t *>(surf)->scissorRect.Intersect( surfRect );
1615 			}
1616 
1617 			for ( surf = vLight->translucentInteractions ; surf ; surf = surf->nextOnLight ) {
1618 				surfRect.Union( surf->scissorRect );
1619 			}
1620 
1621 			vLight->scissorRect.Intersect( surfRect );
1622 		}
1623 	}
1624 }
1625