Torque3D Documentation / _generateds / processedMaterial.cpp

processedMaterial.cpp

Engine/source/materials/processedMaterial.cpp

More...

Detailed Description

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "materials/processedMaterial.h"
 26
 27#include "materials/sceneData.h"
 28#include "materials/materialParameters.h"
 29#include "materials/matTextureTarget.h"
 30#include "materials/materialFeatureTypes.h"
 31#include "materials/materialManager.h"
 32#include "scene/sceneRenderState.h"
 33#include "gfx/gfxPrimitiveBuffer.h"
 34#include "gfx/gfxTextureManager.h"
 35#include "gfx/sim/cubemapData.h"
 36
 37RenderPassData::RenderPassData()
 38{
 39   reset();
 40}
 41
 42void RenderPassData::reset()
 43{
 44   for( U32 i = 0; i < Material::MAX_TEX_PER_PASS; ++ i )
 45   {
 46      destructInPlace( &mTexSlot[ i ] );
 47      mSamplerNames[ i ].clear();
 48   }
 49
 50   dMemset( &mTexSlot, 0, sizeof(mTexSlot) );
 51   dMemset( &mTexType, 0, sizeof(mTexType) );
 52
 53   mCubeMap = NULL;
 54   mNumTex = mNumTexReg = mStageNum = 0;
 55   mGlow = false;
 56   mBlendOp = Material::None;
 57
 58   mFeatureData.clear();
 59
 60   for (U32 i = 0; i < STATE_MAX; i++)
 61      mRenderStates[i] = NULL;
 62}
 63
 64String RenderPassData::describeSelf() const
 65{
 66   String desc;
 67
 68   // Now write all the textures.
 69   String texName;
 70   for ( U32 i=0; i < Material::MAX_TEX_PER_PASS; i++ )
 71   {
 72      if ( mTexType[i] == Material::TexTarget )
 73         texName = ( mTexSlot[i].texTarget ) ? mTexSlot[i].texTarget->getName() : "null_texTarget";
 74      else if ( mTexType[i] == Material::Cube && mCubeMap )
 75         texName = mCubeMap->getPath();
 76      else if ( mTexSlot[i].texObject )
 77         texName = mTexSlot[i].texObject->getPath();
 78      else
 79         continue;
 80
 81      desc += String::ToString( "TexSlot %d: %d, %s\n", i, mTexType[i], texName.c_str() );
 82   }
 83
 84   // Write out the first render state which is the
 85   // basis for all the other states and shoud be
 86   // enough to define the pass uniquely.
 87   desc += mRenderStates[0]->getDesc().describeSelf();
 88
 89   return desc;
 90}
 91
 92ProcessedMaterial::ProcessedMaterial()
 93:  mMaterial( NULL ),
 94   mCurrentParams( NULL ),
 95   mHasSetStageData( false ),
 96   mHasGlow( false ),   
 97   mHasAccumulation( false ),   
 98   mMaxStages( 0 ),
 99   mVertexFormat( NULL ),
