浏览代码

Merge pull request #925 from BeamNG/shaderdata_samplernames

Add sampler names to ShaderData
LuisAntonRebollo 10 年之前
父节点
当前提交
03ffa1ddd3

+ 17 - 1
Engine/source/gfx/D3D9/gfxD3D9Shader.cpp

@@ -1101,11 +1101,13 @@ void GFXD3D9Shader::_getShaderConstants( ID3DXConstantTable *table,
                         desc.constType = GFXSCT_Sampler;
                         desc.arraySize = constantDesc.RegisterIndex;
                         samplerDescriptions.push_back( desc );
+                        mShaderConsts.push_back(desc);
                         break;
                      case D3DXPT_SAMPLERCUBE :
                         desc.constType = GFXSCT_SamplerCube;
                         desc.arraySize = constantDesc.RegisterIndex;
                         samplerDescriptions.push_back( desc );
+                        mShaderConsts.push_back(desc);
                         break;
                   }
                }
@@ -1371,7 +1373,7 @@ GFXShaderConstBufferRef GFXD3D9Shader::allocConstBuffer()
    }
 }
 
-/// Returns a shader constant handle for name, if the variable doesn't exist NULL is returned.
+/// Returns a shader constant handle for name
 GFXShaderConstHandle* GFXD3D9Shader::getShaderConstHandle(const String& name)
 {
    HandleMap::Iterator i = mHandles.find(name);   
@@ -1390,6 +1392,20 @@ GFXShaderConstHandle* GFXD3D9Shader::getShaderConstHandle(const String& name)
    }      
 }
 
+/// Returns a shader constant handle for name, if the variable doesn't exist NULL is returned.
+GFXShaderConstHandle* GFXD3D9Shader::findShaderConstHandle(const String& name)
+{
+   HandleMap::Iterator i = mHandles.find(name);   
+   if ( i != mHandles.end() )
+   {
+      return i->value;
+   } 
+   else 
+   {     
+      return NULL;
+   }      
+}
+
 const Vector<GFXShaderConstDesc>& GFXD3D9Shader::getShaderConstDesc() const
 {
    return mShaderConsts;

+ 1 - 0
Engine/source/gfx/D3D9/gfxD3D9Shader.h

@@ -205,6 +205,7 @@ public:
    virtual GFXShaderConstBufferRef allocConstBuffer();
    virtual const Vector<GFXShaderConstDesc>& getShaderConstDesc() const;
    virtual GFXShaderConstHandle* getShaderConstHandle(const String& name); 
+   virtual GFXShaderConstHandle* findShaderConstHandle(const String& name);
    virtual U32 getAlignmentValue(const GFXShaderConstType constType) const;
    virtual bool getDisassembly( String &outStr ) const;
 

+ 6 - 0
Engine/source/gfx/gfxDevice.h

@@ -1117,4 +1117,10 @@ inline void GFXDevice::setVertexFormat( const GFXVertexFormat *vertexFormat )
 }
 
 
+#if defined(TORQUE_DEBUG) && defined(TORQUE_DEBUG_GFX)
+#define GFXAssertFatal(x, error) AssertFatal(x, error)
+#else
+#define GFXAssertFatal(x, error)
+#endif
+
 #endif // _GFXDEVICE_H_

+ 3 - 0
Engine/source/gfx/gfxShader.h

@@ -332,6 +332,9 @@ public:
    /// if the constant doesn't exist at this time.
    virtual GFXShaderConstHandle* getShaderConstHandle( const String& name ) = 0; 
 
+   /// Returns a shader constant handle for the name constant, if the variable doesn't exist NULL is returned.
+   virtual GFXShaderConstHandle* findShaderConstHandle( const String& name ) = 0;
+
    /// Returns the alignment value for constType
    virtual U32 getAlignmentValue(const GFXShaderConstType constType) const = 0;   
 

+ 4 - 1
Engine/source/lighting/advanced/hlsl/advancedLightingFeaturesHLSL.cpp

