Torque3D/Engine/source/materials/materialDefinition.cpp

847 lines
33 KiB
C++
Raw Normal View History

2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "platform/platform.h"
#include "materials/materialDefinition.h"
#include "console/consoleTypes.h"
#include "console/engineAPI.h"
2012-09-19 15:15:01 +00:00
#include "math/mathTypes.h"
#include "materials/materialManager.h"
#include "sceneData.h"
#include "gfx/sim/cubemapData.h"
#include "gfx/gfxCubemap.h"
#include "math/mathIO.h"
#include "materials/matInstance.h"
#include "sfx/sfxTrack.h"
#include "sfx/sfxTypes.h"
#include "core/util/safeDelete.h"
#include "T3D/accumulationVolume.h"
#include "gui/controls/guiTreeViewCtrl.h"
#include <console/persistenceManager.h>
IMPLEMENT_CONOBJECT(Material);
ConsoleDocClass(Material,
"@brief A material in Torque 3D is a data structure that describes a surface.\n\n"
"It contains many different types of information for rendering properties. "
"Torque 3D generates shaders from Material definitions. The shaders are compiled "
"at runtime and output into the example/shaders directory. Any errors or warnings "
"generated from compiling the procedurally generated shaders are output to the console "
"as well as the output window in the Visual C IDE.\n\n"
"@tsexample\n"
"singleton Material(DECAL_scorch)\n"
"{\n"
" baseTex[0] = \"./scorch_decal.png\";\n"
" vertColor[ 0 ] = true;\n\n"
" translucent = true;\n"
" translucentBlendOp = None;\n"
" translucentZWrite = true;\n"
" alphaTest = true;\n"
" alphaRef = 84;\n"
"};\n"
"@endtsexample\n\n"
"@see Rendering\n"
"@see ShaderData\n"
"@ingroup GFX\n");
ImplementBitfieldType(MaterialAnimType,
2012-09-19 15:15:01 +00:00
"The type of animation effect to apply to this material.\n"
"@ingroup GFX\n\n")
{
Material::Scroll, "Scroll", "Scroll the material along the X/Y axis.\n"
},
{ Material::Rotate, "Rotate" , "Rotate the material around a point.\n" },
{ Material::Wave, "Wave" , "Warps the material with an animation using Sin, Triangle or Square mathematics.\n" },
{ Material::Scale, "Scale", "Scales the material larger and smaller with a pulsing effect.\n" },
{ Material::Sequence, "Sequence", "Enables the material to have multiple frames of animation in its imagemap.\n" }
2012-09-19 15:15:01 +00:00
EndImplementBitfieldType;
ImplementEnumType(MaterialBlendOp,
2012-09-19 15:15:01 +00:00
"The type of graphical blending operation to apply to this material\n"
"@ingroup GFX\n\n")
{
Material::None, "None", "Disable blending for this material."
},
{ Material::Mul, "Mul", "Multiplicative blending." },
{ Material::PreMul, "PreMul", "Premultiplied alpha." },
{ Material::Add, "Add", "Adds the color of the material to the frame buffer with full alpha for each pixel." },
{ Material::AddAlpha, "AddAlpha", "The color is modulated by the alpha channel before being added to the frame buffer." },
{ Material::Sub, "Sub", "Subtractive Blending. Reverses the color model, causing dark colors to have a stronger visual effect." },
{ Material::LerpAlpha, "LerpAlpha", "Linearly interpolates between Material color and frame buffer color based on alpha." }
2012-09-19 15:15:01 +00:00
EndImplementEnumType;
ImplementEnumType(MaterialWaveType,
"When using the Wave material animation, one of these Wave Types will be used to determine the type of wave to display.\n"
2012-09-19 15:15:01 +00:00
"@ingroup GFX\n")
{
Material::Sin, "Sin", "Warps the material along a curved Sin Wave."
},
{ Material::Triangle, "Triangle", "Warps the material along a sharp Triangle Wave." },
{ 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." },
EndImplementEnumType;
2012-09-19 15:15:01 +00:00
bool Material::sAllowTextureTargetAssignment = false;
GFXCubemap* Material::GetNormalizeCube()
2012-09-19 15:15:01 +00:00
{
if (smNormalizeCube)
2012-09-19 15:15:01 +00:00
return smNormalizeCube;
smNormalizeCube = GFX->createCubemap();
smNormalizeCube->initNormalize(64);
return smNormalizeCube;
}
GFXCubemapHandle Material::smNormalizeCube;
2020-05-11 20:59:22 +00:00
2012-09-19 15:15:01 +00:00
Material::Material()
{
for (U32 i = 0; i < MAX_STAGES; i++)
2012-09-19 15:15:01 +00:00
{
mDiffuse[i].set(1.0f, 1.0f, 1.0f, 1.0f);
mDiffuseMapSRGB[i] = true;
2012-09-19 15:15:01 +00:00
2020-09-30 18:51:12 +00:00
mRoughness[i] = 1.0f;
mMetalness[i] = 0.0f;
mIsSRGb[i] = false;
2022-12-03 14:54:30 +00:00
mAOChan[i] = 0;
mInvertRoughness[i] = false;
mRoughnessChan[i] = 1;
mMetalChan[i] = 2;
2012-09-19 15:15:01 +00:00
mAccuEnabled[i] = false;
mAccuScale[i] = 1.0f;
mAccuDirection[i] = 1.0f;
mAccuStrength[i] = 0.6f;
mAccuCoverage[i] = 0.9f;
mAccuSpecular[i] = 16.0f;
INIT_IMAGEASSET_ARRAY(DiffuseMap, GFXStaticTextureSRGBProfile, i);
INIT_IMAGEASSET_ARRAY(OverlayMap, GFXStaticTextureProfile, i);
INIT_IMAGEASSET_ARRAY(LightMap, GFXStaticTextureProfile, i);
INIT_IMAGEASSET_ARRAY(ToneMap, GFXStaticTextureProfile, i);
INIT_IMAGEASSET_ARRAY(DetailMap, GFXStaticTextureProfile, i);
INIT_IMAGEASSET_ARRAY(NormalMap, GFXNormalMapProfile, i);
INIT_IMAGEASSET_ARRAY(ORMConfigMap, GFXStaticTextureProfile, i);
INIT_IMAGEASSET_ARRAY(RoughMap, GFXStaticTextureProfile, i);
INIT_IMAGEASSET_ARRAY(AOMap, GFXStaticTextureProfile, i);
INIT_IMAGEASSET_ARRAY(MetalMap, GFXStaticTextureProfile, i);
INIT_IMAGEASSET_ARRAY(GlowMap, GFXStaticTextureProfile, i);
INIT_IMAGEASSET_ARRAY(DetailNormalMap, GFXNormalMapProfile, i);
2012-09-19 15:15:01 +00:00
mParallaxScale[i] = 0.0f;
mVertLit[i] = false;
mVertColor[i] = false;
2012-09-19 15:15:01 +00:00
mGlow[i] = false;
mReceiveShadows[i] = true;
mIgnoreLighting[i] = false;
2012-09-19 15:15:01 +00:00
mDetailScale[i].set(2.0f, 2.0f);
2012-09-19 15:15:01 +00:00
mDetailNormalMapStrength[i] = 1.0f;
mMinnaertConstant[i] = -1.0f;
mSubSurface[i] = false;
mSubSurfaceColor[i].set(1.0f, 0.2f, 0.2f, 1.0f);
2012-09-19 15:15:01 +00:00
mSubSurfaceRolloff[i] = 0.2f;
2012-09-19 15:15:01 +00:00
mAnimFlags[i] = 0;
mScrollDir[i].set(0.0f, 0.0f);
2012-09-19 15:15:01 +00:00
mScrollSpeed[i] = 0.0f;
mScrollOffset[i].set(0.0f, 0.0f);
2012-09-19 15:15:01 +00:00
mRotSpeed[i] = 0.0f;
mRotPivotOffset[i].set(0.0f, 0.0f);
2012-09-19 15:15:01 +00:00
mRotPos[i] = 0.0f;
mWavePos[i] = 0.0f;
mWaveFreq[i] = 0.0f;
mWaveAmp[i] = 0.0f;
mWaveType[i] = 0;
mSeqFramePerSec[i] = 0.0f;
mSeqSegSize[i] = 0.0f;
The final step (barring any overlooked missing bits, requested refactors, and of course, rolling in dependencies already submitted as PRs) consists of: renderPrePassMgr.cpp related: A) shifting .addFeature( MFT_XYZ); calls from ProcessedShaderMaterial::_determineFeatures to ProcessedPrePassMaterial::_determineFeatures B) mimicking the "// set the XXX if different" entries from RenderMeshMgr::render in RenderPrePassMgr::render C) fleshing out ProcessedPrePassMaterial::getNumStages() so that it shares a 1:1 correlation with ProcessedShaderMaterial::getNumStages() D) causing inline void Swizzle<T, mapLength>::ToBuffer( void *destination, const void *source, const dsize_t size ) to silently fail rather than fatally assert if a source or destination buffer is not yet ready to be filled. (support for #customTarget scripted render targets) Reflections: A) removing reflectRenderState.disableAdvancedLightingBins(true); entries. this would otherwise early out from prepass and provide no color data whatsoever. B) removing the fd.features.addFeature( MFT_ForwardShading ); entry forcing all materials to be forward lit when reflected. C) 2 things best described bluntly as working hacks: C1) when reflected, a scattersky is rotated PI along it's z then x axis in order to draw properly. C2) along similar lines, in terraincellmaterial, we shut off culling if it's a prepass material. Skies: scattersky is given a pair of rotations for reflection purposes, all sky objects are given a z value for depth testing.
2016-02-16 08:50:49 +00:00
// Deferred Shading
mMatInfoFlags[i] = 0.0f;
mGlowMul[i] = 0.0f;
2012-09-19 15:15:01 +00:00
}
dMemset(mCellIndex, 0, sizeof(mCellIndex));
dMemset(mCellLayout, 0, sizeof(mCellLayout));
dMemset(mCellSize, 0, sizeof(mCellSize));
dMemset(mNormalMapAtlas, 0, sizeof(mNormalMapAtlas));
dMemset(mUseAnisotropic, 1, sizeof(mUseAnisotropic));
2012-09-19 15:15:01 +00:00
mImposterLimits = Point4F::Zero;
mDoubleSided = false;
mTranslucent = false;
mTranslucentBlendOp = PreMul;
2012-09-19 15:15:01 +00:00
mTranslucentZWrite = false;
mAlphaTest = false;
mAlphaRef = 1;
mCastShadows = true;
mPlanarReflection = false;
mCubemapData = NULL;
mDynamicCubemap = false;
2012-09-19 15:15:01 +00:00
mLastUpdateTime = 0;
mAutoGenerated = false;
mShowDust = false;
mShowFootprints = true;
dMemset(mEffectColor, 0, sizeof(mEffectColor));
2012-09-19 15:15:01 +00:00
mEffectColor[0] = LinearColorF::WHITE;
mEffectColor[1] = LinearColorF::WHITE;
2012-09-19 15:15:01 +00:00
mFootstepSoundId = -1; mImpactSoundId = -1;
mImpactFXIndex = -1;
2021-10-15 00:09:20 +00:00
INIT_ASSET(CustomFootstepSound);
INIT_ASSET(CustomImpactSound);
2012-09-19 15:15:01 +00:00
mFriction = 0.0;
2012-09-19 15:15:01 +00:00
mDirectSoundOcclusion = 1.f;
mReverbSoundOcclusion = 1.0;
}
2020-05-11 20:59:22 +00:00
2012-09-19 15:15:01 +00:00
void Material::initPersistFields()
{
docsURL;
2012-09-19 15:15:01 +00:00
addField("mapTo", TypeRealString, Offset(mMapTo, Material),
"Used to map this material to the material name used by TSShape.");
addArray("Stages", MAX_STAGES);
addField("diffuseColor", TypeColorF, Offset(mDiffuse, Material), MAX_STAGES,
"This color is multiplied against the diffuse texture color. If no diffuse texture "
"is present this is the material color.");
INITPERSISTFIELD_IMAGEASSET_ARRAY(DiffuseMap, MAX_STAGES, Material, "Albedo");
INITPERSISTFIELD_IMAGEASSET_ARRAY(OverlayMap, MAX_STAGES, Material, "Overlay");
INITPERSISTFIELD_IMAGEASSET_ARRAY(LightMap, MAX_STAGES, Material, "LightMap");
INITPERSISTFIELD_IMAGEASSET_ARRAY(ToneMap, MAX_STAGES, Material, "ToneMap");
INITPERSISTFIELD_IMAGEASSET_ARRAY(DetailMap, MAX_STAGES, Material, "DetailMap");
INITPERSISTFIELD_IMAGEASSET_ARRAY(NormalMap, MAX_STAGES, Material, "NormalMap");
INITPERSISTFIELD_IMAGEASSET_ARRAY(ORMConfigMap, MAX_STAGES, Material, "AO|Roughness|metalness map");
INITPERSISTFIELD_IMAGEASSET_ARRAY(RoughMap, MAX_STAGES, Material, "RoughMap (also needs MetalMap)");
INITPERSISTFIELD_IMAGEASSET_ARRAY(AOMap, MAX_STAGES, Material, "AOMap");
INITPERSISTFIELD_IMAGEASSET_ARRAY(MetalMap, MAX_STAGES, Material, "MetalMap (also needs RoughMap)");
INITPERSISTFIELD_IMAGEASSET_ARRAY(GlowMap, MAX_STAGES, Material, "GlowMap (needs Albedo)");
INITPERSISTFIELD_IMAGEASSET_ARRAY(DetailNormalMap, MAX_STAGES, Material, "DetailNormalMap");
addField("diffuseMapSRGB", TypeBool, Offset(mDiffuseMapSRGB, Material), MAX_STAGES,
"Enable sRGB for the diffuse color texture map.");
addField("detailScale", TypePoint2F, Offset(mDetailScale, Material), MAX_STAGES,
"The scale factor for the detail map.");
addField("detailNormalMapStrength", TypeF32, Offset(mDetailNormalMapStrength, Material), MAX_STAGES,
"Used to scale the strength of the detail normal map when blended with the base normal map.");
addField("roughness", TypeF32, Offset(mRoughness, Material), MAX_STAGES,
"The degree of roughness when not using a ORMConfigMap.");
addField("metalness", TypeF32, Offset(mMetalness, Material), MAX_STAGES,
"The degree of Metalness when not using a ORMConfigMap.");
addField("glowMul", TypeF32, Offset(mGlowMul, Material), MAX_STAGES,
"glow mask multiplier");
addProtectedField("accuEnabled", TYPEID< bool >(), Offset(mAccuEnabled, Material),
&_setAccuEnabled, &defaultProtectedGetFn, MAX_STAGES, "Accumulation texture.");
addField("accuScale", TypeF32, Offset(mAccuScale, Material), MAX_STAGES,
"The scale that is applied to the accu map texture. You can use this to fit the texture to smaller or larger objects.");
addField("accuDirection", TypeF32, Offset(mAccuDirection, Material), MAX_STAGES,
"The direction of the accumulation. Chose whether you want the accu map to go from top to bottom (ie. snow) or upwards (ie. mold).");
addField("accuStrength", TypeF32, Offset(mAccuStrength, Material), MAX_STAGES,
"The strength of the accu map. This changes the transparency of the accu map texture. Make it subtle or add more contrast.");
addField("accuCoverage", TypeF32, Offset(mAccuCoverage, Material), MAX_STAGES,
"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.");
addField("accuSpecular", TypeF32, Offset(mAccuSpecular, Material), MAX_STAGES,
"Changes specularity to this value where the accumulated material is present.");
addField("isSRGb", TypeBool, Offset(mIsSRGb, Material), MAX_STAGES,
"Substance Designer Workaround.");
addField("invertRoughness", TypeBool, Offset(mInvertRoughness, Material), MAX_STAGES,
"Treat Roughness as Roughness");
addField("roughnessChan", TypeF32, Offset(mRoughnessChan, Material), MAX_STAGES,
"The input channel roughness maps use.");
addField("AOChan", TypeF32, Offset(mAOChan, Material), MAX_STAGES,
"The input channel AO maps use.");
addField("metalChan", TypeF32, Offset(mMetalChan, Material), MAX_STAGES,
"The input channel metalness maps use.");
addField("glow", TypeBool, Offset(mGlow, Material), MAX_STAGES,
"Enables rendering as glowing.");
2012-09-19 15:15:01 +00:00
addField("parallaxScale", TypeF32, Offset(mParallaxScale, Material), MAX_STAGES,
"Enables parallax mapping and defines the scale factor for the parallax effect. Typically "
"this value is less than 0.4 else the effect breaks down.");
addField("useAnisotropic", TypeBool, Offset(mUseAnisotropic, Material), MAX_STAGES,
"Use anisotropic filtering for the textures of this stage.");
addField("vertLit", TypeBool, Offset(mVertLit, Material), MAX_STAGES,
"If true the vertex color is used for lighting.");
addField("vertColor", TypeBool, Offset(mVertColor, Material), MAX_STAGES,
"If enabled, vertex colors are premultiplied with diffuse colors.");
addField("minnaertConstant", TypeF32, Offset(mMinnaertConstant, Material), MAX_STAGES,
"The Minnaert shading constant value. Must be greater than 0 to enable the effect.");
addField("subSurface", TypeBool, Offset(mSubSurface, Material), MAX_STAGES,
"Enables the subsurface scattering approximation.");
addField("subSurfaceColor", TypeColorF, Offset(mSubSurfaceColor, Material), MAX_STAGES,
"The color used for the subsurface scattering approximation.");
addField("subSurfaceRolloff", TypeF32, Offset(mSubSurfaceRolloff, Material), MAX_STAGES,
"The 0 to 1 rolloff factor used in the subsurface scattering approximation.");
addField("receiveShadows", TypeBool, Offset(mReceiveShadows, Material), MAX_STAGES,
"Shadows being cast onto the material.");
addField("ignoreLighting", TypeBool, Offset(mIgnoreLighting, Material), MAX_STAGES,
"Enables emissive lighting for the material.");
addField("doubleSided", TypeBool, Offset(mDoubleSided, Material),
"Disables backface culling casing surfaces to be double sided. "
"Note that the lighting on the backside will be a mirror of the front "
"side of the surface.");
addField("animFlags", TYPEID< AnimType >(), Offset(mAnimFlags, Material), MAX_STAGES,
"The types of animation to play on this material.");
addField("scrollDir", TypePoint2F, Offset(mScrollDir, Material), MAX_STAGES,
"The scroll direction in UV space when scroll animation is enabled.");
addField("scrollSpeed", TypeF32, Offset(mScrollSpeed, Material), MAX_STAGES,
"The speed to scroll the texture in UVs per second when scroll animation is enabled.");
addField("rotSpeed", TypeF32, Offset(mRotSpeed, Material), MAX_STAGES,
"The speed to rotate the texture in degrees per second when rotation animation is enabled.");
addField("rotPivotOffset", TypePoint2F, Offset(mRotPivotOffset, Material), MAX_STAGES,
"The piviot position in UV coordinates to center the rotation animation.");
addField("waveType", TYPEID< WaveType >(), Offset(mWaveType, Material), MAX_STAGES,
"The type of wave animation to perform when wave animation is enabled.");
addField("waveFreq", TypeF32, Offset(mWaveFreq, Material), MAX_STAGES,
"The wave frequency when wave animation is enabled.");
addField("waveAmp", TypeF32, Offset(mWaveAmp, Material), MAX_STAGES,
"The wave amplitude when wave animation is enabled.");
addField("sequenceFramePerSec", TypeF32, Offset(mSeqFramePerSec, Material), MAX_STAGES,
"The number of frames per second for frame based sequence animations if greater than zero.");
addField("sequenceSegmentSize", TypeF32, Offset(mSeqSegSize, Material), MAX_STAGES,
"The size of each frame in UV units for sequence animations.");
// Texture atlasing
addField("cellIndex", TypePoint2I, Offset(mCellIndex, Material), MAX_STAGES,
"@internal");
addField("cellLayout", TypePoint2I, Offset(mCellLayout, Material), MAX_STAGES,
"@internal");
addField("cellSize", TypeS32, Offset(mCellSize, Material), MAX_STAGES,
"@internal");
addField("bumpAtlas", TypeBool, Offset(mNormalMapAtlas, Material), MAX_STAGES,
"@internal");
// For backwards compatibility.
//
// They point at the new 'map' fields, but reads always return
// an empty string and writes only apply if the value is not empty.
//
addProtectedField("baseTex", TypeImageFilename, Offset(mDiffuseMapName, Material),
defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
"For backwards compatibility.\n@see diffuseMap\n", AbstractClassRep::FIELD_HideInInspectors);
addProtectedField("detailTex", TypeImageFilename, Offset(mDetailMapName, Material),
defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
"For backwards compatibility.\n@see detailMap\n", AbstractClassRep::FIELD_HideInInspectors);
addProtectedField("overlayTex", TypeImageFilename, Offset(mOverlayMapName, Material),
defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
"For backwards compatibility.\n@see overlayMap\n", AbstractClassRep::FIELD_HideInInspectors);
addProtectedField("bumpTex", TypeImageFilename, Offset(mNormalMapName, Material),
defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
"For backwards compatibility.\n@see normalMap\n", AbstractClassRep::FIELD_HideInInspectors);
addProtectedField("colorMultiply", TypeColorF, Offset(mDiffuse, Material),
defaultProtectedSetNotEmptyFn, emptyStringProtectedGetFn, MAX_STAGES,
"For backwards compatibility.\n@see diffuseColor\n", AbstractClassRep::FIELD_HideInInspectors);
endArray("Stages");
addField("castShadows", TypeBool, Offset(mCastShadows, Material),
"If set to false the lighting system will not cast shadows from this material.");
addField("planarReflection", TypeBool, Offset(mPlanarReflection, Material), "@internal");
2012-09-19 15:15:01 +00:00
addField("translucent", TypeBool, Offset(mTranslucent, Material),
"If true this material is translucent blended.");
2012-09-19 15:15:01 +00:00
addField("translucentBlendOp", TYPEID< BlendOp >(), Offset(mTranslucentBlendOp, Material),
"The type of blend operation to use when the material is translucent.");
2012-09-19 15:15:01 +00:00
addField("translucentZWrite", TypeBool, Offset(mTranslucentZWrite, Material),
"If enabled and the material is translucent it will write into the depth buffer.");
2012-09-19 15:15:01 +00:00
addField("alphaTest", TypeBool, Offset(mAlphaTest, Material),
"Enables alpha test when rendering the material.\n@see alphaRef\n");
2012-09-19 15:15:01 +00:00
addField("alphaRef", TypeS32, Offset(mAlphaRef, Material),
"The alpha reference value for alpha testing. Must be between 0 to 255.\n@see alphaTest\n");
2012-09-19 15:15:01 +00:00
addField("cubemap", TypeRealString, Offset(mCubemapName, Material),
"The name of a CubemapData for environment mapping.");
2012-09-19 15:15:01 +00:00
addField("dynamicCubemap", TypeBool, Offset(mDynamicCubemap, Material),
"Enables the material to use the dynamic cubemap from the ShapeBase object its applied to.");
addGroup("Behavioral");
addField("showFootprints", TypeBool, Offset(mShowFootprints, Material),
"Whether to show player footprint decals on this material.\n\n"
"@see PlayerData::decalData");
addField("showDust", TypeBool, Offset(mShowDust, Material),
"Whether to emit dust particles from a shape moving over the material. This is, for example, used by "
"vehicles or players to decide whether to show dust trails.");
addField("effectColor", TypeColorF, Offset(mEffectColor, Material), NUM_EFFECT_COLOR_STAGES,
"If #showDust is true, this is the set of colors to use for the ParticleData of the dust "
"emitter.\n\n"
"@see ParticleData::colors");
addField("footstepSoundId", TypeS32, Offset(mFootstepSoundId, Material),
"What sound to play from the PlayerData sound list when the player walks over the material. -1 (default) to not play any sound.\n"
"\n"
"The IDs are:\n\n"
"- 0: PlayerData::FootSoftSound\n"
"- 1: PlayerData::FootHardSound\n"
"- 2: PlayerData::FootMetalSound\n"
"- 3: PlayerData::FootSnowSound\n"
"- 4: PlayerData::FootShallowSound\n"
"- 5: PlayerData::FootWadingSound\n"
"- 6: PlayerData::FootUnderwaterSound\n"
"- 7: PlayerData::FootBubblesSound\n"
"- 8: PlayerData::movingBubblesSound\n"
"- 9: PlayerData::waterBreathSound\n"
"- 10: PlayerData::impactSoftSound\n"
"- 11: PlayerData::impactHardSound\n"
"- 12: PlayerData::impactMetalSound\n"
"- 13: PlayerData::impactSnowSound\n"
"- 14: PlayerData::impactWaterEasy\n"
"- 15: PlayerData::impactWaterMedium\n"
"- 16: PlayerData::impactWaterHard\n"
"- 17: PlayerData::exitingWater\n");
2021-10-15 00:09:20 +00:00
INITPERSISTFIELD_SOUNDASSET(CustomFootstepSound, Material,
"The sound to play when the player walks over the material. If this is set, it overrides #footstepSoundId. This field is "
"useful for directly assigning custom footstep sounds to materials without having to rely on the PlayerData sound assignment.\n\n"
"@warn Be aware that materials are client-side objects. This means that the SFXTracks assigned to materials must be client-side, too.");
addField("impactSoundId", TypeS32, Offset(mImpactSoundId, Material),
"What sound to play from the PlayerData sound list when the player impacts on the surface with a velocity equal or greater "
"than PlayerData::groundImpactMinSpeed.\n\n"
"For a list of IDs, see #footstepSoundId");
addField("ImpactFXIndex", TypeS32, Offset(mImpactFXIndex, Material),
"What FX to play from the PlayerData sound list when the player impacts on the surface with a velocity equal or greater "
"than PlayerData::groundImpactMinSpeed.\n\n"
"For a list of IDs, see #impactFXId");
2021-10-15 00:09:20 +00:00
INITPERSISTFIELD_SOUNDASSET(CustomImpactSound, Material,
"The sound to play when the player impacts on the surface with a velocity equal or greater than PlayerData::groundImpactMinSpeed. "
"If this is set, it overrides #impactSoundId. This field is useful for directly assigning custom impact sounds to materials "
"without having to rely on the PlayerData sound assignment.\n\n"
"@warn Be aware that materials are client-side objects. This means that the SFXTracks assigned to materials must be client-side, too.");
//Deactivate these for the moment as they are not used.
#if 0
addField("friction", TypeF32, Offset(mFriction, Material));
addField("directSoundOcclusion", TypeF32, Offset(mDirectSoundOcclusion, Material));
addField("reverbSoundOcclusion", TypeF32, Offset(mReverbSoundOcclusion, Material));
#endif
endGroup("Behavioral");
2012-09-19 15:15:01 +00:00
Parent::initPersistFields();
}
bool Material::writeField(StringTableEntry fieldname, const char* value)
{
2012-09-19 15:15:01 +00:00
// Never allow the old field names to be written.
if (fieldname == StringTable->insert("baseTex") ||
fieldname == StringTable->insert("detailTex") ||
fieldname == StringTable->insert("overlayTex") ||
fieldname == StringTable->insert("bumpTex") ||
fieldname == StringTable->insert("envTex") ||
fieldname == StringTable->insert("colorMultiply") ||
fieldname == StringTable->insert("internalName"))
2012-09-19 15:15:01 +00:00
return false;
return Parent::writeField(fieldname, value);
2012-09-19 15:15:01 +00:00
}
bool Material::onAdd()
{
if (Parent::onAdd() == false)
return false;
mCubemapData = dynamic_cast<CubemapData*>(Sim::findObject(mCubemapName));
2012-09-19 15:15:01 +00:00
if (mTranslucentBlendOp >= NumBlendTypes || mTranslucentBlendOp < 0)
2012-09-19 15:15:01 +00:00
{
Con::errorf("Invalid blend op in material: %s", getName());
mTranslucentBlendOp = PreMul;
2012-09-19 15:15:01 +00:00
}
SimSet* matSet = MATMGR->getMaterialSet();
if (matSet)
matSet->addObject((SimObject*)this);
2012-09-19 15:15:01 +00:00
// save the current script path for texture lookup later
const String scriptFile = Con::getVariable("$Con::File"); // current script file - local materials.tscript
2012-09-19 15:15:01 +00:00
String::SizeType slash = scriptFile.find('/', scriptFile.length(), String::Right);
if (slash != String::NPos)
mPath = scriptFile.substr(0, slash + 1);
//convert any non-assets we have
/*for (U32 i = 0; i < MAX_STAGES; i++)
{
AUTOCONVERT_IMAGEASSET_ARRAY(DiffuseMap, i);
AUTOCONVERT_IMAGEASSET_ARRAY(OverlayMap, i);
AUTOCONVERT_IMAGEASSET_ARRAY(LightMap, i);
AUTOCONVERT_IMAGEASSET_ARRAY(ToneMap, i);
AUTOCONVERT_IMAGEASSET_ARRAY(DetailMap, i);
AUTOCONVERT_IMAGEASSET_ARRAY(ORMConfigMap, i);
AUTOCONVERT_IMAGEASSET_ARRAY(AOMap, i);
AUTOCONVERT_IMAGEASSET_ARRAY(RoughMap, i);
AUTOCONVERT_IMAGEASSET_ARRAY(MetalMap, i);
AUTOCONVERT_IMAGEASSET_ARRAY(GlowMap, i);
AUTOCONVERT_IMAGEASSET_ARRAY(DetailNormalMap, i);
}
2012-09-19 15:15:01 +00:00
//bind any assets we have
for (U32 i = 0; i < MAX_STAGES; i++)
{
LOAD_IMAGEASSET_ARRAY(DiffuseMap, i);
LOAD_IMAGEASSET_ARRAY(OverlayMap, i);
LOAD_IMAGEASSET_ARRAY(LightMap, i);
LOAD_IMAGEASSET_ARRAY(ToneMap, i);
LOAD_IMAGEASSET_ARRAY(DetailMap, i);
LOAD_IMAGEASSET_ARRAY(ORMConfigMap, i);
LOAD_IMAGEASSET_ARRAY(AOMap, i);
LOAD_IMAGEASSET_ARRAY(RoughMap, i);
LOAD_IMAGEASSET_ARRAY(MetalMap, i);
LOAD_IMAGEASSET_ARRAY(GlowMap, i);
LOAD_IMAGEASSET_ARRAY(DetailNormalMap, i);
}*/
inspectPostApply();
2012-09-19 15:15:01 +00:00
_mapMaterial();
return true;
}
void Material::onRemove()
{
smNormalizeCube = NULL;
Parent::onRemove();
}
void Material::inspectPostApply()
{
Parent::inspectPostApply();
// Reload the material instances which
// use this material.
if (isProperlyAdded())
2012-09-19 15:15:01 +00:00
reload();
}
bool Material::isLightmapped() const
{
bool ret = false;
for (U32 i = 0; i < MAX_STAGES; i++)
ret |= mLightMapName[i] != StringTable->EmptyString() || mToneMapName[i] != StringTable->EmptyString() || mVertLit[i];
2012-09-19 15:15:01 +00:00
return ret;
}
void Material::updateTimeBasedParams()
{
U32 lastTime = MATMGR->getLastUpdateTime();
F32 dt = MATMGR->getDeltaTime();
if (mLastUpdateTime != lastTime)
{
for (U32 i = 0; i < MAX_STAGES; i++)
{
mScrollOffset[i] += mScrollDir[i] * mScrollSpeed[i] * dt;
mScrollOffset[i].x = mWrapF(mScrollOffset[i].x, 0.0, 1.0);
mScrollOffset[i].y = mWrapF(mScrollOffset[i].y, 0.0, 1.0);
mRotPos[i] = mWrapF((mRotPos[i] + (mRotSpeed[i] * dt)), 0.0, 360.0);
mWavePos[i] = mWrapF((mWavePos[i] + (mWaveFreq[i] * dt)), 0.0, 1.0);
2012-09-19 15:15:01 +00:00
}
mLastUpdateTime = lastTime;
}
}
void Material::_mapMaterial()
{
if (String(getName()).isEmpty())
2012-09-19 15:15:01 +00:00
{
Con::warnf("[Material::mapMaterial] - Cannot map unnamed Material");
2012-09-19 15:15:01 +00:00
return;
}
// If mapTo not defined in script, try to use the base texture name instead
if (mMapTo.isEmpty())
2012-09-19 15:15:01 +00:00
{
if (mDiffuseMapName[0] == StringTable->EmptyString() && mDiffuseMapAsset->isNull())
2012-09-19 15:15:01 +00:00
return;
else
{
// extract filename from base texture
if (mDiffuseMapName[0] != StringTable->EmptyString())
2012-09-19 15:15:01 +00:00
{
U32 slashPos = String(mDiffuseMapName[0]).find('/', 0, String::Right);
2012-09-19 15:15:01 +00:00
if (slashPos == String::NPos)
// no '/' character, must be no path, just the filename
mMapTo = mDiffuseMapName[0];
2012-09-19 15:15:01 +00:00
else
// use everything after the last slash
mMapTo = String(mDiffuseMapName[0]).substr(slashPos + 1, strlen(mDiffuseMapName[0]) - slashPos - 1);
2012-09-19 15:15:01 +00:00
}
else if (!mDiffuseMapAsset->isNull())
{
mMapTo = mDiffuseMapAsset[0]->getImageFileName();
}
2012-09-19 15:15:01 +00:00
}
}
// add mapping
MATMGR->mapMaterial(mMapTo, getName());
2012-09-19 15:15:01 +00:00
}
BaseMatInstance* Material::createMatInstance()
{
return new MatInstance(*this);
}
void Material::flush()
{
MATMGR->flushInstance(this);
2012-09-19 15:15:01 +00:00
}
void Material::reload()
{
MATMGR->reInitInstance(this);
2012-09-19 15:15:01 +00:00
}
void Material::StageData::getFeatureSet(FeatureSet* outFeatures) const
2012-09-19 15:15:01 +00:00
{
TextureTable::ConstIterator iter = mTextures.begin();
for (; iter != mTextures.end(); iter++)
2012-09-19 15:15:01 +00:00
{
if (iter->value.isValid())
outFeatures->addFeature(*iter->key);
2012-09-19 15:15:01 +00:00
}
}
DefineEngineMethod(Material, flush, void, (), ,
"Flushes all material instances that use this material.")
2012-09-19 15:15:01 +00:00
{
object->flush();
}
DefineEngineMethod(Material, reload, void, (), ,
"Reloads all material instances that use this material.")
2012-09-19 15:15:01 +00:00
{
object->reload();
}
DefineEngineMethod(Material, dumpInstances, void, (), ,
"Dumps a formatted list of the currently allocated material instances for this material to the console.")
2012-09-19 15:15:01 +00:00
{
MATMGR->dumpMaterialInstances(object);
2012-09-19 15:15:01 +00:00
}
DefineEngineMethod(Material, getMaterialInstances, void, (GuiTreeViewCtrl* matTree), (nullAsType< GuiTreeViewCtrl*>()),
"Dumps a formatted list of the currently allocated material instances for this material to the console.")
{
MATMGR->getMaterialInstances(object, matTree);
}
DefineEngineMethod(Material, getAnimFlags, const char*, (U32 id), , "")
2012-09-19 15:15:01 +00:00
{
char* animFlags = Con::getReturnBuffer(512);
2012-09-19 15:15:01 +00:00
if (object->mAnimFlags[id] & Material::Scroll)
2012-09-19 15:15:01 +00:00
{
if (String::compare(animFlags, "") == 0)
dStrcpy(animFlags, "$Scroll", 512);
2012-09-19 15:15:01 +00:00
}
if (object->mAnimFlags[id] & Material::Rotate)
2012-09-19 15:15:01 +00:00
{
if (String::compare(animFlags, "") == 0)
dStrcpy(animFlags, "$Rotate", 512);
else
dStrcat(animFlags, " | $Rotate", 512);
2012-09-19 15:15:01 +00:00
}
if (object->mAnimFlags[id] & Material::Wave)
2012-09-19 15:15:01 +00:00
{
if (String::compare(animFlags, "") == 0)
dStrcpy(animFlags, "$Wave", 512);
else
dStrcat(animFlags, " | $Wave", 512);
2012-09-19 15:15:01 +00:00
}
if (object->mAnimFlags[id] & Material::Scale)
2012-09-19 15:15:01 +00:00
{
if (String::compare(animFlags, "") == 0)
dStrcpy(animFlags, "$Scale", 512);
else
dStrcat(animFlags, " | $Scale", 512);
2012-09-19 15:15:01 +00:00
}
if (object->mAnimFlags[id] & Material::Sequence)
2012-09-19 15:15:01 +00:00
{
if (String::compare(animFlags, "") == 0)
dStrcpy(animFlags, "$Sequence", 512);
else
dStrcat(animFlags, " | $Sequence", 512);
2012-09-19 15:15:01 +00:00
}
return animFlags;
2012-09-19 15:15:01 +00:00
}
DefineEngineMethod(Material, setAnimFlags, void, (S32 id, const char *flags), (0, ""), "setAnimFlags")
{
object->mAnimFlags[id] = 0;
if (String(flags).find("$Scroll") != String::NPos)
object->mAnimFlags[id] |= Material::Scroll;
if (String(flags).find("$Rotate") != String::NPos)
object->mAnimFlags[id] |= Material::Rotate;
if (String(flags).find("$Wave") != String::NPos)
object->mAnimFlags[id] |= Material::Wave;
if (String(flags).find("$Scale") != String::NPos)
object->mAnimFlags[id] |= Material::Scale;
if (String(flags).find("$Sequence") != String::NPos)
object->mAnimFlags[id] |= Material::Sequence;
//if we're still unset, see if they tried assigning a number
if (object->mAnimFlags[id] == 0)
object->mAnimFlags[id] = dAtoi(flags);
}
DefineEngineMethod(Material, getFilename, const char*, (), , "Get filename of material")
2012-09-19 15:15:01 +00:00
{
SimObject* material = static_cast<SimObject*>(object);
2012-09-19 15:15:01 +00:00
return material->getFilename();
}
DefineEngineMethod(Material, isAutoGenerated, bool, (), ,
"Returns true if this Material was automatically generated by MaterialList::mapMaterials()")
2012-09-19 15:15:01 +00:00
{
return object->isAutoGenerated();
}
DefineEngineMethod(Material, setAutoGenerated, void, (bool isAutoGenerated), ,
"setAutoGenerated(bool isAutoGenerated): Set whether or not the Material is autogenerated.")
2012-09-19 15:15:01 +00:00
{
object->setAutoGenerated(isAutoGenerated);
}
2018-12-12 22:01:26 +00:00
DefineEngineMethod(Material, getAutogeneratedFile, const char*, (), , "Get filename of autogenerated shader file")
{
SimObject* material = static_cast<SimObject*>(object);
return material->getFilename();
}
// Accumulation
bool Material::_setAccuEnabled(void* object, const char* index, const char* data)
{
Material* mat = reinterpret_cast<Material*>(object);
if (index)
{
U32 i = dAtoui(index);
mat->mAccuEnabled[i] = dAtob(data);
AccumulationVolume::refreshVolumes();
}
return true;
}
//declare general get<entry>, get<entry>Asset and set<entry> methods
//signatures are:
//using DiffuseMap as an example
//material.getDiffuseMap(%layer); //returns the raw file referenced
//material.getDiffuseMapAsset(%layer); //returns the asset id
//material.setDiffuseMap(%texture, %layer); //tries to set the asset and failing that attempts a flat file reference
DEF_IMAGEASSET_ARRAY_BINDS(Material, DiffuseMap)
DEF_IMAGEASSET_ARRAY_BINDS(Material, OverlayMap);
DEF_IMAGEASSET_ARRAY_BINDS(Material, LightMap);
DEF_IMAGEASSET_ARRAY_BINDS(Material, ToneMap);
DEF_IMAGEASSET_ARRAY_BINDS(Material, DetailMap);
DEF_IMAGEASSET_ARRAY_BINDS(Material, NormalMap);
DEF_IMAGEASSET_ARRAY_BINDS(Material, ORMConfigMap);
DEF_IMAGEASSET_ARRAY_BINDS(Material, RoughMap);
DEF_IMAGEASSET_ARRAY_BINDS(Material, AOMap);
DEF_IMAGEASSET_ARRAY_BINDS(Material, MetalMap);
DEF_IMAGEASSET_ARRAY_BINDS(Material, GlowMap);
DEF_IMAGEASSET_ARRAY_BINDS(Material, DetailNormalMap);