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