Torque3D Documentation / _generateds / lightShadowMap.cpp

lightShadowMap.cpp

Engine/source/lighting/shadowMap/lightShadowMap.cpp

More...

Public Variables

Detailed Description

Public Variables

 MODULE_END 
 MODULE_INIT 

Public Functions

GFX_ImplementTextureProfile(ShadowMapProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da75302d480adb239daa0dd3fec9fd7a0b">GFXTextureProfile::RenderTarget</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da8e64fa44eaa9b6444614dac7bdb1dcf8">GFXTextureProfile::Pooled , GFXTextureProfile::NONE )

GFX_ImplementTextureProfile(ShadowMapZProfile , GFXTextureProfile::DiffuseMap , GFXTextureProfile::PreserveSize</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daf55b13e32bd1a1746406b68ead73ba05">GFXTextureProfile::NoMipmap</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82daa3a2027753aec009ced4f0818a231296">GFXTextureProfile::ZTarget</a>|<a href="/coding/class/classgfxtextureprofile/#classgfxtextureprofile_1a09105f0bf717a1f2ae49ceda21b8e82da8e64fa44eaa9b6444614dac7bdb1dcf8">GFXTextureProfile::Pooled , GFXTextureProfile::NONE )

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "lighting/shadowMap/lightShadowMap.h"
 26
 27#include "lighting/shadowMap/shadowMapManager.h"
 28#include "lighting/shadowMap/shadowMatHook.h"
 29#include "gfx/gfxDevice.h"
 30#include "gfx/gfxTextureManager.h"
 31#include "gfx/gfxOcclusionQuery.h"
 32#include "gfx/gfxCardProfile.h"
 33#include "gfx/sim/debugDraw.h"
 34#include "materials/materialDefinition.h"
 35#include "materials/baseMatInstance.h"
 36#include "scene/sceneManager.h"
 37#include "scene/sceneRenderState.h"
 38#include "scene/zones/sceneZoneSpace.h"
 39#include "lighting/lightManager.h"
 40#include "math/mathUtils.h"
 41#include "shaderGen/shaderGenVars.h"
 42#include "core/util/safeDelete.h"
 43#include "core/stream/bitStream.h"
 44#include "math/mathIO.h"
 45#include "materials/shaderData.h"
 46#include "core/module.h"
 47
 48// Used for creation in ShadowMapParams::getOrCreateShadowMap()
 49#include "lighting/shadowMap/singleLightShadowMap.h"
 50#include "lighting/shadowMap/pssmLightShadowMap.h"
 51#include "lighting/shadowMap/cubeLightShadowMap.h"
 52#include "lighting/shadowMap/dualParaboloidLightShadowMap.h"
 53
 54// Remove this when the shader constants are reworked better
 55#include "lighting/advanced/advancedLightManager.h"
 56#include "lighting/advanced/advancedLightBinManager.h"
 57
 58// TODO: Some cards (Justin's GeForce 7x series) barf on the integer format causing
 59// filtering artifacts. These can (sometimes) be resolved by switching the format
 60// to FP16 instead of Int16.
 61const GFXFormat LightShadowMap::ShadowMapFormat = GFXFormatR32F; // GFXFormatR8G8B8A8;
 62
 63bool LightShadowMap::smDebugRenderFrustums;
 64F32 LightShadowMap::smShadowTexScalar = 1.0f;
 65
 66Vector<LightShadowMap*> LightShadowMap::smUsedShadowMaps;
 67Vector<LightShadowMap*> LightShadowMap::smShadowMaps;
 68
 69GFX_ImplementTextureProfile( ShadowMapProfile,
 70                              GFXTextureProfile::DiffuseMap,
 71                              GFXTextureProfile::PreserveSize | 
 72                              GFXTextureProfile::RenderTarget |
 73                              GFXTextureProfile::Pooled,
 74                              GFXTextureProfile::NONE );
 75
 76GFX_ImplementTextureProfile( ShadowMapZProfile,
 77                             GFXTextureProfile::DiffuseMap, 
 78                             GFXTextureProfile::PreserveSize | 
 79                             GFXTextureProfile::NoMipmap | 
 80                             GFXTextureProfile::ZTarget |
 81                             GFXTextureProfile::Pooled,
 82                             GFXTextureProfile::NONE );
 83
 84
 85LightShadowMap::LightShadowMap( LightInfo *light )
 86   :  mWorldToLightProj( true ),
 87      mTexSize( 0 ),
 88      mLight( light ),
 89      mLastShader( NULL ),
 90      mIsViewDependent( false ),
 91      mLastCull( 0 ),
 92      mLastScreenSize( 0.0f ),
 93      mLastPriority( 0.0f )
 94{
 95   GFXTextureManager::addEventDelegate( this, &LightShadowMap::_onTextureEvent );
 96
 97   mTarget = GFX->allocRenderToTextureTarget();
 98   smShadowMaps.push_back( this );
 99}
