materialManager.cpp 16 KB

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