100   mUserObject( NULL )
101{
102   VECTOR_SET_ASSOCIATION( mPasses );
103}
104
105ProcessedMaterial::~ProcessedMaterial()
106{
107   T3D::for_each( mPasses.begin(), mPasses.end(), T3D::delete_pointer() );
108}
109
110void ProcessedMaterial::_setBlendState(Material::BlendOp blendOp, GFXStateBlockDesc& desc )
111{
112   switch( blendOp )
113   {
114   case Material::Add:
115      {
116         desc.blendSrc = GFXBlendOne;
117         desc.blendDest = GFXBlendOne;
118         break;
119      }
120   case Material::AddAlpha:
121      {
122         desc.blendSrc = GFXBlendSrcAlpha;
123         desc.blendDest = GFXBlendOne;
124         break;
125      }
126   case Material::Mul:
127      {
128         desc.blendSrc = GFXBlendDestColor;
129         desc.blendDest = GFXBlendInvSrcAlpha;
130         break;
131      }
132   case Material::PreMul:
133      {
134         desc.blendSrc = GFXBlendOne;
135         desc.blendDest = GFXBlendInvSrcAlpha;
136         break;
137      }
138   case Material::LerpAlpha:
139      {
140         desc.blendSrc = GFXBlendSrcAlpha;
141         desc.blendDest = GFXBlendInvSrcAlpha;
142         break;
143      }
144   case Material::Sub:
145      {
146         desc.blendOp = GFXBlendOpSubtract;
147         desc.blendSrc = GFXBlendOne;
148         desc.blendDest = GFXBlendOne;
149         break;
150      }
151
152   default:
153      {
154         // default to LerpAlpha
155         desc.blendSrc = GFXBlendSrcAlpha;
156         desc.blendDest = GFXBlendInvSrcAlpha;
157         break;
158      }
159   }
160}
161
162void ProcessedMaterial::setBuffers(GFXVertexBufferHandleBase* vertBuffer, GFXPrimitiveBufferHandle* primBuffer)
163{
164   GFX->setVertexBuffer( *vertBuffer );
165   GFX->setPrimitiveBuffer( *primBuffer );
166}
167
168bool ProcessedMaterial::stepInstance()
169{
170   AssertFatal( false, "ProcessedMaterial::stepInstance() - This type of material doesn't support instancing!" );
171   return false;
172}
173
174String ProcessedMaterial::_getTexturePath(const String& filename)
175{
176   // if '/', then path is specified, use it.
177   if( filename.find('/') != String::NPos )
178   {
179      return filename;
180   }
181
182   // otherwise, construct path
183   return mMaterial->getPath() + filename;
184}
185
186GFXTexHandle ProcessedMaterial::_createTexture( const char* filename, GFXTextureProfile *profile)
187{
188   return GFXTexHandle( _getTexturePath(filename), profile, avar("%s() - NA (line %d)", __FUNCTION__, __LINE__) );
189}
190
191GFXTexHandle ProcessedMaterial::_createCompositeTexture(const char *filenameR, const char *filenameG, const char *filenameB, const char *filenameA, U32 inputKey[4], GFXTextureProfile *profile)
192{
193   return GFXTexHandle(_getTexturePath(filenameR), _getTexturePath(filenameG), _getTexturePath(filenameB), _getTexturePath(filenameA), inputKey, profile, avar("%s() - NA (line %d)", __FUNCTION__, __LINE__));
194}
195
196void ProcessedMaterial::addStateBlockDesc(const GFXStateBlockDesc& sb)
197{
198   mUserDefined = sb;
199}
200
201void ProcessedMaterial::_initStateBlockTemplates(GFXStateBlockDesc& stateTranslucent, GFXStateBlockDesc& stateGlow, GFXStateBlockDesc& stateReflect)
202{
203   // Translucency   
204   stateTranslucent.blendDefined = true;
205   stateTranslucent.blendEnable = mMaterial->mTranslucentBlendOp != Material::None;
206   _setBlendState(mMaterial->mTranslucentBlendOp, stateTranslucent);
207   stateTranslucent.zDefined = true;
208   stateTranslucent.zWriteEnable = mMaterial->mTranslucentZWrite;   
209   stateTranslucent.alphaDefined = true;
210   stateTranslucent.alphaTestEnable = mMaterial->mAlphaTest;
211   stateTranslucent.alphaTestRef = mMaterial->mAlphaRef;
212   stateTranslucent.alphaTestFunc = GFXCmpGreaterEqual;
213   stateTranslucent.samplersDefined = true;
214
215   // Glow   
216   stateGlow.zDefined = true;
217   stateGlow.zWriteEnable = false;
218
219   // Reflect   
220   stateReflect.cullDefined = true;
221   stateReflect.cullMode = mMaterial->mDoubleSided ? GFXCullNone : GFXCullCW;
222}
223
224void ProcessedMaterial::_initRenderPassDataStateBlocks()
225{
226   for (U32 pass = 0; pass < mPasses.size(); pass++)
227      _initRenderStateStateBlocks( mPasses[pass] );
228}
229
230void ProcessedMaterial::_initPassStateBlock( RenderPassData *rpd, GFXStateBlockDesc &result )
231{
232   if ( rpd->mBlendOp != Material::None )
233   {
234      result.blendDefined = true;
235      result.blendEnable = true;
236      _setBlendState( rpd->mBlendOp, result );
237   }
238
239   if (mMaterial && mMaterial->isDoubleSided())
240   {
241      result.cullDefined = true;
242      result.cullMode = GFXCullNone;         
243   }
244
245   if(mMaterial && mMaterial->mAlphaTest)
246   {
247      result.alphaDefined = true;
248      result.alphaTestEnable = mMaterial->mAlphaTest;
249      result.alphaTestRef = mMaterial->mAlphaRef;
250      result.alphaTestFunc = GFXCmpGreaterEqual;
251   }
252
253   result.samplersDefined = true;
254   NamedTexTarget *texTarget;
255
256   U32 maxAnisotropy = 1;
257   if (mMaterial &&  mMaterial->mUseAnisotropic[ rpd->mStageNum ] )
258      maxAnisotropy = MATMGR->getDefaultAnisotropy();
259
260   for( U32 i=0; i < rpd->mNumTex; i++ )
261   {      
262      U32 currTexFlag = rpd->mTexType[i];
263
264      switch( currTexFlag )
265      {
266         default:
267         {
268            result.samplers[i].addressModeU = GFXAddressWrap;
269            result.samplers[i].addressModeV = GFXAddressWrap;
270
271            if ( maxAnisotropy > 1 )
272            {
273               result.samplers[i].minFilter = GFXTextureFilterAnisotropic;
274               result.samplers[i].magFilter = GFXTextureFilterAnisotropic;
275               result.samplers[i].maxAnisotropy = maxAnisotropy;
276            }
277            else
278            {
279               result.samplers[i].minFilter = GFXTextureFilterLinear;
280               result.samplers[i].magFilter = GFXTextureFilterLinear;
281            }
282            break;
283         }
284
285         case Material::Cube:
286         case Material::SGCube:
287         case Material::NormalizeCube:
288         {
289            result.samplers[i].addressModeU = GFXAddressClamp;
290            result.samplers[i].addressModeV = GFXAddressClamp;
291            result.samplers[i].addressModeW = GFXAddressClamp;
292            result.samplers[i].minFilter = GFXTextureFilterLinear;
293            result.samplers[i].magFilter = GFXTextureFilterLinear;
294            break;
295         }
296
297         case Material::TexTarget:
298         {
299            texTarget = mPasses[0]->mTexSlot[i].texTarget;
300            if ( texTarget )
301               texTarget->setupSamplerState( &result.samplers[i] );
302            break;
303         }
304      }
305   }
306
307   // The deferred will take care of writing to the 
308   // zbuffer, so we don't have to by default.
309   if (  MATMGR->getDeferredEnabled() && 
310         !mFeatures.hasFeature(MFT_ForwardShading))
311      result.setZReadWrite( result.zEnable, false );
312
313   result.addDesc(mUserDefined);
314}
315
316/// Creates the default state blocks for a list of render states
317void ProcessedMaterial::_initRenderStateStateBlocks( RenderPassData *rpd )
318{
319   GFXStateBlockDesc stateTranslucent;
320   GFXStateBlockDesc stateGlow;
321   GFXStateBlockDesc stateReflect;
322   GFXStateBlockDesc statePass;
323
324   _initStateBlockTemplates( stateTranslucent, stateGlow, stateReflect );
325   _initPassStateBlock( rpd, statePass );
326
327   // Ok, we've got our templates set up, let's combine them together based on state and
328   // create our state blocks.
329   for (U32 i = 0; i < RenderPassData::STATE_MAX; i++)
330   {
331      GFXStateBlockDesc stateFinal;
332
333      if (i & RenderPassData::STATE_REFLECT)
334         stateFinal.addDesc(stateReflect);
335      if (i & RenderPassData::STATE_TRANSLUCENT)
336         stateFinal.addDesc(stateTranslucent);
337      if (i & RenderPassData::STATE_GLOW)
338         stateFinal.addDesc(stateGlow);
339
340      stateFinal.addDesc(statePass);
341
342      if (i & RenderPassData::STATE_WIREFRAME)
343         stateFinal.fillMode = GFXFillWireframe;
344
345      GFXStateBlockRef sb = GFX->createStateBlock(stateFinal);
346      rpd->mRenderStates[i] = sb;
347   }   
348}
349
350U32 ProcessedMaterial::_getRenderStateIndex( const SceneRenderState *sceneState, 
351                                             const SceneData &sgData )
352{
353   // Based on what the state of the world is, get our render state block
354   U32 currState = 0;
355
356   // NOTE: We should only use per-material or per-pass hints to
357   // change the render state.  This is importaint because we 
358   // only change the state blocks between material passes.
359   //
360   // For example sgData.visibility would be bad to use
361   // in here without changing how RenderMeshMgr works.
362
363   if ( sgData.binType == SceneData::GlowBin )
364      currState |= RenderPassData::STATE_GLOW;
365
366   if ( sceneState && sceneState->isReflectPass() )
367      currState |= RenderPassData::STATE_REFLECT;
368
369   if ( sgData.binType != SceneData::DeferredBin &&
370        mMaterial->isTranslucent() )
371      currState |= RenderPassData::STATE_TRANSLUCENT;
372
373   if ( sgData.wireframe )
374      currState |= RenderPassData::STATE_WIREFRAME;
375
376   return currState;
377}
378
379void ProcessedMaterial::_setRenderState(  const SceneRenderState *state, 
380                                          const SceneData& sgData, 
381                                          U32 pass )
382{   
383   // Make sure we have the pass
384   if ( pass >= mPasses.size() )
385      return;
386
387   U32 currState = _getRenderStateIndex( state, sgData );
388
389   GFX->setStateBlock(mPasses[pass]->mRenderStates[currState]);   
390}
391
392
393void ProcessedMaterial::_setStageData()
394{
395   // Only do this once
396   if (mHasSetStageData)
397      return;
398   mHasSetStageData = true;
399
400   U32 i;
401
402   // Load up all the textures for every possible stage
403   for (i = 0; i < Material::MAX_STAGES; i++)
404   {
405      // DiffuseMap
406      if (mMaterial->mDiffuseMapFilename[i].isNotEmpty())
407      {
408         mStages[i].setTex(MFT_DiffuseMap, _createTexture(mMaterial->mDiffuseMapFilename[i], &GFXStaticTextureSRGBProfile));
409         if (!mStages[i].getTex(MFT_DiffuseMap))
410         {
411            //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
412            //pass on the error rather than spamming the console
413            if (!mMaterial->mDiffuseMapFilename[i].startsWith("#"))
414               mMaterial->logError("Failed to load diffuse map %s for stage %i", _getTexturePath(mMaterial->mDiffuseMapFilename[i]).c_str(), i);
415
416            // Load a debug texture to make it clear to the user 
417            // that the texture for this stage was missing.
418            mStages[i].setTex(MFT_DiffuseMap, _createTexture(GFXTextureManager::getMissingTexturePath().c_str(), &GFXStaticTextureSRGBProfile));
419         }
420      }
421      else if (mMaterial->mDiffuseMapAsset[i] && !mMaterial->mDiffuseMapAsset[i].isNull())
422      {
423         mStages[i].setTex(MFT_DiffuseMap, mMaterial->mDiffuseMapAsset[i]->getImage(GFXStaticTextureSRGBProfile));
424         if (!mStages[i].getTex(MFT_DiffuseMap))
425         {
426            // Load a debug texture to make it clear to the user 
427            // that the texture for this stage was missing.
428            mStages[i].setTex(MFT_DiffuseMap, _createTexture(GFXTextureManager::getMissingTexturePath().c_str(), &GFXStaticTextureSRGBProfile));
429         }
430      }
431
432      // OverlayMap
433      if (mMaterial->mOverlayMapFilename[i].isNotEmpty())
434      {
435         mStages[i].setTex(MFT_OverlayMap, _createTexture(mMaterial->mOverlayMapFilename[i], &GFXStaticTextureSRGBProfile));
436         if (!mStages[i].getTex(MFT_OverlayMap))
437            mMaterial->logError("Failed to load overlay map %s for stage %i", _getTexturePath(mMaterial->mOverlayMapFilename[i]).c_str(), i);
438      }
439
440      // LightMap
441      if (mMaterial->mLightMapFilename[i].isNotEmpty())
442      {
443         mStages[i].setTex(MFT_LightMap, _createTexture(mMaterial->mLightMapFilename[i], &GFXStaticTextureSRGBProfile));
444         if (!mStages[i].getTex(MFT_LightMap))
445            mMaterial->logError("Failed to load light map %s for stage %i", _getTexturePath(mMaterial->mLightMapFilename[i]).c_str(), i);
446      }
447
448      // ToneMap
449      if (mMaterial->mToneMapFilename[i].isNotEmpty())
450      {
451         mStages[i].setTex(MFT_ToneMap, _createTexture(mMaterial->mToneMapFilename[i], &GFXStaticTextureProfile));
452         if (!mStages[i].getTex(MFT_ToneMap))
453            mMaterial->logError("Failed to load tone map %s for stage %i", _getTexturePath(mMaterial->mToneMapFilename[i]).c_str(), i);
454      }
455
456      // DetailMap
457      if (mMaterial->mDetailMapFilename[i].isNotEmpty())
458      {
459         mStages[i].setTex(MFT_DetailMap, _createTexture(mMaterial->mDetailMapFilename[i], &GFXStaticTextureProfile));
460         if (!mStages[i].getTex(MFT_DetailMap))
461            mMaterial->logError("Failed to load detail map %s for stage %i", _getTexturePath(mMaterial->mDetailMapFilename[i]).c_str(), i);
462      }
463
464      // NormalMap
465      if (mMaterial->mNormalMapFilename[i].isNotEmpty())
466      {
467         mStages[i].setTex(MFT_NormalMap, _createTexture(mMaterial->mNormalMapFilename[i], &GFXNormalMapProfile));
468         if (!mStages[i].getTex(MFT_NormalMap))
469            mMaterial->logError("Failed to load normal map %s for stage %i", _getTexturePath(mMaterial->mNormalMapFilename[i]).c_str(), i);
470      }
471
472      // Detail Normal Map
473      if (mMaterial->mDetailNormalMapFilename[i].isNotEmpty())
474      {
475         mStages[i].setTex(MFT_DetailNormalMap, _createTexture(mMaterial->mDetailNormalMapFilename[i], &GFXNormalMapProfile));
476         if (!mStages[i].getTex(MFT_DetailNormalMap))
477            mMaterial->logError("Failed to load normal map %s for stage %i", _getTexturePath(mMaterial->mDetailNormalMapFilename[i]).c_str(), i);
478      }
479
480      GFXTextureProfile* profile = &GFXStaticTextureProfile;
481      if (mMaterial->mIsSRGb[i])
482         profile = &GFXStaticTextureSRGBProfile;
483
484      // ORMConfig
485      if (mMaterial->mORMConfigMapFilename[i].isNotEmpty())
486      {
487         mStages[i].setTex(MFT_OrmMap, _createTexture(mMaterial->mORMConfigMapFilename[i], profile));
488         if (!mStages[i].getTex(MFT_OrmMap))
489            mMaterial->logError("Failed to load PBR Config map %s for stage %i", _getTexturePath(mMaterial->mORMConfigMapFilename[i]).c_str(), i);
490      }
491      else
492      {
493         if (mMaterial->mRoughMapFilename[i].isNotEmpty() && mMaterial->mMetalMapFilename[i].isNotEmpty())
494         {
495            U32 inputKey[4];
496            inputKey[0] = mMaterial->mAOChan[i];
497            inputKey[1] = mMaterial->mRoughnessChan[i];
498            inputKey[2] = mMaterial->mMetalChan[i];
499            inputKey[3] = 0;
500            mStages[i].setTex(MFT_OrmMap, _createCompositeTexture( mMaterial->mAOMapFilename[i], mMaterial->mRoughMapFilename[i],
501               mMaterial->mMetalMapFilename[i], "",
502               inputKey, profile));
503            if (!mStages[i].getTex(MFT_OrmMap))
504               mMaterial->logError("Failed to load PBR Config map %s for stage %i", _getTexturePath(mMaterial->mORMConfigMapFilename[i]).c_str(), i);
505         }
506      }
507      if (mMaterial->mGlowMapFilename[i].isNotEmpty())
508      {
509         mStages[i].setTex(MFT_GlowMap, _createTexture(mMaterial->mGlowMapFilename[i], &GFXStaticTextureProfile));
510         if (!mStages[i].getTex(MFT_GlowMap))
511            mMaterial->logError("Failed to load glow map %s for stage %i", _getTexturePath(mMaterial->mGlowMapFilename[i]).c_str(), i);
512      }
513   }
514
515   mMaterial->mCubemapData = dynamic_cast<CubemapData*>(Sim::findObject(mMaterial->mCubemapName));
516   if (!mMaterial->mCubemapData)
517      mMaterial->mCubemapData = NULL;
518
519
520   // If we have a cubemap put it on stage 0 (cubemaps only supported on stage 0)
521   if (mMaterial->mCubemapData)
522   {
523      mMaterial->mCubemapData->createMap();
524      mStages[0].setCubemap(mMaterial->mCubemapData->mCubemap);
525      if (!mStages[0].getCubemap())
526         mMaterial->logError("Failed to load cubemap");
527   }
528}
529
530