Torque3D Documentation / _generateds / advancedLightBinManager.cpp

advancedLightBinManager.cpp

Engine/source/lighting/advanced/advancedLightBinManager.cpp

More...

Public Variables

Public Functions

ConsoleDocClass(AdvancedLightBinManager , "@brief Rendering Manager responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> lighting, shadows , and global variables affecing <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">both.\n\n</a>" "Should not be exposed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> TorqueScript as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> game object, meant <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only\n\n</a>" " @ingroup Lighting" )
ImplementEnumType(ShadowFilterMode , "The shadow filtering modes <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> Advanced Lighting <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shadows.\n</a>" "@ingroup AdvancedLighting" )

Detailed Description

Public Variables

 EndImplementEnumType 

Public Functions

ConsoleDocClass(AdvancedLightBinManager , "@brief Rendering Manager responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> lighting, shadows , and global variables affecing <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">both.\n\n</a>" "Should not be exposed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> TorqueScript as <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> game object, meant <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> internal use <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">only\n\n</a>" " @ingroup Lighting" )

IMPLEMENT_CONOBJECT(AdvancedLightBinManager )

ImplementEnumType(ShadowFilterMode , "The shadow filtering modes <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> Advanced Lighting <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">shadows.\n</a>" "@ingroup AdvancedLighting" )

  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/advanced/advancedLightBinManager.h"
 26
 27#include "lighting/advanced/advancedLightManager.h"
 28#include "lighting/advanced/advancedLightBufferConditioner.h"
 29#include "lighting/shadowMap/shadowMapManager.h"
 30#include "lighting/shadowMap/shadowMapPass.h"
 31#include "lighting/shadowMap/lightShadowMap.h"
 32#include "lighting/common/lightMapParams.h"
 33#include "renderInstance/renderDeferredMgr.h"
 34#include "gfx/gfxTransformSaver.h"
 35#include "scene/sceneManager.h"
 36#include "scene/sceneRenderState.h"
 37#include "materials/materialManager.h"
 38#include "materials/sceneData.h"
 39#include "core/util/safeDelete.h"
 40#include "core/util/rgb2luv.h"
 41#include "gfx/gfxDebugEvent.h"
 42#include "math/util/matrixSet.h"
 43#include "console/consoleTypes.h"
 44#include "gfx/gfxTextureManager.h"
 45
 46const RenderInstType AdvancedLightBinManager::RIT_LightInfo( "specularLighting" );
 47const String AdvancedLightBinManager::smBufferName( "specularLighting" );
 48
 49ShadowFilterMode AdvancedLightBinManager::smShadowFilterMode = ShadowFilterMode_SoftShadowHighQuality;
 50bool AdvancedLightBinManager::smPSSMDebugRender = false;
 51bool AdvancedLightBinManager::smUseSSAOMask = false;
 52bool AdvancedLightBinManager::smDiffuseLightViz = false;
 53bool AdvancedLightBinManager::smSpecularLightViz = false;
 54bool AdvancedLightBinManager::smDetailLightingViz = false;
 55
 56S32 AdvancedLightBinManager::smMaximumNumOfLights = -1;
 57bool AdvancedLightBinManager::smUseLightFade = false;
 58F32 AdvancedLightBinManager::smLightFadeStart = 50;
 59F32 AdvancedLightBinManager::smLightFadeEnd = 75;
 60
 61bool AdvancedLightBinManager::smAllowLocalLightShadows = true;
 62
 63ImplementEnumType( ShadowFilterMode,
 64   "The shadow filtering modes for Advanced Lighting shadows.\n"
 65   "@ingroup AdvancedLighting" )
 66
 67   { ShadowFilterMode_None, "None", 
 68      "@brief Simple point sampled filtering.\n"
 69      "This is the fastest and lowest quality mode." },
 70
 71   { ShadowFilterMode_SoftShadow, "SoftShadow", 
 72      "@brief A variable tap rotated poisson disk soft shadow filter.\n"
 73      "It performs 4 taps to classify the point as in shadow, out of shadow, or along a "
 74      "shadow edge.  Samples on the edge get an additional 8 taps to soften them." },
 75
 76   { ShadowFilterMode_SoftShadowHighQuality, "SoftShadowHighQuality", 
 77      "@brief A 12 tap rotated poisson disk soft shadow filter.\n"
 78      "It performs all the taps for every point without any early rejection." },
 79
 80EndImplementEnumType;
 81
 82// NOTE: The order here matches that of the LightInfo::Type enum.
 83const String AdvancedLightBinManager::smLightMatNames[] =
 84{
 85   "AL_PointLightMaterial",   // LightInfo::Point
 86   "AL_SpotLightMaterial",    // LightInfo::Spot
 87   "AL_VectorLightMaterial",  // LightInfo::Vector
 88   "",                        // LightInfo::Ambient
 89};
 90
 91// NOTE: The order here matches that of the LightInfo::Type enum.
 92const GFXVertexFormat* AdvancedLightBinManager::smLightMatVertex[] =
 93{
 94   getGFXVertexFormat<AdvancedLightManager::LightVertex>(), // LightInfo::Point
 95   getGFXVertexFormat<AdvancedLightManager::LightVertex>(), // LightInfo::Spot
 96   getGFXVertexFormat<FarFrustumQuadVert>(),                // LightInfo::Vector
 97   NULL,                                                    // LightInfo::Ambient
 98};
 99
100// NOTE: The order here matches that of the ShadowType enum.
101const String AdvancedLightBinManager::smShadowTypeMacro[] =
102{
103   "", // ShadowType_Spot
104   "", // ShadowType_PSSM,
105   "", // ShadowType_Paraboloid,
106   "SHADOW_DUALPARABOLOID_SINGLE_PASS",   // ShadowType_DualParaboloidSinglePass,
107   "SHADOW_DUALPARABOLOID",               // ShadowType_DualParaboloid,
108   "SHADOW_CUBE",                         // ShadowType_CubeMap,
109};
110
111AdvancedLightBinManager::RenderSignal &AdvancedLightBinManager::getRenderSignal()
112{
113   static RenderSignal theSignal;
114   return theSignal;
115}
116
117IMPLEMENT_CONOBJECT(AdvancedLightBinManager);
118
119ConsoleDocClass( AdvancedLightBinManager,
120   "@brief Rendering Manager responsible for lighting, shadows, and global variables affecing both.\n\n"
121
122   "Should not be exposed to TorqueScript as a game object, meant for internal use only\n\n"
123
124   "@ingroup Lighting"
125);
126
127AdvancedLightBinManager::AdvancedLightBinManager( AdvancedLightManager *lm /* = NULL */, 
128                                                 ShadowMapManager *sm /* = NULL */, 
129                                                 GFXFormat lightBufferFormat /* = GFXFormatR8G8B8A8 */ )
130   :  RenderBinManager( RIT_LightInfo, 1.0f, 1.0f ), 
131      mNumLightsCulled(0), 
132      mLightManager(lm), 
133      mShadowManager(sm)
134{
135   mMRTLightmapsDuringDeferred = true;
136
137   Con::NotifyDelegate callback( this, &AdvancedLightBinManager::_deleteLightMaterials );
138   Con::addVariableNotify( "$pref::Shadows::filterMode", callback );
139   Con::addVariableNotify( "$AL::PSSMDebugRender", callback );
140   Con::addVariableNotify( "$AL::UseSSAOMask", callback );
141   Con::addVariableNotify( "$AL::DiffuseLightViz", callback);
142   Con::addVariableNotify( "$AL::SpecularLightViz", callback);
143   Con::addVariableNotify( "$AL::DetailLightingViz", callback);
144}
145
146
147AdvancedLightBinManager::~AdvancedLightBinManager()
148{
149   _deleteLightMaterials();
150
151   Con::NotifyDelegate callback( this, &AdvancedLightBinManager::_deleteLightMaterials );
152   Con::removeVariableNotify( "$pref::shadows::filterMode", callback );
153   Con::removeVariableNotify( "$AL::PSSMDebugRender", callback );
154   Con::removeVariableNotify( "$AL::UseSSAOMask", callback );
155   Con::removeVariableNotify( "$AL::DiffuseLightViz", callback);
156   Con::removeVariableNotify( "$AL::SpecularLightViz", callback);
157   Con::removeVariableNotify( "$AL::DetailLightingViz", callback);
158}
159
160void AdvancedLightBinManager::consoleInit()
161{
162   Parent::consoleInit();
163
164   Con::addVariable( "$pref::shadows::filterMode", 
165      TYPEID<ShadowFilterMode>(), &smShadowFilterMode,
166      "The filter mode to use for shadows.\n"
167      "@ingroup AdvancedLighting\n" );
168
169   Con::addVariable( "$AL::UseSSAOMask", TypeBool, &smUseSSAOMask,
170      "Used by the SSAO PostEffect to toggle the sampling of ssaomask "
171      "texture by the light shaders.\n"
172      "@ingroup AdvancedLighting\n" );
173
174   Con::addVariable( "$AL::PSSMDebugRender", TypeBool, &smPSSMDebugRender,
175      "Enables debug rendering of the PSSM shadows.\n"
176      "@ingroup AdvancedLighting\n" );
177
178   Con::addVariable("$AL::DiffuseLightViz", TypeBool, &smDiffuseLightViz,
179      "Enables debug rendering of the PSSM shadows.\n"
180      "@ingroup AdvancedLighting\n");
181
182   Con::addVariable("$AL::SpecularLightViz", TypeBool, &smSpecularLightViz,
183      "Enables debug rendering of the PSSM shadows.\n"
184      "@ingroup AdvancedLighting\n");
185
186   Con::addVariable("$AL::DetailLightingViz", TypeBool, &smDetailLightingViz,
187      "Enables debug rendering of the PSSM shadows.\n"
188      "@ingroup AdvancedLighting\n");
189
190   Con::addVariable("$pref::maximumNumOfLights",
191      TypeS32, &smMaximumNumOfLights,
192      "The maximum number of local lights that can be rendered at a time. If set to -1, then no limit.\n");
193
194   Con::addVariable("$pref::useLightFade", TypeBool, &smUseLightFade, "Indicates if local lights should utilize the distance-based object fadeout logic.\n");
195   Con::addVariable("$pref::lightFadeStart", TypeF32, &smLightFadeStart, "Distance at which light fading begins if $pref::useLightFade is on.\n");
196   Con::addVariable("$pref::lightFadeEnd", TypeF32, &smLightFadeEnd, "Distance at which light fading should have fully faded if $pref::useLightFade is on.\n");
197
198   Con::addVariable("$pref::allowLocalLightShadows", TypeBool, &smAllowLocalLightShadows, "Indicates if local lights(point/spot) can cast shadows.\n");
199
200}
201
202bool AdvancedLightBinManager::setTargetSize(const Point2I &newTargetSize)
203{
204   /*bool ret = Parent::setTargetSize( newTargetSize );
205
206   // We require the viewport to match the default.
207   mNamedTarget.setViewport( GFX->getViewport() );
208
209   return ret;*/
210   return true;
211}
212
213bool AdvancedLightBinManager::_updateTargets()
214{
215  /* PROFILE_SCOPE(AdvancedLightBinManager_updateTargets);
216
217   bool ret = Parent::_updateTargets();
218
219   mDiffuseLightingTarget = NamedTexTarget::find("diffuseLighting");
220   if (mDiffuseLightingTarget.isValid())
221   {
222      mDiffuseLightingTex = mDiffuseLightingTarget->getTexture();
223
224      for (U32 i = 0; i < mTargetChainLength; i++)
225         mTargetChain[i]->attachTexture(GFXTextureTarget::Color1, mDiffuseLightingTex);
226   }
227
228   GFX->finalizeReset();
229
230   return ret;*/
231   return true;
232}
233
234void AdvancedLightBinManager::addLight( LightInfo *light )
235{
236   // Get the light type.
237   const LightInfo::Type lightType = light->getType();
238
239   AssertFatal(   lightType == LightInfo::Point || 
240                  lightType == LightInfo::Spot, "Bogus light type." );
241
242   // Find a shadow map for this light, if it has one
243   ShadowMapParams *lsp = light->getExtended<ShadowMapParams>();
244   LightShadowMap *lsm = lsp->getShadowMap();
245
246   // Get the right shadow type.
247   ShadowType shadowType = ShadowType_None;
248   if (  light->getCastShadows() && smAllowLocalLightShadows && 
249         lsm && lsm->hasShadowTex() &&
250         !ShadowMapPass::smDisableShadows )
251      shadowType = lsm->getShadowType();
252
253   // Add the entry
254   LightBinEntry lEntry;
255   lEntry.lightInfo = light;
256   lEntry.shadowMap = lsm;
257   lEntry.lightMaterial = _getLightMaterial( lightType, shadowType, lsp->hasCookieTex() );
258
259   if( lightType == LightInfo::Spot )
260      lEntry.vertBuffer = mLightManager->getConeMesh( lEntry.numPrims, lEntry.primBuffer );
261   else
262      lEntry.vertBuffer = mLightManager->getSphereMesh( lEntry.numPrims, lEntry.primBuffer );
263
264   // If it's a point light, push front, spot 
265   // light, push back. This helps batches.
266   Vector<LightBinEntry> &curBin = mLightBin;
267   if ( light->getType() == LightInfo::Point )
268      curBin.push_front( lEntry );
269   else
270      curBin.push_back( lEntry );
271}
272
273void AdvancedLightBinManager::clearAllLights()
274{
275   Con::setIntVariable("lightMetrics::activeLights", mLightBin.size());
276   Con::setIntVariable("lightMetrics::culledLights", mNumLightsCulled);
277
278   mLightBin.clear();
279   mNumLightsCulled = 0;
280}
281
282S32 QSORT_CALLBACK AdvancedLightBinManager::_lightScoreCmp(const LightBinEntry* a, const  LightBinEntry* b)
283{
284   F32 diff = a->lightInfo->getScore() - b->lightInfo->getScore();
285   return diff > 0 ? 1 : diff < 0 ? -1 : 0;
286}
287
288void AdvancedLightBinManager::_scoreLights(const MatrixF& cameraTrans)
289{
290   PROFILE_SCOPE(AdvancedLightBinManager_scoreLights);
291
292   if (!LIGHTMGR)
293      return;
294
295   // Get all the lights.
296   const Point3F lumDot(0.2125f, 0.7154f, 0.0721f);
297
298   for (LightBinIterator itr = mLightBin.begin(); itr != mLightBin.end(); itr++)
299   {
300      // Get the light.
301      LightBinEntry& light = *itr;
302
303      F32 luminace = 0.0f;
304      F32 weight = 0.0f;
305      F32 score = 0.0f;
306
307      const bool isSpot = light.lightInfo->getType() == LightInfo::Spot;
308      const bool isPoint = light.lightInfo->getType() == LightInfo::Point;
309
310      if (isPoint || isSpot)
311      {
312         Point3F distVec = light.lightInfo->getPosition() - cameraTrans.getPosition();
313         F32 dist = distVec.len();
314
315         score = dist;// light.lightInfo->getRange().x / mMax(dist, 1.0f);
316
317         // Get the luminocity.
318         luminace = mDot(light.lightInfo->getColor(), lumDot) * light.lightInfo->getBrightness();
319
320         weight = light.lightInfo->getPriority();
321
322         //Distance fading test
323         if (smUseLightFade)
324         {
325            if (dist > smLightFadeStart)
326            {
327               F32 brightness = light.lightInfo->getBrightness();
328
329               float fadeOutAmt = (dist - smLightFadeStart) / (smLightFadeEnd - smLightFadeStart);
330               fadeOutAmt = 1 - fadeOutAmt;
331
332               light.lightInfo->setFadeAmount(fadeOutAmt);
333            }
334         }
335         else
336         {
337            light.lightInfo->setFadeAmount(1.0);
338         }
339      }
340
341      light.lightInfo->setScore(score * weight - luminace);
342   }
343
344   // Sort them!
345   mLightBin.sort(_lightScoreCmp);
346}
347
348void AdvancedLightBinManager::render( SceneRenderState *state )
349{
350   PROFILE_SCOPE( AdvancedLightManager_Render );
351
352   // Take a look at the SceneRenderState and see if we should skip drawing the pre-pass
353   if( state->disableAdvancedLightingBins() )
354      return;
355
356   // Automagically save & restore our viewport and transforms.
357   GFXTransformSaver saver;
358
359   if( !mLightManager )
360      return;
361
362   // Get the sunlight. If there's no sun, and no lights in the bins, no draw
363   LightInfo *sunLight = mLightManager->getSpecialLight( LightManager::slSunLightType, false );
364   GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render, ColorI::RED );
365
366   // Tell the superclass we're about to render
367   //if ( !_onPreRender( state ) )
368   //   return;
369
370   NamedTexTargetRef sceneColorTargetRef = NamedTexTarget::find("AL_FormatToken");
371   if (sceneColorTargetRef.isNull())
372      return;
373
374      if (mLightingTargetRef.isNull())
375      mLightingTargetRef = GFX->allocRenderToTextureTarget();
376
377   //Do a quick pass to update our probes if they're dirty
378   //PROBEMGR->updateDirtyProbes();
379
380   mLightingTargetRef->attachTexture(GFXTextureTarget::Color0, sceneColorTargetRef->getTexture());
381
382   GFX->pushActiveRenderTarget();
383   GFX->setActiveRenderTarget(mLightingTargetRef);
384
385   GFX->setViewport(sceneColorTargetRef->getViewport());
386
387   // Restore transforms
388   MatrixSet &matrixSet = getRenderPass()->getMatrixSet();
389   matrixSet.restoreSceneViewProjection();
390
391   // Set up the SG Data
392   SceneData sgData;
393   sgData.init( state );
394
395   // There are cases where shadow rendering is disabled.
396   const bool disableShadows = /*state->isReflectPass() || */ShadowMapPass::smDisableShadows;
397
398   // Pick the right material for rendering the sunlight... we only
399   // cast shadows when its enabled and we're not in a reflection.
400   LightMaterialInfo *vectorMatInfo;
401   if (  sunLight &&
402         sunLight->getCastShadows() &&
403         !disableShadows &&
404         sunLight->getExtended<ShadowMapParams>() )
405      vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM, false );
406   else
407      vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None, false );
408
409   // Initialize and set the per-frame parameters after getting
410   // the vector light material as we use lazy creation.
411   _setupPerFrameParameters( state );
412   
413   // Draw sunlight/ambient
414   if ( sunLight && vectorMatInfo )
415   {
416      GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Sunlight, ColorI::RED );
417
418      // Set up SG data
419      setupSGData( sgData, state, sunLight );
420      vectorMatInfo->setLightParameters( sunLight, state );
421
422      // Set light holds the active shadow map.       
423      mShadowManager->setLightShadowMapForLight( sunLight );
424
425      // Set geometry
426      GFX->setVertexBuffer( mFarFrustumQuadVerts );
427      GFX->setPrimitiveBuffer( NULL );
428
429      vectorMatInfo->matInstance->mSpecialLight = true;
430
431      // Render the material passes
432      while( vectorMatInfo->matInstance->setupPass( state, sgData ) )
433      {
434         vectorMatInfo->matInstance->setSceneInfo( state, sgData );
435         vectorMatInfo->matInstance->setTransforms( matrixSet, state );
436         GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
437      }
438   }
439
440   const Frustum& frustum = state->getCameraFrustum();
441   MatrixF invCam(frustum.getTransform());
442   invCam.inverse();
443
444   const MatrixF& cameraTrans = frustum.getTransform();
445
446   if(smUseLightFade || smMaximumNumOfLights != -1)
447      _scoreLights(cameraTrans);
448
449   S32 lightCount = 0;
450
451   // Blend the lights in the bin to the light buffer
452   for( LightBinIterator itr = mLightBin.begin(); itr != mLightBin.end(); itr++ )
453   {
454      if (smMaximumNumOfLights != -1 && lightCount >= smMaximumNumOfLights)
455         break;
456
457      lightCount++;
458
459      LightBinEntry& curEntry = *itr;
460      LightInfo *curLightInfo = curEntry.lightInfo;
461      if (curEntry.lightInfo->getType() >= LightInfo::Vector)
462         continue;
463      LightMaterialInfo *curLightMat = curEntry.lightMaterial;
464      const U32 numPrims = curEntry.numPrims;
465      const U32 numVerts = curEntry.vertBuffer->mNumVerts;
466
467      ShadowMapParams *lsp = curLightInfo->getExtended<ShadowMapParams>();
468
469      // Skip lights which won't affect the scene.
470      if (!curLightMat || curLightInfo->getBrightness() * curLightInfo->getFadeAmount() <= 0.001f)
471         continue;
472
473      GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Light, ColorI::RED );
474
475      setupSGData( sgData, state, curLightInfo );
476      curLightMat->setLightParameters( curLightInfo, state );
477      mShadowManager->setLightShadowMap( curEntry.shadowMap );
478
479      // Set geometry
480      GFX->setVertexBuffer( curEntry.vertBuffer );
481      GFX->setPrimitiveBuffer( curEntry.primBuffer );
482
483      lsp->getOcclusionQuery()->begin();
484
485      curLightMat->matInstance->mSpecialLight = false;
486
487      // Render the material passes
488      while( curLightMat->matInstance->setupPass( state, sgData ) )
489      {
490         // Set transforms
491         matrixSet.setWorld(*sgData.objTrans);
492         curLightMat->matInstance->setTransforms(matrixSet, state);
493         curLightMat->matInstance->setSceneInfo(state, sgData);
494
495         if(curEntry.primBuffer)
496            GFX->drawIndexedPrimitive(GFXTriangleList, 0, 0, numVerts, 0, numPrims);
497         else
498            GFX->drawPrimitive(GFXTriangleList, 0, numPrims);
499      }
500
501      lsp->getOcclusionQuery()->end();
502   }
503
504   // Set NULL for active shadow map (so nothing gets confused)
505   mShadowManager->setLightShadowMap(NULL);
506   GFX->setVertexBuffer( NULL );
507   GFX->setPrimitiveBuffer( NULL );
508
509   // Fire off a signal to let others know that light-bin rendering is ending now
510   getRenderSignal().trigger(state, this);
511
512   // Finish up the rendering
513   //_onPostRender();
514   GFX->popActiveRenderTarget();
515}
516
517AdvancedLightBinManager::LightMaterialInfo* AdvancedLightBinManager::_getLightMaterial(   LightInfo::Type lightType, 
518                                                                                          ShadowType shadowType, 
519                                                                                          bool useCookieTex )
520{
521   PROFILE_SCOPE( AdvancedLightBinManager_GetLightMaterial );
522
523   // Build the key.
524   const LightMatKey key( lightType, shadowType, useCookieTex );
525
526   // See if we've already built this one.
527   LightMatTable::Iterator iter = mLightMaterials.find( key );
528   if ( iter != mLightMaterials.end() )
529      return iter->value;
530   
531   // If we got here we need to build a material for 
532   // this light+shadow combination.
533
534   LightMaterialInfo *info = NULL;
535
536   // First get the light material name and make sure
537   // this light has a material in the first place.
538   const String &lightMatName = smLightMatNames[ lightType ];
539   if ( lightMatName.isNotEmpty() )
540   {
541      Vector<GFXShaderMacro> shadowMacros;
542
543      // Setup the shadow type macros for this material.
544      if ( shadowType == ShadowType_None )
545         shadowMacros.push_back( GFXShaderMacro( "NO_SHADOW" ) );
546      else
547      {
548         shadowMacros.push_back( GFXShaderMacro( smShadowTypeMacro[ shadowType ] ) );
549
550         // Do we need to do shadow filtering?
551         if ( smShadowFilterMode != ShadowFilterMode_None )
552         {
553            shadowMacros.push_back( GFXShaderMacro( "SOFTSHADOW" ) );
554           
555            const F32 SM = GFX->getPixelShaderVersion();
556            if ( SM >= 3.0f && smShadowFilterMode == ShadowFilterMode_SoftShadowHighQuality )
557               shadowMacros.push_back( GFXShaderMacro( "SOFTSHADOW_HIGH_QUALITY" ) );
558         }
559      }
560   
561      if ( useCookieTex )
562         shadowMacros.push_back( GFXShaderMacro( "USE_COOKIE_TEX" ) );
563
564      // Its safe to add the PSSM debug macro to all the materials.
565      if ( smPSSMDebugRender )
566         shadowMacros.push_back( GFXShaderMacro( "PSSM_DEBUG_RENDER" ) );
567
568      if( smDiffuseLightViz )
569         shadowMacros.push_back(GFXShaderMacro("DIFFUSE_LIGHT_VIZ"));
570      else if (smSpecularLightViz)
571         shadowMacros.push_back(GFXShaderMacro("SPECULAR_LIGHT_VIZ"));
572      else if (smDetailLightingViz)
573         shadowMacros.push_back(GFXShaderMacro("DETAIL_LIGHTING_VIZ"));
574
575      // Now create the material info object.
576      info = new LightMaterialInfo( lightMatName, smLightMatVertex[ lightType ], shadowMacros );
577   }
578
579   // Push this into the map and return it.
580   mLightMaterials.insertUnique( key, info );
581   return info;
582}
583
584void AdvancedLightBinManager::_deleteLightMaterials()
585{
586   LightMatTable::Iterator iter = mLightMaterials.begin();
587   for ( ; iter != mLightMaterials.end(); iter++ )
588      delete iter->value;
589      
590   mLightMaterials.clear();
591}
592
593void AdvancedLightBinManager::_setupPerFrameParameters( const SceneRenderState *state )
594{
595   PROFILE_SCOPE( AdvancedLightBinManager_SetupPerFrameParameters );
596   const Frustum &frustum = state->getCameraFrustum();
597
598   MatrixF invCam( frustum.getTransform() );
599   invCam.inverse();
600
601   const Point3F *wsFrustumPoints = frustum.getPoints();
602   const Point3F& cameraPos = frustum.getPosition();
603
604   // Perform a camera offset.  We need to manually perform this offset on the sun (or vector) light's
605   // polygon, which is at the far plane.
606   Point3F cameraOffsetPos = cameraPos;
607
608   // Now build the quad for drawing full-screen vector light
609   // passes.... this is a volatile VB and updates every frame.
610   FarFrustumQuadVert verts[4];
611   {
612      verts[0].point.set(wsFrustumPoints[Frustum::FarTopLeft] - cameraPos);
613      invCam.mulP(wsFrustumPoints[Frustum::FarTopLeft], &verts[0].normal);
614      verts[0].texCoord.set(-1.0, 1.0);
615      verts[0].tangent.set(wsFrustumPoints[Frustum::FarTopLeft] - cameraOffsetPos);
616
617      verts[1].point.set(wsFrustumPoints[Frustum::FarTopRight] - cameraPos);
618      invCam.mulP(wsFrustumPoints[Frustum::FarTopRight], &verts[1].normal);
619      verts[1].texCoord.set(1.0, 1.0);
620      verts[1].tangent.set(wsFrustumPoints[Frustum::FarTopRight] - cameraOffsetPos);
621
622      verts[2].point.set(wsFrustumPoints[Frustum::FarBottomLeft] - cameraPos);
623      invCam.mulP(wsFrustumPoints[Frustum::FarBottomLeft], &verts[2].normal);
624      verts[2].texCoord.set(-1.0, -1.0);
625      verts[2].tangent.set(wsFrustumPoints[Frustum::FarBottomLeft] - cameraOffsetPos);
626
627      verts[3].point.set(wsFrustumPoints[Frustum::FarBottomRight] - cameraPos);
628      invCam.mulP(wsFrustumPoints[Frustum::FarBottomRight], &verts[3].normal);
629      verts[3].texCoord.set(1.0, -1.0);
630      verts[3].tangent.set(wsFrustumPoints[Frustum::FarBottomRight] - cameraOffsetPos);
631   }
632   mFarFrustumQuadVerts.set( GFX, 4 );
633   dMemcpy( mFarFrustumQuadVerts.lock(), verts, sizeof( verts ) );
634   mFarFrustumQuadVerts.unlock();
635
636   PlaneF farPlane(wsFrustumPoints[Frustum::FarBottomLeft], wsFrustumPoints[Frustum::FarTopLeft], wsFrustumPoints[Frustum::FarTopRight]);
637   PlaneF vsFarPlane(verts[0].normal, verts[1].normal, verts[2].normal);
638
639   // Parameters calculated, assign them to the materials
640   LightMatTable::Iterator iter = mLightMaterials.begin();
641   for ( ; iter != mLightMaterials.end(); iter++ )
642   {
643      if ( iter->value )
644         iter->value->setViewParameters(  frustum.getNearDist(), 
645                                          frustum.getFarDist(), 
646                                          frustum.getPosition(), 
647                                          farPlane, 
648                                          vsFarPlane);
649   }
650}
651
652void AdvancedLightBinManager::setupSGData( SceneData &data, const SceneRenderState* state, LightInfo *light )
653{
654   PROFILE_SCOPE( AdvancedLightBinManager_setupSGData );
655
656   data.lights[0] = light;
657   data.ambientLightColor = state->getAmbientLightColor();
658   data.objTrans = &MatrixF::Identity;
659
660   if ( light )
661   {
662      if ( light->getType() == LightInfo::Point )
663      {
664         // The point light volume gets some flat spots along
665         // the perimiter mostly visible in the constant and 
666         // quadradic falloff modes.
667         //
668         // To account for them slightly increase the scale 
669         // instead of greatly increasing the polycount.
670
671         mLightMat = light->getTransform();
672         mLightMat.scale( light->getRange() * 1.01f );
673         data.objTrans = &mLightMat;
674      }
675      else if ( light->getType() == LightInfo::Spot )
676      {
677         mLightMat = light->getTransform();
678
679         // Rotate it to face down the -y axis.
680         MatrixF scaleRotateTranslate( EulerF( M_PI_F / -2.0f, 0.0f, 0.0f ) );
681
682         // Calculate the radius based on the range and angle.
683         F32 range = light->getRange().x;
684         F32 radius = range * mSin( mDegToRad( light->getOuterConeAngle() ) * 0.5f );
685
686         // NOTE: This fudge makes the cone a little bigger
687         // to remove the facet egde of the cone geometry.
688         radius *= 1.1f;
689
690         // Use the scale to distort the cone to
691         // match our radius and range.
692         scaleRotateTranslate.scale( Point3F( radius, radius, range ) );
693
694         // Apply the transform and set the position.
695         mLightMat *= scaleRotateTranslate;
696         mLightMat.setPosition( light->getPosition() );
697
698         data.objTrans = &mLightMat;
699      }
700   }
701}
702
703void AdvancedLightBinManager::MRTLightmapsDuringDeferred( bool val )
704{
705   // Do not enable if the GFX device can't do MRT's
706   if ( GFX->getNumRenderTargets() < 2 )
707      val = false;
708
709   if ( mMRTLightmapsDuringDeferred != val )
710   {
711      mMRTLightmapsDuringDeferred = val;
712
713      // Reload materials to cause a feature recalculation on deferred materials
714      if(mLightManager->isActive())
715         MATMGR->flushAndReInitInstances();
716
717      RenderDeferredMgr *deferred;
718      if ( Sim::findObject( "AL_DeferredBin", deferred ) && deferred->getTargetTexture( 0 ) )
719         deferred->updateTargets();
720   }
721}
722
723AdvancedLightBinManager::LightMaterialInfo::LightMaterialInfo( const String &matName,
724                                                               const GFXVertexFormat *vertexFormat,
725                                                               const Vector<GFXShaderMacro> &macros )
726:  matInstance(NULL),
727   zNearFarInvNearFar(NULL),
728   farPlane(NULL), 
729   vsFarPlane(NULL),
730   negFarPlaneDotEye(NULL),
731   lightPosition(NULL), 
732   lightDirection(NULL), 
733   lightColor(NULL), 
734   lightRange(NULL),
735   lightInvSqrRange(NULL),
736   lightAmbient(NULL),
737   lightSpotParams(NULL)
738{   
739   Material *mat = MATMGR->getMaterialDefinitionByName( matName );
740   if ( !mat )
741      return;
742
743   matInstance = new LightMatInstance( *mat );
744
745   for ( U32 i=0; i < macros.size(); i++ )
746      matInstance->addShaderMacro( macros[i].name, macros[i].value );
747
748   matInstance->init( MATMGR->getDefaultFeatures(), vertexFormat );
749
750   lightDirection = matInstance->getMaterialParameterHandle("$lightDirection");
751   lightAmbient = matInstance->getMaterialParameterHandle("$lightAmbient");
752   lightSpotParams = matInstance->getMaterialParameterHandle("$lightSpotParams");
753   lightRange = matInstance->getMaterialParameterHandle("$lightRange");
754   lightInvSqrRange = matInstance->getMaterialParameterHandle("$lightInvSqrRange");
755   lightPosition = matInstance->getMaterialParameterHandle("$lightPosition");
756   farPlane = matInstance->getMaterialParameterHandle("$farPlane");
757   vsFarPlane = matInstance->getMaterialParameterHandle("$vsFarPlane");
758   negFarPlaneDotEye = matInstance->getMaterialParameterHandle("$negFarPlaneDotEye");
759   zNearFarInvNearFar = matInstance->getMaterialParameterHandle("$zNearFarInvNearFar");
760   lightColor = matInstance->getMaterialParameterHandle("$lightColor");
761   lightBrightness = matInstance->getMaterialParameterHandle("$lightBrightness");
762}
763
764AdvancedLightBinManager::LightMaterialInfo::~LightMaterialInfo()
765{
766   SAFE_DELETE(matInstance);
767}
768
769void AdvancedLightBinManager::LightMaterialInfo::setViewParameters(  const F32 _zNear, 
770                                                                     const F32 _zFar, 
771                                                                     const Point3F &_eyePos, 
772                                                                     const PlaneF &_farPlane,
773                                                                     const PlaneF &_vsFarPlane)
774{
775   MaterialParameters *matParams = matInstance->getMaterialParameters();
776
777   matParams->setSafe( farPlane, *((const Point4F *)&_farPlane) );
778
779   matParams->setSafe( vsFarPlane, *((const Point4F *)&_vsFarPlane) );
780
781   if ( negFarPlaneDotEye->isValid() )
782   {
783      // -dot( farPlane, eyePos )
784      const F32 negFarPlaneDotEyeVal = -( mDot( *((const Point3F *)&_farPlane), _eyePos ) + _farPlane.d );
785      matParams->set( negFarPlaneDotEye, negFarPlaneDotEyeVal );
786   }
787
788   matParams->setSafe( zNearFarInvNearFar, Point4F( _zNear, _zFar, 1.0f / _zNear, 1.0f / _zFar ) );
789}
790
791void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const LightInfo *lightInfo, const SceneRenderState* renderState )
792{
793   MaterialParameters *matParams = matInstance->getMaterialParameters();
794
795   matParams->setSafe( lightColor, lightInfo->getColor() );
796   matParams->setSafe(lightBrightness, lightInfo->getBrightness() * lightInfo->getFadeAmount());
797
798   switch( lightInfo->getType() )
799   {
800   case LightInfo::Vector:
801      {
802         matParams->setSafe( lightDirection, lightInfo->getDirection());
803         matParams->setSafe( lightAmbient, renderState->getAmbientLightColor());
804      }
805      break;
806
807   case LightInfo::Spot:
808      {
809         const F32 outerCone = lightInfo->getOuterConeAngle();
810         const F32 innerCone = getMin(lightInfo->getInnerConeAngle(), outerCone);
811         const F32 outerCos = mCos(mDegToRad(outerCone / 2.0f));
812         const F32 innerCos = mCos(mDegToRad(innerCone / 2.0f));
813         Point2F spotParams(outerCos,innerCos - outerCos); 
814
815         matParams->setSafe( lightSpotParams, spotParams );
816         matParams->setSafe( lightDirection, lightInfo->getDirection());
817         matParams->setSafe( lightPosition, lightInfo->getPosition());
818
819         const F32 radius = lightInfo->getRange().x;
820         const F32 invSqrRadius = 1.0f / mSquared(radius);
821         matParams->setSafe(lightRange, radius);
822         matParams->setSafe(lightInvSqrRange, invSqrRadius);
823      }
824      break;
825
826   case LightInfo::Point:
827      {
828         matParams->setSafe(lightPosition, lightInfo->getPosition());
829
830         const F32 radius = lightInfo->getRange().x;
831         const F32 invSqrRadius = 1.0f / (radius * radius);
832         matParams->setSafe( lightRange, radius);
833         matParams->setSafe( lightInvSqrRange, invSqrRadius);  
834      }
835      break;
836
837   default:
838      AssertFatal( false, "Bad light type!" );
839      break;
840   }
841}
842
843bool LightMatInstance::setupPass( SceneRenderState *state, const SceneData &sgData )
844{
845   // Go no further if the material failed to initialize properly.
846   if (  !mProcessedMaterial || 
847         mProcessedMaterial->getNumPasses() == 0 )
848      return false;
849
850   U32 reflectStatus = Base;
851   if (state->isReflectPass())
852      reflectStatus = Reflecting;
853
854   // Fetch the lightmap params
855   const LightMapParams *lmParams = sgData.lights[0]->getExtended<LightMapParams>();
856   
857   // If no Lightmap params, let parent handle it
858   if(lmParams == NULL)
859      return Parent::setupPass(state, sgData);
860
861   // Defaults
862   bool bRetVal = true;
863
864   // What render pass is this...
865   if(mCurPass == -1)
866   {
867      // First pass, reset this flag
868      mInternalPass = false;
869
870      // Pass call to parent
871      bRetVal = Parent::setupPass(state, sgData);
872   }
873   else
874   {
875      // If this light is represented in a lightmap, it has already done it's 
876      // job for non-lightmapped geometry. Now render the lightmapped geometry
877      // pass (specular + shadow-darkening)
878      if(!mInternalPass && lmParams->representedInLightmap)
879         mInternalPass = true;
880      else
881         return Parent::setupPass(state, sgData);
882   }
883
884   // Set up the shader constants we need to...
885   if(mLightMapParamsSC->isValid())
886   {
887      // If this is an internal pass, special case the parameters
888      if(mInternalPass)
889      {
890         AssertFatal( lmParams->shadowDarkenColor.alpha == -1.0f, "Assumption failed, check unpack code!" );
891         getMaterialParameters()->set( mLightMapParamsSC, lmParams->shadowDarkenColor );
892      }
893      else
894         getMaterialParameters()->set( mLightMapParamsSC, LinearColorF::WHITE );
895   }
896
897   // Now override stateblock with our own
898   if(!mInternalPass)
899   {
900      // If this is not an internal pass, and this light is represented in lightmaps
901      // than only effect non-lightmapped geometry for this pass
902      if (lmParams->representedInLightmap)
903      {
904         GFX->setStateBlock(mLitState[StaticLightNonLMGeometry][reflectStatus]);
905      }
906      else // This is a normal, dynamic light.
907      {
908         if (mSpecialLight)
909            GFX->setStateBlock(mLitState[SunLight][reflectStatus]);
910         else
911            GFX->setStateBlock(mLitState[DynamicLight][reflectStatus]);
912      }
913
914   }
915   else // Internal pass, this is the add-specular/multiply-darken-color pass
916      GFX->setStateBlock(mLitState[StaticLightLMGeometry][reflectStatus]);
917
918   return bRetVal;
919}
920
921bool LightMatInstance::init( const FeatureSet &features, const GFXVertexFormat *vertexFormat )
922{
923   bool success = Parent::init(features, vertexFormat);
924   
925   // If the initialization failed don't continue.
926   if ( !success || !mProcessedMaterial || mProcessedMaterial->getNumPasses() == 0 )   
927      return false;
928
929   mLightMapParamsSC = getMaterialParameterHandle("$lightMapParams");
930
931   // Grab the state block for the first render pass (since this mat instance
932   // inserts a pass after the first pass)
933   AssertFatal(mProcessedMaterial->getNumPasses() > 0, "No passes created! Ohnoes");
934   const RenderPassData *rpd = mProcessedMaterial->getPass(0);
935   AssertFatal(rpd, "No render pass data!");
936   AssertFatal(rpd->mRenderStates[0], "No render state 0!");
937   
938   // Get state block desc for normal (not wireframe, not translucent, not glow, etc)
939   // render state
940   GFXStateBlockDesc litState = rpd->mRenderStates[0]->getDesc();
941
942   // Create state blocks for each of the 3 possible combos in setupPass
943
944   //DynamicLight State: This will effect lightmapped and non-lightmapped geometry
945   // in the same way.
946
947   litState.separateAlphaBlendDefined = true;
948   litState.separateAlphaBlendEnable = false;
949   litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask | RenderDeferredMgr::OpaqueStaticLitMask;
950   litState.setCullMode(GFXCullCW);
951   mLitState[DynamicLight][Base] = GFX->createStateBlock(litState);
952   litState.setCullMode(GFXCullCCW);
953   mLitState[DynamicLight][Reflecting] = GFX->createStateBlock(litState);
954
955   litState.separateAlphaBlendDefined = true;
956   litState.separateAlphaBlendEnable = false;
957   litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask | RenderDeferredMgr::OpaqueStaticLitMask;
958   litState.setCullMode(GFXCullCCW);
959   mLitState[SunLight][Base] = GFX->createStateBlock(litState);
960   litState.setCullMode(GFXCullCCW);
961   mLitState[SunLight][Reflecting] = GFX->createStateBlock(litState);
962
963   // StaticLightNonLMGeometry State: This will treat non-lightmapped geometry
964   // in the usual way, but will not effect lightmapped geometry.
965   litState.separateAlphaBlendDefined = true;
966   litState.separateAlphaBlendEnable = false;
967   litState.stencilMask = RenderDeferredMgr::OpaqueDynamicLitMask;
968   litState.setCullMode(GFXCullCW);
969   mLitState[StaticLightNonLMGeometry][Base] = GFX->createStateBlock(litState);
970   litState.setCullMode(GFXCullCCW);
971   mLitState[StaticLightNonLMGeometry][Reflecting] = GFX->createStateBlock(litState);
972
973   // StaticLightLMGeometry State: This will add specular information (alpha) but
974   // multiply-darken color information. 
975   litState.blendDest = GFXBlendSrcColor;
976   litState.blendSrc = GFXBlendZero;
977   litState.stencilMask = RenderDeferredMgr::OpaqueStaticLitMask;
978   litState.separateAlphaBlendDefined = true;
979   litState.separateAlphaBlendEnable = true;
980   litState.separateAlphaBlendSrc = GFXBlendOne;
981   litState.separateAlphaBlendDest = GFXBlendOne;
982   litState.separateAlphaBlendOp = GFXBlendOpAdd;
983   litState.setCullMode(GFXCullCW);
984   mLitState[StaticLightLMGeometry][Base] = GFX->createStateBlock(litState);
985   litState.setCullMode(GFXCullCCW);
986   mLitState[StaticLightLMGeometry][Reflecting] = GFX->createStateBlock(litState);
987
988   return true;
989}
990