Torque3D Documentation / _generateds / processedCustomMaterial.cpp

processedCustomMaterial.cpp

Engine/source/materials/processedCustomMaterial.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/processedCustomMaterial.h"
 26
 27#include "gfx/sim/cubemapData.h"
 28#include "materials/sceneData.h"
 29#include "shaderGen/shaderGenVars.h"
 30#include "scene/sceneRenderState.h"
 31#include "materials/customMaterialDefinition.h"
 32#include "materials/shaderData.h"
 33#include "materials/materialManager.h"
 34#include "materials/matTextureTarget.h"
 35#include "materials/materialFeatureTypes.h"
 36#include "materials/materialParameters.h"
 37#include "gfx/sim/gfxStateBlockData.h"
 38#include "core/util/safeDelete.h"
 39#include "gfx/genericConstBuffer.h"
 40#include "console/simFieldDictionary.h"
 41#include "console/propertyParsing.h"
 42#include "gfx/util/screenspace.h"
 43#include "scene/reflectionManager.h"
 44#include "renderInstance/renderProbeMgr.h"
 45
 46
 47ProcessedCustomMaterial::ProcessedCustomMaterial(Material &mat)
 48{
 49   mMaterial = &mat;
 50   AssertFatal(dynamic_cast<CustomMaterial*>(mMaterial), "Incompatible Material type!");
 51   mCustomMaterial = static_cast<CustomMaterial*>(mMaterial);
 52   mHasSetStageData = false;
 53   mHasGlow = false;
 54   mHasAccumulation = false;
 55   mMaxStages = 0;
 56   mMaxTex = 0;
 57}
 58
 59ProcessedCustomMaterial::~ProcessedCustomMaterial()
 60{   
 61}
 62
 63void ProcessedCustomMaterial::_setStageData()
 64{
 65   // Only do this once
 66   if ( mHasSetStageData ) 
 67      return;
 68   mHasSetStageData = true;   
 69
 70   ShaderRenderPassData* rpd = _getRPD(0);   
 71   mConditionerMacros.clear();
 72
 73   // Loop through all the possible textures, set the right flags, and load them if needed
 74   for(U32 i=0; i<CustomMaterial::MAX_TEX_PER_PASS; i++ )
 75   {
 76      rpd->mTexType[i] = Material::NoTexture;   // Set none as the default in case none of the cases below catch it.
 77      String filename = mCustomMaterial->mTexFilename[i];
 78
 79      if(filename.isEmpty())
 80         continue;
 81
 82      if(filename.equal(String("$dynamiclight"), String::NoCase))
 83      {
 84         rpd->mTexType[i] = Material::DynamicLight;
 85         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
 86         mMaxTex = i+1;
 87         continue;
 88      }
 89
 90       if(filename.equal(String("$dynamiclightmask"), String::NoCase))
 91      {
 92         rpd->mTexType[i] = Material::DynamicLightMask;
 93         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
 94         mMaxTex = i+1;
 95         continue;
 96      }
 97
 98      if(filename.equal(String("$lightmap"), String::NoCase))
 99      {
100         rpd->mTexType[i] = Material::Lightmap;
101         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
102         mMaxTex = i+1;
103         continue;
104      }
105
106      if(filename.equal(String("$cubemap"), String::NoCase))
107      {
108         if( mCustomMaterial->mCubemapData )
109         {
110            rpd->mTexType[i] = Material::Cube;
111            rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
112            mMaxTex = i+1;
113         }
114         else
115         {
116            mCustomMaterial->logError( "Could not find CubemapData - %s", mCustomMaterial->mCubemapName.c_str());
117         }
118         continue;
119      }
120
121      if(filename.equal(String("$dynamicCubemap"), String::NoCase))
122      {
123         rpd->mTexType[i] = Material::SGCube;
124         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
125         mMaxTex = i+1;
126         continue;
127      }
128
129      if(filename.equal(String("$backbuff"), String::NoCase))
130      {
131         rpd->mTexType[i] = Material::BackBuff;
132         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
133         mMaxTex = i+1;
134         continue;
135      }
136
137      if(filename.equal(String("$reflectbuff"), String::NoCase))
138      {
139         rpd->mTexType[i] = Material::ReflectBuff;
140         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
141         mMaxTex = i+1;
142         continue;
143      }
144
145      if(filename.equal(String("$miscbuff"), String::NoCase))
146      {
147         rpd->mTexType[i] = Material::Misc;
148         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
149         mMaxTex = i+1;
150         continue;
151      }
152
153      // Check for a RenderTexTargetBin assignment
154      if (filename.substr( 0, 1 ).equal("#"))
155      {
156         String texTargetBufferName = filename.substr(1, filename.length() - 1);
157         NamedTexTarget *texTarget = NamedTexTarget::find( texTargetBufferName ); 
158         rpd->mTexSlot[i].texTarget = texTarget;
159
160         // Get the conditioner macros.
161         if ( texTarget )
162            texTarget->getShaderMacros( &mConditionerMacros );
163
164         rpd->mTexType[i] = Material::TexTarget;
165         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
166         mMaxTex = i+1;
167         continue;
168      }
169
170      rpd->mTexSlot[i].texObject = _createTexture( filename, &GFXStaticTextureSRGBProfile );
171      if ( !rpd->mTexSlot[i].texObject )
172      {
173         mMaterial->logError("Failed to load texture %s", _getTexturePath(filename).c_str());
174         continue;
175      }
176      rpd->mTexType[i] = Material::Standard;
177      rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
178      mMaxTex = i+1;
179   }
180
181   // We only get one cubemap
182   if( mCustomMaterial->mCubemapData )
183   {
184      mCustomMaterial->mCubemapData->createMap();      
185      rpd->mCubeMap = mMaterial->mCubemapData->mCubemap; // BTRTODO ?
186      if ( !rpd->mCubeMap )
187         mMaterial->logError("Failed to load cubemap");
188   }
189
190   // If this has a output target defined, it may be writing 
191   // to a tex target bin with a conditioner, so search for 
192   // one and add its macros.
193   if ( mCustomMaterial->mOutputTarget.isNotEmpty() )
194   {
195      NamedTexTarget *texTarget = NamedTexTarget::find( mCustomMaterial->mOutputTarget );
196      if ( texTarget )
197         texTarget->getShaderMacros( &mConditionerMacros );
198   }
199
200   // Copy the glow state over.
201   mHasGlow = mCustomMaterial->mGlow[0];
202}
203
204bool ProcessedCustomMaterial::init( const FeatureSet &features, 
205                                    const GFXVertexFormat *vertexFormat,
206                                    const MatFeaturesDelegate &featuresDelegate )
207{
208   // If we don't have a shader data... we have nothing to do.
209   if ( !mCustomMaterial->mShaderData )
210      return true;
211
212   // Custom materials only do one pass at the moment... so
213   // add one for the stage data to fill in.
214   ShaderRenderPassData *rpd = new ShaderRenderPassData();
215   mPasses.push_back( rpd );
216
217   _setStageData();
218   _initPassStateBlocks();   
219   mStateHint.clear();
220
221   // Note: We don't use the vertex format in a custom 
222   // material at all right now.
223   //
224   // Maybe we can add some required semantics and
225   // validate that the format fits the shader?
226
227   // Build a composite list of shader macros from
228   // the conditioner and the user defined lists.
229   Vector<GFXShaderMacro> macros;
230   macros.merge( mConditionerMacros );
231   macros.merge( mUserMacros );
232
233   // Ask the shader data to give us a shader instance.
234   rpd->shader = mCustomMaterial->mShaderData->getShader( macros );      
235   if ( !rpd->shader )
236   {
237      delete rpd;
238      mPasses.clear();
239      return false;
240   }
241
242   rpd->shaderHandles.init( rpd->shader, mCustomMaterial );
243   _initMaterialParameters();
244   mDefaultParameters = allocMaterialParameters();
245   setMaterialParameters( mDefaultParameters, 0 );
246   mStateHint.init( this );
247   
248   for(int i = 0; i < mMaxTex; i++)
249   {
250      ShaderConstHandles *handles = _getShaderConstHandles( mPasses.size()-1 );
251      AssertFatal(handles,"");
252
253      if(rpd->mSamplerNames[i].isEmpty())      
254         continue;      
255
256      String samplerName = rpd->mSamplerNames[i].startsWith("$") ? rpd->mSamplerNames[i] : String("$") + rpd->mSamplerNames[i];
257      GFXShaderConstHandle *handle = rpd->shader->getShaderConstHandle( samplerName ); 
258      AssertFatal(handle,"");
259      handles->mTexHandlesSC[i] = handle;
260   }
261   
262   return true;
263}
264
265void ProcessedCustomMaterial::_initPassStateBlock( RenderPassData *rpd, GFXStateBlockDesc &result )
266{
267   Parent::_initPassStateBlock( rpd, result );
268
269   if (mCustomMaterial->getStateBlockData())
270      result.addDesc(mCustomMaterial->getStateBlockData()->getState());
271}
272
273void ProcessedCustomMaterial::_initPassStateBlocks()
274{
275   AssertFatal(mHasSetStageData, "State data must be set before initializing state block!");
276   ShaderRenderPassData* rpd = _getRPD(0);
277   _initRenderStateStateBlocks( rpd );
278}
279
280bool ProcessedCustomMaterial::_hasCubemap(U32 pass)
281{
282   // If the material doesn't have a cubemap, we don't
283   if( mMaterial->mCubemapData ) return true;
284   else return false;
285}
286
287bool ProcessedCustomMaterial::setupPass( SceneRenderState *state, const SceneData& sgData, U32 pass )
288{
289   PROFILE_SCOPE( ProcessedCustomMaterial_SetupPass );
290
291   // Make sure we have a pass.
292   if ( pass >= mPasses.size() )
293      return false;
294
295   ShaderRenderPassData* rpd = _getRPD( pass );
296   U32 currState = _getRenderStateIndex( state, sgData );
297   GFX->setStateBlock(rpd->mRenderStates[currState]);      
298
299   // activate shader
300   if ( rpd->shader )
301      GFX->setShader( rpd->shader );
302   else
303      GFX->setupGenericShaders();
304
305   // Set our textures   
306   setTextureStages( state, sgData, pass );   
307   
308   GFXShaderConstBuffer* shaderConsts = _getShaderConstBuffer(pass);
309   GFX->setShaderConstBuffer(shaderConsts);
310   
311   // Set our shader constants.
312   _setTextureTransforms(pass);
313   _setShaderConstants(state, sgData, pass);
314
315   LightManager* lm = state ? LIGHTMGR : NULL;
316   if (lm)
317      lm->setLightInfo(this, NULL, sgData, state, pass, shaderConsts);
318
319   RenderProbeMgr* pm = state ? PROBEMGR : NULL;
320   if (pm)
321      pm->setProbeInfo(this, NULL, sgData, state, pass, shaderConsts);
322
323   shaderConsts->setSafe(rpd->shaderHandles.mAccumTimeSC, MATMGR->getTotalTime());   
324
325   return true;
326}
327
328void ProcessedCustomMaterial::setTextureStages( SceneRenderState *state, const SceneData &sgData, U32 pass )
329{      
330   LightManager* lm = state ? LIGHTMGR : NULL;   
331   ShaderRenderPassData* rpd = _getRPD(pass);
332   ShaderConstHandles* handles = _getShaderConstHandles(pass);
333   GFXShaderConstBuffer* shaderConsts = _getShaderConstBuffer(pass);
334
335   const NamedTexTarget *texTarget;
336   GFXTextureObject *texObject; 
337   
338   for( U32 i=0; i<mMaxTex; i++ )
339   {            
340      U32 currTexFlag = rpd->mTexType[i];
341      if ( !lm || !lm->setTextureStage(sgData, currTexFlag, i, shaderConsts, handles ) )
342      {
343         GFXShaderConstHandle* handle = handles->mTexHandlesSC[i];
344         if ( !handle->isValid() )
345            continue;
346
347         S32 samplerRegister = handle->getSamplerRegister();
348         
349         switch( currTexFlag )
350         {
351         case 0:
352         default:
353            break;
354
355         case Material::Mask:
356         case Material::Standard:
357         case Material::Bump:
358         case Material::Detail:
359            {
360               GFX->setTexture( samplerRegister, rpd->mTexSlot[i].texObject );
361               break;
362            }
363
364         case Material::Lightmap:
365            {
366               GFX->setTexture( samplerRegister, sgData.lightmap );
367               break;
368            }
369         case Material::Cube:
370            {
371               GFX->setCubeTexture( samplerRegister, rpd->mCubeMap );
372               break;
373            }
374         case Material::SGCube:
375            {
376               GFX->setCubeTexture( samplerRegister, sgData.cubemap );
377               break;
378            }
379         case Material::BackBuff:
380            {
381               GFX->setTexture( samplerRegister, sgData.backBuffTex );
382               //if ( sgData.reflectTex )
383               //   GFX->setTexture( samplerRegister, sgData.reflectTex );
384               //else
385               //{
386               //    GFXTextureObject *refractTex = REFLECTMGR->getRefractTex( true );
387               //    GFX->setTexture( samplerRegister, refractTex );
388               //}
389               break;
390            }
391         case Material::ReflectBuff:
392            {
393               GFX->setTexture( samplerRegister, sgData.reflectTex );
394               break;
395            }
396         case Material::Misc:
397            {
398               GFX->setTexture( samplerRegister, sgData.miscTex );
399               break;
400            }
401         case Material::TexTarget:
402            {
403               texTarget = rpd->mTexSlot[i].texTarget;
404               if ( !texTarget )
405               {
406                  GFX->setTexture( samplerRegister, NULL );
407                  break;
408               }
409               
410               texObject = texTarget->getTexture();
411
412               // If no texture is available then map the default 2x2
413               // black texture to it.  This at least will ensure that
414               // we get consistant behavior across GPUs and platforms.
415               if ( !texObject )
416                  texObject = GFXTexHandle::ZERO;
417
418               if ( handles->mRTParamsSC[samplerRegister]->isValid() && texObject )
419               {
420                  const Point3I &targetSz = texObject->getSize();
421                  const RectI &targetVp = texTarget->getViewport();
422                  Point4F rtParams;
423
424                  ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams);
425                  shaderConsts->set(handles->mRTParamsSC[samplerRegister], rtParams);
426               }
427              
428               GFX->setTexture( samplerRegister, texObject );
429               break;
430            }
431         }
432      }
433   }
434}
435
436template <typename T>
437void ProcessedCustomMaterial::setMaterialParameter(MaterialParameters* param, 
438                                                   MaterialParameterHandle* handle,
439                                                   const String& value)
440{
441   T typedValue;
442   if (PropertyInfo::default_scan(value, typedValue))
443   {      
444      param->set(handle, typedValue);
445   } else {
446      Con::errorf("Error setting %s, parse error: %s", handle->getName().c_str(), value.c_str());
447   }
448}
449
450void ProcessedCustomMaterial::setMatrixParameter(MaterialParameters* param, 
451                                                 MaterialParameterHandle* handle,
452                                                 const String& value, GFXShaderConstType matrixType)
453{
454   MatrixF result(true);
455   F32* m = result;
456   switch (matrixType)
457   {
458   case GFXSCT_Float2x2 :
459      dSscanf(value.c_str(),"%g %g %g %g", 
460         m[result.idx(0,0)], m[result.idx(0,1)], 
461         m[result.idx(1,0)], m[result.idx(1,1)]);
462      break;
463   case GFXSCT_Float3x3 :
464      dSscanf(value.c_str(),"%g %g %g %g %g %g %g %g %g", 
465         m[result.idx(0,0)], m[result.idx(0,1)], m[result.idx(0,2)], 
466         m[result.idx(1,0)], m[result.idx(1,1)], m[result.idx(1,2)], 
467         m[result.idx(2,0)], m[result.idx(2,1)], m[result.idx(2,2)]);         
468      break;
469   default:
470      AssertFatal(false, "Invalid type!");
471      break;
472   }
473}
474
475// BTRTODO: Support arrays!?
476MaterialParameters* ProcessedCustomMaterial::allocMaterialParameters()
477{
478   MaterialParameters* ret = Parent::allocMaterialParameters();
479   // See if any of the dynamic fields match up with shader constants we have.
480   SimFieldDictionary* fields = mMaterial->getFieldDictionary();
481   if (!fields || fields->getNumFields() == 0)
482      return ret;
483
484   const Vector<GFXShaderConstDesc>& consts = ret->getShaderConstDesc();
485   for (U32 i = 0; i < consts.size(); i++)
486   {
487      // strip the dollar sign from the front.
488      String stripped(consts[i].name);
489      stripped.erase(0, 1);      
490
491      SimFieldDictionary::Entry* field = fields->findDynamicField(stripped);      
492      if (field)
493      {
494         MaterialParameterHandle* handle = getMaterialParameterHandle(consts[i].name);
495         switch (consts[i].constType)
496         {
497         case GFXSCT_Float :
498            setMaterialParameter<F32>(ret, handle, field->value);
499            break;
500         case GFXSCT_Float2: 
501            setMaterialParameter<Point2F>(ret, handle, field->value);
502            break;            
503         case GFXSCT_Float3: 
504            setMaterialParameter<Point3F>(ret, handle, field->value);
505            break;            
506         case GFXSCT_Float4: 
507            setMaterialParameter<Point4F>(ret, handle, field->value);
508            break;            
509         case GFXSCT_Float2x2:                         
510         case GFXSCT_Float3x3: 
511            setMatrixParameter(ret, handle, field->value, consts[i].constType);
512            break;
513         case GFXSCT_Float4x4: 
514            setMaterialParameter<MatrixF>(ret, handle, field->value);
515            break;            
516         case GFXSCT_Int: 
517            setMaterialParameter<S32>(ret, handle, field->value);
518            break;
519         case GFXSCT_Int2: 
520            setMaterialParameter<Point2I>(ret, handle, field->value);
521            break;
522         case GFXSCT_Int3: 
523            setMaterialParameter<Point3I>(ret, handle, field->value);
524            break;
525         case GFXSCT_Int4: 
526            setMaterialParameter<Point4I>(ret, handle, field->value);
527            break;
528         // Do we want to ignore these?
529         case GFXSCT_Sampler:
530         case GFXSCT_SamplerCube:
531         default:
532            break;
533         }
534      }
535   }
536   return ret;
537}
538