@@ -98,7 +98,7 @@ void DeferredRTLightingFeatHLSL::processPix( Vector<ShaderComponent*> &component
    uvScene->setName( "uvScene" );
    LangElement *uvSceneDecl = new DecOp( uvScene );
 
-   String rtParamName = String::ToString( "rtParams%d", mLastTexIndex );
+   String rtParamName = String::ToString( "rtParams%s", "lightInfoBuffer" );
    Var *rtParams = (Var*) LangElement::find( rtParamName );
    if( !rtParams )
    {
@@ -207,6 +207,7 @@ void DeferredRTLightingFeatHLSL::setTexData( Material::StageData &stageDat,
       mLastTexIndex = texIndex;
 
       passData.mTexType[ texIndex ] = Material::TexTarget;
+      passData.mSamplerNames[ texIndex ]= "lightInfoBuffer";
       passData.mTexSlot[ texIndex++ ].texTarget = texTarget;
    }
 }
@@ -402,12 +403,14 @@ void DeferredBumpFeatHLSL::setTexData( Material::StageData &stageDat,
            fd.features[MFT_PixSpecular] ) )
    {
       passData.mTexType[ texIndex ] = Material::Bump;
+      passData.mSamplerNames[ texIndex ] = "bumpMap";
       passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_NormalMap );
 
       if (  fd.features[MFT_PrePassConditioner] &&
             fd.features.hasFeature( MFT_DetailNormalMap ) )
       {
          passData.mTexType[ texIndex ] = Material::DetailBump;
+         passData.mSamplerNames[ texIndex ] = "detailBumpMap";
          passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_DetailNormalMap );
       }
    }

+ 19 - 3
Engine/source/materials/customMaterialDefinition.cpp

@@ -138,9 +138,25 @@ bool CustomMaterial::onAdd()
             return false;
          }
          
-      	mSamplerNames[i] = entry->slotName + dStrlen(samplerDecl);
-         mSamplerNames[i].insert(0, '$');
-         mTexFilename[i] = entry->value;
+         // Assert sampler names are defined on ShaderData
+         S32 pos = -1;
+         String samplerName = entry->slotName + dStrlen(samplerDecl);
+         samplerName.insert(0, '$');
+         mShaderData->hasSamplerDef(samplerName, pos);
+         
+         if(pos == -1)
+         {
+            const char *error = (avar("CustomMaterial(%s) bind sampler[%s] and is not present on ShaderData(%s)", 
+               getName(), samplerName.c_str(), mShaderDataName.c_str() ));
+            Con::errorf(error);
+
+#if TORQUE_OPENGL
+            GFXAssertFatal(0, error);
+            continue;
+#endif
+         }
+         mSamplerNames[pos] = samplerName;
+         mTexFilename[pos] = entry->value;
          ++i;
       }
    }

+ 26 - 2
Engine/source/materials/processedCustomMaterial.cpp

@@ -79,6 +79,7 @@ void ProcessedCustomMaterial::_setStageData()
       if(filename.equal(String("$dynamiclight"), String::NoCase))
       {
          rpd->mTexType[i] = Material::DynamicLight;
+         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
          mMaxTex = i+1;
          continue;
       }
@@ -86,6 +87,7 @@ void ProcessedCustomMaterial::_setStageData()
       if(filename.equal(String("$dynamiclightmask"), String::NoCase))
       {
          rpd->mTexType[i] = Material::DynamicLightMask;
+         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
          mMaxTex = i+1;
          continue;
       }
@@ -93,6 +95,7 @@ void ProcessedCustomMaterial::_setStageData()
       if(filename.equal(String("$lightmap"), String::NoCase))
       {
          rpd->mTexType[i] = Material::Lightmap;
+         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
          mMaxTex = i+1;
          continue;
       }
@@ -102,6 +105,7 @@ void ProcessedCustomMaterial::_setStageData()
          if( mCustomMaterial->mCubemapData )
          {
             rpd->mTexType[i] = Material::Cube;
+            rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
             mMaxTex = i+1;
          }
          else
@@ -114,6 +118,7 @@ void ProcessedCustomMaterial::_setStageData()
       if(filename.equal(String("$dynamicCubemap"), String::NoCase))
       {
          rpd->mTexType[i] = Material::SGCube;
+         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
          mMaxTex = i+1;
          continue;
       }
@@ -121,6 +126,7 @@ void ProcessedCustomMaterial::_setStageData()
       if(filename.equal(String("$backbuff"), String::NoCase))
       {
          rpd->mTexType[i] = Material::BackBuff;
+         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
          mMaxTex = i+1;
          continue;
       }