100
101LightShadowMap::~LightShadowMap()
102{
103   mTarget = NULL;
104
105   releaseTextures();
106
107   smShadowMaps.remove( this );
108   smUsedShadowMaps.remove( this );
109
110   GFXTextureManager::removeEventDelegate( this, &LightShadowMap::_onTextureEvent );
111}
112
113void LightShadowMap::releaseAllTextures()
114{
115   PROFILE_SCOPE( LightShadowMap_ReleaseAllTextures );
116
117   for ( U32 i=0; i < smShadowMaps.size(); i++ )
118      smShadowMaps[i]->releaseTextures();
119}
120
121U32 LightShadowMap::releaseUnusedTextures()
122{
123   PROFILE_SCOPE( LightShadowMap_ReleaseUnusedTextures );
124
125   const U32 currTime = Sim::getCurrentTime();
126   const U32 purgeTime = 1000;
127
128   for ( U32 i=0; i < smUsedShadowMaps.size(); )
129   {
130      LightShadowMap *lsm = smUsedShadowMaps[i];
131
132      // If the shadow has not been culled in a while then
133      // release its textures for other shadows to use.
134      if (  currTime > ( lsm->mLastCull + purgeTime ) )
135      {
136         // Internally this will remove the map from the used
137         // list, so don't increment the loop.
138         lsm->releaseTextures();         
139         continue;
140      }
141
142      i++;
143   }
144
145   return smUsedShadowMaps.size();
146}
147
148void LightShadowMap::_onTextureEvent( GFXTexCallbackCode code )
149{
150   if ( code == GFXZombify )
151      releaseTextures();
152
153   // We don't initialize here as we want the textures
154   // to be reallocated when the shadow becomes visible.
155}
156
157void LightShadowMap::calcLightMatrices( MatrixF &outLightMatrix, const Frustum &viewFrustum )
158{
159   // Create light matrix, set projection
160
161   switch ( mLight->getType() )
162   {
163   case LightInfo::Vector :
164      {
165         const ShadowMapParams *p = mLight->getExtended<ShadowMapParams>();
166
167         // Calculate the bonding box of the shadowed area 
168         // we're interested in... this is the shadow box 
169         // transformed by the frustum transform.
170         Box3F viewBB( -p->shadowDistance, -p->shadowDistance, -p->shadowDistance,
171                        p->shadowDistance, p->shadowDistance, p->shadowDistance );
172         viewFrustum.getTransform().mul( viewBB );
173
174         // Calculate a light "projection" matrix.
175         MatrixF lightMatrix = MathUtils::createOrientFromDir(mLight->getDirection());
176         outLightMatrix = lightMatrix;
177         static MatrixF rotMat(EulerF( (M_PI_F / 2.0f), 0.0f, 0.0f));
178         lightMatrix.mul( rotMat );
179
180         // This is the box in lightspace
181         Box3F lightViewBB(viewBB);
182         lightMatrix.mul(lightViewBB);
183
184         // Now, let's position our light based on the lightViewBB
185         Point3F newLightPos(viewBB.getCenter());
186         F32 sceneDepth = lightViewBB.maxExtents.z - lightViewBB.minExtents.z;
187         newLightPos += mLight->getDirection() * ((-sceneDepth / 2.0f)-1.0f);         // -1 for the nearplane
188         outLightMatrix.setPosition(newLightPos);
189
190         // Update light info
191         mLight->setRange( sceneDepth );
192         mLight->setPosition( newLightPos );
193
194         // Set our ortho projection
195         F32 width = (lightViewBB.maxExtents.x - lightViewBB.minExtents.x) / 2.0f;
196         F32 height = (lightViewBB.maxExtents.y - lightViewBB.minExtents.y) / 2.0f;
197
198         width = getMax(width, height);
199
200         GFX->setOrtho(-width, width, -width, width, 1.0f, sceneDepth, true);
201
202
203         // TODO: Width * 2... really isn't that pixels being used as
204         // meters?  Is a real physical metric of scene depth better?         
205         //SceneManager::setVisibleDistance(width * 2.0f);
206
207#if 0
208         LinearColorF(1.0f, 0.0f, 0.0f));
209         LinearColorF(0.0f, 1.0f, 0.0f));
210         LinearColorF(0.0f, 0.0f, 1.0f));
211         LinearColorF(1,1,0));
212         LinearColorF(0,1,1));
213
214         a(newLightPos);
215         b(newLightPos);
216         Point3F offset(width, height,0.0f);
217         a -= offset;
218         b += offset;
219         LinearColorF(0.5f, 0.5f, 0.5f));
220#endif
221      }
222      break;
223   case LightInfo::Spot :
224      {
225         outLightMatrix = mLight->getTransform();
226         F32 fov = mDegToRad( mLight->getOuterConeAngle() );
227         F32 farDist = mLight->getRange().x;
228         F32 nearDist = farDist * 0.01f;
229
230         F32 left, right, top, bottom;
231         MathUtils::makeFrustum( &left, &right, &top, &bottom, fov, 1.0f, nearDist );
232         GFX->setFrustum( left, right, bottom, top, nearDist, farDist );
233      }
234      break;
235   default:
236      AssertFatal(false, "Unsupported light type!");
237   }
238}
239
240void LightShadowMap::releaseTextures()
241{
242   mShadowMapTex = NULL;
243   mDebugTarget.setTexture( NULL );
244   smUsedShadowMaps.remove( this );
245}
246
247void LightShadowMap::setDebugTarget( const String &name )
248{
249   mDebugTarget.registerWithName( name );
250   mDebugTarget.setTexture( mShadowMapTex );
251}
252
253GFXTextureObject* LightShadowMap::_getDepthTarget( U32 width, U32 height )
254{
255   // Get a depth texture target from the pooled profile
256   // which is returned as a temporary.
257   GFXTexHandle depthTex( width, height, GFXFormatD24S8, &ShadowMapZProfile, 
258      "LightShadowMap::_getDepthTarget()" );
259
260   return depthTex;
261}
262
263bool LightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants* lsc )
264{
265   if ( currTexFlag == Material::DynamicLight )
266   {
267      S32 reg = lsc->mShadowMapSC->getSamplerRegister();
268
269      if ( reg != -1 )
270         GFX->setTexture( reg, mShadowMapTex);
271
272      return true;
273   } else if ( currTexFlag == Material::DynamicLightMask )
274   {
275      S32 reg = lsc->mCookieMapSC->getSamplerRegister();
276      if ( reg != -1 )
277      {
278         ShadowMapParams *p = mLight->getExtended<ShadowMapParams>();
279
280         if ( lsc->mCookieMapSC->getType() == GFXSCT_SamplerCube )
281            GFX->setCubeTexture( reg, p->getCookieCubeTex() );
282         else
283            GFX->setTexture( reg, p->getCookieTex() );
284      }
285
286      return true;
287   }
288
289   return false;
290}
291
292void LightShadowMap::render(RenderPassManager* renderPass, const SceneRenderState *diffuseState)
293{
294   mDebugTarget.setTexture( NULL );
295   _render( renderPass, diffuseState );
296   mDebugTarget.setTexture( mShadowMapTex );
297
298   // Add it to the used list unless we're been updated.
299   //AssertFatal( !smUsedShadowMaps.contains( this ), "LightShadowMap::render - Used shadow map inserted twice!" );
300   if(!smUsedShadowMaps.contains(this))
301      smUsedShadowMaps.push_back( this );
302}
303
304BaseMatInstance* LightShadowMap::getShadowMaterial( BaseMatInstance *inMat ) const
305{
306   // See if we have an existing material hook.
307   ShadowMaterialHook *hook = static_cast<ShadowMaterialHook*>( inMat->getHook( ShadowMaterialHook::Type ) );
308   if ( !hook )
309   {
310      // Create a hook and initialize it using the incoming material.
311      hook = new ShadowMaterialHook;
312      hook->init( inMat );
313      inMat->addHook( hook );
314   }
315
316   return hook->getShadowMat( getShadowType() );
317}
318
319U32 LightShadowMap::getBestTexSize( U32 scale ) const
320{
321   const ShadowMapParams *params = mLight->getExtended<ShadowMapParams>();
322   
323   // The view dependent shadows don't scale by screen size. 
324   U32 texSize;
325   if ( isViewDependent() )
326      texSize = params->texSize;
327   else
328      texSize = params->texSize * getMin( 1.0f, mLastScreenSize );
329
330   // Apply the shadow texture scale and make
331   // sure this is a power of 2.
332   texSize = getNextPow2( texSize * smShadowTexScalar );
333
334   // Get the max texture size this card supports and
335   // scale it down... ensuring the final texSize can
336   // be scaled up that many times and not go over
337   // the card maximum.
338   U32 maxTexSize = GFX->getCardProfiler()->queryProfile( "maxTextureSize", 2048 );
339   if ( scale > 1 )
340      maxTexSize >>= ( scale - 1 );
341
342   // Never let the shadow texture get smaller than 16x16 as
343   // it just makes the pool bigger and the fillrate savings
344   // are less and leass as we get smaller.
345   texSize = mClamp( texSize, (U32)16, maxTexSize );
346
347   // Return it.
348   return texSize;
349}
350
351void LightShadowMap::updatePriority( const SceneRenderState *state, U32 currTimeMs )
352{
353   PROFILE_SCOPE( LightShadowMap_updatePriority );
354
355   mLastCull = currTimeMs;
356
357   if ( isViewDependent() )
358   {
359      mLastScreenSize = 1.0f;
360      mLastPriority = F32_MAX;
361      return;
362   }
363
364   const Point3F &camPt = state->getCameraPosition();
365   F32 range = mLight->getRange().x;
366   F32 dist;
367
368   if ( mLight->getType() == LightInfo::Spot )
369   {
370      // We treat the cone as a cylinder to get the
371      // approximate projection distance.
372
373      Point3F endPt = mLight->getPosition() + ( mLight->getDirection() * range );
374      Point3F nearPt = MathUtils::mClosestPointOnSegment( mLight->getPosition(), endPt, camPt );
375      dist = ( camPt - nearPt ).len();
376
377      F32 radius = range * mSin( mDegToRad( mLight->getOuterConeAngle() * 0.5f ) );
378      dist -= radius;
379   }
380   else
381      dist = SphereF( mLight->getPosition(), range ).distanceTo( camPt );
382
383   // Get the approximate screen size of the light.
384   mLastScreenSize = state->projectRadius( dist, range );
385   mLastScreenSize /= state->getViewport().extent.y;
386
387   // Update the priority.
388   mLastPriority = mPow( mLastScreenSize * 50.0f, 2.0f );   
389   mLastPriority *= mLight->getPriority();
390}
391
392S32 QSORT_CALLBACK LightShadowMap::cmpPriority( LightShadowMap *const *lsm1, LightShadowMap *const *lsm2 )
393{
394   F32 diff = (*lsm1)->getLastPriority() - (*lsm2)->getLastPriority(); 
395   return diff > 0.0f ? -1 : ( diff < 0.0f ? 1 : 0 );
396}
397
398void LightShadowMap::_debugRender( SceneRenderState* shadowRenderState )
399{
400   #ifdef TORQUE_DEBUG
401
402   // Skip if light does not have debug rendering enabled.
403   if( !getLightInfo()->isDebugRenderingEnabled() )
404      return;
405
406   DebugDrawer* drawer = DebugDrawer::get();
407   if( !drawer )
408      return;
409
410   if( smDebugRenderFrustums )
411      shadowRenderState->getCullingState().debugRenderCullingVolumes();
412
413   #endif
414}
415
416
417LightingShaderConstants::LightingShaderConstants() 
418   :  mInit( false ),
419      mShader( NULL ),
420      mLightParamsSC(NULL), 
421      mLightSpotParamsSC(NULL), 
422      mLightPositionSC(NULL),
423      mLightDiffuseSC(NULL), 
424      mLightAmbientSC(NULL), 
425      mLightConfigDataSC(NULL),
426      mLightSpotDirSC(NULL),
427      mHasVectorLightSC(NULL),
428      mVectorLightDirectionSC(NULL),
429      mVectorLightColorSC(NULL),
430      mVectorLightBrightnessSC(NULL),
431      mShadowMapSC(NULL), 
432      mShadowMapSizeSC(NULL), 
433      mCookieMapSC(NULL),
434      mRandomDirsConst(NULL),
435      mShadowSoftnessConst(NULL), 
436      mAtlasXOffsetSC(NULL), 
437      mAtlasYOffsetSC(NULL),
438      mAtlasScaleSC(NULL), 
439      mFadeStartLength(NULL), 
440      mOverDarkFactorPSSM(NULL), 
441      mTapRotationTexSC(NULL),
442
443      mWorldToLightProjSC(NULL), 
444      mViewToLightProjSC(NULL),
445      mScaleXSC(NULL), 
446      mScaleYSC(NULL),
447      mOffsetXSC(NULL), 
448      mOffsetYSC(NULL), 
449      mFarPlaneScalePSSM(NULL)
450{
451}
452
453LightingShaderConstants::~LightingShaderConstants()
454{
455   if (mShader.isValid())
456   {
457      mShader->getReloadSignal().remove( this, &LightingShaderConstants::_onShaderReload );
458      mShader = NULL;
459   }
460}
461
462void LightingShaderConstants::init(GFXShader* shader)
463{
464   if (mShader.getPointer() != shader)
465   {
466      if (mShader.isValid())
467         mShader->getReloadSignal().remove( this, &LightingShaderConstants::_onShaderReload );
468
469      mShader = shader;
470      mShader->getReloadSignal().notify( this, &LightingShaderConstants::_onShaderReload );
471   }
472
473   mLightParamsSC = shader->getShaderConstHandle("$lightParams");
474   mLightSpotParamsSC = shader->getShaderConstHandle("$lightSpotParams");
475
476   // NOTE: These are the shader constants used for doing lighting 
477   // during the forward pass.  Do not confuse these for the deferred
478   // lighting constants which are used from AdvancedLightBinManager.
479   mLightPositionSC = shader->getShaderConstHandle( ShaderGenVars::lightPosition );
480   mLightDiffuseSC = shader->getShaderConstHandle( ShaderGenVars::lightDiffuse );
481   mLightAmbientSC = shader->getShaderConstHandle( ShaderGenVars::lightAmbient );
482   mLightConfigDataSC = shader->getShaderConstHandle( ShaderGenVars::lightConfigData);
483   mLightSpotDirSC = shader->getShaderConstHandle( ShaderGenVars::lightSpotDir );
484
485   mHasVectorLightSC = shader->getShaderConstHandle(ShaderGenVars::hasVectorLight);
486   mVectorLightDirectionSC = shader->getShaderConstHandle(ShaderGenVars::vectorLightDirection);
487   mVectorLightColorSC = shader->getShaderConstHandle(ShaderGenVars::vectorLightColor);
488   mVectorLightBrightnessSC = shader->getShaderConstHandle(ShaderGenVars::vectorLightBrightness);
489
490   mShadowMapSC = shader->getShaderConstHandle("$shadowMap");
491   mShadowMapSizeSC = shader->getShaderConstHandle("$shadowMapSize");
492
493   mCookieMapSC = shader->getShaderConstHandle("$cookieMap");
494
495   mShadowSoftnessConst = shader->getShaderConstHandle("$shadowSoftness");
496   mAtlasXOffsetSC = shader->getShaderConstHandle("$atlasXOffset");
497   mAtlasYOffsetSC = shader->getShaderConstHandle("$atlasYOffset");
498   mAtlasScaleSC = shader->getShaderConstHandle("$atlasScale");
499
500   mFadeStartLength = shader->getShaderConstHandle("$fadeStartLength");
501   mOverDarkFactorPSSM = shader->getShaderConstHandle("$overDarkPSSM");
502   mTapRotationTexSC = shader->getShaderConstHandle( "$gTapRotationTex" );
503
504   mWorldToLightProjSC = shader->getShaderConstHandle("$worldToLightProj");
505   mViewToLightProjSC = shader->getShaderConstHandle("$viewToLightProj");
506   mScaleXSC = shader->getShaderConstHandle("$scaleX");
507   mScaleYSC = shader->getShaderConstHandle("$scaleY");
508   mOffsetXSC = shader->getShaderConstHandle("$offsetX");
509   mOffsetYSC = shader->getShaderConstHandle("$offsetY");
510   mFarPlaneScalePSSM = shader->getShaderConstHandle("$farPlaneScalePSSM");
511
512   mInit = true;
513}
514
515void LightingShaderConstants::_onShaderReload()
516{
517   if (mShader.isValid())
518      init( mShader );
519}
520
521MODULE_BEGIN( ShadowMapParams )
522MODULE_INIT_BEFORE( LightMapParams )
523MODULE_INIT
524{
525   ShadowMapParams::Type = "ShadowMapParams" ;
526}
527MODULE_END;
528
529LightInfoExType ShadowMapParams::Type( "" );
530
531ShadowMapParams::ShadowMapParams( LightInfo *light ) 
532   :  mShadowMap( NULL ),
533      mLight( light )
534{
535   attenuationRatio.set( 0.0f, 1.0f, 1.0f );
536   shadowType = ShadowType_Spot;
537   overDarkFactor.set(2000.0f, 1000.0f, 500.0f, 100.0f);
538   numSplits = 4;
539   logWeight = 0.91f;
540   texSize = 1024;
541   shadowDistance = 100.0f;
542   shadowSoftness = 0.2f;
543   fadeStartDist = 75.0f;
544   lastSplitTerrainOnly = false;
545   mQuery = GFX->createOcclusionQuery();
546
547   _validate();
548}
549
550ShadowMapParams::~ShadowMapParams()
551{
552   SAFE_DELETE( mQuery );
553   SAFE_DELETE( mShadowMap );
554}
555
556void ShadowMapParams::_validate()
557{
558   switch ( mLight->getType() )
559   {
560      case LightInfo::Spot:
561         shadowType = ShadowType_Spot;
562         break;
563
564      case LightInfo::Vector:
565         shadowType = ShadowType_PSSM;
566         break;
567
568      case LightInfo::Point:
569         if ( shadowType < ShadowType_Paraboloid )
570            shadowType = ShadowType_DualParaboloidSinglePass;
571         break;
572      
573      default:
574         break;
575   }
576
577   // The texture sizes for shadows should always
578   // be power of 2 in size.
579   texSize = getNextPow2( texSize );
580
581   // The maximum shadow texture size setting we're 
582   // gonna allow... this doesn't use your hardware 
583   // settings as you may be on a lower end system 
584   // than your target machine.
585   //
586   // We apply the hardware specific limits during 
587   // shadow rendering.
588   //
589   U32 maxTexSize = 4096;
590
591   if ( mLight->getType() == LightInfo::Vector )
592   {
593      numSplits = mClamp( numSplits, 1, 4 );
594      
595      // Adjust the shadow texture size for the PSSM 
596      // based on the split count to keep the total
597      // shadow texture size within 4096.
598      if ( numSplits == 2 || numSplits == 4 )
599         maxTexSize = 4096;
600      if ( numSplits == 3 )
601         maxTexSize = 2048;
602   }
603   else
604      numSplits = 1;
605
606   // Keep it in a valid range... less than 32 is dumb.
607   texSize = mClamp( texSize, 32, maxTexSize );
608}
609
610LightShadowMap* ShadowMapParams::getOrCreateShadowMap()
611{
612   if (mShadowMap)
613      return mShadowMap;
614
615   if ( !mLight->getCastShadows() )
616      return NULL;
617
618   LightShadowMap* newShadowMap = NULL;
619
620   switch ( mLight->getType() )
621   {
622      case LightInfo::Spot:
623         newShadowMap = new SingleLightShadowMap( mLight );
624         break;
625
626      case LightInfo::Vector:
627         newShadowMap = new PSSMLightShadowMap( mLight );
628         break;
629
630      case LightInfo::Point:
631
632         if ( shadowType == ShadowType_CubeMap )
633            newShadowMap = new CubeLightShadowMap( mLight );
634         else if ( shadowType == ShadowType_Paraboloid )
635            newShadowMap = new ParaboloidLightShadowMap( mLight );
636         else
637            newShadowMap = new DualParaboloidLightShadowMap( mLight );
638         break;
639   
640      default:
641         break;
642   }
643
644   mShadowMap = newShadowMap;
645   return mShadowMap;
646}
647
648GFXTextureObject* ShadowMapParams::getCookieTex()
649{
650   if (  cookie.isNotEmpty() &&
651         (  mCookieTex.isNull() || 
652            cookie != mCookieTex->getPath() ) )
653   {
654      mCookieTex.set(   cookie, 
655                        &GFXStaticTextureSRGBProfile, 
656                        "ShadowMapParams::getCookieTex()" );
657   }
658   else if ( cookie.isEmpty() )
659      mCookieTex = NULL;
660
661   return mCookieTex.getPointer();
662}
663
664GFXCubemap* ShadowMapParams::getCookieCubeTex()
665{
666   if (  cookie.isNotEmpty() &&
667         (  mCookieCubeTex.isNull() || 
668            cookie != mCookieCubeTex->getPath() ) )
669   {
670      mCookieCubeTex.set( cookie );
671   }
672   else if ( cookie.isEmpty() )
673      mCookieCubeTex = NULL;
674
675   return mCookieCubeTex.getPointer();
676}
677
678void ShadowMapParams::set( const LightInfoEx *ex )
679{
680   // TODO: Do we even need this?
681}
682
683void ShadowMapParams::packUpdate( BitStream *stream ) const
684{
685   // HACK: We need to work out proper parameter 
686   // validation when any field changes on the light.
687
688   ((ShadowMapParams*)this)->_validate();
689
690   stream->writeInt( shadowType, 8 );
691   
692   mathWrite( *stream, attenuationRatio );
693   
694   stream->write( texSize );
695
696   stream->write( cookie );
697
698   stream->write( numSplits );
699   stream->write( logWeight );
700
701   mathWrite(*stream, overDarkFactor);
702
703   stream->write( fadeStartDist );
704   stream->writeFlag( lastSplitTerrainOnly );
705
706   stream->write( shadowDistance );
707
708   stream->write( shadowSoftness );   
709}
710
711void ShadowMapParams::unpackUpdate( BitStream *stream )
712{
713   ShadowType newType = (ShadowType)stream->readInt( 8 );
714   if ( shadowType != newType )
715   {
716      // If the shadow type changes delete the shadow
717      // map so it can be reallocated on the next render.
718      shadowType = newType;
719      SAFE_DELETE( mShadowMap );
720   }
721
722   mathRead( *stream, &attenuationRatio );
723
724   stream->read( &texSize );
725
726   stream->read( &cookie );
727
728   stream->read( &numSplits );
729   stream->read( &logWeight );
730   mathRead(*stream, &overDarkFactor);
731
732   stream->read( &fadeStartDist );
733   lastSplitTerrainOnly = stream->readFlag();
734
735   stream->read( &shadowDistance );   
736
737   stream->read( &shadowSoftness );
738}
739