| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 | //-----------------------------------------------------------------------------// 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/lightManager.h"#include "console/console.h"#include "console/consoleTypes.h"#include "core/util/safeDelete.h"#include "console/sim.h"#include "console/simSet.h"#include "scene/sceneManager.h"#include "materials/materialManager.h"#include "materials/sceneData.h"#include "lighting/lightInfo.h"#include "lighting/lightingInterfaces.h"#include "T3D/gameBase/gameConnection.h"#include "gfx/gfxStringEnumTranslate.h"#include "console/engineAPI.h"#include "renderInstance/renderPrePassMgr.h"Signal<void(const char*,bool)> LightManager::smActivateSignal;LightManager *LightManager::smActiveLM = NULL;LightManager::LightManager( const char *name, const char *id )   :  mName( name ),      mId( id ),      mIsActive( false ),            mSceneManager( NULL ),      mDefaultLight( NULL ),      mAvailableSLInterfaces( NULL ),      mCullPos( Point3F::Zero ){    _getLightManagers().insert( mName, this );   dMemset( &mSpecialLights, 0, sizeof( mSpecialLights ) );}LightManager::~LightManager() {   _getLightManagers().erase( mName );   SAFE_DELETE( mAvailableSLInterfaces );   SAFE_DELETE( mDefaultLight );}LightManagerMap& LightManager::_getLightManagers(){   static LightManagerMap lightManagerMap;   return lightManagerMap;}LightManager* LightManager::findByName( const char *name ){   LightManagerMap &lightManagers = _getLightManagers();   LightManagerMap::Iterator iter = lightManagers.find( name );   if ( iter != lightManagers.end() )      return iter->value;   return NULL;}void LightManager::getLightManagerNames( String *outString ){   LightManagerMap &lightManagers = _getLightManagers();   LightManagerMap::Iterator iter = lightManagers.begin();   for ( ; iter != lightManagers.end(); iter++ )      *outString += iter->key + "\t";   // TODO!   //outString->rtrim();}LightInfo* LightManager::createLightInfo(LightInfo* light /* = NULL */){   LightInfo *outLight = (light != NULL) ? light : new LightInfo;   LightManagerMap &lightManagers = _getLightManagers();   LightManagerMap::Iterator iter = lightManagers.begin();   for ( ; iter != lightManagers.end(); iter++ )   {      LightManager *lm = iter->value;      lm->_addLightInfoEx( outLight );   }   return outLight;}void LightManager::initLightFields(){   LightManagerMap &lightManagers = _getLightManagers();   LightManagerMap::Iterator iter = lightManagers.begin();   for ( ; iter != lightManagers.end(); iter++ )   {      LightManager *lm = iter->value;      lm->_initLightFields();   }}IMPLEMENT_GLOBAL_CALLBACK( onLightManagerActivate, void, ( const char *name ), ( name ),   "A callback called by the engine when a light manager is activated.\n"   "@param name The name of the light manager being activated.\n"   "@ingroup Lighting\n" );void LightManager::activate( SceneManager *sceneManager ){   AssertFatal( sceneManager, "LightManager::activate() - Got null scene manager!" );   AssertFatal( mIsActive == false, "LightManager::activate() - Already activated!" );   AssertFatal( smActiveLM == NULL, "LightManager::activate() - A previous LM is still active!" );   mIsActive = true;   mSceneManager = sceneManager;   smActiveLM = this;   onLightManagerActivate_callback( getName() );}IMPLEMENT_GLOBAL_CALLBACK( onLightManagerDeactivate, void, ( const char *name ), ( name ),   "A callback called by the engine when a light manager is deactivated.\n"   "@param name The name of the light manager being deactivated.\n"   "@ingroup Lighting\n" );void LightManager::deactivate(){   AssertFatal( mIsActive == true, "LightManager::deactivate() - Already deactivated!" );   AssertFatal( smActiveLM == this, "LightManager::activate() - This isn't the active light manager!" );   if( Sim::getRootGroup() ) // To protect against shutdown.      onLightManagerDeactivate_callback( getName() );   mIsActive = false;   mSceneManager = NULL;   smActiveLM = NULL;   // Just in case... make sure we're all clear.   unregisterAllLights();}LightInfo* LightManager::getDefaultLight(){   // The sun is always our default light when   // when its registered.   if ( mSpecialLights[ LightManager::slSunLightType ] )      return mSpecialLights[ LightManager::slSunLightType ];   // Else return a dummy special light.   if ( !mDefaultLight )      mDefaultLight = createLightInfo();   return mDefaultLight;}LightInfo* LightManager::getSpecialLight( LightManager::SpecialLightTypesEnum type, bool useDefault ){   if ( mSpecialLights[type] )      return mSpecialLights[type];   if ( useDefault )      return getDefaultLight();   return NULL;}void LightManager::setSpecialLight( LightManager::SpecialLightTypesEnum type, LightInfo *light ){   if ( light && type == slSunLightType )   {      // The sun must be specially positioned and ranged      // so that it can be processed like a point light       // in the stock light shader used by Basic Lighting.            light->setPosition( mCullPos - ( light->getDirection() * 10000.0f ) );      light->setRange( 2000000.0f );   }   mSpecialLights[type] = light;   registerGlobalLight( light, NULL );}void LightManager::registerGlobalLights( const Frustum *frustum, bool staticLighting ){   PROFILE_SCOPE( LightManager_RegisterGlobalLights );   // TODO: We need to work this out...   //   // 1. Why do we register and unregister lights on every    //    render when they don't often change... shouldn't we   //    just register once and keep them?   //    // 2. If we do culling of lights should this happen as part   //    of registration or somewhere else?   //   // Grab the lights to process.   Vector<SceneObject*> activeLights;   const U32 lightMask = LightObjectType;      if ( staticLighting || !frustum )   {      // We're processing static lighting or want all the lights      // in the container registerd...  so no culling.      getSceneManager()->getContainer()->findObjectList( lightMask, &activeLights );   }   else   {      // Cull the lights using the frustum.      getSceneManager()->getContainer()->findObjectList( *frustum, lightMask, &activeLights );      for (U32 i = 0; i < activeLights.size(); ++i)      {         if (!getSceneManager()->mRenderedObjectsList.contains(activeLights[i]))         {            activeLights.erase(i);            --i;         }      }      // Store the culling position for sun placement      // later... see setSpecialLight.      mCullPos = frustum->getPosition();      // HACK: Make sure the control object always gets       // processed as lights mounted to it don't change      // the shape bounds and can often get culled.      GameConnection *conn = GameConnection::getConnectionToServer();      if ( conn->getControlObject() )      {         GameBase *conObject = conn->getControlObject();         activeLights.push_back_unique( conObject );      }   }   // Let the lights register themselves.   for ( U32 i = 0; i < activeLights.size(); i++ )   {      ISceneLight *lightInterface = dynamic_cast<ISceneLight*>( activeLights[i] );      if ( lightInterface )         lightInterface->submitLights( this, staticLighting );   }}void LightManager::registerGlobalLight( LightInfo *light, SimObject *obj ){   AssertFatal( !mRegisteredLights.contains( light ),       "LightManager::registerGlobalLight - This light is already registered!" );   mRegisteredLights.push_back( light );}void LightManager::unregisterGlobalLight( LightInfo *light ){   mRegisteredLights.unregisterLight( light );   // If this is the sun... clear the special light too.   if ( light == mSpecialLights[slSunLightType] )      dMemset( mSpecialLights, 0, sizeof( mSpecialLights ) );}void LightManager::registerLocalLight( LightInfo *light ){   // TODO: What should we do here?}void LightManager::unregisterLocalLight( LightInfo *light ){   // TODO: What should we do here?}void LightManager::unregisterAllLights(){   dMemset( mSpecialLights, 0, sizeof( mSpecialLights ) );   mRegisteredLights.clear();}void LightManager::getAllUnsortedLights( Vector<LightInfo*> *list ) const{   list->merge( mRegisteredLights );}void LightManager::_update4LightConsts(   const SceneData &sgData,                                          GFXShaderConstHandle *lightPositionSC,                                          GFXShaderConstHandle *lightDiffuseSC,                                          GFXShaderConstHandle *lightAmbientSC,                                          GFXShaderConstHandle *lightInvRadiusSqSC,                                          GFXShaderConstHandle *lightSpotDirSC,                                          GFXShaderConstHandle *lightSpotAngleSC,                                GFXShaderConstHandle *lightSpotFalloffSC,                                          GFXShaderConstBuffer *shaderConsts ){   PROFILE_SCOPE( LightManager_Update4LightConsts );   // Skip over gathering lights if we don't have to!   if (  lightPositionSC->isValid() ||          lightDiffuseSC->isValid() ||         lightInvRadiusSqSC->isValid() ||         lightSpotDirSC->isValid() ||         lightSpotAngleSC->isValid() ||       lightSpotFalloffSC->isValid() )   {      PROFILE_SCOPE( LightManager_Update4LightConsts_setLights );         static AlignedArray<Point4F> lightPositions( 3, sizeof( Point4F ) );         static AlignedArray<Point4F> lightSpotDirs( 3, sizeof( Point4F ) );      static AlignedArray<Point4F> lightColors( 4, sizeof( Point4F ) );      static Point4F lightInvRadiusSq;      static Point4F lightSpotAngle;     static Point4F lightSpotFalloff;      F32 range;            // Need to clear the buffers so that we don't leak      // lights from previous passes or have NaNs.      dMemset( lightPositions.getBuffer(), 0, lightPositions.getBufferSize() );      dMemset( lightSpotDirs.getBuffer(), 0, lightSpotDirs.getBufferSize() );      dMemset( lightColors.getBuffer(), 0, lightColors.getBufferSize() );      lightInvRadiusSq = Point4F::Zero;      lightSpotAngle.set( -1.0f, -1.0f, -1.0f, -1.0f );      lightSpotFalloff.set( F32_MAX, F32_MAX, F32_MAX, F32_MAX );      // Gather the data for the first 4 lights.      const LightInfo *light;      for ( U32 i=0; i < 4; i++ )      {         light = sgData.lights[i];         if ( !light )                        break;            // The light positions and spot directions are             // in SoA order to make optimal use of the GPU.            const Point3F &lightPos = light->getPosition();            lightPositions[0][i] = lightPos.x;            lightPositions[1][i] = lightPos.y;            lightPositions[2][i] = lightPos.z;            const VectorF &lightDir = light->getDirection();            lightSpotDirs[0][i] = lightDir.x;            lightSpotDirs[1][i] = lightDir.y;            lightSpotDirs[2][i] = lightDir.z;                        if ( light->getType() == LightInfo::Spot )         {               lightSpotAngle[i] = mCos( mDegToRad( light->getOuterConeAngle() / 2.0f ) );             lightSpotFalloff[i] = 1.0f / getMax( F32_MIN, mCos( mDegToRad( light->getInnerConeAngle() / 2.0f ) ) - lightSpotAngle[i] );         }         // Prescale the light color by the brightness to          // avoid doing this in the shader.         lightColors[i] = Point4F(light->getColor()) * light->getBrightness();         // We need 1 over range^2 here.         range = light->getRange().x;         lightInvRadiusSq[i] = 1.0f / ( range * range );      }      shaderConsts->setSafe( lightPositionSC, lightPositions );         shaderConsts->setSafe( lightDiffuseSC, lightColors );      shaderConsts->setSafe( lightInvRadiusSqSC, lightInvRadiusSq );         shaderConsts->setSafe( lightSpotDirSC, lightSpotDirs );         shaderConsts->setSafe( lightSpotAngleSC, lightSpotAngle );       shaderConsts->setSafe( lightSpotFalloffSC, lightSpotFalloff );         }   // Setup the ambient lighting from the first    // light which is the directional light if    // one exists at all in the scene.   if ( lightAmbientSC->isValid() )      shaderConsts->set( lightAmbientSC, sgData.ambientLightColor );}AvailableSLInterfaces* LightManager::getSceneLightingInterface(){   if ( !mAvailableSLInterfaces )      mAvailableSLInterfaces = new AvailableSLInterfaces();   return mAvailableSLInterfaces;}bool LightManager::lightScene( const char* callback, const char* param ){   BitSet32 flags = 0;   if ( param )   {      if ( !dStricmp( param, "forceAlways" ) )         flags.set( SceneLighting::ForceAlways );      else if ( !dStricmp(param, "forceWritable" ) )         flags.set( SceneLighting::ForceWritable );      else if ( !dStricmp(param, "loadOnly" ) )         flags.set( SceneLighting::LoadOnly );   }   // The SceneLighting object will delete itself    // once the lighting process is complete.      SceneLighting* sl = new SceneLighting( getSceneLightingInterface() );   return sl->lightScene( callback, flags );}RenderPrePassMgr* LightManager::_findPrePassRenderBin(){   RenderPassManager* rpm = getSceneManager()->getDefaultRenderPass();   for( U32 i = 0; i < rpm->getManagerCount(); i++ )   {      RenderBinManager *bin = rpm->getManager( i );      if( bin->getRenderInstType() == RenderPrePassMgr::RIT_PrePass )      {         return ( RenderPrePassMgr* ) bin;      }   }   return NULL;}DefineEngineFunction( setLightManager, bool, ( const char *name ),,   "Finds and activates the named light manager.\n"   "@return Returns true if the light manager is found and activated.\n"   "@ingroup Lighting\n" ){   return gClientSceneGraph->setLightManager( name );}DefineEngineFunction( lightScene, bool, ( const char *completeCallbackFn, const char *mode ), ( nullAsType<const char*>(), nullAsType<const char*>() ),   "Will generate static lighting for the scene if supported by the active light manager.\n\n"   "If mode is \"forceAlways\", the lightmaps will be regenerated regardless of whether "   "lighting cache files can be written to. If mode is \"forceWritable\", then the lightmaps "   "will be regenerated only if the lighting cache files can be written.\n"   "@param completeCallbackFn The name of the function to execute when the lighting is complete.\n"   "@param mode One of \"forceAlways\",  \"forceWritable\" or \"loadOnly\".\n"   "@return Returns true if the scene lighting process was started.\n"   "@ingroup Lighting\n" ){   if ( !LIGHTMGR )      return false;   return LIGHTMGR->lightScene( completeCallbackFn, mode );}DefineEngineFunction( getLightManagerNames, String, (),,   "Returns a tab seperated list of light manager names.\n"   "@ingroup Lighting\n" ){   String names;   LightManager::getLightManagerNames( &names );   return names;}DefineEngineFunction( getActiveLightManager, const char*, (),,   "Returns the active light manager name.\n"   "@ingroup Lighting\n" ){   if ( !LIGHTMGR )      return NULL;   return LIGHTMGR->getName();}DefineEngineFunction( resetLightManager, void, (),,   "@brief Deactivates and then activates the currently active light manager."   "This causes most shaders to be regenerated and is often used when global "   "rendering changes have occured.\n"   "@ingroup Lighting\n" ){   LightManager *lm = LIGHTMGR;   if ( !lm )      return;   SceneManager *sm = lm->getSceneManager();   lm->deactivate();   lm->activate( sm );}
 |