@@ -128,6 +134,7 @@ void ProcessedCustomMaterial::_setStageData()
       if(filename.equal(String("$reflectbuff"), String::NoCase))
       {
          rpd->mTexType[i] = Material::ReflectBuff;
+         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
          mMaxTex = i+1;
          continue;
       }
@@ -135,6 +142,7 @@ void ProcessedCustomMaterial::_setStageData()
       if(filename.equal(String("$miscbuff"), String::NoCase))
       {
          rpd->mTexType[i] = Material::Misc;
+         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
          mMaxTex = i+1;
          continue;
       }
@@ -151,6 +159,7 @@ void ProcessedCustomMaterial::_setStageData()
             texTarget->getShaderMacros( &mConditionerMacros );
 
          rpd->mTexType[i] = Material::TexTarget;
+         rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
          mMaxTex = i+1;
          continue;
       }
@@ -162,6 +171,7 @@ void ProcessedCustomMaterial::_setStageData()
          continue;
       }
       rpd->mTexType[i] = Material::Standard;
+      rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i];
       mMaxTex = i+1;
    }
 
@@ -232,6 +242,20 @@ bool ProcessedCustomMaterial::init( const FeatureSet &features,
    setMaterialParameters( mDefaultParameters, 0 );
    mStateHint.init( this );
    
+   for(int i = 0; i < mMaxTex; i++)
+   {
+      ShaderConstHandles *handles = _getShaderConstHandles( mPasses.size()-1 );
+      AssertFatal(handles,"");
+
+      if(rpd->mSamplerNames[i].isEmpty())      
+         continue;      
+
+      String samplerName = rpd->mSamplerNames[i].startsWith("$") ? rpd->mSamplerNames[i] : String("$") + rpd->mSamplerNames[i];
+      GFXShaderConstHandle *handle = rpd->shader->getShaderConstHandle( samplerName ); 
+      AssertFatal(handle,"");
+      handles->mTexHandlesSC[i] = handle;
+   }
+   
    return true;
 }
 
