| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 | //-----------------------------------------------------------------------------// 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/basic/basicLightManager.h"#include "platform/platformTimer.h"#include "console/simSet.h"#include "console/consoleTypes.h"#include "core/module.h"#include "core/util/safeDelete.h"#include "materials/processedMaterial.h"#include "shaderGen/shaderFeature.h"#include "lighting/basic/basicSceneObjectLightingPlugin.h"#include "shaderGen/shaderGenVars.h"#include "gfx/gfxShader.h"#include "materials/sceneData.h"#include "materials/materialParameters.h"#include "materials/materialManager.h"#include "materials/materialFeatureTypes.h"#include "math/util/frustum.h"#include "scene/sceneObject.h"#include "renderInstance/renderPrePassMgr.h"#include "shaderGen/featureMgr.h"#include "shaderGen/HLSL/shaderFeatureHLSL.h"#include "shaderGen/HLSL/bumpHLSL.h"#include "shaderGen/HLSL/pixSpecularHLSL.h"#include "lighting/basic/blInteriorSystem.h"#include "lighting/basic/blTerrainSystem.h"#include "lighting/common/projectedShadow.h"#if defined( TORQUE_OS_MAC ) || defined( TORQUE_OS_LINUX )#include "shaderGen/GLSL/shaderFeatureGLSL.h"#include "shaderGen/GLSL/bumpGLSL.h"#include "shaderGen/GLSL/pixSpecularGLSL.h"#endifMODULE_BEGIN( BasicLightManager )   MODULE_SHUTDOWN_AFTER( Scene )   MODULE_INIT   {      ManagedSingleton< BasicLightManager >::createSingleton();   }      MODULE_SHUTDOWN   {      ManagedSingleton< BasicLightManager >::deleteSingleton();   }MODULE_END;U32 BasicLightManager::smActiveShadowPlugins = 0;U32 BasicLightManager::smShadowsUpdated = 0;U32 BasicLightManager::smElapsedUpdateMs = 0;F32 BasicLightManager::smProjectedShadowFilterDistance = 40.0f;static S32 QSORT_CALLBACK comparePluginScores( const void *a, const void *b ){   const BasicSceneObjectLightingPlugin *A = *((BasicSceneObjectLightingPlugin**)a);   const BasicSceneObjectLightingPlugin *B = *((BasicSceneObjectLightingPlugin**)b);           F32 dif = B->getScore() - A->getScore();   return (S32)mFloor( dif );}BasicLightManager::BasicLightManager()   : LightManager( "Basic Lighting", "BLM" ),     mLastShader(NULL),     mLastConstants(NULL){   mTimer = PlatformTimer::create();      mInteriorSystem = new blInteriorSystem;   mTerrainSystem = new blTerrainSystem;      getSceneLightingInterface()->registerSystem( mInteriorSystem );   getSceneLightingInterface()->registerSystem( mTerrainSystem );   Con::addVariable( "$BasicLightManagerStats::activePlugins",       TypeS32, &smActiveShadowPlugins,      "The number of active Basic Lighting SceneObjectLightingPlugin objects this frame.\n"      "@ingroup BasicLighting\n" );   Con::addVariable( "$BasicLightManagerStats::shadowsUpdated",       TypeS32, &smShadowsUpdated,      "The number of Basic Lighting shadows updated this frame.\n"      "@ingroup BasicLighting\n" );   Con::addVariable( "$BasicLightManagerStats::elapsedUpdateMs",       TypeS32, &smElapsedUpdateMs,      "The number of milliseconds spent this frame updating Basic Lighting shadows.\n"      "@ingroup BasicLighting\n" );   Con::addVariable( "$BasicLightManager::shadowFilterDistance",       TypeF32, &smProjectedShadowFilterDistance,      "The maximum distance in meters that projected shadows will get soft filtering.\n"      "@ingroup BasicLighting\n" );   Con::addVariable( "$pref::ProjectedShadow::fadeStartPixelSize",       TypeF32, &ProjectedShadow::smFadeStartPixelSize,      "A size in pixels at which BL shadows begin to fade out. "      "This should be a larger value than fadeEndPixelSize.\n"      "@see DecalData\n"      "@ingroup BasicLighting\n" );   Con::addVariable( "$pref::ProjectedShadow::fadeEndPixelSize",       TypeF32, &ProjectedShadow::smFadeEndPixelSize,      "A size in pixels at which BL shadows are fully faded out. "      "This should be a smaller value than fadeStartPixelSize.\n"      "@see DecalData\n"      "@ingroup BasicLighting\n" );}BasicLightManager::~BasicLightManager(){   mLastShader = NULL;   mLastConstants = NULL;   for (LightConstantMap::Iterator i = mConstantLookup.begin(); i != mConstantLookup.end(); i++)   {      if (i->value)         SAFE_DELETE(i->value);   }   mConstantLookup.clear();   if (mTimer)      SAFE_DELETE( mTimer );   SAFE_DELETE( mTerrainSystem );   SAFE_DELETE( mInteriorSystem );}bool BasicLightManager::isCompatible() const{   // As long as we have some shaders this works.   return GFX->getPixelShaderVersion() > 1.0;}void BasicLightManager::activate( SceneManager *sceneManager ){   Parent::activate( sceneManager );   if( GFX->getAdapterType() == OpenGL )   {      #if defined( TORQUE_OS_MAC ) || defined( TORQUE_OS_LINUX )         FEATUREMGR->registerFeature( MFT_LightMap, new LightmapFeatGLSL );         FEATUREMGR->registerFeature( MFT_ToneMap, new TonemapFeatGLSL );         FEATUREMGR->registerFeature( MFT_NormalMap, new BumpFeatGLSL );         FEATUREMGR->registerFeature( MFT_RTLighting, new RTLightingFeatGLSL );         FEATUREMGR->registerFeature( MFT_PixSpecular, new PixelSpecularGLSL );      #endif   }   else   {      #if !defined( TORQUE_OS_MAC ) && !defined( TORQUE_OS_LINUX )         FEATUREMGR->registerFeature( MFT_LightMap, new LightmapFeatHLSL );         FEATUREMGR->registerFeature( MFT_ToneMap, new TonemapFeatHLSL );         FEATUREMGR->registerFeature( MFT_NormalMap, new BumpFeatHLSL );         FEATUREMGR->registerFeature( MFT_RTLighting, new RTLightingFeatHLSL );         FEATUREMGR->registerFeature( MFT_PixSpecular, new PixelSpecularHLSL );      #endif   }   FEATUREMGR->unregisterFeature( MFT_MinnaertShading );   FEATUREMGR->unregisterFeature( MFT_SubSurface );   // First look for the prepass bin...   RenderPrePassMgr *prePassBin = _findPrePassRenderBin();   /*   // If you would like to use forward shading, and have a linear depth pre-pass   // than un-comment this code block.   if ( !prePassBin )   {      Vector<GFXFormat> formats;      formats.push_back( GFXFormatR32F );      formats.push_back( GFXFormatR16F );      formats.push_back( GFXFormatR8G8B8A8 );      GFXFormat linearDepthFormat = GFX->selectSupportedFormat( &GFXDefaultRenderTargetProfile,         formats,         true,         false );      // Uncomment this for a no-color-write z-fill pass.       //linearDepthFormat = GFXFormat_COUNT;      prePassBin = new RenderPrePassMgr( linearDepthFormat != GFXFormat_COUNT, linearDepthFormat );      prePassBin->registerObject();      rpm->addManager( prePassBin );   }   */   mPrePassRenderBin = prePassBin;   // If there is a prepass bin   MATMGR->setPrePassEnabled( mPrePassRenderBin.isValid() );   sceneManager->setPostEffectFog( mPrePassRenderBin.isValid() && mPrePassRenderBin->getTargetChainLength() > 0  );   // Tell the material manager that we don't use prepass.   MATMGR->setPrePassEnabled( false );   GFXShader::addGlobalMacro( "TORQUE_BASIC_LIGHTING" );   // Hook into the SceneManager prerender signal.   sceneManager->getPreRenderSignal().notify( this, &BasicLightManager::_onPreRender );   // Last thing... let everyone know we're active.   smActivateSignal.trigger( getId(), true );}void BasicLightManager::deactivate(){   Parent::deactivate();   mLastShader = NULL;   mLastConstants = NULL;   for (LightConstantMap::Iterator i = mConstantLookup.begin(); i != mConstantLookup.end(); i++)   {      if (i->value)         SAFE_DELETE(i->value);   }   mConstantLookup.clear();   if ( mPrePassRenderBin )      mPrePassRenderBin->deleteObject();   mPrePassRenderBin = NULL;   GFXShader::removeGlobalMacro( "TORQUE_BASIC_LIGHTING" );   // Remove us from the prerender signal.   getSceneManager()->getPreRenderSignal().remove( this, &BasicLightManager::_onPreRender );   // Now let everyone know we've deactivated.   smActivateSignal.trigger( getId(), false );}void BasicLightManager::_onPreRender( SceneManager *sceneManger, const SceneRenderState *state ){   // Update all our shadow plugins here!   Vector<BasicSceneObjectLightingPlugin*> *pluginInsts = BasicSceneObjectLightingPlugin::getPluginInstances();   Vector<BasicSceneObjectLightingPlugin*>::const_iterator pluginIter = (*pluginInsts).begin();   for ( ; pluginIter != (*pluginInsts).end(); pluginIter++ )   {      BasicSceneObjectLightingPlugin *plugin = *pluginIter;      plugin->updateShadow( (SceneRenderState*)state );   }   U32 pluginCount = (*pluginInsts).size();   // Sort them by the score.   dQsort( (*pluginInsts).address(), pluginCount, sizeof(BasicSceneObjectLightingPlugin*), comparePluginScores );   mTimer->getElapsedMs();   mTimer->reset();   U32 numUpdated = 0;   U32 targetMs = 5;   S32 updateMs = 0;   pluginIter = (*pluginInsts).begin();   for ( ; pluginIter != (*pluginInsts).end(); pluginIter++ )   {      BasicSceneObjectLightingPlugin *plugin = *pluginIter;      // If we run out of update time then stop.      updateMs = mTimer->getElapsedMs();      if ( updateMs >= targetMs )         break;      // NOTE! Fix this all up to past const SceneRenderState!      plugin->renderShadow( (SceneRenderState*)state );      numUpdated++;   }   smShadowsUpdated = numUpdated;   smActiveShadowPlugins = pluginCount;   smElapsedUpdateMs = updateMs;}BasicLightManager::LightingShaderConstants::LightingShaderConstants()   :  mInit( false ),      mShader( NULL ),      mLightPosition( NULL ),      mLightDiffuse( NULL ),      mLightAmbient( NULL ),      mLightInvRadiusSq( NULL ),      mLightSpotDir( NULL ),      mLightSpotAngle( NULL ),	  mLightSpotFalloff( NULL ){}BasicLightManager::LightingShaderConstants::~LightingShaderConstants(){   if (mShader.isValid())   {      mShader->getReloadSignal().remove( this, &LightingShaderConstants::_onShaderReload );      mShader = NULL;   }}void BasicLightManager::LightingShaderConstants::init(GFXShader* shader){   if (mShader.getPointer() != shader)   {      if (mShader.isValid())         mShader->getReloadSignal().remove( this, &LightingShaderConstants::_onShaderReload );      mShader = shader;      mShader->getReloadSignal().notify( this, &LightingShaderConstants::_onShaderReload );   }   mLightPosition = shader->getShaderConstHandle( ShaderGenVars::lightPosition );   mLightDiffuse = shader->getShaderConstHandle( ShaderGenVars::lightDiffuse);   mLightInvRadiusSq = shader->getShaderConstHandle( ShaderGenVars::lightInvRadiusSq );   mLightAmbient = shader->getShaderConstHandle( ShaderGenVars::lightAmbient );      mLightSpotDir = shader->getShaderConstHandle( ShaderGenVars::lightSpotDir );   mLightSpotAngle = shader->getShaderConstHandle( ShaderGenVars::lightSpotAngle );   mLightSpotFalloff = shader->getShaderConstHandle( ShaderGenVars::lightSpotFalloff );   mInit = true;}void BasicLightManager::LightingShaderConstants::_onShaderReload(){   if (mShader.isValid())      init( mShader );}void BasicLightManager::setLightInfo(  ProcessedMaterial* pmat,                                        const Material* mat,                                        const SceneData& sgData,                                        const SceneRenderState *state,                                       U32 pass,                                        GFXShaderConstBuffer* shaderConsts ) {   PROFILE_SCOPE( BasicLightManager_SetLightInfo );   GFXShader *shader = shaderConsts->getShader();   // Check to see if this is the same shader.  Since we   // sort by material we should get hit repeatedly by the   // same one.  This optimization should save us many    // hash table lookups.   if ( mLastShader.getPointer() != shader )   {      LightConstantMap::Iterator iter = mConstantLookup.find(shader);         if ( iter != mConstantLookup.end() )      {         mLastConstants = iter->value;      }       else       {              LightingShaderConstants* lsc = new LightingShaderConstants();         mConstantLookup[shader] = lsc;         mLastConstants = lsc;            }      // Set our new shader      mLastShader = shader;   }   // Make sure that our current lighting constants are initialized   if (!mLastConstants->mInit)      mLastConstants->init(shader);   // NOTE: If you encounter a crash from this point forward   // while setting a shader constant its probably because the   // mConstantLookup has bad shaders/constants in it.   //   // This is a known crash bug that can occur if materials/shaders   // are reloaded and the light manager is not reset.   //   // We should look to fix this by clearing the table.   _update4LightConsts( sgData,                        mLastConstants->mLightPosition,                        mLastConstants->mLightDiffuse,                        mLastConstants->mLightAmbient,                        mLastConstants->mLightInvRadiusSq,                        mLastConstants->mLightSpotDir,                        mLastConstants->mLightSpotAngle,						mLastConstants->mLightSpotFalloff,                        shaderConsts );}
 |