123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530 |
- //-----------------------------------------------------------------------------
- // 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/processedMaterial.h"
- #include "materials/sceneData.h"
- #include "materials/materialParameters.h"
- #include "materials/matTextureTarget.h"
- #include "materials/materialFeatureTypes.h"
- #include "materials/materialManager.h"
- #include "scene/sceneRenderState.h"
- #include "gfx/gfxPrimitiveBuffer.h"
- #include "gfx/gfxTextureManager.h"
- #include "gfx/sim/cubemapData.h"
- RenderPassData::RenderPassData()
- {
- reset();
- }
- void RenderPassData::reset()
- {
- for( U32 i = 0; i < Material::MAX_TEX_PER_PASS; ++ i )
- {
- destructInPlace( &mTexSlot[ i ] );
- mSamplerNames[ i ].clear();
- }
- dMemset( &mTexSlot, 0, sizeof(mTexSlot) );
- dMemset( &mTexType, 0, sizeof(mTexType) );
- mCubeMap = NULL;
- mNumTex = mNumTexReg = mStageNum = 0;
- mGlow = false;
- mBlendOp = Material::None;
- mFeatureData.clear();
- for (U32 i = 0; i < STATE_MAX; i++)
- mRenderStates[i] = NULL;
- }
- String RenderPassData::describeSelf() const
- {
- String desc;
- // Now write all the textures.
- String texName;
- for ( U32 i=0; i < Material::MAX_TEX_PER_PASS; i++ )
- {
- if ( mTexType[i] == Material::TexTarget )
- texName = ( mTexSlot[i].texTarget ) ? mTexSlot[i].texTarget->getName() : String("null_texTarget");
- else if ( mTexType[i] == Material::Cube && mCubeMap )
- texName = mCubeMap->getPath();
- else if ( mTexSlot[i].texObject )
- texName = mTexSlot[i].texObject->getPath();
- else
- continue;
- desc += String::ToString( "TexSlot %d: %d, %s\n", i, mTexType[i], texName.c_str() );
- }
- // Write out the first render state which is the
- // basis for all the other states and shoud be
- // enough to define the pass uniquely.
- desc += mRenderStates[0]->getDesc().describeSelf();
- return desc;
- }
- ProcessedMaterial::ProcessedMaterial()
- : mMaterial( NULL ),
- mCurrentParams( NULL ),
- mHasSetStageData( false ),
- mHasGlow( false ),
- mHasAccumulation( false ),
- mMaxStages( 0 ),
- mVertexFormat( NULL ),
- mUserObject( NULL )
- {
- VECTOR_SET_ASSOCIATION( mPasses );
- }
- ProcessedMaterial::~ProcessedMaterial()
- {
- T3D::for_each( mPasses.begin(), mPasses.end(), T3D::delete_pointer() );
- }
- void ProcessedMaterial::_setBlendState(Material::BlendOp blendOp, GFXStateBlockDesc& desc )
- {
- switch( blendOp )
- {
- case Material::Add:
- {
- desc.blendSrc = GFXBlendOne;
- desc.blendDest = GFXBlendOne;
- break;
- }
- case Material::AddAlpha:
- {
- desc.blendSrc = GFXBlendSrcAlpha;
- desc.blendDest = GFXBlendOne;
- break;
- }
- case Material::Mul:
- {
- desc.blendSrc = GFXBlendDestColor;
- desc.blendDest = GFXBlendInvSrcAlpha;
- break;
- }
- case Material::PreMul:
- {
- desc.blendSrc = GFXBlendOne;
- desc.blendDest = GFXBlendInvSrcAlpha;
- break;
- }
- case Material::LerpAlpha:
- {
- desc.blendSrc = GFXBlendSrcAlpha;
- desc.blendDest = GFXBlendInvSrcAlpha;
- break;
- }
- case Material::Sub:
- {
- desc.blendOp = GFXBlendOpSubtract;
- desc.blendSrc = GFXBlendOne;
- desc.blendDest = GFXBlendOne;
- break;
- }
- default:
- {
- // default to LerpAlpha
- desc.blendSrc = GFXBlendSrcAlpha;
- desc.blendDest = GFXBlendInvSrcAlpha;
- break;
- }
- }
- }
- void ProcessedMaterial::setBuffers(GFXVertexBufferHandleBase* vertBuffer, GFXPrimitiveBufferHandle* primBuffer)
- {
- GFX->setVertexBuffer( *vertBuffer );
- GFX->setPrimitiveBuffer( *primBuffer );
- }
- bool ProcessedMaterial::stepInstance()
- {
- AssertFatal( false, "ProcessedMaterial::stepInstance() - This type of material doesn't support instancing!" );
- return false;
- }
- String ProcessedMaterial::_getTexturePath(const String& filename)
- {
- // if '/', then path is specified, use it.
- if( filename.find('/') != String::NPos )
- {
- return filename;
- }
- // otherwise, construct path
- return mMaterial->getPath() + filename;
- }
- GFXTexHandle ProcessedMaterial::_createTexture( const char* filename, GFXTextureProfile *profile)
- {
- return GFXTexHandle( _getTexturePath(filename), profile, avar("%s() - NA (line %d)", __FUNCTION__, __LINE__) );
- }
- GFXTexHandle ProcessedMaterial::_createCompositeTexture(const char *filenameR, const char *filenameG, const char *filenameB, const char *filenameA, U32 inputKey[4], GFXTextureProfile *profile)
- {
- return GFXTexHandle(_getTexturePath(filenameR), _getTexturePath(filenameG), _getTexturePath(filenameB), _getTexturePath(filenameA), inputKey, profile, avar("%s() - NA (line %d)", __FUNCTION__, __LINE__));
- }
- void ProcessedMaterial::addStateBlockDesc(const GFXStateBlockDesc& sb)
- {
- mUserDefined = sb;
- }
- void ProcessedMaterial::_initStateBlockTemplates(GFXStateBlockDesc& stateTranslucent, GFXStateBlockDesc& stateGlow, GFXStateBlockDesc& stateReflect)
- {
- // Translucency
- stateTranslucent.blendDefined = true;
- stateTranslucent.blendEnable = mMaterial->mTranslucentBlendOp != Material::None;
- _setBlendState(mMaterial->mTranslucentBlendOp, stateTranslucent);
- stateTranslucent.zDefined = true;
- stateTranslucent.zWriteEnable = mMaterial->mTranslucentZWrite;
- stateTranslucent.alphaDefined = true;
- stateTranslucent.alphaTestEnable = mMaterial->mAlphaTest;
- stateTranslucent.alphaTestRef = mMaterial->mAlphaRef;
- stateTranslucent.alphaTestFunc = GFXCmpGreaterEqual;
- stateTranslucent.samplersDefined = true;
- // Glow
- stateGlow.zDefined = true;
- stateGlow.zWriteEnable = false;
- // Reflect
- stateReflect.cullDefined = true;
- stateReflect.cullMode = mMaterial->mDoubleSided ? GFXCullNone : GFXCullCW;
- }
- void ProcessedMaterial::_initRenderPassDataStateBlocks()
- {
- for (U32 pass = 0; pass < mPasses.size(); pass++)
- _initRenderStateStateBlocks( mPasses[pass] );
- }
- void ProcessedMaterial::_initPassStateBlock( RenderPassData *rpd, GFXStateBlockDesc &result )
- {
- if ( rpd->mBlendOp != Material::None )
- {
- result.blendDefined = true;
- result.blendEnable = true;
- _setBlendState( rpd->mBlendOp, result );
- }
- if (mMaterial && mMaterial->isDoubleSided())
- {
- result.cullDefined = true;
- result.cullMode = GFXCullNone;
- }
- if(mMaterial && mMaterial->mAlphaTest)
- {
- result.alphaDefined = true;
- result.alphaTestEnable = mMaterial->mAlphaTest;
- result.alphaTestRef = mMaterial->mAlphaRef;
- result.alphaTestFunc = GFXCmpGreaterEqual;
- }
- result.samplersDefined = true;
- NamedTexTarget *texTarget;
- U32 maxAnisotropy = 1;
- if (mMaterial && mMaterial->mUseAnisotropic[ rpd->mStageNum ] )
- maxAnisotropy = MATMGR->getDefaultAnisotropy();
- for( U32 i=0; i < rpd->mNumTex; i++ )
- {
- U32 currTexFlag = rpd->mTexType[i];
- switch( currTexFlag )
- {
- default:
- {
- result.samplers[i].addressModeU = GFXAddressWrap;
- result.samplers[i].addressModeV = GFXAddressWrap;
- if ( maxAnisotropy > 1 )
- {
- result.samplers[i].minFilter = GFXTextureFilterAnisotropic;
- result.samplers[i].magFilter = GFXTextureFilterAnisotropic;
- result.samplers[i].maxAnisotropy = maxAnisotropy;
- }
- else
- {
- result.samplers[i].minFilter = GFXTextureFilterLinear;
- result.samplers[i].magFilter = GFXTextureFilterLinear;
- }
- break;
- }
- case Material::Cube:
- case Material::SGCube:
- case Material::NormalizeCube:
- {
- result.samplers[i].addressModeU = GFXAddressClamp;
- result.samplers[i].addressModeV = GFXAddressClamp;
- result.samplers[i].addressModeW = GFXAddressClamp;
- result.samplers[i].minFilter = GFXTextureFilterLinear;
- result.samplers[i].magFilter = GFXTextureFilterLinear;
- break;
- }
- case Material::TexTarget:
- {
- texTarget = mPasses[0]->mTexSlot[i].texTarget;
- if ( texTarget )
- texTarget->setupSamplerState( &result.samplers[i] );
- break;
- }
- }
- }
- // The deferred will take care of writing to the
- // zbuffer, so we don't have to by default.
- if ( MATMGR->getDeferredEnabled() &&
- !mFeatures.hasFeature(MFT_ForwardShading))
- result.setZReadWrite( result.zEnable, false );
- result.addDesc(mUserDefined);
- }
- /// Creates the default state blocks for a list of render states
- void ProcessedMaterial::_initRenderStateStateBlocks( RenderPassData *rpd )
- {
- GFXStateBlockDesc stateTranslucent;
- GFXStateBlockDesc stateGlow;
- GFXStateBlockDesc stateReflect;
- GFXStateBlockDesc statePass;
- _initStateBlockTemplates( stateTranslucent, stateGlow, stateReflect );
- _initPassStateBlock( rpd, statePass );
- // Ok, we've got our templates set up, let's combine them together based on state and
- // create our state blocks.
- for (U32 i = 0; i < RenderPassData::STATE_MAX; i++)
- {
- GFXStateBlockDesc stateFinal;
- if (i & RenderPassData::STATE_REFLECT)
- stateFinal.addDesc(stateReflect);
- if (i & RenderPassData::STATE_TRANSLUCENT)
- stateFinal.addDesc(stateTranslucent);
- if (i & RenderPassData::STATE_GLOW)
- stateFinal.addDesc(stateGlow);
- stateFinal.addDesc(statePass);
- if (i & RenderPassData::STATE_WIREFRAME)
- stateFinal.fillMode = GFXFillWireframe;
- GFXStateBlockRef sb = GFX->createStateBlock(stateFinal);
- rpd->mRenderStates[i] = sb;
- }
- }
- U32 ProcessedMaterial::_getRenderStateIndex( const SceneRenderState *sceneState,
- const SceneData &sgData )
- {
- // Based on what the state of the world is, get our render state block
- U32 currState = 0;
- // NOTE: We should only use per-material or per-pass hints to
- // change the render state. This is importaint because we
- // only change the state blocks between material passes.
- //
- // For example sgData.visibility would be bad to use
- // in here without changing how RenderMeshMgr works.
- if ( sgData.binType == SceneData::GlowBin )
- currState |= RenderPassData::STATE_GLOW;
- if ( sceneState && sceneState->isReflectPass() )
- currState |= RenderPassData::STATE_REFLECT;
- if ( sgData.binType != SceneData::DeferredBin &&
- mMaterial->isTranslucent() )
- currState |= RenderPassData::STATE_TRANSLUCENT;
- if ( sgData.wireframe )
- currState |= RenderPassData::STATE_WIREFRAME;
- return currState;
- }
- void ProcessedMaterial::_setRenderState( const SceneRenderState *state,
- const SceneData& sgData,
- U32 pass )
- {
- // Make sure we have the pass
- if ( pass >= mPasses.size() )
- return;
- U32 currState = _getRenderStateIndex( state, sgData );
- GFX->setStateBlock(mPasses[pass]->mRenderStates[currState]);
- }
- void ProcessedMaterial::_setStageData()
- {
- // Only do this once
- if (mHasSetStageData)
- return;
- mHasSetStageData = true;
- U32 i;
- // Load up all the textures for every possible stage
- for (i = 0; i < Material::MAX_STAGES; i++)
- {
- // DiffuseMap
- if (mMaterial->mDiffuseMapAsset[i] && !mMaterial->mDiffuseMapAsset[i].isNull())
- {
- mStages[i].setTex(MFT_DiffuseMap, mMaterial->getDiffuseMapResource(i));
- //mStages[i].setTex(MFT_DiffuseMap, _createTexture(mMaterial->getDiffuseMap(i), &GFXStaticTextureSRGBProfile));
- if (!mStages[i].getTex(MFT_DiffuseMap))
- {
- // Load a debug texture to make it clear to the user
- // that the texture for this stage was missing.
- mStages[i].setTex(MFT_DiffuseMap, _createTexture(GFXTextureManager::getMissingTexturePath().c_str(), &GFXStaticTextureSRGBProfile));
- }
- }
- else if (mMaterial->mDiffuseMapName[i] != StringTable->EmptyString())
- {
- mStages[i].setTex(MFT_DiffuseMap, _createTexture(mMaterial->mDiffuseMapName[i], &GFXStaticTextureSRGBProfile));
- if (!mStages[i].getTex(MFT_DiffuseMap))
- {
- //If we start with a #, we're probably actually attempting to hit a named target and it may not get a hit on the first pass. So we'll
- //pass on the error rather than spamming the console
- if (!String(mMaterial->mDiffuseMapName[i]).startsWith("#"))
- mMaterial->logError("Failed to load diffuse map %s for stage %i", mMaterial->mDiffuseMapName[i], i);
- // Load a debug texture to make it clear to the user
- // that the texture for this stage was missing.
- mStages[i].setTex(MFT_DiffuseMap, _createTexture(GFXTextureManager::getMissingTexturePath().c_str(), &GFXStaticTextureSRGBProfile));
- }
- }
- // OverlayMap
- if (mMaterial->getOverlayMap(i) != StringTable->EmptyString())
- {
- mStages[i].setTex(MFT_OverlayMap, mMaterial->getOverlayMapResource(i));
- if (!mStages[i].getTex(MFT_OverlayMap))
- mMaterial->logError("Failed to load overlay map %s for stage %i", mMaterial->getOverlayMap(i), i);
- }
- // LightMap
- if (mMaterial->getLightMap(i) != StringTable->EmptyString())
- {
- mStages[i].setTex(MFT_LightMap, mMaterial->getLightMapResource(i));
- if (!mStages[i].getTex(MFT_LightMap))
- mMaterial->logError("Failed to load light map %s for stage %i", mMaterial->getLightMap(i), i);
- }
- // ToneMap
- if (mMaterial->getToneMap(i) != StringTable->EmptyString())
- {
- mStages[i].setTex(MFT_ToneMap, mMaterial->getToneMapResource(i));
- if (!mStages[i].getTex(MFT_ToneMap))
- mMaterial->logError("Failed to load tone map %s for stage %i", mMaterial->getToneMap(i), i);
- }
- // DetailMap
- if (mMaterial->getDetailMap(i) != StringTable->EmptyString())
- {
- mStages[i].setTex(MFT_DetailMap, mMaterial->getDetailMapResource(i));
- if (!mStages[i].getTex(MFT_DetailMap))
- mMaterial->logError("Failed to load detail map %s for stage %i", mMaterial->getDetailMap(i), i);
- }
- // NormalMap
- if (mMaterial->getNormalMap(i) != StringTable->EmptyString())
- {
- mStages[i].setTex(MFT_NormalMap, mMaterial->getNormalMapResource(i));
- if (!mStages[i].getTex(MFT_NormalMap))
- mMaterial->logError("Failed to load normal map %s for stage %i", mMaterial->getNormalMap(i), i);
- }
- // Detail Normal Map
- if (mMaterial->getDetailNormalMap(i) != StringTable->EmptyString())
- {
- mStages[i].setTex(MFT_DetailNormalMap, mMaterial->getDetailNormalMapResource(i));
- if (!mStages[i].getTex(MFT_DetailNormalMap))
- mMaterial->logError("Failed to load normal map %s for stage %i", mMaterial->getDetailNormalMap(i), i);
- }
- //depending on creation method this may or may not have been shoved into srgb space eroneously
- GFXTextureProfile* profile = &GFXStaticTextureProfile;
- if (mMaterial->mIsSRGb[i])
- profile = &GFXStaticTextureSRGBProfile;
- // ORMConfig
- if (mMaterial->getORMConfigMap(i) != StringTable->EmptyString())
- {
- mStages[i].setTex(MFT_OrmMap, _createTexture(mMaterial->getORMConfigMap(i), profile));
- if (!mStages[i].getTex(MFT_OrmMap))
- mMaterial->logError("Failed to load PBR Config map %s for stage %i", mMaterial->getORMConfigMap(i), i);
- }
- else
- {
- if ((mMaterial->getAOMap(i) != StringTable->EmptyString()) || (mMaterial->getRoughMap(i) != StringTable->EmptyString()) || (mMaterial->getMetalMap(i) != StringTable->EmptyString()))
- {
- U32 inputKey[4];
- inputKey[0] = mMaterial->mAOChan[i];
- inputKey[1] = mMaterial->mRoughnessChan[i];
- inputKey[2] = mMaterial->mMetalChan[i];
- inputKey[3] = 0;
- mStages[i].setTex(MFT_OrmMap, _createCompositeTexture( mMaterial->getAOMap(i), mMaterial->getRoughMap(i),
- mMaterial->getMetalMap(i), "",
- inputKey, profile));
- if (!mStages[i].getTex(MFT_OrmMap))
- mMaterial->logError("Failed to dynamically create ORM Config map for stage %i", i);
- }
- }
- if (mMaterial->getGlowMap(i) != StringTable->EmptyString())
- {
- mStages[i].setTex(MFT_GlowMap, mMaterial->getGlowMapResource(i));
- if (!mStages[i].getTex(MFT_GlowMap))
- mMaterial->logError("Failed to load glow map %s for stage %i", mMaterial->getGlowMap(i), i);
- }
- }
- mMaterial->mCubemapData = dynamic_cast<CubemapData*>(Sim::findObject(mMaterial->mCubemapName));
- if (!mMaterial->mCubemapData)
- mMaterial->mCubemapData = NULL;
- // If we have a cubemap put it on stage 0 (cubemaps only supported on stage 0)
- if (mMaterial->mCubemapData)
- {
- mMaterial->mCubemapData->createMap();
- mStages[0].setCubemap(mMaterial->mCubemapData->mCubemap);
- if (!mStages[0].getCubemap())
- mMaterial->logError("Failed to load cubemap");
- }
- }
|