123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- //-----------------------------------------------------------------------------
- // 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 "materials/materialManager.h"
- #include "materials/matInstance.h"
- #include "materials/materialFeatureTypes.h"
- #include "lighting/lightManager.h"
- #include "core/util/safeDelete.h"
- #include "shaderGen/shaderGen.h"
- #include "core/module.h"
- #include "console/consoleTypes.h"
- #include "console/engineAPI.h"
- #include "gui/controls/guiTreeViewCtrl.h"
- MODULE_BEGIN( MaterialManager )
- MODULE_INIT_BEFORE( GFX )
- MODULE_SHUTDOWN_BEFORE( GFX )
-
- MODULE_INIT
- {
- MaterialManager::createSingleton();
- }
-
- MODULE_SHUTDOWN
- {
- MaterialManager::deleteSingleton();
- }
- MODULE_END;
- MaterialManager::MaterialManager()
- {
- VECTOR_SET_ASSOCIATION( mMatInstanceList );
- mDt = 0.0f;
- mAccumTime = 0.0f;
- mLastTime = 0;
- mDampness = 0.0f;
- mWarningInst = NULL;
-
- GFXDevice::getDeviceEventSignal().notify( this, &MaterialManager::_handleGFXEvent );
- // Make sure we get activation signals
- // and that we're the last to get them.
- LightManager::smActivateSignal.notify( this, &MaterialManager::_onLMActivate, 9999 );
- mMaterialSet = NULL;
- mUsingDeferred = false;
- mFlushAndReInit = false;
- mDefaultAnisotropy = 1;
- Con::addVariable( "$pref::Video::defaultAnisotropy", TypeS32, &mDefaultAnisotropy,
- "@brief Global variable defining the default anisotropy value.\n\n"
- "Controls the default anisotropic texture filtering level for all materials, including the terrain. "
- "This value can be changed at runtime to see its affect without reloading.\n\n "
- "@ingroup Materials");
- Con::NotifyDelegate callabck( this, &MaterialManager::_updateDefaultAnisotropy );
- Con::addVariableNotify( "$pref::Video::defaultAnisotropy", callabck );
- Con::NotifyDelegate callabck2( this, &MaterialManager::_onDisableMaterialFeature );
- Con::setVariable( "$pref::Video::disableNormalMapping", "false" );
- Con::addVariableNotify( "$pref::Video::disableNormalMapping", callabck2 );
- Con::setVariable( "$pref::Video::disableCubemapping", "false" );
- Con::addVariableNotify( "$pref::Video::disableCubemapping", callabck2 );
- Con::setVariable( "$pref::Video::enableParallaxMapping", "true" );
- Con::addVariableNotify( "$pref::Video::enableParallaxMapping", callabck2 );
- }
- MaterialManager::~MaterialManager()
- {
- GFXDevice::getDeviceEventSignal().remove( this, &MaterialManager::_handleGFXEvent );
- LightManager::smActivateSignal.remove( this, &MaterialManager::_onLMActivate );
- SAFE_DELETE( mWarningInst );
- #ifndef TORQUE_SHIPPING
- DebugMaterialMap::Iterator itr = mMeshDebugMaterialInsts.begin();
- for ( ; itr != mMeshDebugMaterialInsts.end(); itr++ )
- delete itr->value;
- #endif
- }
- void MaterialManager::_onLMActivate( const char *lm, bool activate )
- {
- if ( !activate )
- return;
- // Since the light manager usually swaps shadergen features
- // and changes system wide shader defines we need to completely
- // flush and rebuild all the material instances.
- mFlushAndReInit = true;
- }
- void MaterialManager::_updateDefaultAnisotropy()
- {
- // Update all the materials.
- Vector<BaseMatInstance*>::iterator iter = mMatInstanceList.begin();
- for ( ; iter != mMatInstanceList.end(); iter++ )
- (*iter)->updateStateBlocks();
- }
- Material * MaterialManager::allocateAndRegister(const String &objectName, const String &mapToName)
- {
- Material *newMat = new Material();
- if ( mapToName.isNotEmpty() )
- newMat->mMapTo = mapToName;
- bool registered = newMat->registerObject(objectName );
- AssertFatal( registered, "Unable to register material" );
- if (registered)
- Sim::getRootGroup()->addObject( newMat );
- else
- {
- delete newMat;
- newMat = NULL;
- }
- return newMat;
- }
- Material * MaterialManager::getMaterialDefinitionByName(const String &matName)
- {
- // Get the material
- Material * foundMat;
- if(!Sim::findObject(matName, foundMat))
- {
- Con::errorf("MaterialManager: Unable to find material '%s'", matName.c_str());
- return NULL;
- }
- return foundMat;
- }
- Material* MaterialManager::getMaterialDefinitionByMapTo(const String& mapTo)
- {
- // Get the material
- Material* foundMat = nullptr;
- for (SimSet::iterator itr = mMaterialSet->begin(); itr != mMaterialSet->end(); ++itr)
- {
- // Fetch our listed materials.
- Material* materialDef = dynamic_cast<Material*>(*itr);
- if (materialDef && materialDef->mMapTo.compare(mapTo, 0U, String::NoCase) == 0)
- {
- //We have a match, so keep it and bail the loop
- foundMat = materialDef;
- break;
- }
- }
- return foundMat;
- }
- BaseMatInstance* MaterialManager::createMatInstance(const String &matName)
- {
- BaseMaterialDefinition* mat = NULL;
- if (Sim::findObject(matName, mat))
- return mat->createMatInstance();
- return NULL;
- }
- BaseMatInstance* MaterialManager::createMatInstance( const String &matName,
- const GFXVertexFormat *vertexFormat )
- {
- return createMatInstance( matName, getDefaultFeatures(), vertexFormat );
- }
- BaseMatInstance* MaterialManager::createMatInstance( const String &matName,
- const FeatureSet& features,
- const GFXVertexFormat *vertexFormat )
- {
- BaseMatInstance* mat = createMatInstance(matName);
- if (mat)
- {
- mat->init( features, vertexFormat );
- return mat;
- }
- return NULL;
- }
- BaseMatInstance * MaterialManager::createWarningMatInstance()
- {
- Material *warnMat = static_cast<Material*>(Sim::findObject("WarningMaterial"));
- BaseMatInstance *warnMatInstance = NULL;
- if( warnMat != NULL )
- {
- warnMatInstance = warnMat->createMatInstance();
- GFXStateBlockDesc desc;
- desc.setCullMode(GFXCullNone);
- warnMatInstance->addStateBlockDesc(desc);
- warnMatInstance->init( getDefaultFeatures(),
- getGFXVertexFormat<GFXVertexPNTTB>() );
- }
- else
- Con::errorf("WarningMaterial Not Found!");
- return warnMatInstance;
- }
- // Gets the global warning material instance, callers should not free this copy
- BaseMatInstance * MaterialManager::getWarningMatInstance()
- {
- if (!mWarningInst)
- mWarningInst = createWarningMatInstance();
- return mWarningInst;
- }
- #ifndef TORQUE_SHIPPING
- BaseMatInstance * MaterialManager::createMeshDebugMatInstance(const LinearColorF &meshColor)
- {
- String meshDebugStr = String::ToString( "Torque_MeshDebug_%d", meshColor.getRGBAPack() );
- Material *debugMat;
- if (!Sim::findObject(meshDebugStr,debugMat))
- {
- debugMat = allocateAndRegister( meshDebugStr );
- debugMat->mDiffuse[0] = meshColor;
- debugMat->mEmissive[0] = true;
- }
- BaseMatInstance *debugMatInstance = NULL;
- if( debugMat != NULL )
- {
- debugMatInstance = debugMat->createMatInstance();
- GFXStateBlockDesc desc;
- desc.setCullMode(GFXCullNone);
- desc.fillMode = GFXFillWireframe;
- debugMatInstance->addStateBlockDesc(desc);
- // Disable fog and other stuff.
- FeatureSet debugFeatures;
- debugFeatures.addFeature( MFT_DiffuseColor );
- debugMatInstance->init( debugFeatures, getGFXVertexFormat<GFXVertexPCN>() );
- }
- return debugMatInstance;
- }
- // Gets the global material instance for a given color, callers should not free this copy
- BaseMatInstance *MaterialManager::getMeshDebugMatInstance(const LinearColorF &meshColor)
- {
- DebugMaterialMap::Iterator itr = mMeshDebugMaterialInsts.find( meshColor.getRGBAPack() );
- BaseMatInstance *inst = NULL;
- if ( itr == mMeshDebugMaterialInsts.end() )
- inst = createMeshDebugMatInstance( meshColor );
- else
- inst = itr->value;
- mMeshDebugMaterialInsts.insert( meshColor.getRGBAPack(), inst );
- return inst;
- }
- #endif
- void MaterialManager::mapMaterial(const String & textureName, const String & materialName)
- {
- if (getMapEntry(textureName).isNotEmpty())
- {
- if (!textureName.equal("unmapped_mat", String::NoCase))
- Con::warnf(ConsoleLogEntry::General, "Warning, overwriting material for: %s", textureName.c_str());
- }
- mMaterialMap[String::ToLower(textureName)] = materialName;
- }
- String MaterialManager::getMapEntry(const String & textureName) const
- {
- MaterialMap::ConstIterator iter = mMaterialMap.find(String::ToLower(textureName));
- if ( iter == mMaterialMap.end() )
- return String();
- return iter->value;
- }
- void MaterialManager::flushAndReInitInstances()
- {
- // Clear the flag if its set.
- mFlushAndReInit = false;
- // Check to see if any shader preferences have changed.
- recalcFeaturesFromPrefs();
- // First we flush all the shader gen shaders which will
- // invalidate all GFXShader* to them.
- SHADERGEN->flushProceduralShaders();
- mFlushSignal.trigger();
- // First do a pass deleting all hooks as they can contain
- // materials themselves. This means we have to restart the
- // loop every time we delete any hooks... lame.
- Vector<BaseMatInstance*>::iterator iter = mMatInstanceList.begin();
- while ( iter != mMatInstanceList.end() )
- {
- if ( (*iter)->deleteAllHooks() != 0 )
- {
- // Restart the loop.
- iter = mMatInstanceList.begin();
- continue;
- }
- iter++;
- }
- // Now do a pass re-initializing materials.
- iter = mMatInstanceList.begin();
- for ( ; iter != mMatInstanceList.end(); iter++ )
- (*iter)->reInit();
- }
- // Used in the materialEditor. This flushes the material preview object so it can be reloaded easily.
- void MaterialManager::flushInstance( BaseMaterialDefinition *target )
- {
- Vector<BaseMatInstance*>::iterator iter = mMatInstanceList.begin();
- while ( iter != mMatInstanceList.end() )
- {
- if ( (*iter)->getMaterial() == target )
- {
- (*iter)->deleteAllHooks();
- return;
- }
- iter++;
- }
- }
- void MaterialManager::reInitInstance( BaseMaterialDefinition *target )
- {
- Vector<BaseMatInstance*>::iterator iter = mMatInstanceList.begin();
- for ( ; iter != mMatInstanceList.end(); iter++ )
- {
- if ( (*iter)->getMaterial() == target )
- (*iter)->reInit();
- }
- }
- void MaterialManager::updateTime()
- {
- U32 curTime = Sim::getCurrentTime();
- if(curTime > mLastTime)
- {
- mDt = (curTime - mLastTime) / 1000.0f;
- mLastTime = curTime;
- mAccumTime += mDt;
- }
- else
- mDt = 0.0f;
- }
- SimSet * MaterialManager::getMaterialSet()
- {
- if(!mMaterialSet)
- mMaterialSet = static_cast<SimSet*>( Sim::findObject( "MaterialSet" ) );
- AssertFatal( mMaterialSet, "MaterialSet not found" );
- return mMaterialSet;
- }
- void MaterialManager::dumpMaterialInstances( BaseMaterialDefinition *target ) const
- {
- if ( !mMatInstanceList.size() )
- return;
- if ( target )
- Con::printf( "--------------------- %s MatInstances ---------------------", target->getName() );
- else
- Con::printf( "--------------------- MatInstances %d ---------------------", mMatInstanceList.size() );
- for( U32 i=0; i<mMatInstanceList.size(); i++ )
- {
- BaseMatInstance *inst = mMatInstanceList[i];
-
- if ( target && inst->getMaterial() != target )
- continue;
- inst->dumpShaderInfo();
- Con::printf( "" );
- }
- Con::printf( "---------------------- Dump complete ----------------------");
- }
- void MaterialManager::getMaterialInstances(BaseMaterialDefinition* target, GuiTreeViewCtrl* materailInstanceTree)
- {
- if (!mMatInstanceList.size())
- return;
- if (!target)
- {
- Con::errorf("Can't form a list without a specific MaterialDefinition");
- return;
- }
- if (!materailInstanceTree)
- {
- Con::errorf("Requires a valid GuiTreeViewCtrl object to populate data into!");
- return;
- }
- U32 matItem = materailInstanceTree->insertItem(0, target->getName());
- for (U32 i = 0; i < mMatInstanceList.size(); i++)
- {
- BaseMatInstance* inst = mMatInstanceList[i];
- if (target && inst->getMaterial() != target)
- continue;
- inst->getShaderInfo(materailInstanceTree, matItem);
- }
- }
- void MaterialManager::_track( MatInstance *matInstance )
- {
- mMatInstanceList.push_back( matInstance );
- }
- void MaterialManager::_untrack( MatInstance *matInstance )
- {
- mMatInstanceList.remove( matInstance );
- }
- void MaterialManager::recalcFeaturesFromPrefs()
- {
- mDefaultFeatures.clear();
- FeatureType::addDefaultTypes( &mDefaultFeatures );
- mExclusionFeatures.setFeature( MFT_NormalMap,
- Con::getBoolVariable( "$pref::Video::disableNormalMapping", false ) );
- mExclusionFeatures.setFeature( MFT_CubeMap,
- Con::getBoolVariable( "$pref::Video::disableCubemapping", false ) );
- mExclusionFeatures.setFeature( MFT_Parallax,
- !Con::getBoolVariable( "$pref::Video::enableParallaxMapping", true ) );
- }
- bool MaterialManager::_handleGFXEvent( GFXDevice::GFXDeviceEventType event_ )
- {
- switch ( event_ )
- {
- case GFXDevice::deInit:
- recalcFeaturesFromPrefs();
- break;
- case GFXDevice::deDestroy :
- SAFE_DELETE( mWarningInst );
- break;
- case GFXDevice::deStartOfFrame:
- if ( mFlushAndReInit )
- flushAndReInitInstances();
- break;
- default:
- break;
- }
- return true;
- }
- DefineEngineFunction( reInitMaterials, void, (),,
- "@brief Flushes all procedural shaders and re-initializes all active material instances.\n\n"
- "@ingroup Materials")
- {
- MATMGR->flushAndReInitInstances();
- }
- DefineEngineFunction( addMaterialMapping, void, (const char * texName, const char * matName), , "(string texName, string matName)\n"
- "@brief Maps the given texture to the given material.\n\n"
- "Generates a console warning before overwriting.\n\n"
- "Material maps are used by terrain and interiors for triggering "
- "effects when an object moves onto a terrain "
- "block or interior surface using the associated texture.\n\n"
- "@ingroup Materials")
- {
- MATMGR->mapMaterial(texName, matName);
- }
- DefineEngineFunction( getMaterialMapping, const char*, (const char * texName), , "(string texName)\n"
- "@brief Returns the name of the material mapped to this texture.\n\n"
- "If no materials are found, an empty string is returned.\n\n"
- "@param texName Name of the texture\n\n"
- "@ingroup Materials")
- {
- return MATMGR->getMapEntry(texName).c_str();
- }
- DefineEngineFunction( dumpMaterialInstances, void, (), ,
- "@brief Dumps a formatted list of currently allocated material instances to the console.\n\n"
- "@ingroup Materials")
- {
- MATMGR->dumpMaterialInstances();
- }
- DefineEngineFunction(getMaterialInstances, void, (BaseMaterialDefinition* target, GuiTreeViewCtrl* tree), (nullAsType<BaseMaterialDefinition*>(), nullAsType<GuiTreeViewCtrl*>()),
- "@brief Dumps a formatted list of currently allocated material instances to the console.\n\n"
- "@ingroup Materials")
- {
- if (target == nullptr || tree == nullptr)
- return;
- MATMGR->getMaterialInstances(target, tree);
- }
- DefineEngineFunction( getMapEntry, const char*, (const char * texName), ,
- "@hide")
- {
- return MATMGR->getMapEntry( String(texName) );
- }
|