| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860 | //-----------------------------------------------------------------------------// Copyright (c) 2012 GarageGames, LLC//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to// deal in the Software without restriction, including without limitation the// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or// sell copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS// IN THE SOFTWARE.//-----------------------------------------------------------------------------#include "platform/platform.h"#include "lighting/advanced/advancedLightBinManager.h"#include "lighting/advanced/advancedLightManager.h"#include "lighting/advanced/advancedLightBufferConditioner.h"#include "lighting/shadowMap/shadowMapManager.h"#include "lighting/shadowMap/shadowMapPass.h"#include "lighting/shadowMap/lightShadowMap.h"#include "lighting/common/lightMapParams.h"#include "renderInstance/renderPrePassMgr.h"#include "gfx/gfxTransformSaver.h"#include "scene/sceneManager.h"#include "scene/sceneRenderState.h"#include "materials/materialManager.h"#include "materials/sceneData.h"#include "core/util/safeDelete.h"#include "core/util/rgb2luv.h"#include "gfx/gfxDebugEvent.h"#include "math/util/matrixSet.h"#include "console/consoleTypes.h"const RenderInstType AdvancedLightBinManager::RIT_LightInfo( "LightInfo" );const String AdvancedLightBinManager::smBufferName( "lightinfo" );ShadowFilterMode AdvancedLightBinManager::smShadowFilterMode = ShadowFilterMode_SoftShadowHighQuality;bool AdvancedLightBinManager::smPSSMDebugRender = false;bool AdvancedLightBinManager::smUseSSAOMask = false;ImplementEnumType( ShadowFilterMode,   "The shadow filtering modes for Advanced Lighting shadows.\n"   "@ingroup AdvancedLighting" )   { ShadowFilterMode_None, "None",       "@brief Simple point sampled filtering.\n"      "This is the fastest and lowest quality mode." },   { ShadowFilterMode_SoftShadow, "SoftShadow",       "@brief A variable tap rotated poisson disk soft shadow filter.\n"      "It performs 4 taps to classify the point as in shadow, out of shadow, or along a "      "shadow edge.  Samples on the edge get an additional 8 taps to soften them." },   { ShadowFilterMode_SoftShadowHighQuality, "SoftShadowHighQuality",       "@brief A 12 tap rotated poisson disk soft shadow filter.\n"      "It performs all the taps for every point without any early rejection." },EndImplementEnumType;// NOTE: The order here matches that of the LightInfo::Type enum.const String AdvancedLightBinManager::smLightMatNames[] ={   "AL_PointLightMaterial",   // LightInfo::Point   "AL_SpotLightMaterial",    // LightInfo::Spot   "AL_VectorLightMaterial",  // LightInfo::Vector   "",                        // LightInfo::Ambient};// NOTE: The order here matches that of the LightInfo::Type enum.const GFXVertexFormat* AdvancedLightBinManager::smLightMatVertex[] ={   getGFXVertexFormat<AdvancedLightManager::LightVertex>(), // LightInfo::Point   getGFXVertexFormat<AdvancedLightManager::LightVertex>(), // LightInfo::Spot   getGFXVertexFormat<FarFrustumQuadVert>(),                // LightInfo::Vector   NULL,                                                    // LightInfo::Ambient};// NOTE: The order here matches that of the ShadowType enum.const String AdvancedLightBinManager::smShadowTypeMacro[] ={   "", // ShadowType_Spot   "", // ShadowType_PSSM,   "SHADOW_PARABOLOID",                   // ShadowType_Paraboloid,   "SHADOW_DUALPARABOLOID_SINGLE_PASS",   // ShadowType_DualParaboloidSinglePass,   "SHADOW_DUALPARABOLOID",               // ShadowType_DualParaboloid,   "SHADOW_CUBE",                         // ShadowType_CubeMap,};AdvancedLightBinManager::RenderSignal &AdvancedLightBinManager::getRenderSignal(){   static RenderSignal theSignal;   return theSignal;}IMPLEMENT_CONOBJECT(AdvancedLightBinManager);ConsoleDocClass( AdvancedLightBinManager,   "@brief Rendering Manager responsible for lighting, shadows, and global variables affecing both.\n\n"   "Should not be exposed to TorqueScript as a game object, meant for internal use only\n\n"   "@ingroup Lighting");AdvancedLightBinManager::AdvancedLightBinManager( AdvancedLightManager *lm /* = NULL */,                                                  ShadowMapManager *sm /* = NULL */,                                                  GFXFormat lightBufferFormat /* = GFXFormatR8G8B8A8 */ )   :  RenderTexTargetBinManager( RIT_LightInfo, 1.0f, 1.0f, lightBufferFormat ),       mNumLightsCulled(0),       mLightManager(lm),       mShadowManager(sm),      mConditioner(NULL){   // Create an RGB conditioner   mConditioner = new AdvancedLightBufferConditioner( getTargetFormat(),                                                       AdvancedLightBufferConditioner::RGB );   mNamedTarget.setConditioner( mConditioner );    mNamedTarget.registerWithName( smBufferName );   // We want a full-resolution buffer   mTargetSizeType = RenderTexTargetBinManager::WindowSize;   mMRTLightmapsDuringPrePass = false;   Con::NotifyDelegate callback( this, &AdvancedLightBinManager::_deleteLightMaterials );   Con::addVariableNotify( "$pref::Shadows::filterMode", callback );   Con::addVariableNotify( "$AL::PSSMDebugRender", callback );   Con::addVariableNotify( "$AL::UseSSAOMask", callback );}AdvancedLightBinManager::~AdvancedLightBinManager(){   _deleteLightMaterials();   SAFE_DELETE(mConditioner);   Con::NotifyDelegate callback( this, &AdvancedLightBinManager::_deleteLightMaterials );   Con::removeVariableNotify( "$pref::shadows::filterMode", callback );   Con::removeVariableNotify( "$AL::PSSMDebugRender", callback );   Con::removeVariableNotify( "$AL::UseSSAOMask", callback );  }void AdvancedLightBinManager::consoleInit(){   Parent::consoleInit();   Con::addVariable( "$pref::shadows::filterMode",       TYPEID<ShadowFilterMode>(), &smShadowFilterMode,      "The filter mode to use for shadows.\n"      "@ingroup AdvancedLighting\n" );   Con::addVariable( "$AL::UseSSAOMask", TypeBool, &smUseSSAOMask,      "Used by the SSAO PostEffect to toggle the sampling of ssaomask "      "texture by the light shaders.\n"      "@ingroup AdvancedLighting\n" );   Con::addVariable( "$AL::PSSMDebugRender", TypeBool, &smPSSMDebugRender,      "Enables debug rendering of the PSSM shadows.\n"      "@ingroup AdvancedLighting\n" );}bool AdvancedLightBinManager::setTargetSize(const Point2I &newTargetSize){   bool ret = Parent::setTargetSize( newTargetSize );   // We require the viewport to match the default.   mNamedTarget.setViewport( GFX->getViewport() );   return ret;}void AdvancedLightBinManager::addLight( LightInfo *light ){   // Get the light type.   const LightInfo::Type lightType = light->getType();   AssertFatal(   lightType == LightInfo::Point ||                   lightType == LightInfo::Spot, "Bogus light type." );   // Find a shadow map for this light, if it has one   ShadowMapParams *lsp = light->getExtended<ShadowMapParams>();   LightShadowMap *lsm = lsp->getShadowMap();   LightShadowMap *dynamicShadowMap = lsp->getShadowMap(true);   // Get the right shadow type.   ShadowType shadowType = ShadowType_None;   if (  light->getCastShadows() &&           lsm && lsm->hasShadowTex() &&         !ShadowMapPass::smDisableShadows )      shadowType = lsm->getShadowType();   // Add the entry   LightBinEntry lEntry;   lEntry.lightInfo = light;   lEntry.shadowMap = lsm;   lEntry.dynamicShadowMap = dynamicShadowMap;   lEntry.lightMaterial = _getLightMaterial( lightType, shadowType, lsp->hasCookieTex() );   if( lightType == LightInfo::Spot )      lEntry.vertBuffer = mLightManager->getConeMesh( lEntry.numPrims, lEntry.primBuffer );   else      lEntry.vertBuffer = mLightManager->getSphereMesh( lEntry.numPrims, lEntry.primBuffer );   // If it's a point light, push front, spot    // light, push back. This helps batches.   Vector<LightBinEntry> &curBin = mLightBin;   if ( light->getType() == LightInfo::Point )      curBin.push_front( lEntry );   else      curBin.push_back( lEntry );}void AdvancedLightBinManager::clearAllLights(){   Con::setIntVariable("lightMetrics::activeLights", mLightBin.size());   Con::setIntVariable("lightMetrics::culledLights", mNumLightsCulled);   mLightBin.clear();   mNumLightsCulled = 0;}void AdvancedLightBinManager::render( SceneRenderState *state ){   PROFILE_SCOPE( AdvancedLightManager_Render );   // Take a look at the SceneRenderState and see if we should skip drawing the pre-pass   if( state->disableAdvancedLightingBins() )      return;   // Automagically save & restore our viewport and transforms.   GFXTransformSaver saver;   if( !mLightManager )      return;   // Get the sunlight. If there's no sun, and no lights in the bins, no draw   LightInfo *sunLight = mLightManager->getSpecialLight( LightManager::slSunLightType, false );   GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render, ColorI::RED );   // Tell the superclass we're about to render   if ( !_onPreRender( state ) )      return;   // Clear as long as there isn't MRT population of light buffer with lightmap data   if ( !MRTLightmapsDuringPrePass() )      GFX->clear(GFXClearTarget, ColorI(0, 0, 0, 0), 1.0f, 0);   // Restore transforms   MatrixSet &matrixSet = getRenderPass()->getMatrixSet();   matrixSet.restoreSceneViewProjection();   const MatrixF &worldToCameraXfm = matrixSet.getWorldToCamera();   // Set up the SG Data   SceneData sgData;   sgData.init( state );   // There are cases where shadow rendering is disabled.   const bool disableShadows = state->isReflectPass() || ShadowMapPass::smDisableShadows;   // Pick the right material for rendering the sunlight... we only   // cast shadows when its enabled and we're not in a reflection.   LightMaterialInfo *vectorMatInfo;   if (  sunLight &&         sunLight->getCastShadows() &&         !disableShadows &&         sunLight->getExtended<ShadowMapParams>() )      vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM, false );   else      vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None, false );   // Initialize and set the per-frame parameters after getting   // the vector light material as we use lazy creation.   _setupPerFrameParameters( state );      // Draw sunlight/ambient   if ( sunLight && vectorMatInfo )   {      GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Sunlight, ColorI::RED );      // Set up SG data      setupSGData( sgData, state, sunLight );      vectorMatInfo->setLightParameters( sunLight, state, worldToCameraXfm );      // Set light holds the active shadow map.             mShadowManager->setLightShadowMapForLight( sunLight );      // Set geometry      GFX->setVertexBuffer( mFarFrustumQuadVerts );      GFX->setPrimitiveBuffer( NULL );      // Render the material passes      while( vectorMatInfo->matInstance->setupPass( state, sgData ) )      {         vectorMatInfo->matInstance->setSceneInfo( state, sgData );         vectorMatInfo->matInstance->setTransforms( matrixSet, state );         GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );      }   }   // Blend the lights in the bin to the light buffer   for( LightBinIterator itr = mLightBin.begin(); itr != mLightBin.end(); itr++ )   {      LightBinEntry& curEntry = *itr;      LightInfo *curLightInfo = curEntry.lightInfo;      LightMaterialInfo *curLightMat = curEntry.lightMaterial;      const U32 numPrims = curEntry.numPrims;      const U32 numVerts = curEntry.vertBuffer->mNumVerts;      ShadowMapParams *lsp = curLightInfo->getExtended<ShadowMapParams>();      // Skip lights which won't affect the scene.      if ( !curLightMat || curLightInfo->getBrightness() <= 0.001f )         continue;      GFXDEBUGEVENT_SCOPE( AdvancedLightBinManager_Render_Light, ColorI::RED );      setupSGData( sgData, state, curLightInfo );      curLightMat->setLightParameters( curLightInfo, state, worldToCameraXfm );      mShadowManager->setLightShadowMap( curEntry.shadowMap );      mShadowManager->setLightDynamicShadowMap( curEntry.dynamicShadowMap );      // Set geometry      GFX->setVertexBuffer( curEntry.vertBuffer );      GFX->setPrimitiveBuffer( curEntry.primBuffer );      lsp->getOcclusionQuery()->begin();      // Render the material passes      while( curLightMat->matInstance->setupPass( state, sgData ) )      {         // Set transforms         matrixSet.setWorld(*sgData.objTrans);         curLightMat->matInstance->setTransforms(matrixSet, state);         curLightMat->matInstance->setSceneInfo(state, sgData);         if(curEntry.primBuffer)            GFX->drawIndexedPrimitive(GFXTriangleList, 0, 0, numVerts, 0, numPrims);         else            GFX->drawPrimitive(GFXTriangleList, 0, numPrims);      }      lsp->getOcclusionQuery()->end();   }   // Set NULL for active shadow map (so nothing gets confused)   mShadowManager->setLightShadowMap(NULL);   mShadowManager->setLightDynamicShadowMap(NULL);   GFX->setVertexBuffer( NULL );   GFX->setPrimitiveBuffer( NULL );   // Fire off a signal to let others know that light-bin rendering is ending now   getRenderSignal().trigger(state, this);   // Finish up the rendering   _onPostRender();}AdvancedLightBinManager::LightMaterialInfo* AdvancedLightBinManager::_getLightMaterial(   LightInfo::Type lightType,                                                                                           ShadowType shadowType,                                                                                           bool useCookieTex ){   PROFILE_SCOPE( AdvancedLightBinManager_GetLightMaterial );   // Build the key.   const LightMatKey key( lightType, shadowType, useCookieTex );   // See if we've already built this one.   LightMatTable::Iterator iter = mLightMaterials.find( key );   if ( iter != mLightMaterials.end() )      return iter->value;      // If we got here we need to build a material for    // this light+shadow combination.   LightMaterialInfo *info = NULL;   // First get the light material name and make sure   // this light has a material in the first place.   const String &lightMatName = smLightMatNames[ lightType ];   if ( lightMatName.isNotEmpty() )   {      Vector<GFXShaderMacro> shadowMacros;      // Setup the shadow type macros for this material.      if ( shadowType == ShadowType_None )         shadowMacros.push_back( GFXShaderMacro( "NO_SHADOW" ) );      else      {         shadowMacros.push_back( GFXShaderMacro( smShadowTypeMacro[ shadowType ] ) );         // Do we need to do shadow filtering?         if ( smShadowFilterMode != ShadowFilterMode_None )         {            shadowMacros.push_back( GFXShaderMacro( "SOFTSHADOW" ) );                       const F32 SM = GFX->getPixelShaderVersion();            if ( SM >= 3.0f && smShadowFilterMode == ShadowFilterMode_SoftShadowHighQuality )               shadowMacros.push_back( GFXShaderMacro( "SOFTSHADOW_HIGH_QUALITY" ) );         }      }         if ( useCookieTex )         shadowMacros.push_back( GFXShaderMacro( "USE_COOKIE_TEX" ) );      // Its safe to add the PSSM debug macro to all the materials.      if ( smPSSMDebugRender )         shadowMacros.push_back( GFXShaderMacro( "PSSM_DEBUG_RENDER" ) );      // If its a vector light see if we can enable SSAO.      if ( lightType == LightInfo::Vector && smUseSSAOMask )         shadowMacros.push_back( GFXShaderMacro( "USE_SSAO_MASK" ) );      // Now create the material info object.      info = new LightMaterialInfo( lightMatName, smLightMatVertex[ lightType ], shadowMacros );   }   // Push this into the map and return it.   mLightMaterials.insertUnique( key, info );   return info;}void AdvancedLightBinManager::_deleteLightMaterials(){   LightMatTable::Iterator iter = mLightMaterials.begin();   for ( ; iter != mLightMaterials.end(); iter++ )      delete iter->value;         mLightMaterials.clear();}void AdvancedLightBinManager::_setupPerFrameParameters( const SceneRenderState *state ){   PROFILE_SCOPE( AdvancedLightBinManager_SetupPerFrameParameters );   const Frustum &frustum = state->getCameraFrustum();   MatrixF invCam( frustum.getTransform() );   invCam.inverse();   const Point3F *wsFrustumPoints = frustum.getPoints();   const Point3F& cameraPos = frustum.getPosition();   // Perform a camera offset.  We need to manually perform this offset on the sun (or vector) light's   // polygon, which is at the far plane.   Point3F cameraOffsetPos = cameraPos;   // Now build the quad for drawing full-screen vector light   // passes.... this is a volatile VB and updates every frame.   FarFrustumQuadVert verts[4];   {      verts[0].point.set(wsFrustumPoints[Frustum::FarTopLeft] - cameraPos);      invCam.mulP(wsFrustumPoints[Frustum::FarTopLeft], &verts[0].normal);      verts[0].texCoord.set(-1.0, 1.0);      verts[0].tangent.set(wsFrustumPoints[Frustum::FarTopLeft] - cameraOffsetPos);      verts[1].point.set(wsFrustumPoints[Frustum::FarTopRight] - cameraPos);      invCam.mulP(wsFrustumPoints[Frustum::FarTopRight], &verts[1].normal);      verts[1].texCoord.set(1.0, 1.0);      verts[1].tangent.set(wsFrustumPoints[Frustum::FarTopRight] - cameraOffsetPos);      verts[2].point.set(wsFrustumPoints[Frustum::FarBottomLeft] - cameraPos);      invCam.mulP(wsFrustumPoints[Frustum::FarBottomLeft], &verts[2].normal);      verts[2].texCoord.set(-1.0, -1.0);      verts[2].tangent.set(wsFrustumPoints[Frustum::FarBottomLeft] - cameraOffsetPos);      verts[3].point.set(wsFrustumPoints[Frustum::FarBottomRight] - cameraPos);      invCam.mulP(wsFrustumPoints[Frustum::FarBottomRight], &verts[3].normal);      verts[3].texCoord.set(1.0, -1.0);      verts[3].tangent.set(wsFrustumPoints[Frustum::FarBottomRight] - cameraOffsetPos);   }   mFarFrustumQuadVerts.set( GFX, 4 );   dMemcpy( mFarFrustumQuadVerts.lock(), verts, sizeof( verts ) );   mFarFrustumQuadVerts.unlock();   PlaneF farPlane(wsFrustumPoints[Frustum::FarBottomLeft], wsFrustumPoints[Frustum::FarTopLeft], wsFrustumPoints[Frustum::FarTopRight]);   PlaneF vsFarPlane(verts[0].normal, verts[1].normal, verts[2].normal);   // Parameters calculated, assign them to the materials   LightMatTable::Iterator iter = mLightMaterials.begin();   for ( ; iter != mLightMaterials.end(); iter++ )   {      if ( iter->value )         iter->value->setViewParameters(  frustum.getNearDist(),                                           frustum.getFarDist(),                                           frustum.getPosition(),                                           farPlane,                                           vsFarPlane);   }}void AdvancedLightBinManager::setupSGData( SceneData &data, const SceneRenderState* state, LightInfo *light ){   PROFILE_SCOPE( AdvancedLightBinManager_setupSGData );   data.lights[0] = light;   data.ambientLightColor = state->getAmbientLightColor();   data.objTrans = &MatrixF::Identity;   if ( light )   {      if ( light->getType() == LightInfo::Point )      {         // The point light volume gets some flat spots along         // the perimiter mostly visible in the constant and          // quadradic falloff modes.         //         // To account for them slightly increase the scale          // instead of greatly increasing the polycount.         mLightMat = light->getTransform();         mLightMat.scale( light->getRange() * 1.01f );         data.objTrans = &mLightMat;      }      else if ( light->getType() == LightInfo::Spot )      {         mLightMat = light->getTransform();         // Rotate it to face down the -y axis.         MatrixF scaleRotateTranslate( EulerF( M_PI_F / -2.0f, 0.0f, 0.0f ) );         // Calculate the radius based on the range and angle.         F32 range = light->getRange().x;         F32 radius = range * mSin( mDegToRad( light->getOuterConeAngle() ) * 0.5f );         // NOTE: This fudge makes the cone a little bigger         // to remove the facet egde of the cone geometry.         radius *= 1.1f;         // Use the scale to distort the cone to         // match our radius and range.         scaleRotateTranslate.scale( Point3F( radius, radius, range ) );         // Apply the transform and set the position.         mLightMat *= scaleRotateTranslate;         mLightMat.setPosition( light->getPosition() );         data.objTrans = &mLightMat;      }   }}void AdvancedLightBinManager::MRTLightmapsDuringPrePass( bool val ){   // Do not enable if the GFX device can't do MRT's   if ( GFX->getNumRenderTargets() < 2 )      val = false;   if ( mMRTLightmapsDuringPrePass != val )   {      mMRTLightmapsDuringPrePass = val;      // Reload materials to cause a feature recalculation on prepass materials      if(mLightManager->isActive())         MATMGR->flushAndReInitInstances();      RenderPrePassMgr *prepass;      if ( Sim::findObject( "AL_PrePassBin", prepass ) && prepass->getTargetTexture( 0 ) )         prepass->updateTargets();   }}AdvancedLightBinManager::LightMaterialInfo::LightMaterialInfo( const String &matName,                                                               const GFXVertexFormat *vertexFormat,                                                               const Vector<GFXShaderMacro> ¯os ):  matInstance(NULL),   zNearFarInvNearFar(NULL),   farPlane(NULL),    vsFarPlane(NULL),   negFarPlaneDotEye(NULL),   lightPosition(NULL),    lightDirection(NULL),    lightColor(NULL),    lightAttenuation(NULL),   lightRange(NULL),    lightAmbient(NULL),    lightTrilight(NULL),    lightSpotParams(NULL){      Material *mat = MATMGR->getMaterialDefinitionByName( matName );   if ( !mat )      return;   matInstance = new LightMatInstance( *mat );   for ( U32 i=0; i < macros.size(); i++ )      matInstance->addShaderMacro( macros[i].name, macros[i].value );   matInstance->init( MATMGR->getDefaultFeatures(), vertexFormat );   lightDirection = matInstance->getMaterialParameterHandle("$lightDirection");   lightAmbient = matInstance->getMaterialParameterHandle("$lightAmbient");   lightTrilight = matInstance->getMaterialParameterHandle("$lightTrilight");   lightSpotParams = matInstance->getMaterialParameterHandle("$lightSpotParams");   lightAttenuation = matInstance->getMaterialParameterHandle("$lightAttenuation");   lightRange = matInstance->getMaterialParameterHandle("$lightRange");   lightPosition = matInstance->getMaterialParameterHandle("$lightPosition");   farPlane = matInstance->getMaterialParameterHandle("$farPlane");   vsFarPlane = matInstance->getMaterialParameterHandle("$vsFarPlane");   negFarPlaneDotEye = matInstance->getMaterialParameterHandle("$negFarPlaneDotEye");   zNearFarInvNearFar = matInstance->getMaterialParameterHandle("$zNearFarInvNearFar");   lightColor = matInstance->getMaterialParameterHandle("$lightColor");   lightBrightness = matInstance->getMaterialParameterHandle("$lightBrightness");}AdvancedLightBinManager::LightMaterialInfo::~LightMaterialInfo(){   SAFE_DELETE(matInstance);}void AdvancedLightBinManager::LightMaterialInfo::setViewParameters(  const F32 _zNear,                                                                      const F32 _zFar,                                                                      const Point3F &_eyePos,                                                                      const PlaneF &_farPlane,                                                                     const PlaneF &_vsFarPlane){   MaterialParameters *matParams = matInstance->getMaterialParameters();   matParams->setSafe( farPlane, *((const Point4F *)&_farPlane) );   matParams->setSafe( vsFarPlane, *((const Point4F *)&_vsFarPlane) );   if ( negFarPlaneDotEye->isValid() )   {      // -dot( farPlane, eyePos )      const F32 negFarPlaneDotEyeVal = -( mDot( *((const Point3F *)&_farPlane), _eyePos ) + _farPlane.d );      matParams->set( negFarPlaneDotEye, negFarPlaneDotEyeVal );   }   matParams->setSafe( zNearFarInvNearFar, Point4F( _zNear, _zFar, 1.0f / _zNear, 1.0f / _zFar ) );}void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const LightInfo *lightInfo, const SceneRenderState* renderState, const MatrixF &worldViewOnly ){   MaterialParameters *matParams = matInstance->getMaterialParameters();   // Set color in the right format, set alpha to the luminance value for the color.   ColorF col = lightInfo->getColor();   // TODO: The specularity control of the light   // is being scaled by the overall lumiance.   //   // Not sure if this may be the source of our   // bad specularity results maybe?   //   const Point3F colorToLumiance( 0.3576f, 0.7152f, 0.1192f );   F32 lumiance = mDot(*((const Point3F *)&lightInfo->getColor()), colorToLumiance );   col.alpha *= lumiance;   matParams->setSafe( lightColor, col.toLinear() );   matParams->setSafe( lightBrightness, lightInfo->getBrightness() );   switch( lightInfo->getType() )   {   case LightInfo::Vector:      {         VectorF lightDir = lightInfo->getDirection();         worldViewOnly.mulV(lightDir);         lightDir.normalize();         matParams->setSafe( lightDirection, lightDir );         // Set small number for alpha since it represents existing specular in         // the vector light. This prevents a divide by zero.         ColorF ambientColor = renderState->getAmbientLightColor();         ambientColor.alpha = 0.00001f;         matParams->setSafe( lightAmbient, ambientColor.toLinear() );         // If no alt color is specified, set it to the average of         // the ambient and main color to avoid artifacts.         //         // TODO: Trilight disabled until we properly implement it         // in the light info!         //         //ColorF lightAlt = lightInfo->getAltColor();         ColorF lightAlt( ColorF::BLACK ); // = lightInfo->getAltColor();         if ( lightAlt.red == 0.0f && lightAlt.green == 0.0f && lightAlt.blue == 0.0f )            lightAlt = (lightInfo->getColor() + renderState->getAmbientLightColor()) / 2.0f;         ColorF trilightColor = lightAlt;         matParams->setSafe(lightTrilight, trilightColor.toLinear());      }      break;   case LightInfo::Spot:      {         const F32 outerCone = lightInfo->getOuterConeAngle();         const F32 innerCone = getMin( lightInfo->getInnerConeAngle(), outerCone );         const F32 outerCos = mCos( mDegToRad( outerCone / 2.0f ) );         const F32 innerCos = mCos( mDegToRad( innerCone / 2.0f ) );         Point4F spotParams(  outerCos,                               innerCos - outerCos,                               mCos( mDegToRad( outerCone ) ),                               0.0f );         matParams->setSafe( lightSpotParams, spotParams );         VectorF lightDir = lightInfo->getDirection();         worldViewOnly.mulV(lightDir);         lightDir.normalize();         matParams->setSafe( lightDirection, lightDir );      }      // Fall through   case LightInfo::Point:   {      const F32 radius = lightInfo->getRange().x;      matParams->setSafe( lightRange, radius );      Point3F lightPos;      worldViewOnly.mulP(lightInfo->getPosition(), &lightPos);      matParams->setSafe( lightPosition, lightPos );      // Get the attenuation falloff ratio and normalize it.      Point3F attenRatio = lightInfo->getExtended<ShadowMapParams>()->attenuationRatio;      F32 total = attenRatio.x + attenRatio.y + attenRatio.z;      if ( total > 0.0f )         attenRatio /= total;      Point2F attenParams( ( 1.0f / radius ) * attenRatio.y,                           ( 1.0f / ( radius * radius ) ) * attenRatio.z );      matParams->setSafe( lightAttenuation, attenParams );      break;   }   default:      AssertFatal( false, "Bad light type!" );      break;   }}bool LightMatInstance::setupPass( SceneRenderState *state, const SceneData &sgData ){   // Go no further if the material failed to initialize properly.   if (  !mProcessedMaterial ||          mProcessedMaterial->getNumPasses() == 0 )      return false;   // Fetch the lightmap params   const LightMapParams *lmParams = sgData.lights[0]->getExtended<LightMapParams>();      // If no Lightmap params, let parent handle it   if(lmParams == NULL)      return Parent::setupPass(state, sgData);   // Defaults   bool bRetVal = true;   // What render pass is this...   if(mCurPass == -1)   {      // First pass, reset this flag      mInternalPass = false;      // Pass call to parent      bRetVal = Parent::setupPass(state, sgData);   }   else   {      // If this light is represented in a lightmap, it has already done it's       // job for non-lightmapped geometry. Now render the lightmapped geometry      // pass (specular + shadow-darkening)      if(!mInternalPass && lmParams->representedInLightmap)         mInternalPass = true;      else         return Parent::setupPass(state, sgData);   }   // Set up the shader constants we need to...   if(mLightMapParamsSC->isValid())   {      // If this is an internal pass, special case the parameters      if(mInternalPass)      {         AssertFatal( lmParams->shadowDarkenColor.alpha == -1.0f, "Assumption failed, check unpack code!" );         getMaterialParameters()->set( mLightMapParamsSC, lmParams->shadowDarkenColor );      }      else         getMaterialParameters()->set( mLightMapParamsSC, ColorF::WHITE );   }   // Now override stateblock with our own   if(!mInternalPass)   {      // If this is not an internal pass, and this light is represented in lightmaps      // than only effect non-lightmapped geometry for this pass      if(lmParams->representedInLightmap)         GFX->setStateBlock(mLitState[StaticLightNonLMGeometry]);      else // This is a normal, dynamic light.         GFX->setStateBlock(mLitState[DynamicLight]);         }   else // Internal pass, this is the add-specular/multiply-darken-color pass      GFX->setStateBlock(mLitState[StaticLightLMGeometry]);   return bRetVal;}bool LightMatInstance::init( const FeatureSet &features, const GFXVertexFormat *vertexFormat ){   bool success = Parent::init(features, vertexFormat);      // If the initialization failed don't continue.   if ( !success || !mProcessedMaterial || mProcessedMaterial->getNumPasses() == 0 )         return false;   mLightMapParamsSC = getMaterialParameterHandle("$lightMapParams");   // Grab the state block for the first render pass (since this mat instance   // inserts a pass after the first pass)   AssertFatal(mProcessedMaterial->getNumPasses() > 0, "No passes created! Ohnoes");   const RenderPassData *rpd = mProcessedMaterial->getPass(0);   AssertFatal(rpd, "No render pass data!");   AssertFatal(rpd->mRenderStates[0], "No render state 0!");      // Get state block desc for normal (not wireframe, not translucent, not glow, etc)   // render state   GFXStateBlockDesc litState = rpd->mRenderStates[0]->getDesc();   // Create state blocks for each of the 3 possible combos in setupPass   //DynamicLight State: This will effect lightmapped and non-lightmapped geometry   // in the same way.   litState.separateAlphaBlendDefined = true;   litState.separateAlphaBlendEnable = false;   litState.stencilMask = RenderPrePassMgr::OpaqueDynamicLitMask | RenderPrePassMgr::OpaqueStaticLitMask;   mLitState[DynamicLight] = GFX->createStateBlock(litState);   // StaticLightNonLMGeometry State: This will treat non-lightmapped geometry   // in the usual way, but will not effect lightmapped geometry.   litState.separateAlphaBlendDefined = true;   litState.separateAlphaBlendEnable = false;   litState.stencilMask = RenderPrePassMgr::OpaqueDynamicLitMask;   mLitState[StaticLightNonLMGeometry] = GFX->createStateBlock(litState);   // StaticLightLMGeometry State: This will add specular information (alpha) but   // multiply-darken color information.    litState.blendDest = GFXBlendSrcColor;   litState.blendSrc = GFXBlendZero;   litState.stencilMask = RenderPrePassMgr::OpaqueStaticLitMask;   litState.separateAlphaBlendDefined = true;   litState.separateAlphaBlendEnable = true;   litState.separateAlphaBlendSrc = GFXBlendOne;   litState.separateAlphaBlendDest = GFXBlendOne;   litState.separateAlphaBlendOp = GFXBlendOpAdd;   mLitState[StaticLightLMGeometry] = GFX->createStateBlock(litState);   return true;}
 |