materialManager.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "materials/materialManager.h"
  24. #include "materials/matInstance.h"
  25. #include "materials/materialFeatureTypes.h"
  26. #include "lighting/lightManager.h"
  27. #include "core/util/safeDelete.h"
  28. #include "shaderGen/shaderGen.h"
  29. #include "core/module.h"
  30. #include "console/consoleTypes.h"
  31. #include "console/engineAPI.h"
  32. MODULE_BEGIN( MaterialManager )
  33. MODULE_INIT_BEFORE( GFX )
  34. MODULE_SHUTDOWN_BEFORE( GFX )
  35. MODULE_INIT
  36. {
  37. MaterialManager::createSingleton();
  38. }
  39. MODULE_SHUTDOWN
  40. {
  41. MaterialManager::deleteSingleton();
  42. }
  43. MODULE_END;
  44. MaterialManager::MaterialManager()
  45. {
  46. VECTOR_SET_ASSOCIATION( mMatInstanceList );
  47. mDt = 0.0f;
  48. mAccumTime = 0.0f;
  49. mLastTime = 0;
  50. mWarningInst = NULL;
  51. GFXDevice::getDeviceEventSignal().notify( this, &MaterialManager::_handleGFXEvent );
  52. // Make sure we get activation signals
  53. // and that we're the last to get them.
  54. LightManager::smActivateSignal.notify( this, &MaterialManager::_onLMActivate, 9999 );
  55. mMaterialSet = NULL;
  56. mUsingDeferred = false;
  57. mFlushAndReInit = false;
  58. mDefaultAnisotropy = 1;
  59. Con::addVariable( "$pref::Video::defaultAnisotropy", TypeS32, &mDefaultAnisotropy,
  60. "@brief Global variable defining the default anisotropy value.\n\n"
  61. "Controls the default anisotropic texture filtering level for all materials, including the terrain. "
  62. "This value can be changed at runtime to see its affect without reloading.\n\n "
  63. "@ingroup Materials");
  64. Con::NotifyDelegate callabck( this, &MaterialManager::_updateDefaultAnisotropy );
  65. Con::addVariableNotify( "$pref::Video::defaultAnisotropy", callabck );
  66. Con::NotifyDelegate callabck2( this, &MaterialManager::_onDisableMaterialFeature );
  67. Con::setVariable( "$pref::Video::disableNormalMapping", "false" );
  68. Con::addVariableNotify( "$pref::Video::disableNormalMapping", callabck2 );
  69. Con::setVariable( "$pref::Video::disableCubemapping", "false" );
  70. Con::addVariableNotify( "$pref::Video::disableCubemapping", callabck2 );
  71. Con::setVariable( "$pref::Video::disableParallaxMapping", "false" );
  72. Con::addVariableNotify( "$pref::Video::disableParallaxMapping", callabck2 );
  73. }
  74. MaterialManager::~MaterialManager()
  75. {
  76. GFXDevice::getDeviceEventSignal().remove( this, &MaterialManager::_handleGFXEvent );
  77. LightManager::smActivateSignal.remove( this, &MaterialManager::_onLMActivate );
  78. SAFE_DELETE( mWarningInst );
  79. #ifndef TORQUE_SHIPPING
  80. DebugMaterialMap::Iterator itr = mMeshDebugMaterialInsts.begin();
  81. for ( ; itr != mMeshDebugMaterialInsts.end(); itr++ )
  82. delete itr->value;
  83. #endif
  84. }
  85. void MaterialManager::_onLMActivate( const char *lm, bool activate )
  86. {
  87. if ( !activate )
  88. return;
  89. // Since the light manager usually swaps shadergen features
  90. // and changes system wide shader defines we need to completely
  91. // flush and rebuild all the material instances.
  92. mFlushAndReInit = true;
  93. }
  94. void MaterialManager::_updateDefaultAnisotropy()
  95. {
  96. // Update all the materials.
  97. Vector<BaseMatInstance*>::iterator iter = mMatInstanceList.begin();
  98. for ( ; iter != mMatInstanceList.end(); iter++ )
  99. (*iter)->updateStateBlocks();
  100. }
  101. Material * MaterialManager::allocateAndRegister(const String &objectName, const String &mapToName)
  102. {
  103. Material *newMat = new Material();
  104. if ( mapToName.isNotEmpty() )
  105. newMat->mMapTo = mapToName;
  106. bool registered = newMat->registerObject(objectName );
  107. AssertFatal( registered, "Unable to register material" );
  108. if (registered)
  109. Sim::getRootGroup()->addObject( newMat );
  110. else
  111. {
  112. delete newMat;
  113. newMat = NULL;
  114. }
  115. return newMat;
  116. }
  117. Material * MaterialManager::getMaterialDefinitionByName(const String &matName)
  118. {
  119. // Get the material
  120. Material * foundMat;
  121. if(!Sim::findObject(matName, foundMat))
  122. {
  123. Con::errorf("MaterialManager: Unable to find material '%s'", matName.c_str());
  124. return NULL;
  125. }
  126. return foundMat;
  127. }
  128. BaseMatInstance* MaterialManager::createMatInstance(const String &matName)
  129. {
  130. BaseMaterialDefinition* mat = NULL;
  131. if (Sim::findObject(matName, mat))
  132. return mat->createMatInstance();
  133. return NULL;
  134. }
  135. BaseMatInstance* MaterialManager::createMatInstance( const String &matName,
  136. const GFXVertexFormat *vertexFormat )
  137. {
  138. return createMatInstance( matName, getDefaultFeatures(), vertexFormat );
  139. }
  140. BaseMatInstance* MaterialManager::createMatInstance( const String &matName,
  141. const FeatureSet& features,
  142. const GFXVertexFormat *vertexFormat )
  143. {
  144. BaseMatInstance* mat = createMatInstance(matName);
  145. if (mat)
  146. {
  147. mat->init( features, vertexFormat );
  148. return mat;
  149. }
  150. return NULL;
  151. }
  152. BaseMatInstance * MaterialManager::createWarningMatInstance()
  153. {
  154. Material *warnMat = static_cast<Material*>(Sim::findObject("WarningMaterial"));
  155. BaseMatInstance *warnMatInstance = NULL;
  156. if( warnMat != NULL )
  157. {
  158. warnMatInstance = warnMat->createMatInstance();
  159. GFXStateBlockDesc desc;
  160. desc.setCullMode(GFXCullNone);
  161. warnMatInstance->addStateBlockDesc(desc);
  162. warnMatInstance->init( getDefaultFeatures(),
  163. getGFXVertexFormat<GFXVertexPNTTB>() );
  164. }
  165. return warnMatInstance;
  166. }
  167. // Gets the global warning material instance, callers should not free this copy
  168. BaseMatInstance * MaterialManager::getWarningMatInstance()
  169. {
  170. if (!mWarningInst)
  171. mWarningInst = createWarningMatInstance();
  172. return mWarningInst;
  173. }
  174. #ifndef TORQUE_SHIPPING
  175. BaseMatInstance * MaterialManager::createMeshDebugMatInstance(const LinearColorF &meshColor)
  176. {
  177. String meshDebugStr = String::ToString( "Torque_MeshDebug_%d", meshColor.getRGBAPack() );
  178. Material *debugMat;
  179. if (!Sim::findObject(meshDebugStr,debugMat))
  180. {
  181. debugMat = allocateAndRegister( meshDebugStr );
  182. debugMat->mDiffuse[0] = meshColor;
  183. debugMat->mEmissive[0] = true;
  184. }
  185. BaseMatInstance *debugMatInstance = NULL;
  186. if( debugMat != NULL )
  187. {
  188. debugMatInstance = debugMat->createMatInstance();
  189. GFXStateBlockDesc desc;
  190. desc.setCullMode(GFXCullNone);
  191. desc.fillMode = GFXFillWireframe;
  192. debugMatInstance->addStateBlockDesc(desc);
  193. // Disable fog and other stuff.
  194. FeatureSet debugFeatures;
  195. debugFeatures.addFeature( MFT_DiffuseColor );
  196. debugMatInstance->init( debugFeatures, getGFXVertexFormat<GFXVertexPCN>() );
  197. }
  198. return debugMatInstance;
  199. }
  200. // Gets the global material instance for a given color, callers should not free this copy
  201. BaseMatInstance *MaterialManager::getMeshDebugMatInstance(const LinearColorF &meshColor)
  202. {
  203. DebugMaterialMap::Iterator itr = mMeshDebugMaterialInsts.find( meshColor.getRGBAPack() );
  204. BaseMatInstance *inst = NULL;
  205. if ( itr == mMeshDebugMaterialInsts.end() )
  206. inst = createMeshDebugMatInstance( meshColor );
  207. else
  208. inst = itr->value;
  209. mMeshDebugMaterialInsts.insert( meshColor.getRGBAPack(), inst );
  210. return inst;
  211. }
  212. #endif
  213. void MaterialManager::mapMaterial(const String & textureName, const String & materialName)
  214. {
  215. if (getMapEntry(textureName).isNotEmpty())
  216. {
  217. if (!textureName.equal("unmapped_mat", String::NoCase))
  218. Con::warnf(ConsoleLogEntry::General, "Warning, overwriting material for: %s", textureName.c_str());
  219. }
  220. mMaterialMap[String::ToLower(textureName)] = materialName;
  221. }
  222. String MaterialManager::getMapEntry(const String & textureName) const
  223. {
  224. MaterialMap::ConstIterator iter = mMaterialMap.find(String::ToLower(textureName));
  225. if ( iter == mMaterialMap.end() )
  226. return String();
  227. return iter->value;
  228. }
  229. void MaterialManager::flushAndReInitInstances()
  230. {
  231. // Clear the flag if its set.
  232. mFlushAndReInit = false;
  233. // Check to see if any shader preferences have changed.
  234. recalcFeaturesFromPrefs();
  235. // First we flush all the shader gen shaders which will
  236. // invalidate all GFXShader* to them.
  237. SHADERGEN->flushProceduralShaders();
  238. mFlushSignal.trigger();
  239. // First do a pass deleting all hooks as they can contain
  240. // materials themselves. This means we have to restart the
  241. // loop every time we delete any hooks... lame.
  242. Vector<BaseMatInstance*>::iterator iter = mMatInstanceList.begin();
  243. while ( iter != mMatInstanceList.end() )
  244. {
  245. if ( (*iter)->deleteAllHooks() != 0 )
  246. {
  247. // Restart the loop.
  248. iter = mMatInstanceList.begin();
  249. continue;
  250. }
  251. iter++;
  252. }
  253. // Now do a pass re-initializing materials.
  254. iter = mMatInstanceList.begin();
  255. for ( ; iter != mMatInstanceList.end(); iter++ )
  256. (*iter)->reInit();
  257. }
  258. // Used in the materialEditor. This flushes the material preview object so it can be reloaded easily.
  259. void MaterialManager::flushInstance( BaseMaterialDefinition *target )
  260. {
  261. Vector<BaseMatInstance*>::iterator iter = mMatInstanceList.begin();
  262. while ( iter != mMatInstanceList.end() )
  263. {
  264. if ( (*iter)->getMaterial() == target )
  265. {
  266. (*iter)->deleteAllHooks();
  267. return;
  268. }
  269. iter++;
  270. }
  271. }
  272. void MaterialManager::reInitInstance( BaseMaterialDefinition *target )
  273. {
  274. Vector<BaseMatInstance*>::iterator iter = mMatInstanceList.begin();
  275. for ( ; iter != mMatInstanceList.end(); iter++ )
  276. {
  277. if ( (*iter)->getMaterial() == target )
  278. (*iter)->reInit();
  279. }
  280. }
  281. void MaterialManager::updateTime()
  282. {
  283. U32 curTime = Sim::getCurrentTime();
  284. if(curTime > mLastTime)
  285. {
  286. mDt = (curTime - mLastTime) / 1000.0f;
  287. mLastTime = curTime;
  288. mAccumTime += mDt;
  289. }
  290. else
  291. mDt = 0.0f;
  292. }
  293. SimSet * MaterialManager::getMaterialSet()
  294. {
  295. if(!mMaterialSet)
  296. mMaterialSet = static_cast<SimSet*>( Sim::findObject( "MaterialSet" ) );
  297. AssertFatal( mMaterialSet, "MaterialSet not found" );
  298. return mMaterialSet;
  299. }
  300. void MaterialManager::dumpMaterialInstances( BaseMaterialDefinition *target ) const
  301. {
  302. if ( !mMatInstanceList.size() )
  303. return;
  304. if ( target )
  305. Con::printf( "--------------------- %s MatInstances ---------------------", target->getName() );
  306. else
  307. Con::printf( "--------------------- MatInstances %d ---------------------", mMatInstanceList.size() );
  308. for( U32 i=0; i<mMatInstanceList.size(); i++ )
  309. {
  310. BaseMatInstance *inst = mMatInstanceList[i];
  311. if ( target && inst->getMaterial() != target )
  312. continue;
  313. inst->dumpShaderInfo();
  314. Con::printf( "" );
  315. }
  316. Con::printf( "---------------------- Dump complete ----------------------");
  317. }
  318. void MaterialManager::_track( MatInstance *matInstance )
  319. {
  320. mMatInstanceList.push_back( matInstance );
  321. }
  322. void MaterialManager::_untrack( MatInstance *matInstance )
  323. {
  324. mMatInstanceList.remove( matInstance );
  325. }
  326. void MaterialManager::recalcFeaturesFromPrefs()
  327. {
  328. mDefaultFeatures.clear();
  329. FeatureType::addDefaultTypes( &mDefaultFeatures );
  330. mExclusionFeatures.setFeature( MFT_NormalMap,
  331. Con::getBoolVariable( "$pref::Video::disableNormalMapping", false ) );
  332. mExclusionFeatures.setFeature( MFT_CubeMap,
  333. Con::getBoolVariable( "$pref::Video::disableCubemapping", false ) );
  334. mExclusionFeatures.setFeature( MFT_Parallax,
  335. Con::getBoolVariable( "$pref::Video::disableParallaxMapping", false ) );
  336. }
  337. bool MaterialManager::_handleGFXEvent( GFXDevice::GFXDeviceEventType event_ )
  338. {
  339. switch ( event_ )
  340. {
  341. case GFXDevice::deInit:
  342. recalcFeaturesFromPrefs();
  343. break;
  344. case GFXDevice::deDestroy :
  345. SAFE_DELETE( mWarningInst );
  346. break;
  347. case GFXDevice::deStartOfFrame:
  348. if ( mFlushAndReInit )
  349. flushAndReInitInstances();
  350. break;
  351. default:
  352. break;
  353. }
  354. return true;
  355. }
  356. DefineEngineFunction( reInitMaterials, void, (),,
  357. "@brief Flushes all procedural shaders and re-initializes all active material instances.\n\n"
  358. "@ingroup Materials")
  359. {
  360. MATMGR->flushAndReInitInstances();
  361. }
  362. DefineEngineFunction( addMaterialMapping, void, (const char * texName, const char * matName), , "(string texName, string matName)\n"
  363. "@brief Maps the given texture to the given material.\n\n"
  364. "Generates a console warning before overwriting.\n\n"
  365. "Material maps are used by terrain and interiors for triggering "
  366. "effects when an object moves onto a terrain "
  367. "block or interior surface using the associated texture.\n\n"
  368. "@ingroup Materials")
  369. {
  370. MATMGR->mapMaterial(texName, matName);
  371. }
  372. DefineEngineFunction( getMaterialMapping, const char*, (const char * texName), , "(string texName)\n"
  373. "@brief Returns the name of the material mapped to this texture.\n\n"
  374. "If no materials are found, an empty string is returned.\n\n"
  375. "@param texName Name of the texture\n\n"
  376. "@ingroup Materials")
  377. {
  378. return MATMGR->getMapEntry(texName).c_str();
  379. }
  380. DefineEngineFunction( dumpMaterialInstances, void, (), ,
  381. "@brief Dumps a formatted list of currently allocated material instances to the console.\n\n"
  382. "@ingroup Materials")
  383. {
  384. MATMGR->dumpMaterialInstances();
  385. }
  386. DefineEngineFunction( getMapEntry, const char*, (const char * texName), ,
  387. "@hide")
  388. {
  389. return MATMGR->getMapEntry( String(texName) );
  390. }