Torque3D Documentation / _generateds / terrCellMaterial.cpp

terrCellMaterial.cpp

Engine/source/terrain/terrCellMaterial.cpp

More...

Detailed Description

Public Variables

S32 sgMaxTerrainMaterialsPerPass 

Public Functions

_initSamplerNames()

AFTER_MODULE_INIT(MaterialManager )

  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 "terrain/terrCellMaterial.h"
 26
 27
 28#include "core/util/safeRelease.h"
 29#include "terrain/terrData.h"
 30#include "terrain/terrCell.h"
 31#include "materials/materialFeatureTypes.h"
 32#include "materials/materialManager.h"
 33#include "terrain/terrFeatureTypes.h"
 34#include "terrain/terrMaterial.h"
 35#include "renderInstance/renderDeferredMgr.h"
 36#include "shaderGen/shaderGen.h"
 37#include "shaderGen/featureMgr.h"
 38#include "scene/sceneRenderState.h"
 39#include "materials/sceneData.h"
 40#include "gfx/util/screenspace.h"
 41#include "lighting/advanced/advancedLightBinManager.h"
 42
 43S32 sgMaxTerrainMaterialsPerPass = 32;
 44
 45AFTER_MODULE_INIT( MaterialManager )
 46{
 47   Con::NotifyDelegate callabck( &TerrainCellMaterial::_updateDefaultAnisotropy );
 48   Con::addVariableNotify( "$pref::Video::defaultAnisotropy", callabck );
 49}
 50
 51Vector<TerrainCellMaterial*> TerrainCellMaterial::smAllMaterials;
 52
 53Vector<String> _initSamplerNames()
 54{
 55   Vector<String> samplerNames;
 56   samplerNames.push_back("$baseTexMap");
 57   samplerNames.push_back("$layerTex");
 58   samplerNames.push_back("$lightMapTex");
 59   samplerNames.push_back("$lightInfoBuffer");
 60   samplerNames.push_back("$normalMapSampler");
 61   samplerNames.push_back("$detailMapSampler");
 62   samplerNames.push_back("$macroMapSampler");
 63   samplerNames.push_back("$ormMapSampler"); 
 64
 65   return samplerNames;
 66}
 67
 68
 69const Vector<String> TerrainCellMaterial::mSamplerNames = _initSamplerNames();
 70
 71TerrainCellMaterial::TerrainCellMaterial()
 72   :  mTerrain( NULL ),
 73      mDeferredMat( NULL ),
 74      mReflectMat( NULL ),
 75      mShader( NULL ),
 76      mCurrPass( 0 ),
 77      mMaterials( 0 )
 78{
 79   smAllMaterials.push_back( this );
 80}
 81
 82TerrainCellMaterial::~TerrainCellMaterial()
 83{
 84   SAFE_DELETE( mDeferredMat );
 85   SAFE_DELETE( mReflectMat );   
 86   smAllMaterials.remove( this );
 87
 88   T3D::for_each(mMaterialInfos.begin(), mMaterialInfos.end(), T3D::delete_pointer());
 89   mMaterialInfos.clear();
 90}
 91
 92void TerrainCellMaterial::_updateDefaultAnisotropy()
 93{
 94   // TODO: We need to split the stateblock initialization
 95   // from the shader constant lookup and pass setup in a 
 96   // future version of terrain materials.
 97   //
 98   // For now use some custom code in a horrible loop to 
 99   // change the anisotropy directly and fast.
100   //
101
102   const U32 maxAnisotropy = MATMGR->getDefaultAnisotropy();
103
104   Vector<TerrainCellMaterial*>::iterator iter = smAllMaterials.begin();
105   for ( ; iter != smAllMaterials.end(); iter++ )
106   {
107      // Start from the existing state block.
108      GFXStateBlockDesc desc = (*iter)->mStateBlock->getDesc();
109
110      if ((*iter)->mDetailTexArrayConst->isValid())
111      {
112         const S32 sampler = (*iter)->mDetailTexArrayConst->getSamplerRegister();
113
114         if (maxAnisotropy > 1)
115         {
116            desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
117            desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
118         }
119         else
120            desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
121      }
122
123      if ((*iter)->mMacroTexArrayConst->isValid())
124      {
125         const S32 sampler = (*iter)->mMacroTexArrayConst->getSamplerRegister();
126
127         if (maxAnisotropy > 1)
128         {
129            desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
130            desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
131         }
132         else
133            desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
134      }
135
136      if ((*iter)->mNormalTexArrayConst->isValid())
137      {
138         const S32 sampler = (*iter)->mNormalTexArrayConst->getSamplerRegister();
139
140         if (maxAnisotropy > 1)
141         {
142            desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
143            desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
144         }
145         else
146            desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
147      }
148
149      if ((*iter)->mOrmTexArrayConst->isValid())
150      {
151         const S32 sampler = (*iter)->mOrmTexArrayConst->getSamplerRegister();
152
153         if (maxAnisotropy > 1)
154         {
155            desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
156            desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
157         }
158         else
159            desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
160      }
161
162      // Set the updated stateblock.
163      desc.setCullMode(GFXCullCCW);
164      (*iter)->mStateBlock = GFX->createStateBlock(desc);
165
166      //reflection
167      desc.setCullMode(GFXCullCW);
168      (*iter)->mReflectionStateBlock = GFX->createStateBlock(desc);
169
170      // Create the wireframe state blocks.
171      GFXStateBlockDesc wireframe(desc);
172      wireframe.fillMode = GFXFillWireframe;
173      wireframe.setCullMode(GFXCullCCW);
174      (*iter)->mWireframeStateBlock = GFX->createStateBlock(wireframe);
175   }
176
177}
178
179void TerrainCellMaterial::setTransformAndEye(   const MatrixF &modelXfm, 
180                                                const MatrixF &viewXfm,
181                                                const MatrixF &projectXfm,
182                                                F32 farPlane )
183{
184   PROFILE_SCOPE( TerrainCellMaterial_SetTransformAndEye );
185
186   MatrixF modelViewProj = projectXfm * viewXfm * modelXfm;
187  
188   MatrixF invViewXfm( viewXfm );
189   invViewXfm.inverse();
190   Point3F eyePos = invViewXfm.getPosition();
191   
192   MatrixF invModelXfm( modelXfm );
193   invModelXfm.inverse();
194
195   Point3F objEyePos = eyePos;
196   invModelXfm.mulP( objEyePos );
197   
198   VectorF vEye = invViewXfm.getForwardVector();
199   vEye.normalize( 1.0f / farPlane );
200
201   mConsts->setSafe(mModelViewProjConst, modelViewProj);
202
203   if (mViewToObjConst->isValid() || mWorldViewOnlyConst->isValid())
204   {
205      MatrixF worldViewOnly = viewXfm * modelXfm;
206
207      mConsts->setSafe(mWorldViewOnlyConst, worldViewOnly);
208
209      if (mViewToObjConst->isValid())
210      {
211         worldViewOnly.affineInverse();
212         mConsts->set(mViewToObjConst, worldViewOnly);
213      }
214   }
215
216   mConsts->setSafe(mEyePosWorldConst, eyePos);
217   mConsts->setSafe(mEyePosConst, objEyePos);
218   mConsts->setSafe(mObjTransConst, modelXfm);
219   mConsts->setSafe(mWorldToObjConst, invModelXfm);
220   mConsts->setSafe(mVEyeConst, vEye);
221}
222
223TerrainCellMaterial* TerrainCellMaterial::getDeferredMat()
224{
225   if ( !mDeferredMat )
226   {
227      mDeferredMat = new TerrainCellMaterial();
228      mDeferredMat->init( mTerrain, mMaterials, true, false, mMaterials == 0 );
229   }
230
231   return mDeferredMat;
232}
233
234TerrainCellMaterial* TerrainCellMaterial::getReflectMat()
235{
236   if ( !mReflectMat )
237   {
238      mReflectMat = new TerrainCellMaterial();
239      mReflectMat->init( mTerrain, mMaterials, false, true, true );
240   }
241
242   return mReflectMat;
243}
244
245void TerrainCellMaterial::init(  TerrainBlock *block,
246                                 U64 activeMaterials, 
247                                 bool deferredMat,
248                                 bool reflectMat,
249                                 bool baseOnly )
250{
251   // This isn't allowed for now.
252   AssertFatal( !( deferredMat && reflectMat ), "TerrainCellMaterial::init - We shouldn't get deferred and reflection in the same material!" );
253
254   mTerrain = block;
255   mMaterials = activeMaterials;
256
257   mMaterialInfos.clear();
258   for ( U32 i = 0; i < 64; i++ )
259   {
260      if ( !( mMaterials & ((U64)1 << i ) ) )
261         continue;
262
263      TerrainMaterial *mat = block->getMaterial( i );
264
265      MaterialInfo *info = new MaterialInfo();
266      info->layerId = i;
267      info->mat = mat;
268      mMaterialInfos.push_back(info);
269   }
270
271   if (!_initShader(deferredMat,
272                     reflectMat,
273                     baseOnly))
274   {
275      Con::errorf("TerrainCellMaterial::init - Failed to init shader!");
276
277      T3D::for_each(mMaterialInfos.begin(), mMaterialInfos.end(), T3D::delete_pointer());
278      mMaterialInfos.clear();
279      return;
280   }
281
282   // If we have attached mats then update them too.
283   if ( mDeferredMat )
284      mDeferredMat->init( mTerrain, mMaterials, true, false, baseOnly );
285   if ( mReflectMat )
286      mReflectMat->init( mTerrain, mMaterials, false, true, baseOnly );
287}
288
289bool TerrainCellMaterial::_initShader(bool deferredMat,
290   bool reflectMat,
291   bool baseOnly)
292{
293   if (GFX->getPixelShaderVersion() < 3.0f)
294      baseOnly = true;
295
296   // NOTE: At maximum we only try to combine sgMaxTerrainMaterialsPerPass materials 
297   // into a single pass.  This is sub-optimal for the simplest
298   // cases, but the most common case results in much fewer
299   // shader generation failures and permutations leading to
300   // faster load time and less hiccups during gameplay.
301   U32 matCount = getMin(sgMaxTerrainMaterialsPerPass, mMaterialInfos.size());
302
303   Vector<GFXTexHandle> normalMaps;
304
305   // See if we're currently running under the
306   // basic lighting manager.
307   //
308   // TODO: This seems ugly... we should trigger
309   // features like this differently in the future.
310   //
311   bool useBLM = String::compare(LIGHTMGR->getId(), "BLM") == 0;
312
313   // Do we need to disable normal mapping?
314   const bool disableNormalMaps = MATMGR->getExclusionFeatures().hasFeature(MFT_NormalMap) || useBLM;
315
316   // How about parallax?
317   const bool disableParallaxMaps = GFX->getPixelShaderVersion() < 3.0f ||
318      MATMGR->getExclusionFeatures().hasFeature(MFT_Parallax);
319
320   // Has advanced lightmap support been enabled for deferred.
321   bool advancedLightmapSupport = false;
322   if (deferredMat)
323   {
324      // This sucks... but it works.
325      AdvancedLightBinManager* lightBin;
326      if (Sim::findObject("AL_LightBinMgr", lightBin))
327         advancedLightmapSupport = lightBin->MRTLightmapsDuringDeferred();
328   }
329
330   // Loop till we create a valid shader!
331   while (true)
332   {
333      FeatureSet features;
334      features.addFeature(MFT_VertTransform);
335      features.addFeature(MFT_TerrainBaseMap);
336
337      if (deferredMat)
338      {
339         features.addFeature(MFT_EyeSpaceDepthOut);
340         features.addFeature(MFT_DeferredConditioner);
341         features.addFeature(MFT_isDeferred);
342
343         if (advancedLightmapSupport)
344            features.addFeature(MFT_RenderTarget3_Zero);
345      }
346      else
347      {
348         features.addFeature(MFT_RTLighting);
349
350         // The HDR feature is always added... it will compile out
351         // if HDR is not enabled in the engine.
352         features.addFeature(MFT_HDROut);
353      }
354
355      // Enable lightmaps and fogging if we're in BL.
356      if (reflectMat || useBLM)
357      {
358         features.addFeature(MFT_Fog);
359         features.addFeature(MFT_ForwardShading);
360      }
361      if (useBLM)
362         features.addFeature(MFT_TerrainLightMap);
363
364      normalMaps.clear();
365
366      S32 featureIndex = 0;
367
368      // Now add all the material layer features.
369      for (U32 i = 0; i < matCount && !baseOnly; i++)
370      {
371         TerrainMaterial* mat = mMaterialInfos[i]->mat;
372
373         if (mat == NULL)
374            continue;
375
376         // We only include materials that 
377         // have more than a base texture.
378         if (mat->getDetailSize() <= 0 ||
379            mat->getDetailDistance() <= 0 ||
380            mat->getDetailMap().isEmpty())
381            continue;
382
383         // check for macro detail texture
384         if (!(mat->getMacroSize() <= 0 || mat->getMacroDistance() <= 0 || mat->getMacroMap().isEmpty()))
385         {
386            if (deferredMat)
387               features.addFeature(MFT_isDeferred, featureIndex);
388            features.addFeature(MFT_TerrainMacroMap, featureIndex);
389         }
390
391         if (deferredMat)
392            features.addFeature(MFT_isDeferred, featureIndex);
393         features.addFeature(MFT_TerrainDetailMap, featureIndex);
394
395         if (deferredMat)
396         {
397            if (!(mat->getORMConfigMap().isEmpty()))
398            {
399               features.addFeature(MFT_TerrainORMMap, featureIndex);
400            }
401            else
402            {
403               features.addFeature(MFT_DeferredTerrainBlankInfoMap, featureIndex);
404            }
405         }
406         
407         if (mat->getInvertRoughness())
408            features.addFeature(MFT_InvertRoughness, featureIndex);
409
410         normalMaps.increment();
411
412         // Skip normal maps if we need to.
413         if (!disableNormalMaps && mat->getNormalMap().isNotEmpty())
414         {
415            features.addFeature(MFT_TerrainNormalMap, featureIndex);
416
417            normalMaps.last().set(mat->getNormalMap(),
418               &GFXNormalMapProfile, "TerrainCellMaterial::_initShader() - NormalMap");
419
420            GFXFormat normalFmt = normalMaps.last().getFormat();
421            if (normalFmt == GFXFormatBC3)
422               features.addFeature(MFT_IsBC3nm, featureIndex);
423            else if (normalFmt == GFXFormatBC5)
424               features.addFeature(MFT_IsBC5nm, featureIndex);
425
426            // Do we need and can we do parallax mapping?
427            if (!disableParallaxMaps &&
428               mat->getParallaxScale() > 0.0f &&
429               !mat->useSideProjection())
430               features.addFeature(MFT_TerrainParallaxMap, featureIndex);
431         }
432
433         // Is this layer got side projection?
434         if (mat->useSideProjection())
435            features.addFeature(MFT_TerrainSideProject, featureIndex);
436
437         featureIndex++;
438      }
439
440      // New blending
441      if (matCount > 0 && !Con::getBoolVariable("$Terrain::LerpBlend", false))
442      {
443         features.addFeature(MFT_TerrainHeightBlend);
444      }
445
446      MaterialFeatureData featureData;
447      featureData.features = features;
448      featureData.materialFeatures = features;
449
450      // Check to see how many vertex shader output 
451      // registers we're gonna need.
452      U32 numTex = 0;
453      U32 numTexReg = 0;
454      for (U32 i = 0; i < features.getCount(); i++)
455      {
456         S32 index;
457         const FeatureType& type = features.getAt(i, &index);
458         ShaderFeature* sf = FEATUREMGR->getByType(type);
459         if (!sf)
460            continue;
461
462         sf->setProcessIndex(index);
463         ShaderFeature::Resources res = sf->getResources(featureData);
464
465         numTex += res.numTex;
466         numTexReg += res.numTexReg;
467      }
468
469      // Can we build the shader?
470      //
471      // NOTE: The 10 is sort of an abitrary SM 3.0 
472      // limit.  Its really supposed to be 11, but that
473      // always fails to compile so far.
474      //
475      if (numTex < GFX->getNumSamplers() &&
476         numTexReg <= 10)
477      {
478         // NOTE: We really shouldn't be getting errors building the shaders,
479         // but we can generate more instructions than the ps_2_x will allow.
480         //
481         // There is no way to deal with this case that i know of other than
482         // letting the compile fail then recovering by trying to build it
483         // with fewer materials.
484         //
485         // We normally disable the shader error logging so that the user 
486         // isn't fooled into thinking there is a real bug.  That is until
487         // we get down to a single material.  If a single material case
488         // fails it means it cannot generate any passes at all!
489         const bool logErrors = true;// matCount == 1;
490         GFXShader::setLogging(logErrors, true);
491
492         mShader = SHADERGEN->getShader(featureData, getGFXVertexFormat<TerrVertex>(), NULL, mSamplerNames);
493      }
494
495      // If we got a shader then we can continue.
496      if (mShader)
497         break;
498
499      // If the material count is already 1 then this
500      // is a real shader error... give up!
501      if (matCount <= 1)
502         return false;
503
504      // If we failed we next try half the input materials
505      // so that we can more quickly arrive at a valid shader.
506      matCount -= matCount / 2;
507   }
508
509   // Setup the constant buffer.
510   mConsts = mShader->allocConstBuffer();
511
512   // Prepare the basic constants.
513   mModelViewProjConst = mShader->getShaderConstHandle("$modelview");
514   mWorldViewOnlyConst = mShader->getShaderConstHandle("$worldViewOnly");
515   mViewToObjConst = mShader->getShaderConstHandle("$viewToObj");
516   mEyePosWorldConst = mShader->getShaderConstHandle("$eyePosWorld");
517   mEyePosConst = mShader->getShaderConstHandle("$eyePos");
518   mVEyeConst = mShader->getShaderConstHandle("$vEye");
519   mLayerSizeConst = mShader->getShaderConstHandle("$layerSize");
520   mObjTransConst = mShader->getShaderConstHandle("$objTrans");
521   mWorldToObjConst = mShader->getShaderConstHandle("$worldToObj");
522   mLightInfoBufferConst = mShader->getShaderConstHandle("$lightInfoBuffer");
523   mBaseTexMapConst = mShader->getShaderConstHandle("$baseTexMap");
524   mLayerTexConst = mShader->getShaderConstHandle("$layerTex");
525   mFogDataConst = mShader->getShaderConstHandle("$fogData");
526   mFogColorConst = mShader->getShaderConstHandle("$fogColor");
527   mLightMapTexConst = mShader->getShaderConstHandle("$lightMapTex");
528   mOneOverTerrainSizeConst = mShader->getShaderConstHandle("$oneOverTerrainSize");
529   mSquareSizeConst = mShader->getShaderConstHandle("$squareSize");
530   mBlendDepthConst = mShader->getShaderConstHandle("$baseBlendDepth");
531
532   mLightParamsConst = mShader->getShaderConstHandle("$rtParamslightInfoBuffer");
533
534   // Now prepare the basic stateblock.
535   GFXStateBlockDesc desc;
536
537   // We write to the zbuffer if this is a deferred
538   // material or if the deferred is disabled.
539   desc.setZReadWrite(true, !MATMGR->getDeferredEnabled() ||
540      deferredMat ||
541      reflectMat);
542
543   desc.samplersDefined = true;
544   if (mBaseTexMapConst->isValid())
545      desc.samplers[mBaseTexMapConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear();
546
547   if (mLayerTexConst->isValid())
548      desc.samplers[mLayerTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint();
549
550   if (mLightInfoBufferConst->isValid())
551      desc.samplers[mLightInfoBufferConst->getSamplerRegister()] = GFXSamplerStateDesc::getClampPoint();
552
553   if (mLightMapTexConst->isValid())
554      desc.samplers[mLightMapTexConst->getSamplerRegister()] = GFXSamplerStateDesc::getWrapLinear();
555
556   const U32 maxAnisotropy = MATMGR->getDefaultAnisotropy();
557
558   mDetailInfoVArrayConst = mShader->getShaderConstHandle("$detailScaleAndFade");
559   mDetailInfoPArrayConst = mShader->getShaderConstHandle("$detailIdStrengthParallax");
560   mMacroInfoVArrayConst = mShader->getShaderConstHandle("$macroIdStrengthParallax");
561   mMacroInfoPArrayConst = mShader->getShaderConstHandle("$macroIdStrengthParallax");
562
563   mDetailTexArrayConst = mShader->getShaderConstHandle("$detailMapSampler");
564   if (mDetailTexArrayConst->isValid())
565   {
566      const S32 sampler = mDetailTexArrayConst->getSamplerRegister();
567
568      desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear();
569      desc.samplers[sampler].magFilter = GFXTextureFilterLinear;
570      desc.samplers[sampler].mipFilter = GFXTextureFilterLinear;
571
572      if (maxAnisotropy > 1)
573      {
574         desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
575         desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
576      }
577      else
578         desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
579   }
580
581   mMacroTexArrayConst = mShader->getShaderConstHandle("$macroMapSampler");
582   if (mMacroTexArrayConst->isValid())
583   {
584      const S32 sampler = mMacroTexArrayConst->getSamplerRegister();
585
586      desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear();
587      desc.samplers[sampler].magFilter = GFXTextureFilterLinear;
588      desc.samplers[sampler].mipFilter = GFXTextureFilterLinear;
589
590      if (maxAnisotropy > 1)
591      {
592         desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
593         desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
594      }
595      else
596         desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
597   }
598
599   mNormalTexArrayConst = mShader->getShaderConstHandle("$normalMapSampler");
600   if (mNormalTexArrayConst->isValid())
601   {
602      const S32 sampler = mNormalTexArrayConst->getSamplerRegister();
603
604      desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear();
605      desc.samplers[sampler].magFilter = GFXTextureFilterLinear;
606      desc.samplers[sampler].mipFilter = GFXTextureFilterLinear;
607
608      if (maxAnisotropy > 1)
609      {
610         desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
611         desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
612      }
613      else
614         desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
615   }
616
617   mOrmTexArrayConst = mShader->getShaderConstHandle("$ormMapSampler");
618   if (mOrmTexArrayConst->isValid())
619   {
620      GFXTextureProfile* profile = &GFXStaticTextureProfile;
621
622      const S32 sampler = mOrmTexArrayConst->getSamplerRegister();
623
624      desc.samplers[sampler] = GFXSamplerStateDesc::getWrapLinear();
625      desc.samplers[sampler].magFilter = GFXTextureFilterLinear;
626      desc.samplers[sampler].mipFilter = GFXTextureFilterLinear;
627
628      if (maxAnisotropy > 1)
629      {
630         desc.samplers[sampler].minFilter = GFXTextureFilterAnisotropic;
631         desc.samplers[sampler].maxAnisotropy = maxAnisotropy;
632      }
633      else
634         desc.samplers[sampler].minFilter = GFXTextureFilterLinear;
635   }
636
637   for (U32 i = 0; i < matCount && !baseOnly; i++)
638   {
639      TerrainMaterial* mat = mMaterialInfos[i]->mat;
640
641      if (mat == NULL)
642         continue;
643
644      // We only include materials that 
645      // have more than a base texture.
646      if (mat->getDetailSize() <= 0 ||
647         mat->getDetailDistance() <= 0 ||
648         mat->getDetailMap().isEmpty())
649         continue;
650
651      mMaterialInfos[i]->mBlendDepthConst = mShader->getShaderConstHandle(avar("$blendDepth%d", i));
652      mMaterialInfos[i]->mBlendContrastConst = mShader->getShaderConstHandle(avar("$blendContrast%d", i));
653   }
654
655   // If we're doing deferred it requires some 
656   // special stencil settings for it to work.
657   if ( deferredMat )
658      desc.addDesc( RenderDeferredMgr::getOpaqueStenciWriteDesc( false ) );
659
660   desc.setCullMode( GFXCullCCW );
661   mStateBlock = GFX->createStateBlock(desc);
662
663   //reflection stateblock
664   desc.setCullMode( GFXCullCW );
665   mReflectionStateBlock = GFX->createStateBlock(desc);
666
667   // Create the wireframe state blocks.
668   GFXStateBlockDesc wireframe( desc );
669   wireframe.fillMode = GFXFillWireframe;
670   wireframe.setCullMode( GFXCullCCW );
671   mWireframeStateBlock = GFX->createStateBlock( wireframe );
672
673   return true;
674}
675
676void TerrainCellMaterial::_updateMaterialConsts( )
677{
678   PROFILE_SCOPE( TerrainCellMaterial_UpdateMaterialConsts );
679
680   int detailMatCount = 0;
681   for (MaterialInfo* materialInfo : mMaterialInfos)
682   {
683      if (materialInfo == NULL)
684         continue;
685
686      TerrainMaterial* mat = materialInfo->mat;
687
688      if (mat == NULL)
689         continue;
690
691      // We only include materials that 
692      // have more than a base texture.
693      if (mat->getDetailSize() <= 0 ||
694         mat->getDetailDistance() <= 0 ||
695         mat->getDetailMap().isEmpty())
696         continue;
697
698      detailMatCount++;
699   }
700
701   if (detailMatCount == 0)
702   {
703      return;
704   }
705
706   AlignedArray<Point4F> detailInfoArray(detailMatCount, sizeof(Point4F));
707   AlignedArray<Point4F> detailScaleAndFadeArray(detailMatCount, sizeof(Point4F));
708
709   int detailIndex = 0;
710   for (MaterialInfo* matInfo : mMaterialInfos)
711   {
712      if (matInfo == NULL)
713         continue;
714
715      TerrainMaterial* mat = matInfo->mat;
716
717      if (mat == NULL)
718         continue;
719
720      // We only include materials that 
721      // have more than a base texture.
722      if (mat->getDetailSize() <= 0 ||
723         mat->getDetailDistance() <= 0 ||
724         mat->getDetailMap().isEmpty())
725         continue;
726
727      F32 detailSize = matInfo->mat->getDetailSize();
728      F32 detailScale = 1.0f;
729      if ( !mIsZero( detailSize ) )
730         detailScale = mTerrain->getWorldBlockSize() / detailSize;
731
732      // Scale the distance by the global scalar.
733      const F32 distance = mTerrain->smDetailScale * matInfo->mat->getDetailDistance();
734
735      // NOTE: The negation of the y scale is to make up for 
736      // my mistake early in development and passing the wrong
737      // y texture coord into the system.
738      //
739      // This negation fixes detail, normal, and parallax mapping
740      // without harming the layer id blending code.
741      //
742      // Eventually we should rework this to correct this little
743      // mistake, but there isn't really a hurry to.
744      //
745      Point4F detailScaleAndFade(   detailScale,
746                                    -detailScale,
747                                    distance, 
748                                    0 );
749
750      if ( !mIsZero( distance ) )
751         detailScaleAndFade.w = 1.0f / distance;
752
753      Point4F detailIdStrengthParallax( matInfo->layerId,
754                                        matInfo->mat->getDetailStrength(),
755                                        matInfo->mat->getParallaxScale(), 0 );
756
757      detailScaleAndFadeArray[detailIndex] = detailScaleAndFade;
758      detailInfoArray[detailIndex] = detailIdStrengthParallax;
759
760      if (matInfo->mBlendDepthConst != NULL)
761      {
762         mConsts->setSafe(matInfo->mBlendDepthConst, matInfo->mat->getBlendDepth());
763      }
764
765      if (matInfo->mBlendContrastConst != NULL)
766      {
767         mConsts->setSafe(matInfo->mBlendContrastConst, matInfo->mat->getBlendContrast());
768      }
769      detailIndex++;
770   }
771
772   mConsts->setSafe(mDetailInfoVArrayConst, detailScaleAndFadeArray);
773   mConsts->setSafe(mDetailInfoPArrayConst, detailInfoArray);
774
775}
776
777bool TerrainCellMaterial::setupPass(   const SceneRenderState *state, 
778                                       const SceneData &sceneData )
779{
780   PROFILE_SCOPE( TerrainCellMaterial_SetupPass );
781
782   if (mCurrPass > 0)
783   {
784      mCurrPass = 0;
785      return false;
786   }
787
788   mCurrPass++;
789
790   _updateMaterialConsts();
791
792   if ( mBaseTexMapConst->isValid() )
793      GFX->setTexture( mBaseTexMapConst->getSamplerRegister(), mTerrain->mBaseTex.getPointer() );
794
795   if ( mLayerTexConst->isValid() )
796      GFX->setTexture( mLayerTexConst->getSamplerRegister(), mTerrain->mLayerTex.getPointer() );
797
798   if ( mLightMapTexConst->isValid() )
799      GFX->setTexture( mLightMapTexConst->getSamplerRegister(), mTerrain->getLightMapTex() );
800
801   if ( sceneData.wireframe )
802      GFX->setStateBlock( mWireframeStateBlock );
803   else if ( state->isReflectPass( ))
804      GFX->setStateBlock( mReflectionStateBlock );
805   else
806      GFX->setStateBlock( mStateBlock );
807
808   GFX->setShader( mShader );
809   GFX->setShaderConstBuffer( mConsts );
810
811   // Let the light manager prepare any light stuff it needs.
812   LIGHTMGR->setLightInfo( NULL,
813                           NULL,
814                           sceneData,
815                           state,
816                           0,
817                           mConsts );
818
819   if (mDetailTexArrayConst->isValid() && mTerrain->getDetailTextureArray().isValid())
820      GFX->setTextureArray(mDetailTexArrayConst->getSamplerRegister(), mTerrain->getDetailTextureArray());
821   if (mMacroTexArrayConst->isValid() && mTerrain->getMacroTextureArray().isValid())
822      GFX->setTextureArray(mMacroTexArrayConst->getSamplerRegister(), mTerrain->getMacroTextureArray());
823   if (mNormalTexArrayConst->isValid() && mTerrain->getNormalTextureArray().isValid())
824      GFX->setTextureArray(mNormalTexArrayConst->getSamplerRegister(), mTerrain->getNormalTextureArray());
825   if (mOrmTexArrayConst->isValid() && mTerrain->getOrmTextureArray().isValid())
826      GFX->setTextureArray(mOrmTexArrayConst->getSamplerRegister(), mTerrain->getOrmTextureArray());
827
828   mConsts->setSafe( mLayerSizeConst, (F32)mTerrain->mLayerTex.getWidth() );
829
830   if ( mOneOverTerrainSizeConst->isValid() )
831   {
832      F32 oneOverTerrainSize = 1.0f / mTerrain->getWorldBlockSize();
833      mConsts->set( mOneOverTerrainSizeConst, oneOverTerrainSize );
834   }
835
836   mConsts->setSafe( mSquareSizeConst, mTerrain->getSquareSize() );
837
838   if ( mFogDataConst->isValid() )
839   {
840      Point3F fogData;
841      fogData.x = sceneData.fogDensity;
842      fogData.y = sceneData.fogDensityOffset;
843      fogData.z = sceneData.fogHeightFalloff;     
844      mConsts->set( mFogDataConst, fogData );
845   }
846
847   if (String::isEmpty(Con::getVariable("$Terrain::BlendDepth")))
848   {
849      mConsts->setSafe(mBlendDepthConst, 0.2f);
850   }
851   else
852   {
853      mConsts->setSafe(mBlendDepthConst, Con::getFloatVariable("$Terrain::BlendDepth"));
854   }
855
856   mConsts->setSafe( mFogColorConst, sceneData.fogColor );
857
858   if (  mLightInfoBufferConst->isValid() &&
859         mLightParamsConst->isValid() )
860   {
861      if ( !mLightInfoTarget )
862         mLightInfoTarget = NamedTexTarget::find( "diffuseLighting" );
863
864      GFXTextureObject *texObject = mLightInfoTarget->getTexture();
865      
866      // TODO: Sometimes during reset of the light manager we get a
867      // NULL texture here.  This is corrected on the next frame, but
868      // we should still investigate why that happens.
869      
870      if ( texObject )
871      {
872         GFX->setTexture( mLightInfoBufferConst->getSamplerRegister(), texObject );
873
874         const Point3I &targetSz = texObject->getSize();
875         const RectI &targetVp = mLightInfoTarget->getViewport();
876         Point4F rtParams;
877         ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams);
878         mConsts->setSafe( mLightParamsConst, rtParams );
879      }
880   }
881
882   return true;
883}
884
885BaseMatInstance* TerrainCellMaterial::getShadowMat()
886{
887   // Find our material which has some settings
888   // defined on it in script.
889   Material *mat = MATMGR->getMaterialDefinitionByName( "AL_DefaultShadowMaterial" );
890
891   // Create the material instance adding the feature which
892   // handles rendering terrain cut outs.
893   FeatureSet features = MATMGR->getDefaultFeatures();
894   BaseMatInstance *matInst = mat->createMatInstance();
895   if ( !matInst->init( features, getGFXVertexFormat<TerrVertex>() ) )
896   {
897      delete matInst;
898      matInst = NULL;
899   }
900
901   return matInst;
902}
903
904