doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
tr_light.cpp
Go to the documentation of this file.
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 */
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
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 */
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 */
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 
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 */
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 ) {
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 */
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 */
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() ) {
568  continue;
569  }
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
579  continue;
580  }
581 
582  // if any of the edef's interaction match this light, we don't
583  // need to consider it.
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;
691  }
692 
693  // calculate the specular coordinates if we aren't using vertex programs
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 */
714  int i, j;
715  const idRenderLightLocal *light = vLight->lightDef;
716  idScreenRect r;
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 
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 */
792 
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++ ) {
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++;
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
895  *ptr = vLight->next;
896  light->viewCount = -1;
897  continue;
898  }
899  if ( light->parms.allowLightInViewID
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
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
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() ) {
1026  continue;
1027  }
1028  }
1029 
1030  // if we have been purged, re-upload the shadowVertexes
1031  if ( !tri->shadowCache ) {
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 */
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
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 */
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 ) ) {
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
1136 
1137  if ( def->cachedDynamicModel ) {
1138 
1139  // add any overlays to the snapshot of the dynamic model
1140  if ( def->overlay && !r_skipOverlays.GetBool() ) {
1142  } else {
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;
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;
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
1204  drawSurf_t **old = tr.viewDef->drawSurfs;
1205  int count;
1206 
1207  if ( tr.viewDef->maxDrawSurfs == 0 ) {
1209  count = 0;
1210  } else {
1211  count = tr.viewDef->maxDrawSurfs * sizeof( tr.viewDef->drawSurfs[0] );
1212  tr.viewDef->maxDrawSurfs *= 2;
1213  }
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 
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:
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;
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 */
1441  idBounds bounds;
1442  idRenderEntityLocal *def = vEntity->entityDef;
1443 
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 
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;
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 );
1524  } else {
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 */
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 
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 }
idPlane frustum[5]
Definition: tr_local.h:421
static void RemoveOverlaySurfacesFromModel(idRenderModel *baseModel)
idRenderWorldLocal * world
Definition: tr_local.h:255
const idMaterial * lightShader
Definition: tr_local.h:213
bool weaponDepthHack
Definition: tr_local.h:357
idRenderModel * dynamicModel
Definition: tr_local.h:263
idCVar r_useEntityScissors("r_useEntityScissors","0", CVAR_RENDERER|CVAR_BOOL,"1 = use custom scissor rectangle for each entity")
idCVar r_skipOverlays("r_skipOverlays","0", CVAR_RENDERER|CVAR_BOOL,"skip overlay surfaces")
const srfTriangles_t * geo
Definition: tr_local.h:112
viewEntity_t worldSpace
Definition: tr_local.h:373
virtual idRenderModel * InstantiateDynamicModel(const struct renderEntity_s *ent, const struct viewDef_s *view, idRenderModel *cachedModel)=0
idCVar r_useShadowCulling("r_useShadowCulling","1", CVAR_RENDERER|CVAR_BOOL,"try to cull shadows from partially visible lights")
void R_CreatePrivateShadowCache(srfTriangles_t *tri)
Definition: tr_light.cpp:140
idImage * falloffImage
Definition: tr_local.h:328
void R_AddModelSurfaces(void)
Definition: tr_light.cpp:1460
idScreenRect R_ScreenRectFromViewFrustumBounds(const idBounds &bounds)
Definition: tr_main.cpp:151
bool viewSeesGlobalLightOrigin
Definition: tr_local.h:315
const float GetSort(void) const
Definition: Material.h:509
idPlane frustum[6]
Definition: tr_local.h:219
int numVerts
Definition: Model.h:98
struct viewEntity_s * viewEntity
Definition: tr_local.h:274
idCVar r_useIndexBuffers("r_useIndexBuffers","0", CVAR_RENDERER|CVAR_ARCHIVE|CVAR_INTEGER,"use ARB_vertex_buffer_object for indexes", 0, 1, idCmdSystem::ArgCompletion_Integer< 0, 1 >)
void R_AddDrawSurf(const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity, const idMaterial *shader, const idScreenRect &scissor)
Definition: tr_light.cpp:1183
float sort
Definition: tr_local.h:115
idCVar r_showEntityScissors("r_showEntityScissors","0", CVAR_RENDERER|CVAR_BOOL,"show entity scissor rectangles")
short x2
Definition: tr_local.h:55
bool ReceivesLighting(void) const
Definition: Material.h:401
idVec4 xyz
Definition: Model.h:80
float GetFloat(void) const
Definition: CVarSystem.h:144
drawSurf_t ** drawSurfs
Definition: tr_local.h:411
const GLdouble * v
Definition: glext.h:2936
const int GetNumStages(void) const
Definition: Material.h:365
int conditionRegister
Definition: Material.h:204
void R_SkyboxTexGen(drawSurf_t *surf, const idVec3 &viewOrg)
Definition: tr_light.cpp:193
const float * ConstantRegisters() const
Definition: Material.cpp:2588
const float * ToFloatPtr(void) const
Definition: Vector.h:719
idRenderModel * R_EntityDefDynamicModel(idRenderEntityLocal *def)
Definition: tr_light.cpp:1104
float floatTime
Definition: tr_local.h:377
idScreenRect scissorRect
Definition: tr_local.h:307
float Distance(const idVec3 &v) const
Definition: Plane.h:324
bool R_GlobalShaderOverride(const idMaterial **shader)
idVec3 localLightVector
Definition: Model.h:75
idVec3 xyz
Definition: DrawVert.h:42
static const float PI
Definition: Math.h:205
virtual void VPCALL CreateTextureSpaceLightVectors(idVec3 *lightVectors, const idVec3 &lightOrigin, const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes)=0
const idMaterial * referenceShader
Definition: RenderWorld.h:124
float z
Definition: Vector.h:320
idCVar r_skipSpecular("r_skipSpecular","0", CVAR_RENDERER|CVAR_BOOL|CVAR_CHEAT|CVAR_ARCHIVE,"use black for specular1")
texgen_t Texgen() const
Definition: Material.cpp:2499
idCVar r_checkBounds("r_checkBounds","0", CVAR_RENDERER|CVAR_BOOL,"compare all surface bounds with precalculated ones")
idVec3 tangents[2]
Definition: DrawVert.h:45
const idMaterial * shader
Definition: Model.h:146
renderLight_t parms
Definition: tr_local.h:191
void R_RemoveUnecessaryViewLights(void)
Definition: tr_light.cpp:1570
int GetEntityGui(void) const
Definition: Material.h:535
idScreenRect scissorRect
Definition: tr_local.h:118
int suppressShadowInViewID
Definition: RenderWorld.h:105
const struct drawSurf_s * localShadows
Definition: tr_local.h:332
void Union(const idScreenRect &rect)
Definition: tr_main.cpp:113
const char * GetName(void) const
Definition: DeclManager.h:140
Definition: Vector.h:316
idCVar r_useShadowSurfaceScissor("r_useShadowSurfaceScissor","1", CVAR_RENDERER|CVAR_BOOL,"scissor shadows by the scissor rect of the interaction surfaces")
idScreenRect viewport
Definition: tr_local.h:398
case const float
Definition: Callbacks.cpp:62
performanceCounters_t pc
Definition: tr_local.h:788
const struct drawSurf_s * globalInteractions
Definition: tr_local.h:333
virtual const char * Name() const =0
int ambientViewCount
Definition: Model.h:89
idRenderLightLocal * lightDef
Definition: Interaction.h:106
float modelMatrix[16]
Definition: tr_local.h:253
bool IsBlendLight() const
Definition: Material.h:461
short x1
Definition: tr_local.h:55
void R_DeriveTangents(srfTriangles_t *tri, bool allocFacePlanes=true)
float modelDepthHack
Definition: tr_local.h:358
idRenderLightLocal * lightDef
Definition: tr_local.h:302
bool tangentsCalculated
Definition: Model.h:92
GLdouble s
Definition: glext.h:2935
idCVar r_singleSurface("r_singleSurface","-1", CVAR_RENDERER|CVAR_INTEGER,"suppress all but one surface on each entity")
const struct viewEntity_s * space
Definition: tr_local.h:113
struct vertCache_s * ambientCache
Definition: Model.h:137
viewLight_t * R_SetLightDefViewLight(idRenderLightLocal *light)
Definition: tr_light.cpp:458
int i
Definition: process.py:33
static idInteraction * AllocAndLink(idRenderEntityLocal *edef, idRenderLightLocal *ldef)
deferredEntityCallback_t callback
Definition: RenderWorld.h:96
const idMaterial * material
Definition: tr_local.h:114
float projectionMatrix[16]
Definition: tr_local.h:372
idCVar r_useClippedLightScissors("r_useClippedLightScissors","1", CVAR_RENDERER|CVAR_INTEGER,"0 = full screen when near clipped, 1 = exact when near clipped, 2 = exact always", 0, 2, idCmdSystem::ArgCompletion_Integer< 0, 2 >)
bool IsDrawn(void) const
Definition: Material.h:378
void EvaluateRegisters(float *regs, const float entityParms[MAX_ENTITY_SHADER_PARMS], const struct viewDef_s *view, idSoundEmitter *soundEmitter=NULL) const
Definition: Material.cpp:2397
int maxDrawSurfs
Definition: tr_local.h:413
const idMaterial * customShader
Definition: RenderWorld.h:123
void * R_ClearedFrameAlloc(int bytes)
Definition: tr_main.cpp:417
bool ProjectionBounds(const idBounds &bounds, idBounds &projectionBounds) const
Definition: Frustum.cpp:2043
shadowFrustum_t shadowFrustums[6]
Definition: tr_local.h:224
idCVar r_skipSuppress("r_skipSuppress","0", CVAR_RENDERER|CVAR_BOOL,"ignore the per-view suppressions")
bool R_CullLocalBox(const idBounds &bounds, const float modelMatrix[16], int numPlanes, const idPlane *planes)
Definition: tr_main.cpp:675
bool isXraySubview
Definition: tr_local.h:391
const int MAX_ENTITY_SHADER_PARMS
Definition: Material.h:258
const idMaterial * lightShader
Definition: tr_local.h:326
struct srfTriangles_s * ambientSurface
Definition: Model.h:130
virtual dynamicModel_t IsDynamicModel() const =0
bool IsEmpty() const
Definition: tr_main.cpp:142
int suppressLightInViewID
Definition: RenderWorld.h:164
float shaderParms[MAX_ENTITY_SHADER_PARMS]
Definition: RenderWorld.h:201
backEndName_t backEndRenderer
Definition: tr_local.h:762
bool LightCastsShadows() const
Definition: Material.h:468
idBounds referenceBounds
Definition: tr_local.h:268
int c_clippedLight
Definition: tr_light.cpp:791
struct viewLight_s * next
Definition: tr_local.h:299
int suppressShadowInLightID
Definition: RenderWorld.h:109
struct viewLight_s * viewLights
Definition: tr_local.h:415
idPlane lightProject[4]
Definition: tr_local.h:211
idUserInterface * GlobalGui(void) const
Definition: Material.h:435
bool noDynamicInteractions
Definition: RenderWorld.h:144
virtual void VPCALL CreateSpecularTextureCoords(idVec4 *texCoords, const idVec3 &lightOrigin, const idVec3 &viewOrigin, const idDrawVert *verts, const int numVerts, const int *indexes, const int numIndexes)=0
idInteraction ** interactionTable
idFrustum viewFrustum
Definition: tr_local.h:422
bool backEndRendererHasVertexPrograms
Definition: tr_local.h:763
int dynamicModelFrameCount
Definition: tr_local.h:264
int viewSeesShadowPlaneBits
Definition: tr_local.h:320
GLuint GLuint GLsizei count
Definition: glext.h:2845
int registers[4]
Definition: Material.h:145
void AddPoint(float x, float y)
Definition: tr_main.cpp:58
void Clear()
Definition: tr_main.cpp:47
int GetNumPoints(void) const
Definition: Winding.h:238
idRenderModelDecal * decals
Definition: tr_local.h:282
GLuint index
Definition: glext.h:3476
void R_CreateVertexProgramShadowCache(srfTriangles_t *tri)
Definition: tr_light.cpp:156
const GLubyte * c
Definition: glext.h:4677
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:3454
Definition: Vector.h:808
idVec3 lightRadius
Definition: RenderWorld.h:178
struct viewEntity_s * next
Definition: tr_local.h:345
const shaderStage_t * GetStage(const int index) const
Definition: Material.h:368
idScreenRect R_ClippedLightScissorRectangle(viewLight_t *vLight)
Definition: tr_light.cpp:713
bool IsEmpty(void) const
Definition: Interaction.h:133
areaReference_t * references
Definition: tr_local.h:229
idBounds bounds
Definition: Model.h:87
idCVar r_lightSourceRadius("r_lightSourceRadius","0", CVAR_RENDERER|CVAR_FLOAT,"for soft-shadow sampling")
bool R_IssueEntityDefCallback(idRenderEntityLocal *def)
Definition: tr_light.cpp:1060
renderView_t renderView
Definition: tr_local.h:370
idCommon * common
Definition: Common.cpp:206
void Expand()
Definition: tr_main.cpp:81
bool weaponDepthHack
Definition: RenderWorld.h:149
idImage * falloffImage
Definition: tr_local.h:214
#define NULL
Definition: Lib.h:88
bool R_PreciseCullSurface(const drawSurf_t *drawSurf, idBounds &ndcBounds)
Definition: tr_subview.cpp:109
bool viewInsideLight
Definition: tr_local.h:311
srfTriangles_t * geometry
Definition: Model.h:147
const idDeclSkin * customSkin
Definition: RenderWorld.h:125
struct vertCache_s * dynamicTexCoords
Definition: tr_local.h:120
const idMaterial * R_RemapShaderBySkin(const idMaterial *shader, const idDeclSkin *skin, const idMaterial *customShader)
int GetInteger(void) const
Definition: CVarSystem.h:143
struct areaReference_s * ownerNext
Definition: tr_local.h:144
const int MAX_RENDERENTITY_GUI
Definition: RenderWorld.h:74
virtual const modelSurface_t * Surface(int surfaceNum) const =0
float modelDepthHack
Definition: RenderWorld.h:138
Definition: Plane.h:71
void Intersect(const idScreenRect &rect)
Definition: tr_main.cpp:93
void AddActiveInteraction(void)
idCVar r_useLightScissors("r_useLightScissors","1", CVAR_RENDERER|CVAR_BOOL,"1 = use custom scissor rectangle for each light")
int allowLightInViewID
Definition: RenderWorld.h:168
idCVar r_showLightScissors("r_showLightScissors","0", CVAR_RENDERER|CVAR_BOOL,"show light scissor rectangles")
struct vertCache_s * lightingCache
Definition: Model.h:138
colorStage_t color
Definition: Material.h:207
void Touch(vertCache_t *buffer)
const struct drawSurf_s * translucentInteractions
Definition: tr_local.h:334
idVec3 normal
Definition: DrawVert.h:44
shadowCache_t * shadowVertexes
Definition: Model.h:127
void 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)
Definition: tr_light.cpp:658
void R_TransformClipToDevice(const idPlane &clip, const viewDef_t *view, idVec3 &normalized)
Definition: tr_main.cpp:771
idScreenRect scissorRect
Definition: tr_local.h:355
int c_unclippedLight
Definition: tr_light.cpp:791
idRenderEntityLocal * entityDef
Definition: tr_local.h:348
struct vertCache_s * shadowCache
Definition: Model.h:139
idRenderModel * hModel
Definition: RenderWorld.h:81
GLubyte GLubyte GLubyte a
Definition: glext.h:4662
virtual void Printf(const char *fmt,...) id_attribute((format(printf
float modelMatrix[16]
Definition: tr_local.h:360
idCVar r_useInteractionTable("r_useInteractionTable","1", CVAR_RENDERER|CVAR_BOOL,"create a full entityDefs * lightDefs table to make finding interactions faster")
virtual idBounds Bounds(const struct renderEntity_s *ent=NULL) const =0
void MakeEmpty(void)
vertCache_t * AllocFrameTemp(void *data, int bytes)
const int * GetTexGenRegisters(void) const
Definition: Material.h:528
idRenderModel * cachedDynamicModel
Definition: tr_local.h:266
void R_TransformModelToClip(const idVec3 &src, const float *modelMatrix, const float *projectionMatrix, idPlane &eye, idPlane &dst)
Definition: tr_main.cpp:687
const float * shaderRegisters
Definition: tr_local.h:327
srfTriangles_t * frustumTris
Definition: tr_local.h:221
GLubyte GLubyte b
Definition: glext.h:4662
idPlane planes[6]
Definition: tr_local.h:127
idScreenRect R_CalcEntityScissorRectangle(viewEntity_t *vEntity)
Definition: tr_light.cpp:1440
void myGlMultMatrix(const float *a, const float *b, float *out)
idPlane fogPlane
Definition: tr_local.h:324
void R_GlobalPointToLocal(const float modelMatrix[16], const idVec3 &in, idVec3 &out)
Definition: tr_main.cpp:522
idVec3 vieworg
Definition: RenderWorld.h:215
viewDef_t * viewDef
Definition: tr_local.h:786
GLdouble GLdouble GLdouble r
Definition: glext.h:2951
idRenderModel * prelightModel
Definition: RenderWorld.h:194
const int GetNumRegisters() const
Definition: Material.h:575
void CreateLightDefInteractions(idRenderLightLocal *ldef)
Definition: tr_light.cpp:541
struct viewEntity_s * viewEntitys
Definition: tr_local.h:416
void R_RenderGuiSurf(idUserInterface *gui, drawSurf_t *drawSurf)
Definition: tr_guisurf.cpp:128
void R_AddLightSurfaces(void)
Definition: tr_light.cpp:875
bool GetBool(void) const
Definition: CVarSystem.h:142
const struct drawSurf_s * globalShadows
Definition: tr_local.h:330
const int INITIAL_DRAWSURFS
Definition: tr_local.h:508
tuple f
Definition: idal.py:89
const struct drawSurf_s * localInteractions
Definition: tr_local.h:331
void Alloc(void *data, int bytes, vertCache_t **buffer, bool indexBuffer=false)
idScreenRect R_CalcLightScissorRectangle(viewLight_t *vLight)
Definition: tr_light.cpp:793
GLsizeiptr size
Definition: glext.h:3112
idInteraction * entityNext
Definition: Interaction.h:110
idScreenRect scissor
Definition: tr_local.h:400
const struct drawSurf_s * nextOnLight
Definition: tr_local.h:117
bool R_CreateAmbientCache(srfTriangles_t *tri, bool needsLighting)
Definition: tr_light.cpp:52
idRenderModelDecal * Next(void) const
Definition: ModelDecal.h:88
idRenderModelOverlay * overlay
Definition: tr_local.h:283
float modelViewMatrix[16]
Definition: tr_local.h:361
idWinding * frustumWindings[6]
Definition: tr_local.h:220
struct portalArea_s * area
Definition: tr_local.h:147
class idSoundEmitter * referenceSound
Definition: RenderWorld.h:126
idRenderEntityLocal * entity
Definition: tr_local.h:145
class idUserInterface * gui[MAX_RENDERENTITY_GUI]
Definition: RenderWorld.h:130
bool IsFogLight() const
Definition: Material.h:458
areaReference_t entityRefs
int numDrawSurfs
Definition: tr_local.h:412
void * R_FrameAlloc(int bytes)
Definition: tr_main.cpp:365
glIndex_t * indexes
Definition: Model.h:102
idVertexCache vertexCache
Definition: VertexCache.cpp:41
void AddOverlaySurfacesToModel(idRenderModel *baseModel)
idRenderSystemLocal tr
int dsFlags
Definition: tr_local.h:119
idVec3 globalLightOrigin
Definition: tr_local.h:322
viewEntity_t * R_SetEntityDefViewEntity(idRenderEntityLocal *def)
Definition: tr_light.cpp:378
idPlane lightProject[4]
Definition: tr_local.h:323
struct areaReference_s * areaNext
Definition: tr_local.h:142
idGame * game
Definition: Game_local.cpp:65
short y1
Definition: tr_local.h:55
GLint j
Definition: qgl.h:264
GLuint GLenum GLenum transform
Definition: glext.h:5179
int numIndexes
Definition: Model.h:101
void R_WobbleskyTexGen(drawSurf_t *surf, const idVec3 &viewOrg)
Definition: tr_light.cpp:218
virtual int GetTimeGroupTime(int timeGroup)=0
idInteraction * firstInteraction
Definition: tr_local.h:286
idRenderWorldLocal * renderWorld
Definition: tr_local.h:375
struct vertCache_s * indexCache
Definition: Model.h:136
const srfTriangles_t * frustumTris
Definition: tr_local.h:325
renderEntity_t parms
Definition: tr_local.h:251
short y2
Definition: tr_local.h:55
void R_LocalPointToGlobal(const float modelMatrix[16], const idVec3 &in, idVec3 &out)
Definition: tr_main.cpp:470
idSoundEmitter * referenceSound
Definition: RenderWorld.h:202
virtual void Error(const char *fmt,...) id_attribute((format(printf
GLfloat GLfloat p
Definition: glext.h:4674
void R_DeformDrawSurf(drawSurf_t *drawSurf)
Definition: tr_deform.cpp:1228
idCVar r_useOptimizedShadows("r_useOptimizedShadows","1", CVAR_RENDERER|CVAR_BOOL,"use the dmap generated static shadow volumes")
void R_AxisToModelMatrix(const idMat3 &axis, const idVec3 &origin, float modelMatrix[16])
Definition: tr_main.cpp:445
GLdouble GLdouble z
Definition: glext.h:3067
bool ClipInPlace(const idPlane &plane, const float epsilon=ON_EPSILON, const bool keepOn=false)
Definition: Winding.cpp:349
struct lightingCache_s lightingCache_t
void R_ShowColoredScreenRect(const idScreenRect &rect, int colorIndex)
Definition: tr_main.cpp:172
float shaderParms[MAX_ENTITY_SHADER_PARMS]
Definition: RenderWorld.h:127
virtual void SelectTimeGroup(int timeGroup)=0
Definition: Box.h:40
const float * shaderRegisters
Definition: tr_local.h:116
void R_ClearEntityDefDynamicModel(idRenderEntityLocal *def)
idDrawVert * verts
Definition: Model.h:99
virtual float DepthHack() const =0
static float RSqrt(float x)
Definition: Math.h:241
struct viewLight_s * viewLight
Definition: tr_local.h:227
bool R_CreateLightingCache(const idRenderEntityLocal *ent, const idRenderLightLocal *light, srfTriangles_t *tri)
Definition: tr_light.cpp:75
idVec3 globalLightOrigin
Definition: tr_local.h:216
virtual int VPCALL CreateVertexProgramShadowCache(idVec4 *vertexCache, const idDrawVert *verts, const int numVerts)=0
idSIMDProcessor * SIMDProcessor
Definition: Simd.cpp:43
virtual int NumSurfaces() const =0