Torque3D Documentation / _generateds / terrFeatureGLSL.cpp

terrFeatureGLSL.cpp

Engine/source/terrain/glsl/terrFeatureGLSL.cpp

More...

Public Variables

Detailed Description

Public Variables

 MODULE_END 
 MODULE_INIT 
   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/glsl/terrFeatureGLSL.h"
  26
  27#include "terrain/terrFeatureTypes.h"
  28#include "materials/materialFeatureTypes.h"
  29#include "materials/materialFeatureData.h"
  30#include "materials/processedMaterial.h"
  31#include "gfx/gfxDevice.h"
  32#include "shaderGen/langElement.h"
  33#include "shaderGen/shaderOp.h"
  34#include "shaderGen/featureMgr.h"
  35#include "shaderGen/shaderGen.h"
  36#include "core/module.h"
  37
  38namespace 
  39{
  40   void register_glsl_shader_features_for_terrain(GFXAdapterType type)
  41   {
  42      if(type != OpenGL)
  43         return;
  44
  45      FEATUREMGR->registerFeature( MFT_TerrainBaseMap, new TerrainBaseMapFeatGLSL );
  46      FEATUREMGR->registerFeature( MFT_TerrainParallaxMap, new NamedFeatureGLSL( "Terrain Parallax Texture" ) );   
  47      FEATUREMGR->registerFeature( MFT_TerrainDetailMap, new TerrainDetailMapFeatGLSL );
  48      FEATUREMGR->registerFeature( MFT_TerrainNormalMap, new TerrainNormalMapFeatGLSL );
  49      FEATUREMGR->registerFeature( MFT_TerrainMacroMap, new NamedFeatureGLSL("TerrainMacroMap Deprecated")); // new TerrainMacroMapFeatGLSL);
  50      FEATUREMGR->registerFeature( MFT_TerrainLightMap, new TerrainLightMapFeatGLSL );
  51      FEATUREMGR->registerFeature( MFT_TerrainSideProject, new NamedFeatureGLSL( "Terrain Side Projection" ) );
  52      FEATUREMGR->registerFeature(MFT_TerrainHeightBlend, new TerrainHeightMapBlendGLSL);
  53      FEATUREMGR->registerFeature( MFT_TerrainORMMap, new TerrainORMMapFeatGLSL );
  54      FEATUREMGR->registerFeature( MFT_DeferredTerrainBlankInfoMap, new TerrainBlankInfoMapFeatGLSL );
  55   }
  56
  57};
  58
  59MODULE_BEGIN( TerrainFeatGLSL )
  60
  61   MODULE_INIT_AFTER( ShaderGen )
  62
  63   MODULE_INIT
  64   {      
  65      SHADERGEN->getFeatureInitSignal().notify(&register_glsl_shader_features_for_terrain);
  66   }
  67
  68MODULE_END;
  69
  70
  71TerrainFeatGLSL::TerrainFeatGLSL()
  72   : mTorqueDep(ShaderGen::smCommonShaderPath + String("/gl/torque.glsl" ))
  73   {      
  74   addDependency( &mTorqueDep );
  75   }
  76
  77Var* TerrainFeatGLSL::_getUniformVar( const char *name, const char *type, ConstantSortPosition csp )
  78{
  79   Var *theVar = (Var*)LangElement::find( name );
  80   if ( !theVar )
  81   {
  82      theVar = new Var;
  83      theVar->setType( type );
  84      theVar->setName( name );
  85      theVar->uniform = true;
  86      theVar->constSortPos = csp;
  87   }
  88   
  89   return theVar;
  90}
  91
  92Var* TerrainFeatGLSL::_getInDetailCoord( Vector<ShaderComponent*> &componentList )
  93{
  94   String name( String::ToString( "detCoord%d", getProcessIndex() ) );
  95   Var *inDet = (Var*)LangElement::find( name );
  96   
  97   if ( !inDet )
  98   {
  99      ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 100      
 101      inDet = connectComp->getElement( RT_TEXCOORD );
 102      inDet->setName( name );
 103      inDet->setStructName( "IN" );
 104      inDet->setType( "vec4" );
 105   }
 106   
 107   return inDet;
 108}
 109
 110Var* TerrainFeatGLSL::_getInMacroCoord( Vector<ShaderComponent*> &componentList )
 111{
 112   String name( String::ToString( "macroCoord%d", getProcessIndex() ) );
 113   Var *inDet = (Var*)LangElement::find( name );
 114
 115   if ( !inDet )
 116   {
 117      ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 118
 119      inDet = connectComp->getElement( RT_TEXCOORD );
 120      inDet->setName( name );
 121      inDet->setStructName( "IN" );
 122      inDet->setType( "vec4" );
 123   }
 124
 125   return inDet;
 126}
 127
 128Var* TerrainFeatGLSL::_getDetailMapSampler()
 129{
 130   String name("detailMapSampler");
 131   Var* detailMapSampler = (Var*)LangElement::find(name);
 132
 133   if (!detailMapSampler)
 134   {
 135      detailMapSampler = new Var;
 136      detailMapSampler->setName(name);
 137      detailMapSampler->setType("sampler2DArray");
 138      detailMapSampler->uniform = true;
 139      detailMapSampler->sampler = true;
 140      detailMapSampler->constNum = Var::getTexUnitNum();
 141   }
 142
 143   return detailMapSampler;
 144}
 145
 146Var* TerrainFeatGLSL::_getNormalMapSampler()
 147{
 148   String name("normalMapSampler");
 149   Var* normalMapSampler = (Var*)LangElement::find(name);
 150
 151   if (!normalMapSampler)
 152   {
 153      normalMapSampler = new Var;
 154      normalMapSampler->setName(name);
 155      normalMapSampler->setType("sampler2DArray");
 156      normalMapSampler->uniform = true;
 157      normalMapSampler->sampler = true;
 158      normalMapSampler->constNum = Var::getTexUnitNum();
 159   }
 160
 161   return normalMapSampler;
 162}
 163
 164Var* TerrainFeatGLSL::_getOrmMapSampler()
 165{
 166   String name("ormMapSampler");
 167   Var* ormMapSampler = (Var*)LangElement::find(name);
 168
 169   if (!ormMapSampler)
 170   {
 171      ormMapSampler = new Var;
 172      ormMapSampler->setName(name);
 173      ormMapSampler->setType("sampler2DArray");
 174      ormMapSampler->uniform = true;
 175      ormMapSampler->sampler = true;
 176      ormMapSampler->constNum = Var::getTexUnitNum();
 177   }
 178
 179   return ormMapSampler;
 180}
 181
 182Var* TerrainFeatGLSL::_getDetailIdStrengthParallax()
 183{
 184   String name(String::ToString("detailIdStrengthParallax", getProcessIndex()));
 185
 186   Var* detailInfo = (Var*)LangElement::find(name);
 187   if (!detailInfo)
 188   {
 189      detailInfo = new Var;
 190      detailInfo->setType("vec4");
 191      detailInfo->setName(name);
 192      detailInfo->uniform = true;
 193      detailInfo->constSortPos = cspPotentialPrimitive;
 194      detailInfo->arraySize = getProcessIndex();
 195   }
 196
 197   detailInfo->arraySize = mMax(detailInfo->arraySize, getProcessIndex() + 1);
 198
 199   return detailInfo;
 200}
 201
 202Var* TerrainFeatGLSL::_getMacroIdStrengthParallax()
 203{
 204   String name(String::ToString("macroIdStrengthParallax%d", getProcessIndex()));
 205
 206   Var* detailInfo = (Var*)LangElement::find(name);
 207   if (!detailInfo)
 208   {
 209      detailInfo = new Var;
 210      detailInfo->setType("vec3");
 211      detailInfo->setName(name);
 212      detailInfo->uniform = true;
 213      detailInfo->constSortPos = cspPotentialPrimitive;
 214   }
 215
 216   return detailInfo;
 217}
 218
 219
 220void TerrainBaseMapFeatGLSL::processVert( Vector<ShaderComponent*> &componentList, 
 221                                          const MaterialFeatureData &fd )
 222{
 223   MultiLine *meta = new MultiLine;
 224   output = meta;
 225
 226   // Generate the incoming texture var.
 227   Var *inTex;
 228   {
 229      Var *inPos = (Var*)LangElement::find( "inPosition" );
 230      if ( !inPos )
 231         inPos = (Var*)LangElement::find( "position" );
 232
 233      inTex = new Var( "texCoord", "vec3" );
 234
 235      Var *oneOverTerrainSize = _getUniformVar( "oneOverTerrainSize", "float", cspPass );
 236
 237      // NOTE: The y coord here should be negative to have
 238      // the texture maps not end up flipped which also caused
 239      // normal and parallax mapping to be incorrect.
 240      //
 241      // This mistake early in development means that the layer
 242      // id bilinear blend depends on it being that way.
 243      //
 244      // So instead i fixed this by flipping the base and detail
 245      // coord y scale to compensate when rendering.
 246      //
 247      meta->addStatement( new GenOp( "   @ = @.xyz * vec3( @, @, -@ );\r\n", 
 248         new DecOp( inTex ), inPos, oneOverTerrainSize, oneOverTerrainSize, oneOverTerrainSize ) );
 249   }
 250
 251   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 252
 253   // Pass the texture coord to the pixel shader.
 254   Var *outTex = connectComp->getElement( RT_TEXCOORD );
 255   outTex->setName( "outTexCoord" );
 256   outTex->setStructName( "OUT" );
 257   outTex->setType( "vec3" );
 258   meta->addStatement( new GenOp( "   @.xy = @.xy;\r\n", outTex, inTex ) );
 259
 260   // If this shader has a side projected layer then we 
 261   // pass the dot product between the +Y and the normal
 262   // thru outTexCoord.z for use in blending the textures.
 263   if ( fd.features.hasFeature( MFT_TerrainSideProject ) )
 264   {
 265      Var *inNormal = (Var*)LangElement::find( "normal" );
 266      meta->addStatement( 
 267         new GenOp( "   @.z = pow( abs( dot( normalize( vec3( @.x, @.y, 0 ) ), vec3( 0, 1, 0 ) ) ), 10.0 );\r\n", 
 268            outTex, inNormal, inNormal ) );
 269   }
 270   else
 271      meta->addStatement( new GenOp( "   @.z = 0;\r\n", outTex ) );
 272
 273   // HACK: This is sort of lazy... we generate the tanget
 274   // vector here so that we're sure it exists in the parallax
 275   // and normal features which will expect "T" to exist.
 276   //
 277   // If this shader doesn't use it the shader compiler will
 278   // optimize away this code.
 279   //
 280   Var *inTangentZ = getVertTexCoord( "tcTangentZ" );
 281   Var *inTanget = new Var( "T", "vec3" );
 282   Var *squareSize = _getUniformVar( "squareSize", "float", cspPass );
 283   meta->addStatement( new GenOp( "   @ = normalize( vec3( @, 0, @ ) );\r\n", 
 284      new DecOp( inTanget ), squareSize, inTangentZ ) );
 285}
 286
 287void TerrainBaseMapFeatGLSL::processPix(  Vector<ShaderComponent*> &componentList, 
 288                                          const MaterialFeatureData &fd )
 289{
 290   // grab connector texcoord register
 291   Var *texCoord = getInTexCoord( "texCoord", "vec3", componentList );
 292
 293   // create texture var
 294   Var *diffuseMap = new Var;
 295   diffuseMap->setType( "sampler2D" );
 296   diffuseMap->setName( "baseTexMap" );
 297   diffuseMap->uniform = true;
 298   diffuseMap->sampler = true;
 299   diffuseMap->constNum = Var::getTexUnitNum();     // used as texture unit num here
 300
 301   MultiLine *meta = new MultiLine;
 302
 303   Var *baseColor = new Var;
 304   baseColor->setType( "vec4" );
 305   baseColor->setName( "baseColor" );
 306   meta->addStatement( new GenOp( "   @ = tex2D( @, @.xy );\r\n", new DecOp( baseColor ), diffuseMap, texCoord ) );
 307
 308  ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget;
 309
 310   if(fd.features.hasFeature(MFT_isDeferred))
 311   {
 312      target= ShaderFeature::RenderTarget1;
 313   }
 314   meta->addStatement( new GenOp( "   @;\r\n", assignColor( baseColor, Material::Mul,NULL,target ) ) );
 315
 316   // Set base ORM info
 317   Var* ormConfig;
 318   OutputTarget targ = RenderTarget1;
 319   if (fd.features[MFT_isDeferred])
 320   {
 321      targ = RenderTarget2;
 322   }
 323   ormConfig = (Var*)LangElement::find(getOutputTargetVarName(targ));
 324   if (!ormConfig)
 325   {
 326      // create color var
 327      ormConfig = new Var;
 328      ormConfig->setType("fragout");
 329      ormConfig->setName(getOutputTargetVarName(targ));
 330      ormConfig->setStructName("OUT");
 331   }
 332
 333   meta->addStatement(new GenOp("   @ = float4(0.0, 1.0, 1.0, 0.0);\r\n", ormConfig));
 334
 335   output = meta;
 336}
 337
 338ShaderFeature::Resources TerrainBaseMapFeatGLSL::getResources( const MaterialFeatureData &fd )
 339{
 340   Resources res;
 341
 342   // Sample base texture
 343   res.numTexReg = 1;
 344   res.numTex = 1;
 345
 346   return res;
 347}
 348
 349U32 TerrainBaseMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const
 350{
 351   return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget1 | ShaderFeature::RenderTarget2 : ShaderFeature::DefaultTarget | ShaderFeature::RenderTarget1;
 352}
 353
 354TerrainDetailMapFeatGLSL::TerrainDetailMapFeatGLSL()
 355   :  mTorqueDep(ShaderGen::smCommonShaderPath + String("/gl/torque.glsl" )),
 356      mTerrainDep(ShaderGen::smCommonShaderPath + String("/terrain/terrain.glsl" ))
 357      
 358{
 359   addDependency( &mTorqueDep );
 360   addDependency( &mTerrainDep );
 361}
 362
 363void TerrainDetailMapFeatGLSL::processVert(  Vector<ShaderComponent*> &componentList, 
 364                                             const MaterialFeatureData &fd )
 365{
 366   const S32 detailIndex = getProcessIndex();
 367
 368   // Grab incoming texture coords... the base map feature
 369   // made sure this was created.
 370   Var *inTex = (Var*)LangElement::find( "texCoord" );
 371   AssertFatal( inTex, "The texture coord is missing!" );
 372
 373   // Grab the input position.
 374   Var *inPos = (Var*)LangElement::find( "inPosition" );
 375   if ( !inPos )
 376      inPos = (Var*)LangElement::find( "position" );
 377
 378   // Get the object space eye position.
 379   Var *eyePos = _getUniformVar( "eyePos", "vec3", cspPotentialPrimitive );
 380
 381   MultiLine *meta = new MultiLine;
 382
 383   // If we have parallax mapping then make sure we've sent
 384   // the negative view vector to the pixel shader.
 385   if (  fd.features.hasFeature( MFT_TerrainParallaxMap ) &&
 386         !LangElement::find( "outNegViewTS" ) )
 387   {
 388      // Get the object to tangent transform which
 389      // will consume 3 output registers.
 390      Var *objToTangentSpace = getOutObjToTangentSpace( componentList, meta, fd );
 391
 392      // Now use a single output register to send the negative
 393      // view vector in tangent space to the pixel shader.
 394      ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 395      Var *outNegViewTS = connectComp->getElement( RT_TEXCOORD );
 396      outNegViewTS->setName( "outNegViewTS" );
 397      outNegViewTS->setStructName( "OUT" );
 398      outNegViewTS->setType( "vec3" );
 399      meta->addStatement( new GenOp( "   @ = tMul( @, vec3( @ - @.xyz ) );\r\n", 
 400         outNegViewTS, objToTangentSpace, eyePos, inPos ) );
 401   }
 402
 403   // Get the distance from the eye to this vertex.
 404   Var *dist = (Var*)LangElement::find( "dist" );
 405   if ( !dist )
 406   {
 407      dist = new Var;
 408      dist->setType( "float" );
 409      dist->setName( "dist" );  
 410
 411      meta->addStatement( new GenOp( "   @ = distance( @.xyz, @ );\r\n", 
 412                                       new DecOp( dist ), inPos, eyePos ) );
 413   }
 414
 415   // grab connector texcoord register
 416   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 417   Var *outTex = connectComp->getElement( RT_TEXCOORD );
 418   outTex->setName( String::ToString( "detCoord%d", detailIndex ) );
 419   outTex->setStructName( "OUT" );
 420   outTex->setType( "vec4" );
 421
 422   // Get the detail scale and fade info.
 423   Var *detScaleAndFade = (Var*)LangElement::find("detailScaleAndFade");
 424   if (!detScaleAndFade)
 425   {
 426      detScaleAndFade = new Var;
 427      detScaleAndFade->setType("vec4");
 428      detScaleAndFade->setName("detailScaleAndFade");
 429      detScaleAndFade->uniform = true;
 430      detScaleAndFade->constSortPos = cspPotentialPrimitive;
 431   }
 432
 433   detScaleAndFade->arraySize = mMax(detScaleAndFade->arraySize, detailIndex + 1);
 434
 435   // Setup the detail coord.
 436   //
 437   // NOTE: You see here we scale the texture coord by 'xyx'
 438   // to generate the detail coord.  This y is here because
 439   // its scale is flipped to correct for the non negative y
 440   // in texCoord.
 441   //
 442   // See TerrainBaseMapFeatGLSL::processVert().
 443   //
 444   meta->addStatement( new GenOp( "   @.xyz = @ * @.xyx;\r\n", outTex, inTex, new IndexOp(detScaleAndFade, detailIndex) ) );
 445
 446   // And sneak the detail fade thru the w detailCoord.
 447   meta->addStatement( new GenOp( "   @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n", 
 448                                    outTex, new IndexOp(detScaleAndFade, detailIndex), dist, new IndexOp(detScaleAndFade, detailIndex)) );
 449
 450   output = meta;
 451}
 452
 453void TerrainDetailMapFeatGLSL::processPix(   Vector<ShaderComponent*> &componentList, 
 454                                             const MaterialFeatureData &fd )
 455{
 456   const S32 detailIndex = getProcessIndex();
 457   Var *inTex = getVertTexCoord( "texCoord" );
 458
 459   MultiLine *meta = new MultiLine;
 460
 461   // We need the negative tangent space view vector
 462   // as in parallax mapping we step towards the camera.
 463   Var *negViewTS = (Var*)LangElement::find( "negViewTS" );
 464   if (  !negViewTS &&
 465         fd.features.hasFeature( MFT_TerrainParallaxMap ) )
 466   {
 467      Var *inNegViewTS = (Var*)LangElement::find( "outNegViewTS" );
 468      if ( !inNegViewTS )
 469      {
 470         ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 471         inNegViewTS = connectComp->getElement( RT_TEXCOORD );
 472         inNegViewTS->setName( "outNegViewTS" );
 473         inNegViewTS->setStructName( "IN" );
 474         inNegViewTS->setType( "vec3" );
 475      }
 476   
 477      negViewTS = new Var( "negViewTS", "vec3" );
 478      meta->addStatement( new GenOp( "   @ = normalize( @ );\r\n", new DecOp( negViewTS ), inNegViewTS ) );
 479   }
 480
 481   // Get the layer samples.
 482   Var *layerSample = (Var*)LangElement::find( "layerSample" );
 483   if ( !layerSample )
 484   {
 485      layerSample = new Var;
 486      layerSample->setType( "vec4" );
 487      layerSample->setName( "layerSample" );
 488
 489      // Get the layer texture var
 490      Var *layerTex = new Var;
 491      layerTex->setType( "sampler2D" );
 492      layerTex->setName( "layerTex" );
 493      layerTex->uniform = true;
 494      layerTex->sampler = true;
 495      layerTex->constNum = Var::getTexUnitNum();
 496
 497      // Read the layer texture to get the samples.
 498      meta->addStatement( new GenOp( "   @ = round( tex2D( @, @.xy ) * 255.0f );\r\n", 
 499                                       new DecOp( layerSample ), layerTex, inTex ) );
 500   }
 501
 502   Var *layerSize = (Var*)LangElement::find( "layerSize" );
 503   if ( !layerSize )
 504   {
 505      layerSize = new Var;
 506      layerSize->setType( "float" );
 507      layerSize->setName( "layerSize" );
 508      layerSize->uniform = true;
 509      layerSize->constSortPos = cspPass;
 510   }
 511
 512   // Grab the incoming detail coord.
 513   Var *inDet = _getInDetailCoord( componentList );
 514
 515   // Get the detail id.
 516   Var *detailInfo = _getDetailIdStrengthParallax();
 517
 518   // Create the detail blend var.
 519   Var *detailBlend = new Var;
 520   detailBlend->setType( "float" );
 521   detailBlend->setName( String::ToString( "detailBlend%d", detailIndex ) );
 522
 523   // Calculate the blend for this detail texture.
 524   meta->addStatement( new GenOp( "   @ = calcBlend( @.x, @.xy, @, @ );\r\n", 
 525                                    new DecOp( detailBlend ), new IndexOp(detailInfo, detailIndex), inTex, layerSize, layerSample ) );
 526
 527   // If we had a parallax feature... then factor in the parallax
 528   // amount so that it fades out with the layer blending.
 529   if (fd.features.hasFeature(MFT_TerrainParallaxMap, detailIndex))
 530   {
 531      // Get the normal map texture.
 532      Var* normalMap = _getNormalMapSampler();
 533
 534      // Call the library function to do the rest.
 535      if (fd.features.hasFeature(MFT_IsBC3nm, detailIndex))
 536      {
 537         meta->addStatement(new GenOp("   @.xy += parallaxOffsetDxtnm( @, vec3(@.xy, @.x), @, @.z * @ );\r\n",
 538            inDet, normalMap, inDet, new IndexOp(detailInfo, detailIndex), negViewTS, new IndexOp(detailInfo, detailIndex), detailBlend));
 539      }
 540      else
 541      {
 542         meta->addStatement(new GenOp("   @.xy += parallaxOffset( @, vec3(@.xy, @.x), @, @.z * @ );\r\n",
 543            inDet, normalMap, inDet, new IndexOp(detailInfo, detailIndex), negViewTS, new IndexOp(detailInfo, detailIndex), detailBlend));
 544      }
 545   }
 546
 547   Var* detailColor = (Var*)LangElement::find(String::ToString("detailColor%d", detailIndex));
 548   if (!detailColor)
 549   {
 550      detailColor = new Var;
 551      detailColor->setType("vec4");
 552      detailColor->setName(String::ToString("detailColor%d", detailIndex));
 553      meta->addStatement(new GenOp("   @;\r\n", new DecOp(detailColor)));
 554   }
 555
 556   // Get the detail texture.
 557   Var *detailMap = _getDetailMapSampler();
 558
 559   // If we had a parallax feature... then factor in the parallax
 560  // amount so that it fades out with the layer blending.
 561   if (fd.features.hasFeature(MFT_TerrainSideProject, detailIndex))
 562   {
 563      meta->addStatement(new GenOp("   @ = ( lerp( tex2D( @, vec3(@.yz, @.x) ), tex2D( @, vec3(@.xz, @.x) ), @.z ) * 2.0 ) - 1.0;\r\n",
 564         detailColor, detailMap, inDet, new IndexOp(detailInfo, detailIndex), detailMap, inDet, new IndexOp(detailInfo, detailIndex), inTex));
 565   }
 566   else
 567   {
 568      meta->addStatement(new GenOp("   @ = ( tex2D( @, vec3(@.xy, @.x) ) * 2.0 ) - 1.0;\r\n",
 569         detailColor, detailMap, inDet, new IndexOp(detailInfo, detailIndex)));
 570   }
 571
 572   meta->addStatement(new GenOp("   @ *= @.y * @.w;\r\n",
 573      detailColor, new IndexOp(detailInfo, detailIndex), inDet));
 574
 575   if (!fd.features.hasFeature(MFT_TerrainHeightBlend))
 576   {
 577      // Check to see if we have a gbuffer normal.
 578      Var* gbNormal = (Var*)LangElement::find("gbNormal");
 579
 580      // If we have a gbuffer normal and we don't have a
 581      // normal map feature then we need to lerp in a 
 582      // default normal else the normals below this layer
 583      // will show thru.
 584      if (gbNormal &&
 585         !fd.features.hasFeature(MFT_TerrainNormalMap, detailIndex))
 586      {
 587         Var* viewToTangent = getInViewToTangent(componentList);
 588
 589         meta->addStatement(new GenOp("   @ = lerp( @, tGetMatrix3Row(@, 2), min( @, @.w ) );\r\n",
 590            gbNormal, gbNormal, viewToTangent, detailBlend, inDet));
 591      }
 592
 593      // If we're using SM 3.0 then take advantage of 
 594      // dynamic branching to skip layers per-pixel.
 595      if (GFX->getPixelShaderVersion() >= 3.0f)
 596         meta->addStatement(new GenOp("   if ( @ > 0.0f )\r\n", detailBlend));
 597
 598      meta->addStatement(new GenOp("   {\r\n"));
 599
 600      ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget;
 601
 602      if (fd.features.hasFeature(MFT_isDeferred))
 603         target = ShaderFeature::RenderTarget1;
 604
 605      Var* outColor = (Var*)LangElement::find(getOutputTargetVarName(target));
 606
 607      meta->addStatement(new GenOp("      @.rgb = toGamma(@.rgb);\r\n", outColor, outColor));
 608
 609      meta->addStatement(new GenOp("      @ += @ * @;\r\n",
 610         outColor, detailColor, detailBlend));
 611
 612      meta->addStatement(new GenOp("      @.rgb = toLinear(clamp(@.rgb, 0, 1));\r\n", outColor, outColor));
 613
 614      meta->addStatement(new GenOp("   }\r\n"));
 615   }
 616
 617   output = meta;
 618}
 619
 620ShaderFeature::Resources TerrainDetailMapFeatGLSL::getResources( const MaterialFeatureData &fd )
 621{
 622   Resources res;
 623
 624   if ( getProcessIndex() == 0 )
 625   {
 626      // If this is the first detail pass then we 
 627      // samples from the layer tex.
 628      res.numTex = 1;
 629      res.numTexReg = 1;
 630
 631      // Add Detail TextureArray
 632      res.numTex += 1;
 633      res.numTexReg += 1;
 634   }
 635
 636   return res;
 637}
 638
 639U32 TerrainDetailMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const
 640{
 641   return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget;
 642}
 643
 644
 645TerrainMacroMapFeatGLSL::TerrainMacroMapFeatGLSL()
 646   :  mTorqueDep(ShaderGen::smCommonShaderPath + String("/gl/torque.glsl" )),
 647      mTerrainDep(ShaderGen::smCommonShaderPath + String("/terrain/terrain.glsl" ))
 648      
 649{
 650   addDependency( &mTorqueDep );
 651   addDependency( &mTerrainDep );
 652}
 653
 654
 655void TerrainMacroMapFeatGLSL::processVert(  Vector<ShaderComponent*> &componentList, 
 656                                             const MaterialFeatureData &fd )
 657{
 658   const S32 detailIndex = getProcessIndex();
 659
 660   // Grab incoming texture coords... the base map feature
 661   // made sure this was created.
 662   Var *inTex = (Var*)LangElement::find( "texCoord" );
 663   AssertFatal( inTex, "The texture coord is missing!" );
 664
 665   // Grab the input position.
 666   Var *inPos = (Var*)LangElement::find( "inPosition" );
 667   if ( !inPos )
 668      inPos = (Var*)LangElement::find( "position" );
 669
 670   // Get the object space eye position.
 671   Var *eyePos = _getUniformVar( "eyePos", "vec3", cspPotentialPrimitive );
 672
 673   MultiLine *meta = new MultiLine;
 674
 675   // Get the distance from the eye to this vertex.
 676   Var *dist = (Var*)LangElement::find( "macroDist" );
 677   if ( !dist )
 678   {
 679      dist = new Var;
 680      dist->setType( "float" );
 681      dist->setName( "macroDist" );  
 682
 683      meta->addStatement( new GenOp( "   @ = distance( @.xyz, @ );\r\n", 
 684                                       new DecOp( dist ), inPos, eyePos ) );
 685   }
 686
 687   // grab connector texcoord register
 688   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 689   Var *outTex = connectComp->getElement( RT_TEXCOORD );
 690   outTex->setName( String::ToString( "macroCoord%d", detailIndex ) );
 691   outTex->setStructName( "OUT" );
 692   outTex->setType( "vec4" );
 693
 694   // Get the detail scale and fade info.
 695   Var *detScaleAndFade = new Var;
 696   detScaleAndFade->setType( "vec4" );
 697   detScaleAndFade->setName( String::ToString( "macroScaleAndFade%d", detailIndex ) );
 698   detScaleAndFade->uniform = true;
 699   detScaleAndFade->constSortPos = cspPotentialPrimitive;
 700
 701   // Setup the detail coord.
 702   meta->addStatement( new GenOp( "   @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade ) );
 703
 704   // And sneak the detail fade thru the w detailCoord.
 705   meta->addStatement( new GenOp( "   @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n", 
 706                                    outTex, detScaleAndFade, dist, detScaleAndFade ) );   
 707
 708   output = meta;
 709}
 710
 711
 712void TerrainMacroMapFeatGLSL::processPix(   Vector<ShaderComponent*> &componentList, 
 713                                             const MaterialFeatureData &fd )
 714{
 715   const S32 detailIndex = getProcessIndex();
 716   Var *inTex = getVertTexCoord( "texCoord" );
 717   
 718   MultiLine *meta = new MultiLine;
 719
 720   // We need the negative tangent space view vector
 721   // as in parallax mapping we step towards the camera.
 722   Var *negViewTS = (Var*)LangElement::find( "negViewTS" );
 723   if (  !negViewTS &&
 724         fd.features.hasFeature( MFT_TerrainParallaxMap ) )
 725   {
 726      Var *inNegViewTS = (Var*)LangElement::find( "outNegViewTS" );
 727      if ( !inNegViewTS )
 728      {
 729         ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 730         inNegViewTS = connectComp->getElement( RT_TEXCOORD );
 731         inNegViewTS->setName( "outNegViewTS" );
 732         inNegViewTS->setStructName( "IN" );
 733         inNegViewTS->setType( "vec3" );
 734      }
 735
 736      negViewTS = new Var( "negViewTS", "vec3" );
 737      meta->addStatement( new GenOp( "   @ = normalize( @ );\r\n", new DecOp( negViewTS ), inNegViewTS ) );
 738   }
 739
 740   // Get the layer samples.
 741   Var *layerSample = (Var*)LangElement::find( "layerSample" );
 742   if ( !layerSample )
 743   {
 744      layerSample = new Var;
 745      layerSample->setType( "vec4" );
 746      layerSample->setName( "layerSample" );
 747
 748      // Get the layer texture var
 749      Var *layerTex = new Var;
 750      layerTex->setType( "sampler2D" );
 751      layerTex->setName( "macrolayerTex" );
 752      layerTex->uniform = true;
 753      layerTex->sampler = true;
 754      layerTex->constNum = Var::getTexUnitNum();
 755
 756      // Read the layer texture to get the samples.
 757      meta->addStatement( new GenOp( "   @ = round( tex2D( @, @.xy ) * 255.0f );\r\n", 
 758                                       new DecOp( layerSample ), layerTex, inTex ) );
 759   }
 760
 761   Var *layerSize = (Var*)LangElement::find( "layerSize" );
 762   if ( !layerSize )
 763   {
 764      layerSize = new Var;
 765      layerSize->setType( "float" );
 766      layerSize->setName( "layerSize" );
 767      layerSize->uniform = true;
 768      layerSize->constSortPos = cspPass;
 769   }
 770
 771   // Grab the incoming detail coord.
 772   Var *inDet = _getInMacroCoord( componentList );
 773
 774   // Get the detail id.
 775   Var *detailInfo = _getMacroIdStrengthParallax();
 776
 777   // Create the detail blend var.
 778   Var *detailBlend = new Var;
 779   detailBlend->setType( "float" );
 780   detailBlend->setName( String::ToString( "macroBlend%d", detailIndex ) );
 781
 782   // Calculate the blend for this detail texture.
 783   meta->addStatement( new GenOp( "   @ = calcBlend( @.x, @.xy, @, @ );\r\n", 
 784                                    new DecOp( detailBlend ), detailInfo, inTex, layerSize, layerSample ) );
 785
 786   Var *detailColor = (Var*)LangElement::find( "macroColor" ); 
 787   if ( !detailColor )
 788   {
 789      detailColor = new Var;
 790      detailColor->setType( "vec4" );
 791      detailColor->setName( "macroColor" );
 792      meta->addStatement( new GenOp( "   @;\r\n", new DecOp( detailColor ) ) );
 793   }
 794
 795   // Get the detail texture.
 796   Var *detailMap = new Var;
 797   detailMap->setType( "sampler2D" );
 798   detailMap->setName( String::ToString( "macroMap%d", detailIndex ) );
 799   detailMap->uniform = true;
 800   detailMap->sampler = true;
 801   detailMap->constNum = Var::getTexUnitNum();     // used as texture unit num here
 802
 803   // If we're using SM 3.0 then take advantage of 
 804   // dynamic branching to skip layers per-pixel.
 805   if ( GFX->getPixelShaderVersion() >= 3.0f )
 806      meta->addStatement( new GenOp( "   if ( @ > 0.0f )\r\n", detailBlend ) );
 807
 808   meta->addStatement( new GenOp( "   {\r\n" ) );
 809
 810   // Note that we're doing the standard greyscale detail 
 811   // map technique here which can darken and lighten the 
 812   // diffuse texture.
 813   //
 814   // We take two color samples and lerp between them for
 815   // side projection layers... else a single sample.
 816   //
 817   if ( fd.features.hasFeature( MFT_TerrainSideProject, detailIndex ) )
 818   {
 819      meta->addStatement( new GenOp( "      @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n", 
 820                                                detailColor, detailMap, inDet, detailMap, inDet, inTex ) );
 821   }
 822   else
 823   {
 824      meta->addStatement( new GenOp( "      @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n", 
 825                                       detailColor, detailMap, inDet ) );
 826   }
 827
 828   meta->addStatement( new GenOp( "      @ *= @.y * @.w;\r\n",
 829                                    detailColor, detailInfo, inDet ) );
 830
 831   ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget;
 832
 833   if (fd.features.hasFeature(MFT_isDeferred))
 834      target= ShaderFeature::RenderTarget1;
 835
 836   Var *outColor = (Var*)LangElement::find( getOutputTargetVarName(target) );
 837
 838   meta->addStatement(new GenOp("      @.rgb = toGamma(@.rgb);\r\n", outColor, outColor));
 839
 840   meta->addStatement(new GenOp("      @ += @ * @;\r\n",
 841                                    outColor, detailColor, detailBlend));
 842
 843   meta->addStatement(new GenOp("      @.rgb = toLinear(clamp(@.rgb, 0, 1));\r\n", outColor, outColor));
 844
 845   meta->addStatement( new GenOp( "   }\r\n" ) );
 846
 847   output = meta;
 848}
 849
 850
 851
 852ShaderFeature::Resources TerrainMacroMapFeatGLSL::getResources( const MaterialFeatureData &fd )
 853{
 854   Resources res;
 855
 856   if ( getProcessIndex() == 0 )
 857   {
 858      // If this is the first detail pass then we 
 859      // samples from the layer tex.
 860      res.numTex += 1;
 861   }
 862
 863      res.numTex += 1;
 864
 865   // Finally we always send the detail texture 
 866   // coord to the pixel shader.
 867   res.numTexReg += 1;
 868
 869   return res;
 870}
 871
 872U32 TerrainMacroMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const
 873{
 874   return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget;
 875}
 876
 877void TerrainNormalMapFeatGLSL::processVert(  Vector<ShaderComponent*> &componentList, 
 878                                             const MaterialFeatureData &fd )
 879{
 880   // We only need to process normals during the deferred.
 881   if ( !fd.features.hasFeature( MFT_DeferredConditioner ) )
 882      return;
 883
 884   MultiLine *meta = new MultiLine;
 885
 886   if (!fd.features.hasFeature(MFT_TerrainHeightBlend))
 887   {
 888      // Make sure the world to tangent transform
 889      // is created and available for the pixel shader.
 890      getOutViewToTangent(componentList, meta, fd);
 891   }
 892
 893   output = meta;
 894}
 895
 896void TerrainNormalMapFeatGLSL::processPix(   Vector<ShaderComponent*> &componentList, 
 897                                             const MaterialFeatureData &fd )
 898{
 899   // We only need to process normals during the deferred.
 900   if (!fd.features.hasFeature(MFT_DeferredConditioner))
 901      return;
 902
 903   MultiLine *meta = new MultiLine;
 904
 905   const S32 normalIndex = getProcessIndex();
 906
 907   Var *detailBlend = (Var*)LangElement::find( String::ToString( "detailBlend%d", normalIndex ) );
 908   AssertFatal( detailBlend, "The detail blend is missing!" );
 909
 910   // Get the normal map texture.
 911   Var *normalMap = _getNormalMapSampler();
 912
 913   /// Get the texture coord.
 914   Var *inDet = _getInDetailCoord( componentList );
 915   Var *inTex = getVertTexCoord( "texCoord" );
 916   Var* detailInfo = _getDetailIdStrengthParallax();
 917
 918   // Sample the normal map.
 919   //
 920   // We take two normal samples and lerp between them for
 921   // side projection layers... else a single sample.
 922   LangElement *texOp;
 923   if ( fd.features.hasFeature( MFT_TerrainSideProject, normalIndex ) )
 924   {
 925      texOp = new GenOp( "lerp( tex2D( @, vec3(@.yz, @.x) ), tex2D( @, vec3(@.xz, @.x) ), @.z )",
 926         normalMap, inDet, new IndexOp(detailInfo, normalIndex), normalMap, inDet, inTex, new IndexOp(detailInfo, normalIndex));
 927   }
 928   else
 929      texOp = new GenOp( String::ToString("tex2D(@, vec3(@.xy, @.x))", normalIndex), normalMap, inDet, new IndexOp(detailInfo, normalIndex));
 930
 931   // create bump normal
 932   Var *bumpNorm = new Var;
 933   bumpNorm->setName( String::ToString("bumpNormal%d", normalIndex) );
 934   bumpNorm->setType( "vec4" );
 935
 936   LangElement *bumpNormDecl = new DecOp( bumpNorm );
 937   meta->addStatement( expandNormalMap( texOp, bumpNormDecl, bumpNorm, fd ) );
 938
 939   if (!fd.features.hasFeature(MFT_TerrainHeightBlend))
 940   {
 941      Var* viewToTangent = getInViewToTangent(componentList);
 942
 943      // This var is read from GBufferConditionerGLSL and 
 944      // used in the deferred output.
 945      Var* gbNormal = (Var*)LangElement::find("gbNormal");
 946      if (!gbNormal)
 947      {
 948         gbNormal = new Var;
 949         gbNormal->setName("gbNormal");
 950         gbNormal->setType("vec3");
 951         meta->addStatement(new GenOp("   @ = tGetMatrix3Row(@, 2);\r\n", new DecOp(gbNormal), viewToTangent));
 952      }
 953
 954      // If we're using SM 3.0 then take advantage of 
 955      // dynamic branching to skip layers per-pixel.
 956      if (GFX->getPixelShaderVersion() >= 3.0f)
 957         meta->addStatement(new GenOp("   if ( @ > 0.0f )\r\n", detailBlend));
 958
 959      meta->addStatement(new GenOp("   {\r\n"));
 960
 961      // Normalize is done later... 
 962      // Note: The reverse mul order is intentional. Affine matrix.
 963      meta->addStatement(new GenOp("      @ = lerp( @, tMul( @.xyz, @ ), min( @, @.w ) );\r\n",
 964         gbNormal, gbNormal, bumpNorm, viewToTangent, detailBlend, inDet));
 965
 966      // End the conditional block.
 967      meta->addStatement(new GenOp("   }\r\n"));
 968   }
 969
 970   output = meta;
 971}
 972
 973ShaderFeature::Resources TerrainNormalMapFeatGLSL::getResources( const MaterialFeatureData &fd )
 974{
 975   Resources res;
 976
 977   // We only need to process normals during the deferred.
 978   if (!fd.features.hasFeature(MFT_DeferredConditioner))
 979   {
 980      return  res;
 981   }
 982
 983   S32 featureIndex = 0, firstNormalMapIndex = 0;
 984   for (int idx = 0; idx < fd.features.getCount(); ++idx) {
 985      const FeatureType& type = fd.features.getAt(idx, &featureIndex);
 986      if (type == MFT_TerrainNormalMap) {
 987         firstNormalMapIndex = getMin(firstNormalMapIndex, featureIndex);
 988      }
 989   }
 990
 991   // We only need to process normals during the deferred.
 992   if (getProcessIndex() == firstNormalMapIndex)
 993   {
 994      // Normal Texture Array
 995      res.numTexReg += 1;
 996      res.numTex += 1;
 997   }
 998
 999   return res;
1000}
1001
1002void TerrainLightMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList, 
1003                                          const MaterialFeatureData &fd )
1004{
1005   // grab connector texcoord register
1006   Var *inTex = (Var*)LangElement::find( "texCoord" );
1007   if ( !inTex )
1008      return;
1009
1010   // Get the lightmap texture.
1011   Var *lightMap = new Var;
1012   lightMap->setType( "sampler2D" );
1013   lightMap->setName( "lightMapTex" );
1014   lightMap->uniform = true;
1015   lightMap->sampler = true;
1016   lightMap->constNum = Var::getTexUnitNum();
1017
1018   MultiLine *meta = new MultiLine;
1019
1020   // Find or create the lightMask value which is read by
1021   // RTLighting to mask out the lights.
1022   //
1023   // The first light is always the sunlight so we apply
1024   // the shadow mask to only the first channel.
1025   //
1026   Var *lightMask = (Var*)LangElement::find( "lightMask" );
1027   if ( !lightMask )
1028   {
1029      lightMask = new Var( "lightMask", "vec4" );
1030      meta->addStatement( new GenOp( "   @ = vec4(1);\r\n", new DecOp( lightMask ) ) );
1031   }
1032
1033   meta->addStatement( new GenOp( "   @[0] = tex2D( @, @.xy ).r;\r\n", lightMask, lightMap, inTex ) );
1034   output = meta;
1035}
1036
1037ShaderFeature::Resources TerrainLightMapFeatGLSL::getResources( const MaterialFeatureData &fd )
1038{
1039   Resources res; 
1040   res.numTex = 1;
1041   return res;
1042}
1043
1044//standard matInfo map contains data of the form .r = bitflags, .g = (will contain AO), 
1045//.b = specular strength, a= spec power. 
1046
1047
1048void TerrainORMMapFeatGLSL::processVert(Vector<ShaderComponent*> &componentList,
1049   const MaterialFeatureData &fd)
1050{
1051   const S32 detailIndex = getProcessIndex();
1052
1053   // Grab incoming texture coords... the base map feature
1054   // made sure this was created.
1055   Var *inTex = (Var*)LangElement::find("texCoord");
1056   AssertFatal(inTex, "The texture coord is missing!");
1057
1058   // Grab the input position.
1059   Var *inPos = (Var*)LangElement::find("inPosition");
1060   if (!inPos)
1061      inPos = (Var*)LangElement::find("position");
1062
1063   // Get the object space eye position.
1064   Var *eyePos = _getUniformVar("eyePos", "vec3", cspPotentialPrimitive);
1065
1066   MultiLine *meta = new MultiLine;
1067
1068   // If we have parallax mapping then make sure we've sent
1069   // the negative view vector to the pixel shader.
1070   if (fd.features.hasFeature(MFT_TerrainParallaxMap) &&
1071      !LangElement::find("outNegViewTS"))
1072   {
1073      // Get the object to tangent transform which
1074      // will consume 3 output registers.
1075      Var *objToTangentSpace = getOutObjToTangentSpace(componentList, meta, fd);
1076
1077      // Now use a single output register to send the negative
1078      // view vector in tangent space to the pixel shader.
1079      ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>(componentList[C_CONNECTOR]);
1080      Var *outNegViewTS = connectComp->getElement(RT_TEXCOORD);
1081      outNegViewTS->setName("outNegViewTS");
1082      outNegViewTS->setStructName("OUT");
1083      outNegViewTS->setType("vec3");
1084      meta->addStatement(new GenOp("   @ =  @ * vec3( @ - @.xyz );\r\n",
1085         outNegViewTS, objToTangentSpace, eyePos, inPos));
1086   }
1087
1088   // Get the distance from the eye to this vertex.
1089   Var *dist = (Var*)LangElement::find("dist");
1090   if (!dist)
1091   {
1092      dist = new Var;
1093      dist->setType("float");
1094      dist->setName("dist");
1095
1096      meta->addStatement(new GenOp("   @ = distance( @.xyz, @ );\r\n",
1097         new DecOp(dist), inPos, eyePos));
1098   }
1099
1100   // grab connector texcoord register
1101   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>(componentList[C_CONNECTOR]);
1102   Var *outTex = (Var*)LangElement::find(String::ToString("detCoord%d", detailIndex));
1103   if (outTex == NULL)
1104   {
1105      outTex = new Var;
1106      outTex = connectComp->getElement(RT_TEXCOORD);
1107      outTex->setName(String::ToString("detCoord%d", detailIndex));
1108      outTex->setStructName("OUT");
1109      outTex->setType("vec4");
1110   }
1111   // Get the detail scale and fade info.
1112   Var *detScaleAndFade = (Var*)LangElement::find("detailScaleAndFade");
1113   if (detScaleAndFade == NULL)
1114   {
1115      detScaleAndFade = new Var;
1116      detScaleAndFade->setType("vec4");
1117      detScaleAndFade->setName("detailScaleAndFade");
1118      detScaleAndFade->uniform = true;
1119      detScaleAndFade->constSortPos = cspPotentialPrimitive;
1120   }
1121
1122   detScaleAndFade->arraySize = mMax(detScaleAndFade->arraySize, detailIndex + 1);
1123
1124   // Setup the detail coord.
1125   //
1126   // NOTE: You see here we scale the texture coord by 'xyx'
1127   // to generate the detail coord.  This y is here because
1128   // its scale is flipped to correct for the non negative y
1129   // in texCoord.
1130   //
1131   // See TerrainBaseMapFeatGLSL::processVert().
1132   //
1133   meta->addStatement(new GenOp("   @.xyz = @ * @.xyx;\r\n", outTex, inTex, new IndexOp(detScaleAndFade, detailIndex)));
1134
1135   // And sneak the detail fade thru the w detailCoord.
1136   meta->addStatement(new GenOp("   @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n",
1137      outTex, new IndexOp(detScaleAndFade, detailIndex), dist, new IndexOp(detScaleAndFade, detailIndex)));
1138
1139   output = meta;
1140}
1141
1142U32 TerrainORMMapFeatGLSL::getOutputTargets(const MaterialFeatureData &fd) const
1143{
1144   return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget2 : ShaderFeature::RenderTarget1;
1145}
1146
1147void TerrainORMMapFeatGLSL::processPix(Vector<ShaderComponent*> &componentList,
1148   const MaterialFeatureData &fd)
1149{
1150   /// Get the texture coord.
1151   Var *inDet = _getInDetailCoord(componentList);
1152   Var *inTex = getVertTexCoord("texCoord");
1153   Var* detailInfo = _getDetailIdStrengthParallax();
1154
1155   const S32 compositeIndex = getProcessIndex();
1156   Var *ormConfigMap = _getOrmMapSampler();
1157   // Sample the normal map.
1158   //
1159   // We take two normal samples and lerp between them for
1160   // side projection layers... else a single sample.
1161   LangElement *texOp;
1162   
1163   if (fd.features.hasFeature(MFT_TerrainSideProject, compositeIndex))
1164   {
1165      texOp = new GenOp("lerp( tex2D( @, vec3(@.yz, @.x) ), tex2D( @, vec3(@.xz, @.x) ), @.z )",
1166         ormConfigMap, inDet, new IndexOp(detailInfo, compositeIndex), ormConfigMap, inDet, new IndexOp(detailInfo, compositeIndex), inTex);
1167   }
1168   else
1169      texOp = new GenOp("tex2D(@, vec3(@.xy, @.x))", ormConfigMap, inDet, new IndexOp(detailInfo, compositeIndex));
1170
1171   // search for material var
1172   Var * ormConfig;
1173   OutputTarget targ = RenderTarget1;
1174   if (fd.features[MFT_isDeferred])
1175   {
1176      targ = RenderTarget2;
1177   }
1178   ormConfig = (Var*)LangElement::find(getOutputTargetVarName(targ));
1179
1180   MultiLine * meta = new MultiLine;
1181   if (!ormConfig)
1182   {
1183      // create color var
1184      ormConfig = new Var;
1185      ormConfig->setType("fragout");
1186      ormConfig->setName(getOutputTargetVarName(targ));
1187      ormConfig->setStructName("OUT");
1188   }
1189
1190   Var *detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", compositeIndex));
1191   AssertFatal(detailBlend, "The detail blend is missing!");
1192
1193   String matinfoName(String::ToString("matinfoCol%d", compositeIndex));
1194   Var *matinfoCol = new Var(matinfoName, "vec3");
1195
1196   if (compositeIndex == 0)
1197   {
1198      meta->addStatement(new GenOp("   @ = vec4(0.0, 0.0, 0.0, 0.0);\r\n", ormConfig));
1199   }
1200
1201   meta->addStatement(new GenOp("   @ = @.rgb;\r\n", new DecOp(matinfoCol), texOp));
1202
1203   if (fd.features.hasFeature(MFT_InvertRoughness, compositeIndex))
1204   {
1205      meta->addStatement(new GenOp("   @.b = 1.0 - @.b;\r\n", matinfoCol, matinfoCol));
1206   }
1207
1208
1209   meta->addStatement(new GenOp("   @ = lerp(float3(1.0, 1.0, 0.0), @, @.y * @.w);\r\n", matinfoCol, matinfoCol, new IndexOp(detailInfo, compositeIndex), inDet));
1210
1211   if (!fd.features.hasFeature(MFT_TerrainHeightBlend))
1212   {
1213      meta->addStatement(new GenOp("   @.gba += @ * @;\r\n", ormConfig, matinfoCol, detailBlend));
1214   }
1215
1216   output = meta;
1217}
1218
1219ShaderFeature::Resources TerrainORMMapFeatGLSL::getResources(const MaterialFeatureData &fd)
1220{
1221   Resources res;
1222
1223   S32 featureIndex = 0, firstOrmMapIndex = 0;
1224   for (int idx = 0; idx < fd.features.getCount(); ++idx) {
1225      const FeatureType& type = fd.features.getAt(idx, &featureIndex);
1226      if (type == MFT_TerrainORMMap) {
1227         firstOrmMapIndex = getMin(firstOrmMapIndex, featureIndex);
1228      }
1229   }
1230
1231   // We only need to process normals during the deferred.
1232   if (getProcessIndex() == firstOrmMapIndex)
1233   {
1234      res.numTexReg = 1;
1235      res.numTex = 1;
1236   }
1237   return res;
1238}
1239
1240
1241U32 TerrainBlankInfoMapFeatGLSL::getOutputTargets(const MaterialFeatureData &fd) const
1242{
1243   return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget2 : ShaderFeature::RenderTarget1;
1244}
1245
1246// reminder, the matinfo buffer is flags, smooth, ao, metal
1247void TerrainBlankInfoMapFeatGLSL::processPix(Vector<ShaderComponent*> &componentList,
1248   const MaterialFeatureData &fd)
1249{
1250   S32 compositeIndex = getProcessIndex();
1251
1252   // search for material var
1253   Var *material;
1254   OutputTarget targ = DefaultTarget;
1255   if (fd.features[MFT_isDeferred])
1256   {
1257      targ = RenderTarget2;
1258   }
1259   material = (Var*)LangElement::find(getOutputTargetVarName(targ));
1260
1261   MultiLine * meta = new MultiLine;
1262   if (!material)
1263   {
1264      // create color var
1265      material = new Var;
1266      material->setType("vec4");
1267      material->setName(getOutputTargetVarName(targ));
1268      material->setStructName("OUT");
1269   }
1270
1271   if (compositeIndex == 0)
1272   {
1273      meta->addStatement(new GenOp("   @ = vec4(0.0, 0.0, 0.0, 0.0);\r\n", material));
1274   }
1275
1276   Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", compositeIndex));
1277   AssertFatal(detailBlend, "The detail blend is missing!");
1278
1279   String matinfoName(String::ToString("matinfoCol%d", compositeIndex));
1280
1281   meta->addStatement(new GenOp("   @.gba += vec3(@, @, 0.0);\r\n", material, detailBlend, detailBlend));
1282
1283   output = meta;
1284}
1285
1286void TerrainHeightMapBlendGLSL::processVert(
1287    Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd) {
1288   // We only need to process normals during the deferred.
1289   if (!fd.features.hasFeature(MFT_DeferredConditioner))
1290      return;
1291
1292   MultiLine* meta = new MultiLine;
1293   
1294   // Handle an edge-case when there are no detail-maps available
1295   if (fd.features.getNextFeatureIndex(MFT_TerrainDetailMap, -1) >= 0)
1296   {
1297      // Make sure the world to tangent transform
1298      // is created and available for the pixel shader.
1299      getOutViewToTangent(componentList, meta, fd);
1300   }
1301
1302   output = meta;
1303}
1304
1305void TerrainHeightMapBlendGLSL::processPix(Vector<ShaderComponent*>& componentList,
1306                                           const MaterialFeatureData& fd)
1307{
1308
1309   ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget;
1310
1311   if (fd.features.hasFeature(MFT_isDeferred))
1312      target = ShaderFeature::RenderTarget1;
1313
1314   Var* outColor = (Var*)LangElement::find(getOutputTargetVarName(target));
1315
1316   if (!outColor)
1317      return;
1318
1319   MultiLine* meta = new MultiLine;
1320
1321   // Count the number of detail textures
1322   int detailCount = 0;
1323   while (true)
1324   {
1325      if (LangElement::find(String::ToString("detailBlend%d", detailCount)) == NULL)
1326      {
1327         break;
1328      }
1329
1330      ++detailCount;
1331   }
1332
1333   if (detailCount == 0)
1334   {
1335      return;
1336   }
1337
1338   // Compute the "height" of each detail layer and store it detailHX
1339   for (S32 idx = 0; idx < detailCount; ++idx)
1340   {
1341      Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx));
1342      Var* bumpNormal = (Var*)LangElement::find(String::ToString("bumpNormal%d", idx));
1343      Var* blendDepth = (Var*)LangElement::find(String::ToString("blendDepth%d", idx));
1344      if (!blendDepth)
1345      {
1346         blendDepth = new Var;
1347         blendDepth->setType("float");
1348         blendDepth->setName(String::ToString("blendDepth%d", idx));
1349         blendDepth->uniform = true;
1350         blendDepth->constSortPos = cspPrimitive;
1351      }
1352
1353      Var* blendContrast = (Var*)LangElement::find(String::ToString("blendContrast%d", idx));
1354      if (!blendContrast)
1355      {
1356         blendContrast = new Var;
1357         blendContrast->setType("float");
1358         blendContrast->setName(String::ToString("blendContrast%d", idx));
1359         blendContrast->uniform = true;
1360         blendContrast->constSortPos = cspPrimitive;
1361      }
1362
1363      Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx));
1364      if (!detailH)
1365      {
1366         detailH = new Var;
1367         detailH->setType("float");
1368         detailH->setName(String::ToString("detailH%d", idx));
1369
1370         meta->addStatement(new GenOp("   @ = 0;\r\n",
1371            new DecOp(detailH)));
1372         meta->addStatement(new GenOp("   if (@ > 0.0f) {\r\n", detailBlend));
1373         if (bumpNormal != NULL)
1374         {
1375            meta->addStatement(new GenOp("      @ = clamp(@.a + @, 0.0, 1.0);\r\n",
1376               detailH, bumpNormal, blendDepth));
1377         }
1378         else
1379         {
1380            meta->addStatement(new GenOp("      @ = clamp(0.5 + @, 0.0, 1.0);\r\n",
1381               detailH, blendDepth));
1382         }
1383
1384         meta->addStatement(new GenOp("      @ = max((@ * 2.0f - 1.0f) * @ + 0.5f, 0.0f);\r\n",
1385            detailH, detailH, blendContrast));
1386
1387         meta->addStatement(new GenOp("   }\r\n"));
1388      }
1389   }
1390
1391   meta->addStatement(new GenOp("\r\n"));
1392
1393   // Compute blending factors
1394   Var* depth = (Var*)LangElement::find("baseBlendDepth");
1395   if (depth == NULL)
1396   {
1397      depth = new Var;
1398      depth->setType("float");
1399      depth->setName("baseBlendDepth");
1400      depth->uniform = true;
1401      depth->constSortPos = cspPrimitive;
1402   }
1403
1404   Var* ma = (Var*)LangElement::find("ma");
1405   if (ma == NULL)
1406   {
1407      ma = new Var;
1408      ma->setType("float");
1409      ma->setName("ma");
1410      meta->addStatement(new GenOp("   @ = 0;\r\n",
1411         new DecOp(ma)));
1412   }
1413
1414   for (S32 idx = 0; idx < detailCount; ++idx)
1415   {
1416      Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx));
1417      Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx));
1418
1419      meta->addStatement(new GenOp("   @ = max(@, @ + @);\r\n",
1420         ma, ma, detailH, detailBlend));
1421   }
1422
1423   meta->addStatement(new GenOp("   @ -= @;\r\n",
1424      ma, depth));
1425
1426   meta->addStatement(new GenOp("\r\n"));
1427
1428   for (S32 idx = 0; idx < detailCount; ++idx)
1429   {
1430      Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx));
1431      Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx));
1432      Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx));
1433      if (!detailB)
1434      {
1435         detailB = new Var;
1436         detailB->setType("float");
1437         detailB->setName(String::ToString("detailB%d", idx));
1438
1439         meta->addStatement(new GenOp("   @ = max(@ + @ - @, 0);\r\n",
1440            new DecOp(detailB), detailH, detailBlend, ma));
1441      }
1442   }
1443
1444   meta->addStatement(new GenOp("\r\n"));
1445
1446   // Compute albedo
1447   meta->addStatement(new GenOp("   @.rgb = toGamma(@.rgb);\r\n",
1448      outColor, outColor));
1449
1450   meta->addStatement(new GenOp("   @.rgb += (",
1451      outColor));
1452
1453   for (S32 idx = 0; idx < detailCount; ++idx)
1454   {
1455      Var* detailColor = (Var*)LangElement::find(String::ToString("detailColor%d", idx));
1456      Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx));
1457
1458
1459      if (idx > 0)
1460      {
1461         meta->addStatement(new GenOp(" + "));
1462      }
1463
1464      meta->addStatement(new GenOp("@.rgb * @", detailColor, detailB));
1465   }
1466
1467   meta->addStatement(new GenOp(") / ("));
1468
1469   for (S32 idx = 0; idx < detailCount; ++idx)
1470   {
1471      Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx));
1472
1473      if (idx > 0)
1474      {
1475         meta->addStatement(new GenOp(" + "));
1476      }
1477
1478      meta->addStatement(new GenOp("@", detailB));
1479   }
1480
1481
1482   meta->addStatement(new GenOp(");\r\n"));
1483
1484   meta->addStatement(new GenOp("   @.rgb = toLinear(clamp(@.rgb, 0, 1));\r\n",
1485      outColor, outColor));
1486
1487   meta->addStatement(new GenOp("\r\n"));
1488
1489   // Compute ORM
1490   Var* ormOutput;
1491   OutputTarget targ = DefaultTarget;
1492   if (fd.features[MFT_isDeferred])
1493   {
1494      targ = RenderTarget2;
1495   }
1496   ormOutput = (Var*)LangElement::find(getOutputTargetVarName(targ));
1497
1498   meta->addStatement(new GenOp("   @.gba = (",
1499      ormOutput));
1500
1501   for (S32 idx = 0; idx < detailCount; ++idx)
1502   {
1503      Var* matinfoCol = (Var*)LangElement::find(String::ToString("matinfoCol%d", idx));
1504      Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx));
1505
1506
1507      if (idx > 0)
1508      {
1509         meta->addStatement(new GenOp(" + "));
1510      }
1511      if (matinfoCol)
1512      {
1513         meta->addStatement(new GenOp("@ * @", matinfoCol, detailB));
1514      }
1515      else
1516      {
1517         meta->addStatement(new GenOp("vec3(1.0, 1.0, 0.0) * @", detailB));
1518      }
1519   }
1520
1521   meta->addStatement(new GenOp(") / ("));
1522
1523   for (S32 idx = 0; idx < detailCount; ++idx)
1524   {
1525      Var* detailB = (Var*)LangElement::find(String::ToString("detailB%d", idx));
1526
1527      if (idx > 0)
1528      {
1529         meta->addStatement(new GenOp(" + "));
1530      }
1531
1532      meta->addStatement(new GenOp("@", detailB));
1533   }
1534
1535
1536   meta->addStatement(new GenOp(");\r\n"));
1537
1538
1539   meta->addStatement(new GenOp("\r\n"));
1540
1541   // Compute normal-specific blending factors
1542   // LukasPJ: I'm not sure why this is necessary, it might not be.
1543   Var* normalMa = (Var*)LangElement::find("normalMa");
1544   if (normalMa == NULL)
1545   {
1546      normalMa = new Var;
1547      normalMa->setType("float");
1548      normalMa->setName("normalMa");
1549      meta->addStatement(new GenOp("   @ = 0;\r\n",
1550         new DecOp(normalMa)));
1551   }
1552
1553   for (S32 idx = 0; idx < detailCount; ++idx)
1554   {
1555      Var* detCoord = (Var*)LangElement::find(String::ToString("detCoord%d", idx));
1556
1557      Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx));
1558      Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx));
1559
1560      meta->addStatement(new GenOp("   @ = max(@, @ + min(@, @.w));\r\n",
1561         normalMa, normalMa, detailH, detailBlend, detCoord));
1562   }
1563
1564   meta->addStatement(new GenOp("   @ -= @;\r\n",
1565      normalMa, depth));
1566
1567   meta->addStatement(new GenOp("\r\n"));
1568
1569   for (S32 idx = 0; idx < detailCount; ++idx)
1570   {
1571      Var* detCoord = (Var*)LangElement::find(String::ToString("detCoord%d", idx));
1572
1573      Var* detailH = (Var*)LangElement::find(String::ToString("detailH%d", idx));
1574      Var* detailBlend = (Var*)LangElement::find(String::ToString("detailBlend%d", idx));
1575      Var* normalDetailB = (Var*)LangElement::find(String::ToString("normalDetailB%d", idx));
1576      if (!normalDetailB)
1577      {
1578         normalDetailB = new Var;
1579         normalDetailB->setType("float");
1580         normalDetailB->setName(String::ToString("normalDetailB%d", idx));
1581
1582         meta->addStatement(new GenOp("   @ = max(@ + min(@, @.w) - @, 0);\r\n",
1583            new DecOp(normalDetailB), detailH, detailBlend, detCoord, normalMa));
1584      }
1585   }
1586
1587   // Compute normals
1588   Var* gbNormal = (Var*)LangElement::find("gbNormal");
1589   if (!gbNormal)
1590   {
1591      gbNormal = new Var;
1592      gbNormal->setName("gbNormal");
1593      gbNormal->setType("vec3");
1594      meta->addStatement(new GenOp("   @;\r\n", new DecOp(gbNormal)));
1595   }
1596
1597   if (gbNormal != NULL)
1598   {
1599      meta->addStatement(new GenOp("   @ = (",
1600         gbNormal));
1601
1602      for (S32 idx = 0; idx < detailCount; ++idx)
1603      {
1604         Var* normalDetailB = (Var*)LangElement::find(String::ToString("normalDetailB%d", idx));
1605         Var* bumpNormal = (Var*)LangElement::find(String::ToString("bumpNormal%d", idx));
1606         Var* viewToTangent = getInViewToTangent(componentList);
1607
1608
1609         if (idx > 0)
1610         {
1611            meta->addStatement(new GenOp(" + "));
1612         }
1613
1614         if (bumpNormal != NULL)
1615         {
1616            meta->addStatement(new GenOp("tMul(@.xyz, @) * @", bumpNormal, viewToTangent, normalDetailB));
1617         }
1618         else
1619         {
1620            meta->addStatement(new GenOp("tGetMatrix3Row(@, 2) * @", viewToTangent, normalDetailB));
1621         }
1622      }
1623
1624      meta->addStatement(new GenOp(") / ("));
1625
1626      for (S32 idx = 0; idx < detailCount; ++idx)
1627      {
1628         Var* normalDetailB = (Var*)LangElement::find(String::ToString("normalDetailB%d", idx));
1629
1630         if (idx > 0)
1631         {
1632            meta->addStatement(new GenOp(" + "));
1633         }
1634
1635         meta->addStatement(new GenOp("@", normalDetailB));
1636      }
1637
1638
1639      meta->addStatement(new GenOp(");\r\n"));
1640   }
1641
1642
1643   output = meta;
1644}
1645