123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition 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 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- 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.
- ===========================================================================
- */
- #pragma hdrstop
- #include "../idlib/precompiled.h"
- #include "tr_local.h"
- /*
- =================================================================================
- ENTITY DEFS
- =================================================================================
- */
- /*
- =================
- R_DeriveEntityData
- =================
- */
- void R_DeriveEntityData( idRenderEntityLocal * entity ) {
- R_AxisToModelMatrix( entity->parms.axis, entity->parms.origin, entity->modelMatrix );
- idRenderMatrix::CreateFromOriginAxis( entity->parms.origin, entity->parms.axis, entity->modelRenderMatrix );
- // calculate the matrix that transforms the unit cube to exactly cover the model in world space
- idRenderMatrix::OffsetScaleForBounds( entity->modelRenderMatrix, entity->localReferenceBounds, entity->inverseBaseModelProject );
- // calculate the global model bounds by inverse projecting the unit cube with the 'inverseBaseModelProject'
- idRenderMatrix::ProjectedBounds( entity->globalReferenceBounds, entity->inverseBaseModelProject, bounds_unitCube, false );
- }
- /*
- ===================
- R_FreeEntityDefDerivedData
- Used by both FreeEntityDef and UpdateEntityDef
- Does not actually free the entityDef.
- ===================
- */
- void R_FreeEntityDefDerivedData( idRenderEntityLocal *def, bool keepDecals, bool keepCachedDynamicModel ) {
- // demo playback needs to free the joints, while normal play
- // leaves them in the control of the game
- if ( common->ReadDemo() ) {
- if ( def->parms.joints ) {
- Mem_Free16( def->parms.joints );
- def->parms.joints = NULL;
- }
- if ( def->parms.callbackData ) {
- Mem_Free( def->parms.callbackData );
- def->parms.callbackData = NULL;
- }
- for ( int i = 0; i < MAX_RENDERENTITY_GUI; i++ ) {
- if ( def->parms.gui[ i ] ) {
- delete def->parms.gui[ i ];
- def->parms.gui[ i ] = NULL;
- }
- }
- }
- // free all the interactions
- while ( def->firstInteraction != NULL ) {
- def->firstInteraction->UnlinkAndFree();
- }
- def->dynamicModelFrameCount = 0;
- // clear the dynamic model if present
- if ( def->dynamicModel ) {
- def->dynamicModel = NULL;
- }
- if ( !keepDecals ) {
- R_FreeEntityDefDecals( def );
- R_FreeEntityDefOverlay( def );
- }
- if ( !keepCachedDynamicModel ) {
- delete def->cachedDynamicModel;
- def->cachedDynamicModel = NULL;
- }
- // free the entityRefs from the areas
- areaReference_t * next = NULL;
- for ( areaReference_t * ref = def->entityRefs; ref != NULL; ref = next ) {
- next = ref->ownerNext;
- // unlink from the area
- ref->areaNext->areaPrev = ref->areaPrev;
- ref->areaPrev->areaNext = ref->areaNext;
- // put it back on the free list for reuse
- def->world->areaReferenceAllocator.Free( ref );
- }
- def->entityRefs = NULL;
- }
- /*
- ===================
- R_FreeEntityDefDecals
- ===================
- */
- void R_FreeEntityDefDecals( idRenderEntityLocal *def ) {
- def->decals = NULL;
- }
- /*
- ===================
- R_FreeEntityDefFadedDecals
- ===================
- */
- void R_FreeEntityDefFadedDecals( idRenderEntityLocal *def, int time ) {
- if ( def->decals != NULL ) {
- def->decals->RemoveFadedDecals( time );
- }
- }
- /*
- ===================
- R_FreeEntityDefOverlay
- ===================
- */
- void R_FreeEntityDefOverlay( idRenderEntityLocal *def ) {
- def->overlays = NULL;
- }
- /*
- ===============
- R_CreateEntityRefs
- Creates all needed model references in portal areas,
- chaining them to both the area and the entityDef.
- Bumps tr.viewCount, which means viewCount can change many times each frame.
- ===============
- */
- void R_CreateEntityRefs( idRenderEntityLocal *entity ) {
- if ( entity->parms.hModel == NULL ) {
- entity->parms.hModel = renderModelManager->DefaultModel();
- }
- // if the entity hasn't been fully specified due to expensive animation calcs
- // for md5 and particles, use the provided conservative bounds.
- if ( entity->parms.callback != NULL ) {
- entity->localReferenceBounds = entity->parms.bounds;
- } else {
- entity->localReferenceBounds = entity->parms.hModel->Bounds( &entity->parms );
- }
- // some models, like empty particles, may not need to be added at all
- if ( entity->localReferenceBounds.IsCleared() ) {
- return;
- }
- if ( r_showUpdates.GetBool() &&
- ( entity->localReferenceBounds[1][0] - entity->localReferenceBounds[0][0] > 1024.0f ||
- entity->localReferenceBounds[1][1] - entity->localReferenceBounds[0][1] > 1024.0f ) ) {
- common->Printf( "big entityRef: %f,%f\n", entity->localReferenceBounds[1][0] - entity->localReferenceBounds[0][0],
- entity->localReferenceBounds[1][1] - entity->localReferenceBounds[0][1] );
- }
- // derive entity data
- R_DeriveEntityData( entity );
- // bump the view count so we can tell if an
- // area already has a reference
- tr.viewCount++;
- // push the model frustum down the BSP tree into areas
- entity->world->PushFrustumIntoTree( entity, NULL, entity->inverseBaseModelProject, bounds_unitCube );
- }
- /*
- =================================================================================
- LIGHT DEFS
- =================================================================================
- */
- /*
- ========================
- R_ComputePointLightProjectionMatrix
- Computes the light projection matrix for a point light.
- ========================
- */
- static float R_ComputePointLightProjectionMatrix( idRenderLightLocal * light, idRenderMatrix & localProject ) {
- assert( light->parms.pointLight );
- // A point light uses a box projection.
- // This projects into the 0.0 - 1.0 texture range instead of -1.0 to 1.0 clip space range.
- localProject.Zero();
- localProject[0][0] = 0.5f / light->parms.lightRadius[0];
- localProject[1][1] = 0.5f / light->parms.lightRadius[1];
- localProject[2][2] = 0.5f / light->parms.lightRadius[2];
- localProject[0][3] = 0.5f;
- localProject[1][3] = 0.5f;
- localProject[2][3] = 0.5f;
- localProject[3][3] = 1.0f; // identity perspective
- return 1.0f;
- }
- static const float SPOT_LIGHT_MIN_Z_NEAR = 8.0f;
- static const float SPOT_LIGHT_MIN_Z_FAR = 16.0f;
- /*
- ========================
- R_ComputeSpotLightProjectionMatrix
- Computes the light projection matrix for a spot light.
- ========================
- */
- static float R_ComputeSpotLightProjectionMatrix( idRenderLightLocal * light, idRenderMatrix & localProject ) {
- const float targetDistSqr = light->parms.target.LengthSqr();
- const float invTargetDist = idMath::InvSqrt( targetDistSqr );
- const float targetDist = invTargetDist * targetDistSqr;
- const idVec3 normalizedTarget = light->parms.target * invTargetDist;
- const idVec3 normalizedRight = light->parms.right * ( 0.5f * targetDist / light->parms.right.LengthSqr() );
- const idVec3 normalizedUp = light->parms.up * ( -0.5f * targetDist / light->parms.up.LengthSqr() );
- localProject[0][0] = normalizedRight[0];
- localProject[0][1] = normalizedRight[1];
- localProject[0][2] = normalizedRight[2];
- localProject[0][3] = 0.0f;
- localProject[1][0] = normalizedUp[0];
- localProject[1][1] = normalizedUp[1];
- localProject[1][2] = normalizedUp[2];
- localProject[1][3] = 0.0f;
- localProject[3][0] = normalizedTarget[0];
- localProject[3][1] = normalizedTarget[1];
- localProject[3][2] = normalizedTarget[2];
- localProject[3][3] = 0.0f;
- // Set the falloff vector.
- // This is similar to the Z calculation for depth buffering, which means that the
- // mapped texture is going to be perspective distorted heavily towards the zero end.
- const float zNear = Max( light->parms.start * normalizedTarget, SPOT_LIGHT_MIN_Z_NEAR );
- const float zFar = Max( light->parms.end * normalizedTarget, SPOT_LIGHT_MIN_Z_FAR );
- const float zScale = ( zNear + zFar ) / zFar;
- localProject[2][0] = normalizedTarget[0] * zScale;
- localProject[2][1] = normalizedTarget[1] * zScale;
- localProject[2][2] = normalizedTarget[2] * zScale;
- localProject[2][3] = - zNear * zScale;
- // now offset to the 0.0 - 1.0 texture range instead of -1.0 to 1.0 clip space range
- idVec4 projectedTarget;
- localProject.TransformPoint( light->parms.target, projectedTarget );
- const float ofs0 = 0.5f - projectedTarget[0] / projectedTarget[3];
- localProject[0][0] += ofs0 * localProject[3][0];
- localProject[0][1] += ofs0 * localProject[3][1];
- localProject[0][2] += ofs0 * localProject[3][2];
- localProject[0][3] += ofs0 * localProject[3][3];
- const float ofs1 = 0.5f - projectedTarget[1] / projectedTarget[3];
- localProject[1][0] += ofs1 * localProject[3][0];
- localProject[1][1] += ofs1 * localProject[3][1];
- localProject[1][2] += ofs1 * localProject[3][2];
- localProject[1][3] += ofs1 * localProject[3][3];
- return 1.0f / ( zNear + zFar );
- }
- /*
- ========================
- R_ComputeParallelLightProjectionMatrix
- Computes the light projection matrix for a parallel light.
- ========================
- */
- static float R_ComputeParallelLightProjectionMatrix( idRenderLightLocal * light, idRenderMatrix & localProject ) {
- assert( light->parms.parallel );
- // A parallel light uses a box projection.
- // This projects into the 0.0 - 1.0 texture range instead of -1.0 to 1.0 clip space range.
- localProject.Zero();
- localProject[0][0] = 0.5f / light->parms.lightRadius[0];
- localProject[1][1] = 0.5f / light->parms.lightRadius[1];
- localProject[2][2] = 0.5f / light->parms.lightRadius[2];
- localProject[0][3] = 0.5f;
- localProject[1][3] = 0.5f;
- localProject[2][3] = 0.5f;
- localProject[3][3] = 1.0f; // identity perspective
- return 1.0f;
- }
- /*
- =================
- R_DeriveLightData
- Fills everything in based on light->parms
- =================
- */
- static void R_DeriveLightData( idRenderLightLocal * light ) {
- // decide which light shader we are going to use
- if ( light->parms.shader != NULL ) {
- light->lightShader = light->parms.shader;
- } else if ( light->lightShader == NULL ) {
- if ( light->parms.pointLight ) {
- light->lightShader = tr.defaultPointLight;
- } else {
- light->lightShader = tr.defaultProjectedLight;
- }
- }
- // get the falloff image
- light->falloffImage = light->lightShader->LightFalloffImage();
- if ( light->falloffImage == NULL ) {
- // use the falloff from the default shader of the correct type
- const idMaterial * defaultShader;
- if ( light->parms.pointLight ) {
- defaultShader = tr.defaultPointLight;
- // Touch the default shader. to make sure it's decl has been parsed ( it might have been purged ).
- declManager->Touch( static_cast< const idDecl *>( defaultShader ) );
- light->falloffImage = defaultShader->LightFalloffImage();
- } else {
- // projected lights by default don't diminish with distance
- defaultShader = tr.defaultProjectedLight;
- // Touch the light shader. to make sure it's decl has been parsed ( it might have been purged ).
- declManager->Touch( static_cast< const idDecl *>( defaultShader ) );
- light->falloffImage = defaultShader->LightFalloffImage();
- }
- }
- // ------------------------------------
- // compute the light projection matrix
- // ------------------------------------
- idRenderMatrix localProject;
- float zScale = 1.0f;
- if ( light->parms.parallel ) {
- zScale = R_ComputeParallelLightProjectionMatrix( light, localProject );
- } else if ( light->parms.pointLight ) {
- zScale = R_ComputePointLightProjectionMatrix( light, localProject );
- } else {
- zScale = R_ComputeSpotLightProjectionMatrix( light, localProject );
- }
- // set the old style light projection where Z and W are flipped and
- // for projected lights lightProject[3] is divided by ( zNear + zFar )
- light->lightProject[0][0] = localProject[0][0];
- light->lightProject[0][1] = localProject[0][1];
- light->lightProject[0][2] = localProject[0][2];
- light->lightProject[0][3] = localProject[0][3];
- light->lightProject[1][0] = localProject[1][0];
- light->lightProject[1][1] = localProject[1][1];
- light->lightProject[1][2] = localProject[1][2];
- light->lightProject[1][3] = localProject[1][3];
- light->lightProject[2][0] = localProject[3][0];
- light->lightProject[2][1] = localProject[3][1];
- light->lightProject[2][2] = localProject[3][2];
- light->lightProject[2][3] = localProject[3][3];
- light->lightProject[3][0] = localProject[2][0] * zScale;
- light->lightProject[3][1] = localProject[2][1] * zScale;
- light->lightProject[3][2] = localProject[2][2] * zScale;
- light->lightProject[3][3] = localProject[2][3] * zScale;
- // transform the lightProject
- float lightTransform[16];
- R_AxisToModelMatrix( light->parms.axis, light->parms.origin, lightTransform );
- for ( int i = 0; i < 4; i++ ) {
- idPlane temp = light->lightProject[i];
- R_LocalPlaneToGlobal( lightTransform, temp, light->lightProject[i] );
- }
- // adjust global light origin for off center projections and parallel projections
- // we are just faking parallel by making it a very far off center for now
- if ( light->parms.parallel ) {
- idVec3 dir = light->parms.lightCenter;
- if ( dir.Normalize() == 0.0f ) {
- // make point straight up if not specified
- dir[2] = 1.0f;
- }
- light->globalLightOrigin = light->parms.origin + dir * 100000.0f;
- } else {
- light->globalLightOrigin = light->parms.origin + light->parms.axis * light->parms.lightCenter;
- }
- // Rotate and translate the light projection by the light matrix.
- // 99% of lights remain axis aligned in world space.
- idRenderMatrix lightMatrix;
- idRenderMatrix::CreateFromOriginAxis( light->parms.origin, light->parms.axis, lightMatrix );
- idRenderMatrix inverseLightMatrix;
- if ( !idRenderMatrix::Inverse( lightMatrix, inverseLightMatrix ) ) {
- idLib::Warning( "lightMatrix invert failed" );
- }
- // 'baseLightProject' goes from global space -> light local space -> light projective space
- idRenderMatrix::Multiply( localProject, inverseLightMatrix, light->baseLightProject );
- // Invert the light projection so we can deform zero-to-one cubes into
- // the light model and calculate global bounds.
- if ( !idRenderMatrix::Inverse( light->baseLightProject, light->inverseBaseLightProject ) ) {
- idLib::Warning( "baseLightProject invert failed" );
- }
- // calculate the global light bounds by inverse projecting the zero to one cube with the 'inverseBaseLightProject'
- idRenderMatrix::ProjectedBounds( light->globalLightBounds, light->inverseBaseLightProject, bounds_zeroOneCube, false );
- }
- /*
- ====================
- R_FreeLightDefDerivedData
- Frees all references and lit surfaces from the light
- ====================
- */
- void R_FreeLightDefDerivedData( idRenderLightLocal *ldef ) {
- // remove any portal fog references
- for ( doublePortal_t *dp = ldef->foggedPortals; dp != NULL; dp = dp->nextFoggedPortal ) {
- dp->fogLight = NULL;
- }
- // free all the interactions
- while ( ldef->firstInteraction != NULL ) {
- ldef->firstInteraction->UnlinkAndFree();
- }
- // free all the references to the light
- areaReference_t * nextRef = NULL;
- for ( areaReference_t * lref = ldef->references; lref != NULL; lref = nextRef ) {
- nextRef = lref->ownerNext;
- // unlink from the area
- lref->areaNext->areaPrev = lref->areaPrev;
- lref->areaPrev->areaNext = lref->areaNext;
- // put it back on the free list for reuse
- ldef->world->areaReferenceAllocator.Free( lref );
- }
- ldef->references = NULL;
- }
- /*
- ===============
- WindingCompletelyInsideLight
- ===============
- */
- static bool WindingCompletelyInsideLight( const idWinding *w, const idRenderLightLocal *ldef ) {
- for ( int i = 0; i < w->GetNumPoints(); i++ ) {
- if ( idRenderMatrix::CullPointToMVP( ldef->baseLightProject, (*w)[i].ToVec3(), true ) ) {
- return false;
- }
- }
- return true;
- }
- /*
- ======================
- R_CreateLightDefFogPortals
- When a fog light is created or moved, see if it completely
- encloses any portals, which may allow them to be fogged closed.
- ======================
- */
- static void R_CreateLightDefFogPortals( idRenderLightLocal *ldef ) {
- ldef->foggedPortals = NULL;
- if ( !ldef->lightShader->IsFogLight() ) {
- return;
- }
- // some fog lights will explicitly disallow portal fogging
- if ( ldef->lightShader->TestMaterialFlag( MF_NOPORTALFOG ) ) {
- return;
- }
- for ( areaReference_t * lref = ldef->references; lref != NULL; lref = lref->ownerNext ) {
- // check all the models in this area
- portalArea_t * area = lref->area;
- for ( portal_t * prt = area->portals; prt != NULL; prt = prt->next ) {
- doublePortal_t * dp = prt->doublePortal;
- // we only handle a single fog volume covering a portal
- // this will never cause incorrect drawing, but it may
- // fail to cull a portal
- if ( dp->fogLight ) {
- continue;
- }
- if ( WindingCompletelyInsideLight( prt->w, ldef ) ) {
- dp->fogLight = ldef;
- dp->nextFoggedPortal = ldef->foggedPortals;
- ldef->foggedPortals = dp;
- }
- }
- }
- }
- /*
- =================
- R_CreateLightRefs
- =================
- */
- void R_CreateLightRefs( idRenderLightLocal * light ) {
- // derive light data
- R_DeriveLightData( light );
- // determine the areaNum for the light origin, which may let us
- // cull the light if it is behind a closed door
- // it is debatable if we want to use the entity origin or the center offset origin,
- // but we definitely don't want to use a parallel offset origin
- light->areaNum = light->world->PointInArea( light->globalLightOrigin );
- if ( light->areaNum == -1 ) {
- light->areaNum = light->world->PointInArea( light->parms.origin );
- }
- // bump the view count so we can tell if an
- // area already has a reference
- tr.viewCount++;
- // if we have a prelight model that includes all the shadows for the major world occluders,
- // we can limit the area references to those visible through the portals from the light center.
- // We can't do this in the normal case, because shadows are cast from back facing triangles, which
- // may be in areas not directly visible to the light projection center.
- if ( light->parms.prelightModel != NULL && r_useLightPortalFlow.GetBool() && light->lightShader->LightCastsShadows() ) {
- light->world->FlowLightThroughPortals( light );
- } else {
- // push the light frustum down the BSP tree into areas
- light->world->PushFrustumIntoTree( NULL, light, light->inverseBaseLightProject, bounds_zeroOneCube );
- }
- R_CreateLightDefFogPortals( light );
- }
- /*
- =================================================================================
- WORLD MODEL & LIGHT DEFS
- =================================================================================
- */
- /*
- ===================
- R_FreeDerivedData
- ReloadModels and RegenerateWorld call this
- ===================
- */
- void R_FreeDerivedData() {
- for ( int j = 0; j < tr.worlds.Num(); j++ ) {
- idRenderWorldLocal * rw = tr.worlds[j];
- for ( int i = 0; i < rw->entityDefs.Num(); i++ ) {
- idRenderEntityLocal * def = rw->entityDefs[i];
- if ( def == NULL ) {
- continue;
- }
- R_FreeEntityDefDerivedData( def, false, false );
- }
- for ( int i = 0; i < rw->lightDefs.Num(); i++ ) {
- idRenderLightLocal * light = rw->lightDefs[i];
- if ( light == NULL ) {
- continue;
- }
- R_FreeLightDefDerivedData( light );
- }
- }
- }
- /*
- ===================
- R_CheckForEntityDefsUsingModel
- ===================
- */
- void R_CheckForEntityDefsUsingModel( idRenderModel *model ) {
- for ( int j = 0; j < tr.worlds.Num(); j++ ) {
- idRenderWorldLocal * rw = tr.worlds[j];
- for ( int i = 0; i < rw->entityDefs.Num(); i++ ) {
- idRenderEntityLocal * def = rw->entityDefs[i];
- if ( !def ) {
- continue;
- }
- if ( def->parms.hModel == model ) {
- //assert( 0 );
- // this should never happen but Radiant messes it up all the time so just free the derived data
- R_FreeEntityDefDerivedData( def, false, false );
- }
- }
- }
- }
- /*
- ===================
- R_ReCreateWorldReferences
- ReloadModels and RegenerateWorld call this
- ===================
- */
- void R_ReCreateWorldReferences() {
- // let the interaction generation code know this
- // shouldn't be optimized for a particular view
- tr.viewDef = NULL;
- for ( int j = 0; j < tr.worlds.Num(); j++ ) {
- idRenderWorldLocal * rw = tr.worlds[j];
- for ( int i = 0; i < rw->entityDefs.Num(); i++ ) {
- idRenderEntityLocal * def = rw->entityDefs[i];
- if ( def == NULL ) {
- continue;
- }
- // the world model entities are put specifically in a single
- // area, instead of just pushing their bounds into the tree
- if ( i < rw->numPortalAreas ) {
- rw->AddEntityRefToArea( def, &rw->portalAreas[i] );
- } else {
- R_CreateEntityRefs( def );
- }
- }
- for ( int i = 0; i < rw->lightDefs.Num(); i++ ) {
- idRenderLightLocal * light = rw->lightDefs[i];
- if ( light == NULL ) {
- continue;
- }
- renderLight_t parms = light->parms;
- light->world->FreeLightDef( i );
- rw->UpdateLightDef( i, &parms );
- }
- }
- }
- /*
- ====================
- R_ModulateLights_f
- Modifies the shaderParms on all the lights so the level
- designers can easily test different color schemes
- ====================
- */
- void R_ModulateLights_f( const idCmdArgs &args ) {
- if ( !tr.primaryWorld ) {
- return;
- }
- if ( args.Argc() != 4 ) {
- common->Printf( "usage: modulateLights <redFloat> <greenFloat> <blueFloat>\n" );
- return;
- }
- float modulate[3];
- for ( int i = 0; i < 3; i++ ) {
- modulate[i] = atof( args.Argv( i+1 ) );
- }
- int count = 0;
- for ( int i = 0; i < tr.primaryWorld->lightDefs.Num(); i++ ) {
- idRenderLightLocal * light = tr.primaryWorld->lightDefs[i];
- if ( light != NULL ) {
- count++;
- for ( int j = 0; j < 3; j++ ) {
- light->parms.shaderParms[j] *= modulate[j];
- }
- }
- }
- common->Printf( "modulated %i lights\n", count );
- }
|