@@ -384,14 +408,14 @@ void ProcessedCustomMaterial::setTextureStages( SceneRenderState *state, const S
                if ( !texObject )
                   texObject = GFXTexHandle::ZERO;
 
-               if ( handles->mRTParamsSC[samplerRegister]->isValid() && texObject )
+               if ( handles->mRTParamsSC[i]->isValid() && texObject )
                {
                   const Point3I &targetSz = texObject->getSize();
                   const RectI &targetVp = texTarget->getViewport();
                   Point4F rtParams;
 
                   ScreenSpace::RenderTargetParameters(targetSz, targetVp, rtParams);
-                  shaderConsts->set(handles->mRTParamsSC[samplerRegister], rtParams);
+                  shaderConsts->set(handles->mRTParamsSC[i], rtParams);
                }
               
                GFX->setTexture( samplerRegister, texObject );

+ 56 - 1
Engine/source/materials/processedShaderMaterial.cpp

@@ -221,6 +221,7 @@ bool ProcessedShaderMaterial::init( const FeatureSet &features,
          {
             rpd->mTexSlot[0].texTarget = texTarget;
             rpd->mTexType[0] = Material::TexTarget;
+            rpd->mSamplerNames[0] = "diffuseMap";
          }
       }
 
@@ -516,8 +517,23 @@ bool ProcessedShaderMaterial::_createPasses( MaterialFeatureData &stageFeatures,
 
       passData.mNumTexReg += numTexReg;
       passData.mFeatureData.features.addFeature( *info.type );
+
+#if defined(TORQUE_DEBUG) && defined( TORQUE_OPENGL)
+      U32 oldTexNumber = texIndex;
+#endif
+
       info.feature->setTexData( mStages[stageNum], stageFeatures, passData, texIndex );
 
+#if defined(TORQUE_DEBUG) && defined( TORQUE_OPENGL)
+      if(oldTexNumber != texIndex)
+      {
+         for(int i = oldTexNumber; i < texIndex; i++)
+         {
+            AssertFatal(passData.mSamplerNames[ oldTexNumber ].isNotEmpty(), avar( "ERROR: ShaderGen feature %s don't set used sampler name", info.feature->getName().c_str()) );
+         }
+      }
+#endif
+
       // Add pass if tex units are maxed out
       if( texIndex > GFX->getNumSamplers() )
       {
@@ -527,6 +543,13 @@ bool ProcessedShaderMaterial::_createPasses( MaterialFeatureData &stageFeatures,
       }
    }
 
+#if defined(TORQUE_DEBUG) && defined( TORQUE_OPENGL)
+   for(int i = 0; i < texIndex; i++)
+   {
+      AssertFatal(passData.mSamplerNames[ i ].isNotEmpty(),"");
+   }
+#endif
+
    const FeatureSet &passFeatures = passData.mFeatureData.codify();
    if ( passFeatures.isNotEmpty() )
    {
@@ -587,9 +610,16 @@ bool ProcessedShaderMaterial::_addPass( ShaderRenderPassData &rpd,
    // Copy over features
    rpd.mFeatureData.materialFeatures = fd.features;
 
+   Vector<String> samplers;
+   samplers.setSize(Material::MAX_TEX_PER_PASS);
+   for(int i = 0; i < Material::MAX_TEX_PER_PASS; ++i)
+   {
+      samplers[i] = (rpd.mSamplerNames[i].isEmpty() || rpd.mSamplerNames[i][0] == '$') ? rpd.mSamplerNames[i] : "$" + rpd.mSamplerNames[i];
+   }
+
    // Generate shader
    GFXShader::setLogging( true, true );
-   rpd.shader = SHADERGEN->getShader( rpd.mFeatureData, mVertexFormat, &mUserMacros );
+   rpd.shader = SHADERGEN->getShader( rpd.mFeatureData, mVertexFormat, &mUserMacros, samplers );
    if( !rpd.shader )
       return false;
    rpd.shaderHandles.init( rpd.shader );   
@@ -601,6 +631,30 @@ bool ProcessedShaderMaterial::_addPass( ShaderRenderPassData &rpd,
    ShaderRenderPassData *newPass = new ShaderRenderPassData( rpd );
    mPasses.push_back( newPass );
 
+   //initSamplerHandles
+   ShaderConstHandles *handles = _getShaderConstHandles( mPasses.size()-1 );
+   AssertFatal(handles,"");
+   for(int i = 0; i < rpd.mNumTex; i++)
+   { 
+      if(rpd.mSamplerNames[i].isEmpty())
+      {
+         handles->mTexHandlesSC[i] = newPass->shader->getShaderConstHandle( String::EmptyString );
+         handles->mRTParamsSC[i] = newPass->shader->getShaderConstHandle( String::EmptyString );
+         continue;
+      }
+
+      String samplerName = rpd.mSamplerNames[i];
+      if( !samplerName.startsWith("$"))
+         samplerName.insert(0, "$");
+
+      GFXShaderConstHandle *handle = newPass->shader->getShaderConstHandle( samplerName ); 
+
+      handles->mTexHandlesSC[i] = handle;
+      handles->mRTParamsSC[i] = newPass->shader->getShaderConstHandle( String::ToString( "$rtParams%s", samplerName.c_str()+1 ) ); 
+      
+      AssertFatal( handle,"");
+   }
+
    // Give each active feature a chance to create specialized shader consts.
    for( U32 i=0; i < FEATUREMGR->getFeatureCount(); i++ )
    {
@@ -705,6 +759,7 @@ void ProcessedShaderMaterial::setTextureStages( SceneRenderState *state, const S
    PROFILE_SCOPE( ProcessedShaderMaterial_SetTextureStages );
 
    ShaderConstHandles *handles = _getShaderConstHandles(pass);
+   AssertFatal(handles,"");
 
    // Set all of the textures we need to render the give pass.
 #ifdef TORQUE_DEBUG

+ 114 - 2
Engine/source/materials/shaderData.cpp

@@ -64,6 +64,9 @@ ShaderData::ShaderData()
 
    mUseDevicePixVersion = false;
    mPixVersion = 1.0;
+
+   for( int i = 0; i < NumTextures; ++i)
+      mRTParams[i] = false;
 }
 
 void ShaderData::initPersistFields()
@@ -115,6 +118,14 @@ void ShaderData::initPersistFields()
       "@endtsexample\n\n"
       );
 
+   addField("samplerNames",              TypeRealString,      Offset(mSamplerNames,   ShaderData), NumTextures, 
+      "@brief Indicates names of samplers present in shader. Order is important.\n\n"
+	   "Order of sampler names are used to assert correct sampler register/location"
+      "Other objects (GFXStateBlockData, PostEffect...) use index number to link samplers."
+      );
+
+   addField("rtParams",              TypeBool,      Offset(mRTParams,   ShaderData), NumTextures, "");
+
    Parent::initPersistFields();
 
    // Make sure we get activation signals.
@@ -133,6 +144,12 @@ bool ShaderData::onAdd()
 
    // NOTE: We initialize the shader on request.
 
+   for(int i = 0; i < NumTextures; ++i)
+   {
+      if( mSamplerNames[i].isNotEmpty() && !mSamplerNames[i].startsWith("$") )      
+         mSamplerNames[i].insert(0, "$");      
+   }
+
    return true;
 }
 
@@ -190,6 +207,8 @@ GFXShader* ShaderData::getShader( const Vector<GFXShaderMacro> &macros )
    if ( !shader )
       return NULL;
 
+   _checkDefinition(shader);
+
    // Store the shader in the cache and return it.
    mShaders.insertUnique( cacheKey, shader );
    return shader;
@@ -207,6 +226,11 @@ GFXShader* ShaderData::_createShader( const Vector<GFXShaderMacro> &macros )
    GFXShader *shader = GFX->createShader();
    bool success = false;
 
+   Vector<String> samplers;
+   samplers.setSize(ShaderData::NumTextures);
+   for(int i = 0; i < ShaderData::NumTextures; ++i)
+      samplers[i] = mSamplerNames[i][0] == '$' ? mSamplerNames[i] : "$"+mSamplerNames[i];
+
    // Initialize the right shader type.
    switch( GFX->getAdapterType() )
    {
@@ -216,7 +240,8 @@ GFXShader* ShaderData::_createShader( const Vector<GFXShaderMacro> &macros )
          success = shader->init( mDXVertexShaderName, 
                                  mDXPixelShaderName, 
                                  pixver,
-                                 macros );
+                                 macros,
+                                 samplers);
          break;
       }
 
@@ -225,7 +250,8 @@ GFXShader* ShaderData::_createShader( const Vector<GFXShaderMacro> &macros )
          success = shader->init( mOGLVertexShaderName,
                                  mOGLPixelShaderName,
                                  pixver,
-                                 macros );
+                                 macros,
+                                 samplers);
          break;
       }
          
@@ -235,6 +261,29 @@ GFXShader* ShaderData::_createShader( const Vector<GFXShaderMacro> &macros )
          break;
    }
 
