materialManager.cpp 15 KB

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