materialDefinition.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  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/materialDefinition.h"
  24. #include "console/consoleTypes.h"
  25. #include "console/engineAPI.h"
  26. #include "math/mathTypes.h"
  27. #include "materials/materialManager.h"
  28. #include "sceneData.h"
  29. #include "gfx/sim/cubemapData.h"
  30. #include "gfx/gfxCubemap.h"
  31. #include "math/mathIO.h"
  32. #include "materials/matInstance.h"
  33. #include "sfx/sfxTrack.h"
  34. #include "sfx/sfxTypes.h"
  35. #include "core/util/safeDelete.h"
  36. #include "T3D/accumulationVolume.h"
  37. #include "gui/controls/guiTreeViewCtrl.h"
  38. IMPLEMENT_CONOBJECT( Material );
  39. ConsoleDocClass( Material,
  40. "@brief A material in Torque 3D is a data structure that describes a surface.\n\n"
  41. "It contains many different types of information for rendering properties. "
  42. "Torque 3D generates shaders from Material definitions. The shaders are compiled "
  43. "at runtime and output into the example/shaders directory. Any errors or warnings "
  44. "generated from compiling the procedurally generated shaders are output to the console "
  45. "as well as the output window in the Visual C IDE.\n\n"
  46. "@tsexample\n"
  47. "singleton Material(DECAL_scorch)\n"
  48. "{\n"
  49. " baseTex[0] = \"./scorch_decal.png\";\n"
  50. " vertColor[ 0 ] = true;\n\n"
  51. " translucent = true;\n"
  52. " translucentBlendOp = None;\n"
  53. " translucentZWrite = true;\n"
  54. " alphaTest = true;\n"
  55. " alphaRef = 84;\n"
  56. "};\n"
  57. "@endtsexample\n\n"
  58. "@see Rendering\n"
  59. "@see ShaderData\n"
  60. "@ingroup GFX\n");
  61. ImplementBitfieldType( MaterialAnimType,
  62. "The type of animation effect to apply to this material.\n"
  63. "@ingroup GFX\n\n")
  64. { Material::Scroll, "Scroll", "Scroll the material along the X/Y axis.\n" },
  65. { Material::Rotate, "Rotate" , "Rotate the material around a point.\n"},
  66. { Material::Wave, "Wave" , "Warps the material with an animation using Sin, Triangle or Square mathematics.\n"},
  67. { Material::Scale, "Scale", "Scales the material larger and smaller with a pulsing effect.\n" },
  68. { Material::Sequence, "Sequence", "Enables the material to have multiple frames of animation in its imagemap.\n" }
  69. EndImplementBitfieldType;
  70. ImplementEnumType( MaterialBlendOp,
  71. "The type of graphical blending operation to apply to this material\n"
  72. "@ingroup GFX\n\n")
  73. { Material::None, "None", "Disable blending for this material." },
  74. { Material::Mul, "Mul", "Multiplicative blending." },
  75. { Material::PreMul, "PreMul", "Premultiplied alpha." },
  76. { Material::Add, "Add", "Adds the color of the material to the frame buffer with full alpha for each pixel." },
  77. { Material::AddAlpha, "AddAlpha", "The color is modulated by the alpha channel before being added to the frame buffer." },
  78. { Material::Sub, "Sub", "Subtractive Blending. Reverses the color model, causing dark colors to have a stronger visual effect." },
  79. { Material::LerpAlpha, "LerpAlpha", "Linearly interpolates between Material color and frame buffer color based on alpha." }
  80. EndImplementEnumType;
  81. ImplementEnumType( MaterialWaveType,
  82. "When using the Wave material animation, one of these Wave Types will be used to determine the type of wave to display.\n"
  83. "@ingroup GFX\n")
  84. { Material::Sin, "Sin", "Warps the material along a curved Sin Wave." },
  85. { Material::Triangle, "Triangle", "Warps the material along a sharp Triangle Wave." },
  86. { Material::Square, "Square", "Warps the material along a wave which transitions between two oppposite states. As a Square Wave, the transition is quick and sudden." },
  87. EndImplementEnumType;
  88. #define initMapSlot(name,id) m##name##Filename[id] = String::EmptyString; m##name##AssetId[id] = StringTable->EmptyString(); m##name##Asset[id] = NULL;
  89. #define bindMapSlot(name,id) if (m##name##AssetId[id] != String::EmptyString) m##name##Asset[id] = m##name##AssetId[id];
  90. bool Material::sAllowTextureTargetAssignment = false;
  91. GFXCubemap * Material::GetNormalizeCube()
  92. {
  93. if(smNormalizeCube)
  94. return smNormalizeCube;
  95. smNormalizeCube = GFX->createCubemap();
  96. smNormalizeCube->initNormalize(64);
  97. return smNormalizeCube;
  98. }
  99. GFXCubemapHandle Material::smNormalizeCube;
  100. Material::Material()
  101. {
  102. for( U32 i=0; i<MAX_STAGES; i++ )
  103. {
  104. mDiffuse[i].set( 1.0f, 1.0f, 1.0f, 1.0f );
  105. mDiffuseMapSRGB[i] = true;
  106. mSmoothness[i] = 0.0f;
  107. mMetalness[i] = 0.0f;
  108. mIsSRGb[i] = true;
  109. mInvertSmoothness[i] = false;
  110. mSmoothnessChan[i] = 0;
  111. mAOChan[i] = 1;
  112. mMetalChan[i] = 2;
  113. mAccuEnabled[i] = false;
  114. mAccuScale[i] = 1.0f;
  115. mAccuDirection[i] = 1.0f;
  116. mAccuStrength[i] = 0.6f;
  117. mAccuCoverage[i] = 0.9f;
  118. mAccuSpecular[i] = 16.0f;
  119. initMapSlot(DiffuseMap, i);
  120. initMapSlot(OverlayMap, i);
  121. initMapSlot(LightMap, i);
  122. initMapSlot(ToneMap, i);
  123. initMapSlot(DetailMap, i);
  124. initMapSlot(NormalMap, i);
  125. initMapSlot(PBRConfigMap, i);
  126. initMapSlot(RoughMap, i);
  127. initMapSlot(AOMap, i);
  128. initMapSlot(MetalMap, i);
  129. initMapSlot(GlowMap, i);
  130. initMapSlot(DetailNormalMap, i);
  131. //cogs specific
  132. initMapSlot(AlbedoDamageMap, i);
  133. initMapSlot(NormalDamageMap, i);
  134. initMapSlot(CompositeDamageMap, i);
  135. mParallaxScale[i] = 0.0f;
  136. mVertLit[i] = false;
  137. mVertColor[ i ] = false;
  138. mGlow[i] = false;
  139. mEmissive[i] = false;
  140. mDetailScale[i].set( 2.0f, 2.0f );
  141. mDetailNormalMapStrength[i] = 1.0f;
  142. mMinnaertConstant[i] = -1.0f;
  143. mSubSurface[i] = false;
  144. mSubSurfaceColor[i].set( 1.0f, 0.2f, 0.2f, 1.0f );
  145. mSubSurfaceRolloff[i] = 0.2f;
  146. mAnimFlags[i] = 0;
  147. mScrollDir[i].set( 0.0f, 0.0f );
  148. mScrollSpeed[i] = 0.0f;
  149. mScrollOffset[i].set( 0.0f, 0.0f );
  150. mRotSpeed[i] = 0.0f;
  151. mRotPivotOffset[i].set( 0.0f, 0.0f );
  152. mRotPos[i] = 0.0f;
  153. mWavePos[i] = 0.0f;
  154. mWaveFreq[i] = 0.0f;
  155. mWaveAmp[i] = 0.0f;
  156. mWaveType[i] = 0;
  157. mSeqFramePerSec[i] = 0.0f;
  158. mSeqSegSize[i] = 0.0f;
  159. // Deferred Shading
  160. mMatInfoFlags[i] = 0.0f;
  161. // Damage
  162. mMaterialDamageMin[i] = 0.0f;
  163. mAlbedoDamageMapSRGB[i] = true;
  164. mGlowMul[i] = 0.0f;
  165. }
  166. dMemset(mCellIndex, 0, sizeof(mCellIndex));
  167. dMemset(mCellLayout, 0, sizeof(mCellLayout));
  168. dMemset(mCellSize, 0, sizeof(mCellSize));
  169. dMemset(mNormalMapAtlas, 0, sizeof(mNormalMapAtlas));
  170. dMemset(mUseAnisotropic, 1, sizeof(mUseAnisotropic));
  171. mImposterLimits = Point4F::Zero;
  172. mDoubleSided = false;
  173. mTranslucent = false;
  174. mTranslucentBlendOp = LerpAlpha;
  175. mTranslucentZWrite = false;
  176. mAlphaTest = false;
  177. mAlphaRef = 1;
  178. mCastShadows = true;
  179. mPlanarReflection = false;
  180. mCubemapData = NULL;
  181. mDynamicCubemap = NULL;
  182. mLastUpdateTime = 0;
  183. mAutoGenerated = false;
  184. mShowDust = false;
  185. mShowFootprints = true;
  186. dMemset( mEffectColor, 0, sizeof( mEffectColor ) );
  187. mFootstepSoundId = -1; mImpactSoundId = -1;
  188. mImpactFXIndex = -1;
  189. mFootstepSoundCustom = 0; mImpactSoundCustom = 0;
  190. mFriction = 0.0;
  191. mDirectSoundOcclusion = 1.f;
  192. mReverbSoundOcclusion = 1.0;
  193. }
  194. #define assetText(x,suff) std::string(std::string(#x) + std::string(#suff)).c_str()
  195. #define scriptBindMapSlot(name,arraySize) addField(#name, TypeImageFilename, Offset(m##name##Filename, Material), arraySize, assetText(name,texture map.)); \
  196. addField(assetText(name,Asset), TypeImageAssetPtr, Offset(m##name##AssetId, Material), arraySize, assetText(name,asset reference.));
  197. void Material::initPersistFields()
  198. {
  199. addField("mapTo", TypeRealString, Offset(mMapTo, Material),
  200. "Used to map this material to the material name used by TSShape." );
  201. addArray( "Stages", MAX_STAGES );
  202. addField("diffuseColor", TypeColorF, Offset(mDiffuse, Material), MAX_STAGES,
  203. "This color is multiplied against the diffuse texture color. If no diffuse texture "
  204. "is present this is the material color." );
  205. scriptBindMapSlot(DiffuseMap, MAX_STAGES);
  206. scriptBindMapSlot(OverlayMap, MAX_STAGES);
  207. scriptBindMapSlot(LightMap, MAX_STAGES);
  208. scriptBindMapSlot(ToneMap, MAX_STAGES);
  209. scriptBindMapSlot(DetailMap, MAX_STAGES);
  210. scriptBindMapSlot(NormalMap, MAX_STAGES);
  211. scriptBindMapSlot(PBRConfigMap, MAX_STAGES);
  212. scriptBindMapSlot(RoughMap, MAX_STAGES);
  213. scriptBindMapSlot(AOMap, MAX_STAGES);
  214. scriptBindMapSlot(MetalMap, MAX_STAGES);
  215. scriptBindMapSlot(GlowMap, MAX_STAGES);
  216. scriptBindMapSlot(DetailNormalMap, MAX_STAGES);
  217. addField("diffuseMapSRGB", TypeBool, Offset(mDiffuseMapSRGB, Material), MAX_STAGES,
  218. "Enable sRGB for the diffuse color texture map.");
  219. addField("detailScale", TypePoint2F, Offset(mDetailScale, Material), MAX_STAGES,
  220. "The scale factor for the detail map." );
  221. addField( "detailNormalMapStrength", TypeF32, Offset(mDetailNormalMapStrength, Material), MAX_STAGES,
  222. "Used to scale the strength of the detail normal map when blended with the base normal map." );
  223. addField("smoothness", TypeF32, Offset(mSmoothness, Material), MAX_STAGES,
  224. "The degree of smoothness when not using a PBRConfigMap." );
  225. addField("metalness", TypeF32, Offset(mMetalness, Material), MAX_STAGES,
  226. "The degree of Metalness when not using a PBRConfigMap." );
  227. addField("glowMul", TypeF32, Offset(mGlowMul, Material), MAX_STAGES,
  228. "glow mask multiplier");
  229. addProtectedField( "accuEnabled", TYPEID< bool >(), Offset( mAccuEnabled, Material ),
  230. &_setAccuEnabled, &defaultProtectedGetFn, MAX_STAGES, "Accumulation texture." );
  231. addField("accuScale", TypeF32, Offset(mAccuScale, Material), MAX_STAGES,
  232. "The scale that is applied to the accu map texture. You can use this to fit the texture to smaller or larger objects.");
  233. addField("accuDirection", TypeF32, Offset(mAccuDirection, Material), MAX_STAGES,
  234. "The direction of the accumulation. Chose whether you want the accu map to go from top to bottom (ie. snow) or upwards (ie. mold).");
  235. addField("accuStrength", TypeF32, Offset(mAccuStrength, Material), MAX_STAGES,
  236. "The strength of the accu map. This changes the transparency of the accu map texture. Make it subtle or add more contrast.");
  237. addField("accuCoverage", TypeF32, Offset(mAccuCoverage, Material), MAX_STAGES,
  238. "The coverage ratio of the accu map texture. Use this to make the entire shape pick up some of the accu map texture or none at all.");
  239. addField("accuSpecular", TypeF32, Offset(mAccuSpecular, Material), MAX_STAGES,
  240. "Changes specularity to this value where the accumulated material is present.");
  241. addField("isSRGb", TypeBool, Offset(mIsSRGb, Material), MAX_STAGES,
  242. "Substance Designer Workaround.");
  243. addField("invertSmoothness", TypeBool, Offset(mInvertSmoothness, Material), MAX_STAGES,
  244. "Treat Smoothness as Roughness");
  245. addField("smoothnessChan", TypeF32, Offset(mSmoothnessChan, Material), MAX_STAGES,
  246. "The input channel smoothness maps use.");
  247. addField("AOChan", TypeF32, Offset(mAOChan, Material), MAX_STAGES,
  248. "The input channel AO maps use.");
  249. addField("metalChan", TypeF32, Offset(mMetalChan, Material), MAX_STAGES,
  250. "The input channel metalness maps use.");
  251. addField("glowMul", TypeF32, Offset(mGlowMul, Material), MAX_STAGES,
  252. "The input channel metalness maps use.");
  253. addField("glow", TypeBool, Offset(mGlow, Material), MAX_STAGES,
  254. "Enables rendering as glowing.");
  255. addField( "parallaxScale", TypeF32, Offset(mParallaxScale, Material), MAX_STAGES,
  256. "Enables parallax mapping and defines the scale factor for the parallax effect. Typically "
  257. "this value is less than 0.4 else the effect breaks down." );
  258. addField( "useAnisotropic", TypeBool, Offset(mUseAnisotropic, Material), MAX_STAGES,
  259. "Use anisotropic filtering for the textures of this stage." );
  260. addField("vertLit", TypeBool, Offset(mVertLit, Material), MAX_STAGES,
  261. "If true the vertex color is used for lighting." );
  262. addField( "vertColor", TypeBool, Offset( mVertColor, Material ), MAX_STAGES,
  263. "If enabled, vertex colors are premultiplied with diffuse colors." );
  264. addField("minnaertConstant", TypeF32, Offset(mMinnaertConstant, Material), MAX_STAGES,
  265. "The Minnaert shading constant value. Must be greater than 0 to enable the effect." );
  266. addField("subSurface", TypeBool, Offset(mSubSurface, Material), MAX_STAGES,
  267. "Enables the subsurface scattering approximation." );
  268. addField("subSurfaceColor", TypeColorF, Offset(mSubSurfaceColor, Material), MAX_STAGES,
  269. "The color used for the subsurface scattering approximation." );
  270. addField("subSurfaceRolloff", TypeF32, Offset(mSubSurfaceRolloff, Material), MAX_STAGES,
  271. "The 0 to 1 rolloff factor used in the subsurface scattering approximation." );
  272. addField("emissive", TypeBool, Offset(mEmissive, Material), MAX_STAGES,
  273. "Enables emissive lighting for the material." );
  274. addField("doubleSided", TypeBool, Offset(mDoubleSided, Material),
  275. "Disables backface culling casing surfaces to be double sided. "
  276. "Note that the lighting on the backside will be a mirror of the front "
  277. "side of the surface." );
  278. addField("animFlags", TYPEID< AnimType >(), Offset(mAnimFlags, Material), MAX_STAGES,
  279. "The types of animation to play on this material." );
  280. addField("scrollDir", TypePoint2F, Offset(mScrollDir, Material), MAX_STAGES,
  281. "The scroll direction in UV space when scroll animation is enabled." );
  282. addField("scrollSpeed", TypeF32, Offset(mScrollSpeed, Material), MAX_STAGES,
  283. "The speed to scroll the texture in UVs per second when scroll animation is enabled." );
  284. addField("rotSpeed", TypeF32, Offset(mRotSpeed, Material), MAX_STAGES,
  285. "The speed to rotate the texture in degrees per second when rotation animation is enabled." );
  286. addField("rotPivotOffset", TypePoint2F, Offset(mRotPivotOffset, Material), MAX_STAGES,
  287. "The piviot position in UV coordinates to center the rotation animation." );
  288. addField("waveType", TYPEID< WaveType >(), Offset(mWaveType, Material), MAX_STAGES,
  289. "The type of wave animation to perform when wave animation is enabled." );
  290. addField("waveFreq", TypeF32, Offset(mWaveFreq, Material), MAX_STAGES,
  291. "The wave frequency when wave animation is enabled." );
  292. addField("waveAmp", TypeF32, Offset(mWaveAmp, Material), MAX_STAGES,
  293. "The wave amplitude when wave animation is enabled." );
  294. addField("sequenceFramePerSec", TypeF32, Offset(mSeqFramePerSec, Material), MAX_STAGES,
  295. "The number of frames per second for frame based sequence animations if greater than zero." );
  296. addField("sequenceSegmentSize", TypeF32, Offset(mSeqSegSize, Material), MAX_STAGES,
  297. "The size of each frame in UV units for sequence animations." );
  298. // Texture atlasing
  299. addField("cellIndex", TypePoint2I, Offset(mCellIndex, Material), MAX_STAGES,
  300. "@internal" );
  301. addField("cellLayout", TypePoint2I, Offset(mCellLayout, Material), MAX_STAGES,
  302. "@internal");
  303. addField("cellSize", TypeS32, Offset(mCellSize, Material), MAX_STAGES,
  304. "@internal");
  305. addField("bumpAtlas", TypeBool, Offset(mNormalMapAtlas, Material), MAX_STAGES,
  306. "@internal");
  307. // For backwards compatibility.
  308. //
  309. // They point at the new 'map' fields, but reads always return
  310. // an empty string and writes only apply if the value is not empty.
  311. //
  312. addProtectedField("baseTex", TypeImageFilename, Offset(mDiffuseMapFilename, Material),
  313. defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
  314. "For backwards compatibility.\n@see diffuseMap\n" );
  315. addProtectedField("detailTex", TypeImageFilename, Offset(mDetailMapFilename, Material),
  316. defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
  317. "For backwards compatibility.\n@see detailMap\n");
  318. addProtectedField("overlayTex", TypeImageFilename, Offset(mOverlayMapFilename, Material),
  319. defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
  320. "For backwards compatibility.\n@see overlayMap\n");
  321. addProtectedField("bumpTex", TypeImageFilename, Offset(mNormalMapFilename, Material),
  322. defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
  323. "For backwards compatibility.\n@see normalMap\n");
  324. addProtectedField("colorMultiply", TypeColorF, Offset(mDiffuse, Material),
  325. defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
  326. "For backwards compatibility.\n@see diffuseColor\n");
  327. endArray( "Stages" );
  328. addGroup("Damage");
  329. //cogs
  330. scriptBindMapSlot(AlbedoDamageMap, MAX_STAGES);
  331. /// Damage blend maps (normal)
  332. scriptBindMapSlot(NormalDamageMap, MAX_STAGES);
  333. /// Damage blend maps (Roughness, AO, Metalness)
  334. scriptBindMapSlot(CompositeDamageMap, MAX_STAGES);
  335. addField("albedoDamageSRGB", TypeBool, Offset(mAlbedoDamageMapSRGB, Material), MAX_STAGES,
  336. "Enable sRGB for the albedo damage map");
  337. addField("minDamage", TypeF32, Offset(mMaterialDamageMin, Material), MAX_STAGES,
  338. "The minimum ammount of blended damage.");
  339. endGroup("Damage");
  340. addField( "castShadows", TypeBool, Offset(mCastShadows, Material),
  341. "If set to false the lighting system will not cast shadows from this material." );
  342. addField("planarReflection", TypeBool, Offset(mPlanarReflection, Material), "@internal" );
  343. addField("translucent", TypeBool, Offset(mTranslucent, Material),
  344. "If true this material is translucent blended." );
  345. addField("translucentBlendOp", TYPEID< BlendOp >(), Offset(mTranslucentBlendOp, Material),
  346. "The type of blend operation to use when the material is translucent." );
  347. addField("translucentZWrite", TypeBool, Offset(mTranslucentZWrite, Material),
  348. "If enabled and the material is translucent it will write into the depth buffer." );
  349. addField("alphaTest", TypeBool, Offset(mAlphaTest, Material),
  350. "Enables alpha test when rendering the material.\n@see alphaRef\n" );
  351. addField("alphaRef", TypeS32, Offset(mAlphaRef, Material),
  352. "The alpha reference value for alpha testing. Must be between 0 to 255.\n@see alphaTest\n" );
  353. addField("cubemap", TypeRealString, Offset(mCubemapName, Material),
  354. "The name of a CubemapData for environment mapping." );
  355. addField("dynamicCubemap", TypeBool, Offset(mDynamicCubemap, Material),
  356. "Enables the material to use the dynamic cubemap from the ShapeBase object its applied to." );
  357. addGroup( "Behavioral" );
  358. addField( "showFootprints", TypeBool, Offset( mShowFootprints, Material ),
  359. "Whether to show player footprint decals on this material.\n\n"
  360. "@see PlayerData::decalData" );
  361. addField( "showDust", TypeBool, Offset( mShowDust, Material ),
  362. "Whether to emit dust particles from a shape moving over the material. This is, for example, used by "
  363. "vehicles or players to decide whether to show dust trails." );
  364. addField( "effectColor", TypeColorF, Offset( mEffectColor, Material ), NUM_EFFECT_COLOR_STAGES,
  365. "If #showDust is true, this is the set of colors to use for the ParticleData of the dust "
  366. "emitter.\n\n"
  367. "@see ParticleData::colors" );
  368. addField( "footstepSoundId", TypeS32, Offset( mFootstepSoundId, Material ),
  369. "What sound to play from the PlayerData sound list when the player walks over the material. -1 (default) to not play any sound.\n"
  370. "\n"
  371. "The IDs are:\n\n"
  372. "- 0: PlayerData::FootSoftSound\n"
  373. "- 1: PlayerData::FootHardSound\n"
  374. "- 2: PlayerData::FootMetalSound\n"
  375. "- 3: PlayerData::FootSnowSound\n"
  376. "- 4: PlayerData::FootShallowSound\n"
  377. "- 5: PlayerData::FootWadingSound\n"
  378. "- 6: PlayerData::FootUnderwaterSound\n"
  379. "- 7: PlayerData::FootBubblesSound\n"
  380. "- 8: PlayerData::movingBubblesSound\n"
  381. "- 9: PlayerData::waterBreathSound\n"
  382. "- 10: PlayerData::impactSoftSound\n"
  383. "- 11: PlayerData::impactHardSound\n"
  384. "- 12: PlayerData::impactMetalSound\n"
  385. "- 13: PlayerData::impactSnowSound\n"
  386. "- 14: PlayerData::impactWaterEasy\n"
  387. "- 15: PlayerData::impactWaterMedium\n"
  388. "- 16: PlayerData::impactWaterHard\n"
  389. "- 17: PlayerData::exitingWater\n" );
  390. addField( "customFootstepSound", TypeSFXTrackName, Offset( mFootstepSoundCustom, Material ),
  391. "The sound to play when the player walks over the material. If this is set, it overrides #footstepSoundId. This field is "
  392. "useful for directly assigning custom footstep sounds to materials without having to rely on the PlayerData sound assignment.\n\n"
  393. "@warn Be aware that materials are client-side objects. This means that the SFXTracks assigned to materials must be client-side, too." );
  394. addField( "impactSoundId", TypeS32, Offset( mImpactSoundId, Material ),
  395. "What sound to play from the PlayerData sound list when the player impacts on the surface with a velocity equal or greater "
  396. "than PlayerData::groundImpactMinSpeed.\n\n"
  397. "For a list of IDs, see #footstepSoundId" );
  398. addField("ImpactFXIndex", TypeS32, Offset(mImpactFXIndex, Material),
  399. "What FX to play from the PlayerData sound list when the player impacts on the surface with a velocity equal or greater "
  400. "than PlayerData::groundImpactMinSpeed.\n\n"
  401. "For a list of IDs, see #impactFXId");
  402. addField( "customImpactSound", TypeSFXTrackName, Offset( mImpactSoundCustom, Material ),
  403. "The sound to play when the player impacts on the surface with a velocity equal or greater than PlayerData::groundImpactMinSpeed. "
  404. "If this is set, it overrides #impactSoundId. This field is useful for directly assigning custom impact sounds to materials "
  405. "without having to rely on the PlayerData sound assignment.\n\n"
  406. "@warn Be aware that materials are client-side objects. This means that the SFXTracks assigned to materials must be client-side, too." );
  407. //Deactivate these for the moment as they are not used.
  408. #if 0
  409. addField( "friction", TypeF32, Offset( mFriction, Material ) );
  410. addField( "directSoundOcclusion", TypeF32, Offset( mDirectSoundOcclusion, Material ) );
  411. addField( "reverbSoundOcclusion", TypeF32, Offset( mReverbSoundOcclusion, Material ) );
  412. #endif
  413. endGroup( "Behavioral" );
  414. addProtectedField("customShaderFeature", TypeRealString, NULL, &protectedSetCustomShaderFeature, &defaultProtectedGetFn,
  415. "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors);
  416. addProtectedField("CustomShaderFeatureUniforms", TypeRealString, NULL, &protectedSetCustomShaderFeatureUniforms, &defaultProtectedGetFn,
  417. "Do not modify, for internal use.", AbstractClassRep::FIELD_HideInInspectors);
  418. Parent::initPersistFields();
  419. }
  420. bool Material::writeField( StringTableEntry fieldname, const char *value )
  421. {
  422. // Never allow the old field names to be written.
  423. if ( fieldname == StringTable->insert("baseTex") ||
  424. fieldname == StringTable->insert("detailTex") ||
  425. fieldname == StringTable->insert("overlayTex") ||
  426. fieldname == StringTable->insert("bumpTex") ||
  427. fieldname == StringTable->insert("envTex") ||
  428. fieldname == StringTable->insert("colorMultiply") )
  429. return false;
  430. return Parent::writeField( fieldname, value );
  431. }
  432. bool Material::protectedSetCustomShaderFeature(void *object, const char *index, const char *data)
  433. {
  434. Material *material = static_cast< Material* >(object);
  435. CustomShaderFeatureData* customFeature;
  436. if (!Sim::findObject(data, customFeature))
  437. return false;
  438. material->mCustomShaderFeatures.push_back(customFeature);
  439. return false;
  440. }
  441. bool Material::protectedSetCustomShaderFeatureUniforms(void *object, const char *index, const char *data)
  442. {
  443. Material *material = static_cast< Material* >(object);
  444. if (index != NULL)
  445. {
  446. char featureName[256] = { 0 };
  447. U32 id = 0;
  448. dSscanf(index, "%s_%i", featureName, id);
  449. String uniformName = data;
  450. }
  451. return false;
  452. }
  453. bool Material::onAdd()
  454. {
  455. if (Parent::onAdd() == false)
  456. return false;
  457. mCubemapData = dynamic_cast<CubemapData*>(Sim::findObject( mCubemapName ) );
  458. if( mTranslucentBlendOp >= NumBlendTypes || mTranslucentBlendOp < 0 )
  459. {
  460. Con::errorf( "Invalid blend op in material: %s", getName() );
  461. mTranslucentBlendOp = LerpAlpha;
  462. }
  463. SimSet *matSet = MATMGR->getMaterialSet();
  464. if( matSet )
  465. matSet->addObject( (SimObject*)this );
  466. // save the current script path for texture lookup later
  467. const String scriptFile = Con::getVariable("$Con::File"); // current script file - local materials.cs
  468. String::SizeType slash = scriptFile.find( '/', scriptFile.length(), String::Right );
  469. if ( slash != String::NPos )
  470. mPath = scriptFile.substr( 0, slash + 1 );
  471. /*
  472. //bind any assets we have
  473. for (U32 i = 0; i < MAX_STAGES; i++)
  474. {
  475. if (mDiffuseMapAssetId[i] != StringTable->EmptyString())
  476. {
  477. mDiffuseMapAsset[0] = mDiffuseMapAssetId[0];
  478. }
  479. }
  480. */
  481. for (U32 i = 0; i < MAX_STAGES; i++)
  482. {
  483. bindMapSlot(DiffuseMap, i);
  484. bindMapSlot(OverlayMap, i);
  485. bindMapSlot(LightMap, i);
  486. bindMapSlot(ToneMap, i);
  487. bindMapSlot(DetailMap, i);
  488. bindMapSlot(PBRConfigMap, i);
  489. bindMapSlot(RoughMap, i);
  490. bindMapSlot(AOMap, i);
  491. bindMapSlot(MetalMap, i);
  492. bindMapSlot(GlowMap, i);
  493. bindMapSlot(DetailNormalMap, i);
  494. //cogs specific
  495. bindMapSlot(AlbedoDamageMap, i);
  496. bindMapSlot(NormalDamageMap, i);
  497. bindMapSlot(CompositeDamageMap, i);
  498. }
  499. _mapMaterial();
  500. return true;
  501. }
  502. void Material::onRemove()
  503. {
  504. smNormalizeCube = NULL;
  505. Parent::onRemove();
  506. }
  507. void Material::inspectPostApply()
  508. {
  509. Parent::inspectPostApply();
  510. // Reload the material instances which
  511. // use this material.
  512. if ( isProperlyAdded() )
  513. reload();
  514. }
  515. bool Material::isLightmapped() const
  516. {
  517. bool ret = false;
  518. for( U32 i=0; i<MAX_STAGES; i++ )
  519. ret |= mLightMapFilename[i].isNotEmpty() || mToneMapFilename[i].isNotEmpty() || mVertLit[i];
  520. return ret;
  521. }
  522. void Material::updateTimeBasedParams()
  523. {
  524. U32 lastTime = MATMGR->getLastUpdateTime();
  525. F32 dt = MATMGR->getDeltaTime();
  526. if (mLastUpdateTime != lastTime)
  527. {
  528. for (U32 i = 0; i < MAX_STAGES; i++)
  529. {
  530. mScrollOffset[i] += mScrollDir[i] * mScrollSpeed[i] * dt;
  531. mRotPos[i] += mRotSpeed[i] * dt;
  532. mWavePos[i] += mWaveFreq[i] * dt;
  533. }
  534. mLastUpdateTime = lastTime;
  535. }
  536. }
  537. void Material::_mapMaterial()
  538. {
  539. if( String(getName()).isEmpty() )
  540. {
  541. Con::warnf( "[Material::mapMaterial] - Cannot map unnamed Material" );
  542. return;
  543. }
  544. // If mapTo not defined in script, try to use the base texture name instead
  545. if( mMapTo.isEmpty() )
  546. {
  547. if ( mDiffuseMapFilename[0].isEmpty() && mDiffuseMapAsset->isNull())
  548. return;
  549. else
  550. {
  551. // extract filename from base texture
  552. if ( mDiffuseMapFilename[0].isNotEmpty() )
  553. {
  554. U32 slashPos = mDiffuseMapFilename[0].find('/',0,String::Right);
  555. if (slashPos == String::NPos)
  556. // no '/' character, must be no path, just the filename
  557. mMapTo = mDiffuseMapFilename[0];
  558. else
  559. // use everything after the last slash
  560. mMapTo = mDiffuseMapFilename[0].substr(slashPos+1, mDiffuseMapFilename[0].length() - slashPos - 1);
  561. }
  562. else if (!mDiffuseMapAsset->isNull())
  563. {
  564. mMapTo = mDiffuseMapAsset[0]->getImageFileName();
  565. }
  566. }
  567. }
  568. // add mapping
  569. MATMGR->mapMaterial(mMapTo,getName());
  570. }
  571. BaseMatInstance* Material::createMatInstance()
  572. {
  573. return new MatInstance(*this);
  574. }
  575. void Material::flush()
  576. {
  577. MATMGR->flushInstance( this );
  578. }
  579. void Material::reload()
  580. {
  581. MATMGR->reInitInstance( this );
  582. }
  583. void Material::StageData::getFeatureSet( FeatureSet *outFeatures ) const
  584. {
  585. TextureTable::ConstIterator iter = mTextures.begin();
  586. for ( ; iter != mTextures.end(); iter++ )
  587. {
  588. if ( iter->value.isValid() )
  589. outFeatures->addFeature( *iter->key );
  590. }
  591. }
  592. DefineEngineMethod( Material, flush, void, (),,
  593. "Flushes all material instances that use this material." )
  594. {
  595. object->flush();
  596. }
  597. DefineEngineMethod( Material, reload, void, (),,
  598. "Reloads all material instances that use this material." )
  599. {
  600. object->reload();
  601. }
  602. DefineEngineMethod( Material, dumpInstances, void, (),,
  603. "Dumps a formatted list of the currently allocated material instances for this material to the console." )
  604. {
  605. MATMGR->dumpMaterialInstances( object );
  606. }
  607. DefineEngineMethod(Material, getMaterialInstances, void, (GuiTreeViewCtrl* matTree), (nullAsType< GuiTreeViewCtrl*>()),
  608. "Dumps a formatted list of the currently allocated material instances for this material to the console.")
  609. {
  610. MATMGR->getMaterialInstances(object, matTree);
  611. }
  612. DefineEngineMethod( Material, getAnimFlags, const char*, (U32 id), , "" )
  613. {
  614. char * animFlags = Con::getReturnBuffer(512);
  615. if(object->mAnimFlags[ id ] & Material::Scroll)
  616. {
  617. if(dStrcmp( animFlags, "" ) == 0)
  618. dStrcpy( animFlags, "$Scroll", 512 );
  619. }
  620. if(object->mAnimFlags[ id ] & Material::Rotate)
  621. {
  622. if(dStrcmp( animFlags, "" ) == 0)
  623. dStrcpy( animFlags, "$Rotate", 512 );
  624. else
  625. dStrcat( animFlags, " | $Rotate", 512);
  626. }
  627. if(object->mAnimFlags[ id ] & Material::Wave)
  628. {
  629. if(dStrcmp( animFlags, "" ) == 0)
  630. dStrcpy( animFlags, "$Wave", 512 );
  631. else
  632. dStrcat( animFlags, " | $Wave", 512);
  633. }
  634. if(object->mAnimFlags[ id ] & Material::Scale)
  635. {
  636. if(dStrcmp( animFlags, "" ) == 0)
  637. dStrcpy( animFlags, "$Scale", 512 );
  638. else
  639. dStrcat( animFlags, " | $Scale", 512);
  640. }
  641. if(object->mAnimFlags[ id ] & Material::Sequence)
  642. {
  643. if(dStrcmp( animFlags, "" ) == 0)
  644. dStrcpy( animFlags, "$Sequence", 512 );
  645. else
  646. dStrcat( animFlags, " | $Sequence", 512);
  647. }
  648. return animFlags;
  649. }
  650. DefineEngineMethod(Material, getFilename, const char*, (),, "Get filename of material")
  651. {
  652. SimObject *material = static_cast<SimObject *>(object);
  653. return material->getFilename();
  654. }
  655. DefineEngineMethod( Material, isAutoGenerated, bool, (),,
  656. "Returns true if this Material was automatically generated by MaterialList::mapMaterials()" )
  657. {
  658. return object->isAutoGenerated();
  659. }
  660. DefineEngineMethod( Material, setAutoGenerated, void, (bool isAutoGenerated), ,
  661. "setAutoGenerated(bool isAutoGenerated): Set whether or not the Material is autogenerated." )
  662. {
  663. object->setAutoGenerated(isAutoGenerated);
  664. }
  665. DefineEngineMethod(Material, getAutogeneratedFile, const char*, (), , "Get filename of autogenerated shader file")
  666. {
  667. SimObject *material = static_cast<SimObject *>(object);
  668. return material->getFilename();
  669. }
  670. // Accumulation
  671. bool Material::_setAccuEnabled( void *object, const char *index, const char *data )
  672. {
  673. Material* mat = reinterpret_cast< Material* >( object );
  674. if ( index )
  675. {
  676. U32 i = dAtoui(index);
  677. mat->mAccuEnabled[i] = dAtob(data);
  678. AccumulationVolume::refreshVolumes();
  679. }
  680. return true;
  681. }