materialDefinition.cpp 33 KB

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