+#if defined(TORQUE_DEBUG)
+   //Assert Sampler registers
+   const Vector<GFXShaderConstDesc>& descs = shader->getShaderConstDesc();
+   for(int i = 0; i < descs.size(); ++i)
+   {
+      if(descs[i].constType != GFXSCT_Sampler && descs[i].constType != GFXSCT_SamplerCube)
+         continue;
+      
+      GFXShaderConstHandle *handle = shader->findShaderConstHandle(descs[i].name);
+      if(!handle || !handle->isValid())
+         continue;
+
+      int reg = handle->getSamplerRegister();
+      if( descs[i].name != samplers[reg] )
+      {
+         const char *err = avar("ShaderData(%s): samplerNames[%d] = \"%s\" are diferent to sampler in shader: %s : register(S%d)"
+            ,getName(), reg, samplers[reg].c_str(), handle->getName().c_str(), reg);
+         Con::printf(err);
+         GFXAssertFatal(0, err);
+      }
+   }
+#endif
+
    // If we failed to load the shader then
    // cleanup and return NULL.
    if ( !success )
@@ -270,6 +319,69 @@ void ShaderData::_onLMActivate( const char *lm, bool activate )
    reloadAllShaders();
 }
 
+bool ShaderData::hasSamplerDef(const String &_samplerName, int &pos) const
+{
+   String samplerName = _samplerName.startsWith("$") ? _samplerName : "$"+_samplerName;   
+   for(int i = 0; i < NumTextures; ++i)
+   {
+      if( mSamplerNames[i].equal(samplerName, String::NoCase ) )
+      {
+         pos = i;
+         return true;
+      }
+   }
+
+   pos = -1;
+   return false;
+}
+
+bool ShaderData::_checkDefinition(GFXShader *shader)
+{
+   bool error = false;
+   Vector<String> samplers;
+   samplers.reserve(NumTextures);
+   bool rtParams[NumTextures];
+   for(int i = 0; i < NumTextures; ++i)
+      rtParams[i] = false;   
+
+   const Vector<GFXShaderConstDesc> &shaderConstDesc = shader->getShaderConstDesc(); 
+
+   for(int i = 0; i < shaderConstDesc.size(); ++i)
+   {
+      const GFXShaderConstDesc &desc = shaderConstDesc[i];
+      if(desc.constType == GFXSCT_Sampler)
+      {
+         samplers.push_back(desc.name );
+      }      
+   }
+
+   for(int i = 0; i < samplers.size(); ++i)
+   {
+      int pos;
+      bool find = hasSamplerDef(samplers[i], pos);
+
+      if(find && pos >= 0 && mRTParams[pos])
+      {              
+         if( !shader->findShaderConstHandle( String::ToString("$rtParams%d", pos)) )
+         {
+            String error = String::ToString("ShaderData(%s) sampler[%d] used but rtParams%d not used in shader compilation. Possible error", getName(), pos, pos);
+            Con::errorf( error );
+            error = true;
+         }
+      }     
+
+      if(!find)
+      {
+         String error = String::ToString("ShaderData(%s) sampler %s not defined", getName(), samplers[i].c_str());
+         Con::errorf(error );
+         GFXAssertFatal(0, error );
+         error = true;
+      }
+   }  
+
+   return !error;
+}
+
 DefineEngineMethod( ShaderData, reload, void, (),,
 				   "@brief Rebuilds all the vertex and pixel shader instances created from this ShaderData.\n\n"
 

+ 15 - 0
Engine/source/materials/shaderData.h

@@ -91,8 +91,23 @@ protected:
    /// @see LightManager::smActivateSignal
    static void _onLMActivate( const char *lm, bool activate );
 
+   enum
+   {
+      NumTextures = 8
+   };
+
+   String mSamplerNames[NumTextures]; 
+   bool mRTParams[NumTextures];
+
+   bool _checkDefinition(GFXShader *shader);   
+
 public:
 
+   void setSamplerName(const String &name, int idx) { mSamplerNames[idx] = name; }
+   String getSamplerName(int idx) const { return mSamplerNames[idx]; }
+
+   bool hasSamplerDef(const String &samplerName, int &pos) const;
+   bool hasRTParamsDef(const int pos) const { return mRTParams[pos]; }
 
    ShaderData();
 

+ 3 - 0
Engine/source/shaderGen/HLSL/bumpHLSL.cpp

@@ -222,12 +222,14 @@ void BumpFeatHLSL::setTexData(   Material::StageData &stageDat,
    if ( fd.features[MFT_NormalMap] )
    {
       passData.mTexType[ texIndex ] = Material::Bump;
+      passData.mSamplerNames[ texIndex ] = "bumpMap";
       passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_NormalMap );
    }
 
    if ( fd.features[ MFT_DetailNormalMap ] )
    {
       passData.mTexType[ texIndex ] = Material::DetailBump;
+      passData.mSamplerNames[ texIndex ] = "detailBumpMap";
       passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_DetailNormalMap );
    }
 }
