2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
29 #include "../idlib/precompiled.h"
39 "_prelight_<lightname>", ie "_prelight_light1"
41 Static surfaces available to dmap will be processed to optimized
42 shadow and lit surface geometry
44 Entity models are never prelighted.
46 Light entity can have a "noPrelight 1" key set to avoid the preprocessing
47 and carving of the world. A light that will move should usually have this
50 Prelight models will usually have multiple surfaces
52 Shadow volume surfaces will have the material "_shadowVolume"
54 The exact same vertexes as the ambient surfaces will be used for the
55 non-shadow surfaces, so there is opportunity to share
58 Reference their parent surfaces?
59 Reference their parent area?
62 If we don't track parts that are in different areas, there will be huge
63 losses when an areaportal closed door has a light poking slightly
66 There is potential benefit to splitting even the shadow volumes
67 at area boundaries, but it would involve the possibility of an
68 extra plane of shadow drawing at the area boundary.
71 interaction lightName numIndexes
75 Surfaces in the world cannot have "no self shadow" properties, because all
76 the surfaces are considered together for the optimized shadow volume. If
77 you want no self shadow on a static surface, you must still make it into an
78 entity so it isn't considered in the prelight.
86 each surface could include prelight indexes
88 generation procedure in dmap:
90 carve original surfaces into areas
93 build shadow volume and beam tree
94 cut all potentially lit surfaces into the beam tree
95 move lit fragments into a new optimize group
107 =================================================================================
111 =================================================================================
119 Modifies the shaderParms on all the lights so the level
120 designers can easily test different color schemes
123 void R_ModulateLights_f( const idCmdArgs &args ) {
124 if ( !tr.primaryWorld ) {
127 if ( args.Argc() != 4 ) {
128 common->Printf( "usage: modulateLights <redFloat> <greenFloat> <blueFloat>\n" );
134 for ( i = 0 ; i < 3 ; i++ ) {
135 modulate[i] = atof( args.Argv( i+1 ) );
139 for ( i = 0 ; i < tr.primaryWorld->lightDefs.Num() ; i++ ) {
140 idRenderLightLocal *light;
142 light = tr.primaryWorld->lightDefs[i];
145 for ( int j = 0 ; j < 3 ; j++ ) {
146 light->parms.shaderParms[j] *= modulate[j];
150 common->Printf( "modulated %i lights\n", count );
155 //======================================================================================
162 Creates all needed model references in portal areas,
163 chaining them to both the area and the entityDef.
168 void R_CreateEntityRefs( idRenderEntityLocal *def ) {
170 idVec3 transformed[8];
173 if ( !def->parms.hModel ) {
174 def->parms.hModel = renderModelManager->DefaultModel();
177 // if the entity hasn't been fully specified due to expensive animation calcs
178 // for md5 and particles, use the provided conservative bounds.
179 if ( def->parms.callback ) {
180 def->referenceBounds = def->parms.bounds;
182 def->referenceBounds = def->parms.hModel->Bounds( &def->parms );
185 // some models, like empty particles, may not need to be added at all
186 if ( def->referenceBounds.IsCleared() ) {
190 if ( r_showUpdates.GetBool() &&
191 ( def->referenceBounds[1][0] - def->referenceBounds[0][0] > 1024 ||
192 def->referenceBounds[1][1] - def->referenceBounds[0][1] > 1024 ) ) {
193 common->Printf( "big entityRef: %f,%f\n", def->referenceBounds[1][0] - def->referenceBounds[0][0],
194 def->referenceBounds[1][1] - def->referenceBounds[0][1] );
197 for (i = 0 ; i < 8 ; i++) {
198 v[0] = def->referenceBounds[i&1][0];
199 v[1] = def->referenceBounds[(i>>1)&1][1];
200 v[2] = def->referenceBounds[(i>>2)&1][2];
202 R_LocalPointToGlobal( def->modelMatrix, v, transformed[i] );
205 // bump the view count so we can tell if an
206 // area already has a reference
209 // push these points down the BSP tree into areas
210 def->world->PushVolumeIntoTree( def, NULL, 8, transformed );
215 =================================================================================
219 =================================================================================
223 =====================
226 All values are reletive to the origin
227 Assumes that right and up are not normalized
228 This is also called by dmap during map processing.
229 =====================
231 void R_SetLightProject( idPlane lightProject[4], const idVec3 origin, const idVec3 target,
232 const idVec3 rightVector, const idVec3 upVector, const idVec3 start, const idVec3 stop ) {
243 rLen = right.Normalize();
245 uLen = up.Normalize();
246 normal = up.Cross( right );
247 //normal = right.Cross( up );
250 dist = target * normal; // - ( origin * normal );
256 scale = ( 0.5f * dist ) / rLen;
258 scale = -( 0.5f * dist ) / uLen;
261 lightProject[2] = normal;
262 lightProject[2][3] = -( origin * lightProject[2].Normal() );
264 lightProject[0] = right;
265 lightProject[0][3] = -( origin * lightProject[0].Normal() );
267 lightProject[1] = up;
268 lightProject[1][3] = -( origin * lightProject[1].Normal() );
270 // now offset to center
271 targetGlobal.ToVec3() = target + origin;
273 ofs = 0.5f - ( targetGlobal * lightProject[0].ToVec4() ) / ( targetGlobal * lightProject[2].ToVec4() );
274 lightProject[0].ToVec4() += ofs * lightProject[2].ToVec4();
275 ofs = 0.5f - ( targetGlobal * lightProject[1].ToVec4() ) / ( targetGlobal * lightProject[2].ToVec4() );
276 lightProject[1].ToVec4() += ofs * lightProject[2].ToVec4();
278 // set the falloff vector
279 normal = stop - start;
280 dist = normal.Normalize();
284 lightProject[3] = normal * ( 1.0f / dist );
285 startGlobal = start + origin;
286 lightProject[3][3] = -( startGlobal * lightProject[3].Normal() );
293 Creates plane equations from the light projection, positive sides
294 face out of the light
297 void R_SetLightFrustum( const idPlane lightProject[4], idPlane frustum[6] ) {
300 // we want the planes of s=0, s=q, t=0, and t=q
301 frustum[0] = lightProject[0];
302 frustum[1] = lightProject[1];
303 frustum[2] = lightProject[2] - lightProject[0];
304 frustum[3] = lightProject[2] - lightProject[1];
306 // we want the planes of s=0 and s=1 for front and rear clipping planes
307 frustum[4] = lightProject[3];
309 frustum[5] = lightProject[3];
310 frustum[5][3] -= 1.0f;
311 frustum[5] = -frustum[5];
313 for ( i = 0 ; i < 6 ; i++ ) {
316 frustum[i] = -frustum[i];
317 l = frustum[i].Normalize();
324 R_FreeLightDefFrustum
327 void R_FreeLightDefFrustum( idRenderLightLocal *ldef ) {
330 // free the frustum tris
331 if ( ldef->frustumTris ) {
332 R_FreeStaticTriSurf( ldef->frustumTris );
333 ldef->frustumTris = NULL;
335 // free frustum windings
336 for ( i = 0; i < 6; i++ ) {
337 if ( ldef->frustumWindings[i] ) {
338 delete ldef->frustumWindings[i];
339 ldef->frustumWindings[i] = NULL;
348 Fills everything in based on light->parms
351 void R_DeriveLightData( idRenderLightLocal *light ) {
354 // decide which light shader we are going to use
355 if ( light->parms.shader ) {
356 light->lightShader = light->parms.shader;
358 if ( !light->lightShader ) {
359 if ( light->parms.pointLight ) {
360 light->lightShader = declManager->FindMaterial( "lights/defaultPointLight" );
362 light->lightShader = declManager->FindMaterial( "lights/defaultProjectedLight" );
366 // get the falloff image
367 light->falloffImage = light->lightShader->LightFalloffImage();
368 if ( !light->falloffImage ) {
369 // use the falloff from the default shader of the correct type
370 const idMaterial *defaultShader;
372 if ( light->parms.pointLight ) {
373 defaultShader = declManager->FindMaterial( "lights/defaultPointLight" );
374 light->falloffImage = defaultShader->LightFalloffImage();
376 // projected lights by default don't diminish with distance
377 defaultShader = declManager->FindMaterial( "lights/defaultProjectedLight" );
378 light->falloffImage = defaultShader->LightFalloffImage();
382 // set the projection
383 if ( !light->parms.pointLight ) {
386 R_SetLightProject( light->lightProject, vec3_origin /* light->parms.origin */, light->parms.target,
387 light->parms.right, light->parms.up, light->parms.start, light->parms.end);
390 memset( light->lightProject, 0, sizeof( light->lightProject ) );
391 light->lightProject[0][0] = 0.5f / light->parms.lightRadius[0];
392 light->lightProject[1][1] = 0.5f / light->parms.lightRadius[1];
393 light->lightProject[3][2] = 0.5f / light->parms.lightRadius[2];
394 light->lightProject[0][3] = 0.5f;
395 light->lightProject[1][3] = 0.5f;
396 light->lightProject[2][3] = 1.0f;
397 light->lightProject[3][3] = 0.5f;
400 // set the frustum planes
401 R_SetLightFrustum( light->lightProject, light->frustum );
403 // rotate the light planes and projections by the axis
404 R_AxisToModelMatrix( light->parms.axis, light->parms.origin, light->modelMatrix );
406 for ( i = 0 ; i < 6 ; i++ ) {
408 temp = light->frustum[i];
409 R_LocalPlaneToGlobal( light->modelMatrix, temp, light->frustum[i] );
411 for ( i = 0 ; i < 4 ; i++ ) {
413 temp = light->lightProject[i];
414 R_LocalPlaneToGlobal( light->modelMatrix, temp, light->lightProject[i] );
417 // adjust global light origin for off center projections and parallel projections
418 // we are just faking parallel by making it a very far off center for now
419 if ( light->parms.parallel ) {
422 dir = light->parms.lightCenter;
423 if ( !dir.Normalize() ) {
424 // make point straight up if not specified
427 light->globalLightOrigin = light->parms.origin + dir * 100000;
429 light->globalLightOrigin = light->parms.origin + light->parms.axis * light->parms.lightCenter;
432 R_FreeLightDefFrustum( light );
434 light->frustumTris = R_PolytopeSurface( 6, light->frustum, light->frustumWindings );
436 // a projected light will have one shadowFrustum, a point light will have
437 // six unless the light center is outside the box
438 R_MakeShadowFrustums( light );
446 #define MAX_LIGHT_VERTS 40
447 void R_CreateLightRefs( idRenderLightLocal *light ) {
448 idVec3 points[MAX_LIGHT_VERTS];
452 tri = light->frustumTris;
454 // because a light frustum is made of only six intersecting planes,
455 // we should never be able to get a stupid number of points...
456 if ( tri->numVerts > MAX_LIGHT_VERTS ) {
457 common->Error( "R_CreateLightRefs: %i points in frustumTris!", tri->numVerts );
459 for ( i = 0 ; i < tri->numVerts ; i++ ) {
460 points[i] = tri->verts[i].xyz;
463 if ( r_showUpdates.GetBool() && ( tri->bounds[1][0] - tri->bounds[0][0] > 1024 ||
464 tri->bounds[1][1] - tri->bounds[0][1] > 1024 ) ) {
465 common->Printf( "big lightRef: %f,%f\n", tri->bounds[1][0] - tri->bounds[0][0]
466 ,tri->bounds[1][1] - tri->bounds[0][1] );
469 // determine the areaNum for the light origin, which may let us
470 // cull the light if it is behind a closed door
471 // it is debatable if we want to use the entity origin or the center offset origin,
472 // but we definitely don't want to use a parallel offset origin
473 light->areaNum = light->world->PointInArea( light->globalLightOrigin );
474 if ( light->areaNum == -1 ) {
475 light->areaNum = light->world->PointInArea( light->parms.origin );
478 // bump the view count so we can tell if an
479 // area already has a reference
482 // if we have a prelight model that includes all the shadows for the major world occluders,
483 // we can limit the area references to those visible through the portals from the light center.
484 // We can't do this in the normal case, because shadows are cast from back facing triangles, which
485 // may be in areas not directly visible to the light projection center.
486 if ( light->parms.prelightModel && r_useLightPortalFlow.GetBool() && light->lightShader->LightCastsShadows() ) {
487 light->world->FlowLightThroughPortals( light );
489 // push these points down the BSP tree into areas
490 light->world->PushVolumeIntoTree( NULL, light, tri->numVerts, points );
498 Called by the editor and dmap to operate on light volumes
501 void R_RenderLightFrustum( const renderLight_t &renderLight, idPlane lightFrustum[6] ) {
502 idRenderLightLocal fakeLight;
504 memset( &fakeLight, 0, sizeof( fakeLight ) );
505 fakeLight.parms = renderLight;
507 R_DeriveLightData( &fakeLight );
509 R_FreeStaticTriSurf( fakeLight.frustumTris );
511 for ( int i = 0 ; i < 6 ; i++ ) {
512 lightFrustum[i] = fakeLight.frustum[i];
517 //=================================================================================
521 WindingCompletelyInsideLight
524 bool WindingCompletelyInsideLight( const idWinding *w, const idRenderLightLocal *ldef ) {
527 for ( i = 0 ; i < w->GetNumPoints() ; i++ ) {
528 for ( j = 0 ; j < 6 ; j++ ) {
531 d = (*w)[i].ToVec3() * ldef->frustum[j].Normal() + ldef->frustum[j][3];
541 ======================
542 R_CreateLightDefFogPortals
544 When a fog light is created or moved, see if it completely
545 encloses any portals, which may allow them to be fogged closed.
546 ======================
548 void R_CreateLightDefFogPortals( idRenderLightLocal *ldef ) {
549 areaReference_t *lref;
552 ldef->foggedPortals = NULL;
554 if ( !ldef->lightShader->IsFogLight() ) {
558 // some fog lights will explicitly disallow portal fogging
559 if ( ldef->lightShader->TestMaterialFlag( MF_NOPORTALFOG ) ) {
563 for ( lref = ldef->references ; lref ; lref = lref->ownerNext ) {
564 // check all the models in this area
570 for ( prt = area->portals ; prt ; prt = prt->next ) {
571 dp = prt->doublePortal;
573 // we only handle a single fog volume covering a portal
574 // this will never cause incorrect drawing, but it may
575 // fail to cull a portal
576 if ( dp->fogLight ) {
580 if ( WindingCompletelyInsideLight( prt->w, ldef ) ) {
582 dp->nextFoggedPortal = ldef->foggedPortals;
583 ldef->foggedPortals = dp;
591 R_FreeLightDefDerivedData
593 Frees all references and lit surfaces from the light
596 void R_FreeLightDefDerivedData( idRenderLightLocal *ldef ) {
597 areaReference_t *lref, *nextRef;
599 // rmove any portal fog references
600 for ( doublePortal_t *dp = ldef->foggedPortals ; dp ; dp = dp->nextFoggedPortal ) {
604 // free all the interactions
605 while ( ldef->firstInteraction != NULL ) {
606 ldef->firstInteraction->UnlinkAndFree();
609 // free all the references to the light
610 for ( lref = ldef->references ; lref ; lref = nextRef ) {
611 nextRef = lref->ownerNext;
613 // unlink from the area
614 lref->areaNext->areaPrev = lref->areaPrev;
615 lref->areaPrev->areaNext = lref->areaNext;
617 // put it back on the free list for reuse
618 ldef->world->areaReferenceAllocator.Free( lref );
620 ldef->references = NULL;
622 R_FreeLightDefFrustum( ldef );
627 R_FreeEntityDefDerivedData
629 Used by both RE_FreeEntityDef and RE_UpdateEntityDef
630 Does not actually free the entityDef.
633 void R_FreeEntityDefDerivedData( idRenderEntityLocal *def, bool keepDecals, bool keepCachedDynamicModel ) {
635 areaReference_t *ref, *next;
637 // demo playback needs to free the joints, while normal play
638 // leaves them in the control of the game
639 if ( session->readDemo ) {
640 if ( def->parms.joints ) {
641 Mem_Free16( def->parms.joints );
642 def->parms.joints = NULL;
644 if ( def->parms.callbackData ) {
645 Mem_Free( def->parms.callbackData );
646 def->parms.callbackData = NULL;
648 for ( i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
649 if ( def->parms.gui[ i ] ) {
650 delete def->parms.gui[ i ];
651 def->parms.gui[ i ] = NULL;
656 // free all the interactions
657 while ( def->firstInteraction != NULL ) {
658 def->firstInteraction->UnlinkAndFree();
661 // clear the dynamic model if present
662 if ( def->dynamicModel ) {
663 def->dynamicModel = NULL;
667 R_FreeEntityDefDecals( def );
668 R_FreeEntityDefOverlay( def );
671 if ( !keepCachedDynamicModel ) {
672 delete def->cachedDynamicModel;
673 def->cachedDynamicModel = NULL;
676 // free the entityRefs from the areas
677 for ( ref = def->entityRefs ; ref ; ref = next ) {
678 next = ref->ownerNext;
680 // unlink from the area
681 ref->areaNext->areaPrev = ref->areaPrev;
682 ref->areaPrev->areaNext = ref->areaNext;
684 // put it back on the free list for reuse
685 def->world->areaReferenceAllocator.Free( ref );
687 def->entityRefs = NULL;
692 R_ClearEntityDefDynamicModel
694 If we know the reference bounds stays the same, we
695 only need to do this on entity update, not the full
696 R_FreeEntityDefDerivedData
699 void R_ClearEntityDefDynamicModel( idRenderEntityLocal *def ) {
700 // free all the interaction surfaces
701 for( idInteraction *inter = def->firstInteraction; inter != NULL && !inter->IsEmpty(); inter = inter->entityNext ) {
702 inter->FreeSurfaces();
705 // clear the dynamic model if present
706 if ( def->dynamicModel ) {
707 def->dynamicModel = NULL;
713 R_FreeEntityDefDecals
716 void R_FreeEntityDefDecals( idRenderEntityLocal *def ) {
717 while( def->decals ) {
718 idRenderModelDecal *next = def->decals->Next();
719 idRenderModelDecal::Free( def->decals );
726 R_FreeEntityDefFadedDecals
729 void R_FreeEntityDefFadedDecals( idRenderEntityLocal *def, int time ) {
730 def->decals = idRenderModelDecal::RemoveFadedDecals( def->decals, time );
735 R_FreeEntityDefOverlay
738 void R_FreeEntityDefOverlay( idRenderEntityLocal *def ) {
739 if ( def->overlay ) {
740 idRenderModelOverlay::Free( def->overlay );
749 ReloadModels and RegenerateWorld call this
750 // FIXME: need to do this for all worlds
753 void R_FreeDerivedData( void ) {
755 idRenderWorldLocal *rw;
756 idRenderEntityLocal *def;
757 idRenderLightLocal *light;
759 for ( j = 0; j < tr.worlds.Num(); j++ ) {
762 for ( i = 0; i < rw->entityDefs.Num(); i++ ) {
763 def = rw->entityDefs[i];
767 R_FreeEntityDefDerivedData( def, false, false );
770 for ( i = 0; i < rw->lightDefs.Num(); i++ ) {
771 light = rw->lightDefs[i];
775 R_FreeLightDefDerivedData( light );
782 R_CheckForEntityDefsUsingModel
785 void R_CheckForEntityDefsUsingModel( idRenderModel *model ) {
787 idRenderWorldLocal *rw;
788 idRenderEntityLocal *def;
790 for ( j = 0; j < tr.worlds.Num(); j++ ) {
793 for ( i = 0 ; i < rw->entityDefs.Num(); i++ ) {
794 def = rw->entityDefs[i];
798 if ( def->parms.hModel == model ) {
800 // this should never happen but Radiant messes it up all the time so just free the derived data
801 R_FreeEntityDefDerivedData( def, false, false );
809 R_ReCreateWorldReferences
811 ReloadModels and RegenerateWorld call this
812 // FIXME: need to do this for all worlds
815 void R_ReCreateWorldReferences( void ) {
817 idRenderWorldLocal *rw;
818 idRenderEntityLocal *def;
819 idRenderLightLocal *light;
821 // let the interaction generation code know this shouldn't be optimized for
825 for ( j = 0; j < tr.worlds.Num(); j++ ) {
828 for ( i = 0 ; i < rw->entityDefs.Num() ; i++ ) {
829 def = rw->entityDefs[i];
833 // the world model entities are put specifically in a single
834 // area, instead of just pushing their bounds into the tree
835 if ( i < rw->numPortalAreas ) {
836 rw->AddEntityRefToArea( def, &rw->portalAreas[i] );
838 R_CreateEntityRefs( def );
842 for ( i = 0 ; i < rw->lightDefs.Num() ; i++ ) {
843 light = rw->lightDefs[i];
847 renderLight_t parms = light->parms;
849 light->world->FreeLightDef( i );
850 rw->UpdateLightDef( i, &parms );
859 Frees and regenerates all references and interactions, which
860 must be done when switching between display list mode and immediate mode
863 void R_RegenerateWorld_f( const idCmdArgs &args ) {
866 // watch how much memory we allocate
867 tr.staticAllocCount = 0;
869 R_ReCreateWorldReferences();
871 common->Printf( "Regenerated world, staticAllocCount = %i.\n", tr.staticAllocCount );