@@ -382,6 +384,7 @@ void ParallaxFeatHLSL::setTexData(  Material::StageData &stageDat,
    GFXTextureObject *tex = stageDat.getTex( MFT_NormalMap );
    if ( tex )
    {
+      passData.mSamplerNames[ texIndex ] = "bumpMap";
       passData.mTexType[ texIndex ] = Material::Bump;
       passData.mTexSlot[ texIndex++ ].texObject = tex;
    }

+ 1 - 0
Engine/source/shaderGen/HLSL/pixSpecularHLSL.cpp

@@ -147,6 +147,7 @@ void SpecularMapHLSL::setTexData( Material::StageData &stageDat,
    if ( tex )
    {
       passData.mTexType[ texIndex ] = Material::Standard;
+      passData.mSamplerNames[ texIndex ] = "specularMap";
       passData.mTexSlot[ texIndex++ ].texObject = tex;
    }
 }

+ 21 - 4
Engine/source/shaderGen/HLSL/shaderFeatureHLSL.cpp

@@ -985,7 +985,10 @@ void DiffuseMapFeatHLSL::setTexData(   Material::StageData &stageDat,
 {
    GFXTextureObject *tex = stageDat.getTex( MFT_DiffuseMap );
    if ( tex )
+   {
+      passData.mSamplerNames[ texIndex ] = "diffuseMap";
       passData.mTexSlot[ texIndex++ ].texObject = tex;
+   }
 }
 
 
@@ -1069,7 +1072,10 @@ void OverlayTexFeatHLSL::setTexData(   Material::StageData &stageDat,
 {
    GFXTextureObject *tex = stageDat.getTex( MFT_OverlayMap );
    if ( tex )
+   {
+      passData.mSamplerNames[texIndex] = "overlayMap";
       passData.mTexSlot[ texIndex++ ].texObject = tex;
+   }
 }
 
 
@@ -1257,6 +1263,7 @@ void LightmapFeatHLSL::setTexData(  Material::StageData &stageDat,
                                     U32 &texIndex )
 {
    GFXTextureObject *tex = stageDat.getTex( MFT_LightMap );
+   passData.mSamplerNames[ texIndex ] = "lightMap";
    if ( tex )
       passData.mTexSlot[ texIndex++ ].texObject = tex;
    else
@@ -1386,6 +1393,7 @@ void TonemapFeatHLSL::setTexData(  Material::StageData &stageDat,
    if ( tex )
    {
       passData.mTexType[ texIndex ] = Material::ToneMapTex;
+      passData.mSamplerNames[ texIndex ] = "toneMap";
       passData.mTexSlot[ texIndex++ ].texObject = tex;
    }
 }
@@ -1576,7 +1584,10 @@ void DetailFeatHLSL::setTexData( Material::StageData &stageDat,
 {
    GFXTextureObject *tex = stageDat.getTex( MFT_DetailMap );
    if ( tex )
+   {
+      passData.mSamplerNames[texIndex] = "detailMap";
       passData.mTexSlot[ texIndex++ ].texObject = tex;
+   }
 }
 
 
@@ -1846,22 +1857,27 @@ void ReflectCubeFeatHLSL::setTexData(  Material::StageData &stageDat,
        !passData.mFeatureData.features[MFT_NormalMap] )
    {
       GFXTextureObject *tex = stageDat.getTex( MFT_DetailMap );
-      if (  tex &&
-            stageFeatures.features[MFT_DiffuseMap] )
+      if (  tex && stageFeatures.features[MFT_DiffuseMap] )
+      {
+         passData.mSamplerNames[ texIndex ] = "diffuseMap";
          passData.mTexSlot[ texIndex++ ].texObject = tex;
+      }
       else
       {
          tex = stageDat.getTex( MFT_NormalMap );
 
-         if (  tex &&
-               stageFeatures.features[ MFT_NormalMap ] )
+         if (  tex && stageFeatures.features[ MFT_NormalMap ] )
+         {
+            passData.mSamplerNames[ texIndex ] = "bumpMap";
             passData.mTexSlot[ texIndex++ ].texObject = tex;
       }
    }
+   }
    
    if( stageDat.getCubemap() )
    {
       passData.mCubeMap = stageDat.getCubemap();
+      passData.mSamplerNames[texIndex] = "cubeMap";
       passData.mTexType[texIndex++] = Material::Cube;
    }
    else
@@ -1869,6 +1885,7 @@ void ReflectCubeFeatHLSL::setTexData(  Material::StageData &stageDat,
       if( stageFeatures.features[MFT_CubeMap] )
       {
          // assuming here that it is a scenegraph cubemap
+         passData.mSamplerNames[texIndex] = "cubeMap";
          passData.mTexType[texIndex++] = Material::SGCube;
       }
    }

+ 2 - 2
Engine/source/shaderGen/shaderGen.cpp

@@ -443,7 +443,7 @@ void ShaderGen::_printPixShader( Stream &stream )
    mPrinter->printPixelShaderCloser(stream);
 }
 
-GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const GFXVertexFormat *vertexFormat, const Vector<GFXShaderMacro> *macros )
+GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const GFXVertexFormat *vertexFormat, const Vector<GFXShaderMacro> *macros, const Vector<String> &samplers )
 {
    PROFILE_SCOPE( ShaderGen_GetShader );
 
@@ -488,7 +488,7 @@ GFXShader* ShaderGen::getShader( const MaterialFeatureData &featureData, const G
 
    GFXShader *shader = GFX->createShader();
    shader->mInstancingFormat.copy( mInstancingFormat ); // TODO: Move to init() below!
-   if ( !shader->init( vertFile, pixFile, pixVersion, shaderMacros ) )
+   if ( !shader->init( vertFile, pixFile, pixVersion, shaderMacros, samplers ) )
    {
       delete shader;
       return NULL;

+ 1 - 1
Engine/source/shaderGen/shaderGen.h

@@ -155,7 +155,7 @@ public:
                         Vector<GFXShaderMacro> &macros );
 
    // Returns a shader that implements the features listed by dat.
-   GFXShader* getShader( const MaterialFeatureData &dat, const GFXVertexFormat *vertexFormat, const Vector<GFXShaderMacro> *macros );
+   GFXShader* getShader( const MaterialFeatureData &dat, const GFXVertexFormat *vertexFormat, const Vector<GFXShaderMacro> *macros, const Vector<String> &samplers );
 
    // This will delete all of the procedural shaders that we have.  Used to regenerate shaders when
    // the ShaderFeatures have changed (due to lighting system change, or new plugin)

+ 23 - 9
Engine/source/terrain/terrCellMaterial.cpp

@@ -46,6 +46,27 @@ AFTER_MODULE_INIT( MaterialManager )
 
 Vector<TerrainCellMaterial*> TerrainCellMaterial::smAllMaterials;
 
+Vector<String> _initSamplerNames()
+{
+   Vector<String> samplerNames;
+   samplerNames.push_back("$baseTexMap");
+   samplerNames.push_back("$layerTex");   
+   samplerNames.push_back("$macrolayerTex");   
+   samplerNames.push_back("$lightMapTex");
+   samplerNames.push_back("$lightInfoBuffer");
+   for(int i = 0; i < 3; ++i)
+   {
+      samplerNames.push_back(avar("$normalMap%d",i));
+      samplerNames.push_back(avar("$detailMap%d",i));
+      samplerNames.push_back(avar("$macroMap%d",i));
+   }   
+
+   return samplerNames;
+}
+
+
+const Vector<String> TerrainCellMaterial::mSamplerNames = _initSamplerNames();
+
 TerrainCellMaterial::TerrainCellMaterial()
    :  mCurrPass( 0 ),
       mTerrain( NULL ),
@@ -460,7 +481,7 @@ bool TerrainCellMaterial::_createPass( Vector<MaterialInfo*> *materials,
          const bool logErrors = matCount == 1;
          GFXShader::setLogging( logErrors, true );
 
-         pass->shader = SHADERGEN->getShader( featureData, getGFXVertexFormat<TerrVertex>(), NULL );
+         pass->shader = SHADERGEN->getShader( featureData, getGFXVertexFormat<TerrVertex>(), NULL, mSamplerNames );
       }
 
       // If we got a shader then we can continue.
@@ -499,14 +520,7 @@ bool TerrainCellMaterial::_createPass( Vector<MaterialInfo*> *materials,
    pass->oneOverTerrainSize = pass->shader->getShaderConstHandle( "$oneOverTerrainSize" );
    pass->squareSize = pass->shader->getShaderConstHandle( "$squareSize" );
 
-   // NOTE: We're assuming rtParams0 here as we know its the only
-   // render target we currently get in a terrain material and the
-   // DeferredRTLightingFeatHLSL will always use 0.
-   //
-   // This could change in the future and we would need to fix
-   // the ShaderFeature API to allow us to do this right.
-   //
-   pass->lightParamsConst = pass->shader->getShaderConstHandle( "$rtParams0" );
+   pass->lightParamsConst = pass->shader->getShaderConstHandle( "$rtParamslightInfoBuffer" );
 
    // Now prepare the basic stateblock.
    GFXStateBlockDesc desc;

+ 2 - 0
Engine/source/terrain/terrCellMaterial.h

@@ -144,6 +144,8 @@ protected:
 
    U32 mCurrPass;
 
+   static const Vector<String> mSamplerNames;
+
    GFXTexHandle mBaseMapTexture;
 
    GFXTexHandle mLayerMapTexture;