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 TerrainMacroMapFeatGLSL );
  50      FEATUREMGR->registerFeature( MFT_TerrainLightMap, new TerrainLightMapFeatGLSL );
  51      FEATUREMGR->registerFeature( MFT_TerrainSideProject, new NamedFeatureGLSL( "Terrain Side Projection" ) );
  52      FEATUREMGR->registerFeature( MFT_TerrainAdditive, new TerrainAdditiveFeatGLSL );     
  53      FEATUREMGR->registerFeature( MFT_DeferredTerrainBaseMap, new TerrainBaseMapFeatGLSL );
  54      FEATUREMGR->registerFeature( MFT_DeferredTerrainMacroMap, new TerrainMacroMapFeatGLSL );
  55      FEATUREMGR->registerFeature( MFT_DeferredTerrainDetailMap, new TerrainDetailMapFeatGLSL ); 
  56      FEATUREMGR->registerFeature( MFT_DeferredTerrainBlankInfoMap, new TerrainBlankInfoMapFeatGLSL );
  57   }
  58
  59};
  60
  61MODULE_BEGIN( TerrainFeatGLSL )
  62
  63   MODULE_INIT_AFTER( ShaderGen )
  64
  65   MODULE_INIT
  66   {      
  67      SHADERGEN->getFeatureInitSignal().notify(&register_glsl_shader_features_for_terrain);
  68   }
  69
  70MODULE_END;
  71
  72
  73TerrainFeatGLSL::TerrainFeatGLSL()
  74   : mTorqueDep( "shaders/common/gl/torque.glsl" )
  75   {      
  76   addDependency( &mTorqueDep );
  77   }
  78
  79Var* TerrainFeatGLSL::_getUniformVar( const char *name, const char *type, ConstantSortPosition csp )
  80{
  81   Var *theVar = (Var*)LangElement::find( name );
  82   if ( !theVar )
  83   {
  84      theVar = new Var;
  85      theVar->setType( type );
  86      theVar->setName( name );
  87      theVar->uniform = true;
  88      theVar->constSortPos = csp;
  89   }
  90   
  91   return theVar;
  92}
  93
  94Var* TerrainFeatGLSL::_getInDetailCoord( Vector<ShaderComponent*> &componentList )
  95{
  96   String name( String::ToString( "detCoord%d", getProcessIndex() ) );
  97   Var *inDet = (Var*)LangElement::find( name );
  98   
  99   if ( !inDet )
 100   {
 101      ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 102      
 103      inDet = connectComp->getElement( RT_TEXCOORD );
 104      inDet->setName( name );
 105      inDet->setStructName( "IN" );
 106      inDet->setType( "vec4" );
 107      inDet->mapsToSampler = true;
 108   }
 109   
 110   return inDet;
 111}
 112
 113Var* TerrainFeatGLSL::_getInMacroCoord( Vector<ShaderComponent*> &componentList )
 114{
 115   String name( String::ToString( "macroCoord%d", getProcessIndex() ) );
 116   Var *inDet = (Var*)LangElement::find( name );
 117
 118   if ( !inDet )
 119   {
 120      ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 121
 122      inDet = connectComp->getElement( RT_TEXCOORD );
 123      inDet->setName( name );
 124      inDet->setStructName( "IN" );
 125      inDet->setType( "vec4" );
 126      inDet->mapsToSampler = true;
 127   }
 128
 129   return inDet;
 130}
 131
 132Var* TerrainFeatGLSL::_getNormalMapTex()
 133{
 134   String name( String::ToString( "normalMap%d", getProcessIndex() ) );
 135   Var *normalMap =  (Var*)LangElement::find( name );
 136   
 137   if ( !normalMap )
 138   {
 139      normalMap = new Var;
 140      normalMap->setType( "sampler2D" );
 141      normalMap->setName( name );
 142      normalMap->uniform = true;
 143      normalMap->sampler = true;
 144      normalMap->constNum = Var::getTexUnitNum();
 145   }
 146   
 147   return normalMap;
 148}
 149
 150Var* TerrainFeatGLSL::_getDetailIdStrengthParallax()
 151{
 152   String name( String::ToString( "detailIdStrengthParallax%d", getProcessIndex() ) );
 153   
 154   Var *detailInfo = (Var*)LangElement::find( name );
 155   if ( !detailInfo )
 156   {
 157      detailInfo = new Var;
 158      detailInfo->setType( "vec3" );
 159      detailInfo->setName( name );
 160      detailInfo->uniform = true;
 161      detailInfo->constSortPos = cspPotentialPrimitive;
 162   }
 163   
 164   return detailInfo;
 165}
 166
 167Var* TerrainFeatGLSL::_getMacroIdStrengthParallax()
 168{
 169   String name( String::ToString( "macroIdStrengthParallax%d", getProcessIndex() ) );
 170
 171   Var *detailInfo = (Var*)LangElement::find( name );
 172   if ( !detailInfo )
 173   {
 174      detailInfo = new Var;
 175      detailInfo->setType( "vec3" );
 176      detailInfo->setName( name );
 177      detailInfo->uniform = true;
 178      detailInfo->constSortPos = cspPotentialPrimitive;
 179   }
 180
 181   return detailInfo;
 182}
 183
 184
 185void TerrainBaseMapFeatGLSL::processVert( Vector<ShaderComponent*> &componentList, 
 186                                          const MaterialFeatureData &fd )
 187{
 188   MultiLine *meta = new MultiLine;
 189   output = meta;
 190
 191   // Generate the incoming texture var.
 192   Var *inTex;
 193   {
 194      Var *inPos = (Var*)LangElement::find( "inPosition" );
 195      if ( !inPos )
 196         inPos = (Var*)LangElement::find( "position" );
 197
 198      inTex = new Var( "texCoord", "vec3" );
 199
 200      Var *oneOverTerrainSize = _getUniformVar( "oneOverTerrainSize", "float", cspPass );
 201
 202      // NOTE: The y coord here should be negative to have
 203      // the texture maps not end up flipped which also caused
 204      // normal and parallax mapping to be incorrect.
 205      //
 206      // This mistake early in development means that the layer
 207      // id bilinear blend depends on it being that way.
 208      //
 209      // So instead i fixed this by flipping the base and detail
 210      // coord y scale to compensate when rendering.
 211      //
 212      meta->addStatement( new GenOp( "   @ = @.xyz * float3( @, @, -@ );\r\n", 
 213         new DecOp( inTex ), inPos, oneOverTerrainSize, oneOverTerrainSize, oneOverTerrainSize ) );
 214   }
 215
 216   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 217
 218   // Pass the texture coord to the pixel shader.
 219   Var *outTex = connectComp->getElement( RT_TEXCOORD );
 220   outTex->setName( "outTexCoord" );
 221   outTex->setStructName( "OUT" );
 222   outTex->setType( "vec3" );
 223   outTex->mapsToSampler = true;
 224   meta->addStatement( new GenOp( "   @.xy = @.xy;\r\n", outTex, inTex ) );
 225
 226   // If this shader has a side projected layer then we 
 227   // pass the dot product between the +Y and the normal
 228   // thru outTexCoord.z for use in blending the textures.
 229   if ( fd.features.hasFeature( MFT_TerrainSideProject ) )
 230   {
 231      Var *inNormal = (Var*)LangElement::find( "normal" );
 232      meta->addStatement( 
 233         new GenOp( "   @.z = pow( abs( dot( normalize( float3( @.x, @.y, 0 ) ), float3( 0, 1, 0 ) ) ), 10.0 );\r\n", 
 234            outTex, inNormal, inNormal ) );
 235   }
 236   else
 237      meta->addStatement( new GenOp( "   @.z = 0;\r\n", outTex ) );
 238
 239   // HACK: This is sort of lazy... we generate the tanget
 240   // vector here so that we're sure it exists in the parallax
 241   // and normal features which will expect "T" to exist.
 242   //
 243   // If this shader doesn't use it the shader compiler will
 244   // optimize away this code.
 245   //
 246   Var *inTangentZ = getVertTexCoord( "tcTangentZ" );
 247   Var *inTanget = new Var( "T", "vec3" );
 248   Var *squareSize = _getUniformVar( "squareSize", "float", cspPass );
 249   meta->addStatement( new GenOp( "   @ = normalize( float3( @, 0, @ ) );\r\n", 
 250      new DecOp( inTanget ), squareSize, inTangentZ ) );  
 251}
 252
 253void TerrainBaseMapFeatGLSL::processPix(  Vector<ShaderComponent*> &componentList, 
 254                                          const MaterialFeatureData &fd )
 255{
 256   // grab connector texcoord register
 257   Var *texCoord = getInTexCoord( "texCoord", "vec3", true, componentList );
 258
 259   // create texture var
 260   Var *diffuseMap = new Var;
 261   diffuseMap->setType( "sampler2D" );
 262   diffuseMap->setName( "baseTexMap" );
 263   diffuseMap->uniform = true;
 264   diffuseMap->sampler = true;
 265   diffuseMap->constNum = Var::getTexUnitNum();     // used as texture unit num here
 266
 267   MultiLine *meta = new MultiLine;
 268
 269   Var *baseColor = new Var;
 270   baseColor->setType( "vec4" );
 271   baseColor->setName( "baseColor" );
 272   meta->addStatement( new GenOp( "   @ = tex2D( @, @.xy );\r\n", new DecOp( baseColor ), diffuseMap, texCoord ) );
 273   meta->addStatement(new GenOp("   @ = toLinear(@);\r\n", baseColor, baseColor));
 274
 275  ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget;
 276
 277   if(fd.features.hasFeature(MFT_isDeferred))
 278   {
 279      target= ShaderFeature::RenderTarget1;
 280   }
 281   meta->addStatement( new GenOp( "   @;\r\n", assignColor( baseColor, Material::Mul,NULL,target ) ) );
 282
 283   output = meta;
 284}
 285
 286ShaderFeature::Resources TerrainBaseMapFeatGLSL::getResources( const MaterialFeatureData &fd )
 287{
 288   Resources res; 
 289   res.numTexReg = 1;
 290      res.numTex = 1;
 291
 292   return res;
 293}
 294
 295U32 TerrainBaseMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const
 296{
 297   return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget;
 298}
 299
 300TerrainDetailMapFeatGLSL::TerrainDetailMapFeatGLSL()
 301   :  mTorqueDep( "shaders/common/gl/torque.glsl" ),
 302      mTerrainDep( "shaders/common/terrain/terrain.glsl" )
 303      
 304{
 305   addDependency( &mTorqueDep );
 306   addDependency( &mTerrainDep );
 307}
 308
 309void TerrainDetailMapFeatGLSL::processVert(  Vector<ShaderComponent*> &componentList, 
 310                                             const MaterialFeatureData &fd )
 311{
 312   const S32 detailIndex = getProcessIndex();
 313
 314   // Grab incoming texture coords... the base map feature
 315   // made sure this was created.
 316   Var *inTex = (Var*)LangElement::find( "texCoord" );
 317   AssertFatal( inTex, "The texture coord is missing!" );
 318
 319   // Grab the input position.
 320   Var *inPos = (Var*)LangElement::find( "inPosition" );
 321   if ( !inPos )
 322      inPos = (Var*)LangElement::find( "position" );
 323
 324   // Get the object space eye position.
 325   Var *eyePos = _getUniformVar( "eyePos", "vec3", cspPotentialPrimitive );
 326
 327   MultiLine *meta = new MultiLine;
 328
 329   // If we have parallax mapping then make sure we've sent
 330   // the negative view vector to the pixel shader.
 331   if (  fd.features.hasFeature( MFT_TerrainParallaxMap ) &&
 332         !LangElement::find( "outNegViewTS" ) )
 333   {
 334      // Get the object to tangent transform which
 335      // will consume 3 output registers.
 336      Var *objToTangentSpace = getOutObjToTangentSpace( componentList, meta, fd );
 337
 338      // Now use a single output register to send the negative
 339      // view vector in tangent space to the pixel shader.
 340      ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 341      Var *outNegViewTS = connectComp->getElement( RT_TEXCOORD );
 342      outNegViewTS->setName( "outNegViewTS" );
 343      outNegViewTS->setStructName( "OUT" );
 344      outNegViewTS->setType( "vec3" );
 345      meta->addStatement( new GenOp( "   @ = tMul( @, float3( @ - @.xyz ) );\r\n", 
 346         outNegViewTS, objToTangentSpace, eyePos, inPos ) );
 347   }
 348
 349   // Get the distance from the eye to this vertex.
 350   Var *dist = (Var*)LangElement::find( "dist" );
 351   if ( !dist )
 352   {
 353      dist = new Var;
 354      dist->setType( "float" );
 355      dist->setName( "dist" );  
 356
 357      meta->addStatement( new GenOp( "   @ = distance( @.xyz, @ );\r\n", 
 358                                       new DecOp( dist ), inPos, eyePos ) );
 359   }
 360
 361   // grab connector texcoord register
 362   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 363   Var *outTex = connectComp->getElement( RT_TEXCOORD );
 364   outTex->setName( String::ToString( "detCoord%d", detailIndex ) );
 365   outTex->setStructName( "OUT" );
 366   outTex->setType( "vec4" );
 367   outTex->mapsToSampler = true;
 368
 369   // Get the detail scale and fade info.
 370   Var *detScaleAndFade = new Var;
 371   detScaleAndFade->setType( "vec4" );
 372   detScaleAndFade->setName( String::ToString( "detailScaleAndFade%d", detailIndex ) );
 373   detScaleAndFade->uniform = true;
 374   detScaleAndFade->constSortPos = cspPotentialPrimitive;
 375
 376   // Setup the detail coord.
 377   //
 378   // NOTE: You see here we scale the texture coord by 'xyx'
 379   // to generate the detail coord.  This y is here because
 380   // its scale is flipped to correct for the non negative y
 381   // in texCoord.
 382   //
 383   // See TerrainBaseMapFeatGLSL::processVert().
 384   //
 385   meta->addStatement( new GenOp( "   @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade ) );
 386
 387   // And sneak the detail fade thru the w detailCoord.
 388   meta->addStatement( new GenOp( "   @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n", 
 389                                    outTex, detScaleAndFade, dist, detScaleAndFade ) );   
 390
 391   output = meta;
 392}
 393
 394void TerrainDetailMapFeatGLSL::processPix(   Vector<ShaderComponent*> &componentList, 
 395                                             const MaterialFeatureData &fd )
 396{
 397   const S32 detailIndex = getProcessIndex();
 398   Var *inTex = getVertTexCoord( "texCoord" );
 399
 400   MultiLine *meta = new MultiLine;
 401
 402   // We need the negative tangent space view vector
 403   // as in parallax mapping we step towards the camera.
 404   Var *negViewTS = (Var*)LangElement::find( "negViewTS" );
 405   if (  !negViewTS &&
 406         fd.features.hasFeature( MFT_TerrainParallaxMap ) )
 407   {
 408      Var *inNegViewTS = (Var*)LangElement::find( "outNegViewTS" );
 409      if ( !inNegViewTS )
 410      {
 411         ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 412         inNegViewTS = connectComp->getElement( RT_TEXCOORD );
 413         inNegViewTS->setName( "outNegViewTS" );
 414         inNegViewTS->setStructName( "IN" );
 415         inNegViewTS->setType( "vec3" );
 416      }
 417   
 418      negViewTS = new Var( "negViewTS", "vec3" );
 419      meta->addStatement( new GenOp( "   @ = normalize( @ );\r\n", new DecOp( negViewTS ), inNegViewTS ) );
 420   }
 421
 422   // Get the layer samples.
 423   Var *layerSample = (Var*)LangElement::find( "layerSample" );
 424   if ( !layerSample )
 425   {
 426      layerSample = new Var;
 427      layerSample->setType( "vec4" );
 428      layerSample->setName( "layerSample" );
 429
 430      // Get the layer texture var
 431      Var *layerTex = new Var;
 432      layerTex->setType( "sampler2D" );
 433      layerTex->setName( "layerTex" );
 434      layerTex->uniform = true;
 435      layerTex->sampler = true;
 436      layerTex->constNum = Var::getTexUnitNum();
 437
 438      // Read the layer texture to get the samples.
 439      meta->addStatement( new GenOp( "   @ = round( tex2D( @, @.xy ) * 255.0f );\r\n", 
 440                                       new DecOp( layerSample ), layerTex, inTex ) );
 441   }
 442
 443   Var *layerSize = (Var*)LangElement::find( "layerSize" );
 444   if ( !layerSize )
 445   {
 446      layerSize = new Var;
 447      layerSize->setType( "float" );
 448      layerSize->setName( "layerSize" );
 449      layerSize->uniform = true;
 450      layerSize->constSortPos = cspPass;
 451   }
 452
 453   // Grab the incoming detail coord.
 454   Var *inDet = _getInDetailCoord( componentList );
 455
 456   // Get the detail id.
 457   Var *detailInfo = _getDetailIdStrengthParallax();
 458
 459   // Create the detail blend var.
 460   Var *detailBlend = new Var;
 461   detailBlend->setType( "float" );
 462   detailBlend->setName( String::ToString( "detailBlend%d", detailIndex ) );
 463
 464   // Calculate the blend for this detail texture.
 465   meta->addStatement( new GenOp( "   @ = calcBlend( @.x, @.xy, @, @ );\r\n", 
 466                                    new DecOp( detailBlend ), detailInfo, inTex, layerSize, layerSample ) );
 467
 468   // New terrain
 469
 470   Var *lerpBlend = (Var*)LangElement::find("lerpBlend");
 471   if (!lerpBlend)
 472   {
 473      lerpBlend = new Var;
 474      lerpBlend->setType("float");
 475      lerpBlend->setName("lerpBlend");
 476      lerpBlend->uniform = true;
 477      lerpBlend->constSortPos = cspPrimitive;
 478   }
 479
 480
 481   Var *blendDepth = (Var*)LangElement::find(String::ToString("blendDepth%d", detailIndex));
 482   if (!blendDepth)
 483   {
 484      blendDepth = new Var;
 485      blendDepth->setType("float");
 486      blendDepth->setName(String::ToString("blendDepth%d", detailIndex));
 487      blendDepth->uniform = true;
 488      blendDepth->constSortPos = cspPrimitive;
 489   }
 490
 491   ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget;
 492
 493   if(fd.features.hasFeature( MFT_DeferredTerrainDetailMap ))
 494      target= ShaderFeature::RenderTarget1;
 495
 496   Var *outColor = (Var*)LangElement::find( getOutputTargetVarName(target) );
 497
 498   if (!outColor)
 499   {
 500      // create color var
 501      outColor = new Var;
 502      outColor->setType("float4");
 503      outColor->setName("col");
 504       outColor->setStructName("OUT");
 505      meta->addStatement(new GenOp("   @;\r\n", outColor));
 506   }
 507
 508   Var *detailColor = (Var*)LangElement::find("detailColor");
 509   if (!detailColor)
 510   {
 511      detailColor = new Var;
 512      detailColor->setType("float4");
 513      detailColor->setName("detailColor");
 514      meta->addStatement(new GenOp("   @;\r\n", new DecOp(detailColor)));
 515   }
 516
 517   // Get the detail texture.
 518   Var *detailMap = new Var;
 519   detailMap->setType("sampler2D");
 520   detailMap->setName(String::ToString("detailMap%d", detailIndex));
 521   detailMap->uniform = true;
 522   detailMap->sampler = true;
 523   detailMap->constNum = Var::getTexUnitNum();     // used as texture unit num here
 524
 525   // Get the normal map texture.
 526   Var *normalMap = _getNormalMapTex();
 527
 528   // Issue happens somewhere here -----
 529
 530   // Sample the normal map.
 531   //
 532   // We take two normal samples and lerp between them for
 533   // side projection layers... else a single sample.
 534   LangElement *texOp;
 535
 536   // Note that we're doing the standard greyscale detail 
 537   // map technique here which can darken and lighten the 
 538   // diffuse texture.
 539   //
 540   // We take two color samples and lerp between them for
 541   // side projection layers... else a single sample.
 542   //
 543   if (fd.features.hasFeature(MFT_TerrainSideProject, detailIndex))
 544   {
 545      meta->addStatement(new GenOp("   @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n",
 546         detailColor, detailMap, inDet, detailMap, inDet, inTex));
 547
 548      texOp = new GenOp("lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z )",
 549         normalMap, inDet, normalMap, inDet, inTex);
 550   }
 551   else
 552   {
 553      meta->addStatement(new GenOp("   @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n",
 554         detailColor, detailMap, inDet));
 555
 556      texOp = new GenOp("tex2D(@, @.xy)", normalMap, inDet);
 557   }
 558
 559   // New terrain
 560
 561   // Get a var and accumulate the blend amount.
 562   Var *blendTotal = (Var*)LangElement::find( "blendTotal" );
 563   if ( !blendTotal )
 564   {
 565      blendTotal = new Var;
 566      blendTotal->setName( "blendTotal" );
 567      blendTotal->setType( "float" );
 568      meta->addStatement( new GenOp( "   @ = 0;\r\n", new DecOp( blendTotal ) ) );
 569   }
 570
 571   // Add to the blend total.
 572   meta->addStatement(new GenOp("   @ = max( @, @ );\r\n", blendTotal, blendTotal, detailBlend));
 573
 574   // If we had a parallax feature... then factor in the parallax
 575   // amount so that it fades out with the layer blending.
 576   if ( fd.features.hasFeature( MFT_TerrainParallaxMap, detailIndex ) )
 577   {
 578      // Get the rest of our inputs.
 579      Var *normalMap = _getNormalMapTex();
 580
 581      // Call the library function to do the rest.
 582      if (fd.features.hasFeature(MFT_IsDXTnm, detailIndex))
 583      {
 584         meta->addStatement(new GenOp("   @.xy += parallaxOffsetDxtnm( @, @.xy, @, @.z * @ );\r\n",
 585         inDet, normalMap, inDet, negViewTS, detailInfo, detailBlend));
 586      }
 587      else
 588      {
 589         meta->addStatement(new GenOp("   @.xy += parallaxOffset( @, @.xy, @, @.z * @ );\r\n",
 590         inDet, normalMap, inDet, negViewTS, detailInfo, detailBlend));
 591      }
 592   }
 593
 594   // If we're using SM 3.0 then take advantage of 
 595   // dynamic branching to skip layers per-pixel.
 596   
 597
 598   if ( GFX->getPixelShaderVersion() >= 3.0f )
 599      meta->addStatement( new GenOp( "   if ( @ > 0.0f )\r\n", detailBlend ) );
 600
 601   meta->addStatement( new GenOp( "   {\r\n" ) );
 602
 603   // Note that we're doing the standard greyscale detail 
 604   // map technique here which can darken and lighten the 
 605   // diffuse texture.
 606   //
 607   // We take two color samples and lerp between them for
 608   // side projection layers... else a single sample.
 609   //
 610   if ( fd.features.hasFeature( MFT_TerrainSideProject, detailIndex ) )
 611   {
 612      meta->addStatement( new GenOp( "      @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n", 
 613                                                detailColor, detailMap, inDet, detailMap, inDet, inTex ) );
 614   }
 615   else
 616   {
 617      meta->addStatement( new GenOp( "      @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n", 
 618                                       detailColor, detailMap, inDet ) );
 619   }
 620
 621   meta->addStatement( new GenOp( "      @ *= @.y * @.w;\r\n",
 622                                    detailColor, detailInfo, inDet ) );
 623
 624   meta->addStatement( new GenOp( "      @ += @ * @;\r\n",
 625                                    outColor, detailColor, detailBlend));
 626
 627   meta->addStatement( new GenOp( "   }\r\n" ) );
 628
 629   output = meta;
 630}
 631
 632ShaderFeature::Resources TerrainDetailMapFeatGLSL::getResources( const MaterialFeatureData &fd )
 633{
 634   Resources res;
 635
 636   if ( getProcessIndex() == 0 )
 637   {
 638      // If this is the first detail pass then we 
 639      // samples from the layer tex.
 640      res.numTex += 1;
 641
 642      // If this material also does parallax then it
 643      // will generate the negative view vector and the
 644      // worldToTanget transform.
 645      if ( fd.features.hasFeature( MFT_TerrainParallaxMap ) )
 646         res.numTexReg += 4;
 647   }
 648
 649   // sample from the detail texture for diffuse coloring.
 650      res.numTex += 1;
 651
 652   // If we have parallax for this layer then we'll also
 653   // be sampling the normal map for the parallax heightmap.
 654   if ( fd.features.hasFeature( MFT_TerrainParallaxMap, getProcessIndex() ) )
 655      res.numTex += 1;
 656
 657   // Finally we always send the detail texture 
 658   // coord to the pixel shader.
 659   res.numTexReg += 1;
 660
 661   return res;
 662}
 663
 664U32 TerrainDetailMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const
 665{
 666   return fd.features[MFT_DeferredTerrainDetailMap] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget;
 667}
 668
 669
 670TerrainMacroMapFeatGLSL::TerrainMacroMapFeatGLSL()
 671   :  mTorqueDep( "shaders/common/gl/torque.glsl" ),
 672      mTerrainDep( "shaders/common/terrain/terrain.glsl" )
 673      
 674{
 675   addDependency( &mTorqueDep );
 676   addDependency( &mTerrainDep );
 677}
 678
 679
 680void TerrainMacroMapFeatGLSL::processVert(  Vector<ShaderComponent*> &componentList, 
 681                                             const MaterialFeatureData &fd )
 682{
 683   const S32 detailIndex = getProcessIndex();
 684
 685   // Grab incoming texture coords... the base map feature
 686   // made sure this was created.
 687   Var *inTex = (Var*)LangElement::find( "texCoord" );
 688   AssertFatal( inTex, "The texture coord is missing!" );
 689
 690   // Grab the input position.
 691   Var *inPos = (Var*)LangElement::find( "inPosition" );
 692   if ( !inPos )
 693      inPos = (Var*)LangElement::find( "position" );
 694
 695   // Get the object space eye position.
 696   Var *eyePos = _getUniformVar( "eyePos", "vec3", cspPotentialPrimitive );
 697
 698   MultiLine *meta = new MultiLine;
 699
 700   // Get the distance from the eye to this vertex.
 701   Var *dist = (Var*)LangElement::find( "macroDist" );
 702   if ( !dist )
 703   {
 704      dist = new Var;
 705      dist->setType( "float" );
 706      dist->setName( "macroDist" );  
 707
 708      meta->addStatement( new GenOp( "   @ = distance( @.xyz, @ );\r\n", 
 709                                       new DecOp( dist ), inPos, eyePos ) );
 710   }
 711
 712   // grab connector texcoord register
 713   ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 714   Var *outTex = connectComp->getElement( RT_TEXCOORD );
 715   outTex->setName( String::ToString( "macroCoord%d", detailIndex ) );
 716   outTex->setStructName( "OUT" );
 717   outTex->setType( "vec4" );
 718   outTex->mapsToSampler = true;
 719
 720   // Get the detail scale and fade info.
 721   Var *detScaleAndFade = new Var;
 722   detScaleAndFade->setType( "vec4" );
 723   detScaleAndFade->setName( String::ToString( "macroScaleAndFade%d", detailIndex ) );
 724   detScaleAndFade->uniform = true;
 725   detScaleAndFade->constSortPos = cspPotentialPrimitive;
 726
 727   // Setup the detail coord.
 728   meta->addStatement( new GenOp( "   @.xyz = @ * @.xyx;\r\n", outTex, inTex, detScaleAndFade ) );
 729
 730   // And sneak the detail fade thru the w detailCoord.
 731   meta->addStatement( new GenOp( "   @.w = clamp( ( @.z - @ ) * @.w, 0.0, 1.0 );\r\n", 
 732                                    outTex, detScaleAndFade, dist, detScaleAndFade ) );   
 733
 734   output = meta;
 735}
 736
 737
 738void TerrainMacroMapFeatGLSL::processPix(   Vector<ShaderComponent*> &componentList, 
 739                                             const MaterialFeatureData &fd )
 740{
 741   const S32 detailIndex = getProcessIndex();
 742   Var *inTex = getVertTexCoord( "texCoord" );
 743   
 744   MultiLine *meta = new MultiLine;
 745
 746   // We need the negative tangent space view vector
 747   // as in parallax mapping we step towards the camera.
 748   Var *negViewTS = (Var*)LangElement::find( "negViewTS" );
 749   if (  !negViewTS &&
 750         fd.features.hasFeature( MFT_TerrainParallaxMap ) )
 751   {
 752      Var *inNegViewTS = (Var*)LangElement::find( "outNegViewTS" );
 753      if ( !inNegViewTS )
 754      {
 755         ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
 756         inNegViewTS = connectComp->getElement( RT_TEXCOORD );
 757         inNegViewTS->setName( "outNegViewTS" );
 758         inNegViewTS->setStructName( "IN" );
 759         inNegViewTS->setType( "vec3" );
 760      }
 761
 762      negViewTS = new Var( "negViewTS", "vec3" );
 763      meta->addStatement( new GenOp( "   @ = normalize( @ );\r\n", new DecOp( negViewTS ), inNegViewTS ) );
 764   }
 765
 766   // Get the layer samples.
 767   Var *layerSample = (Var*)LangElement::find( "layerSample" );
 768   if ( !layerSample )
 769   {
 770      layerSample = new Var;
 771      layerSample->setType( "vec4" );
 772      layerSample->setName( "layerSample" );
 773
 774      // Get the layer texture var
 775      Var *layerTex = new Var;
 776      layerTex->setType( "sampler2D" );
 777      layerTex->setName( "macrolayerTex" );
 778      layerTex->uniform = true;
 779      layerTex->sampler = true;
 780      layerTex->constNum = Var::getTexUnitNum();
 781
 782      // Read the layer texture to get the samples.
 783      meta->addStatement( new GenOp( "   @ = round( tex2D( @, @.xy ) * 255.0f );\r\n", 
 784                                       new DecOp( layerSample ), layerTex, inTex ) );
 785   }
 786
 787   Var *layerSize = (Var*)LangElement::find( "layerSize" );
 788   if ( !layerSize )
 789   {
 790      layerSize = new Var;
 791      layerSize->setType( "float" );
 792      layerSize->setName( "layerSize" );
 793      layerSize->uniform = true;
 794      layerSize->constSortPos = cspPass;
 795   }
 796
 797   // Grab the incoming detail coord.
 798   Var *inDet = _getInMacroCoord( componentList );
 799
 800   // Get the detail id.
 801   Var *detailInfo = _getMacroIdStrengthParallax();
 802
 803   // Create the detail blend var.
 804   Var *detailBlend = new Var;
 805   detailBlend->setType( "float" );
 806   detailBlend->setName( String::ToString( "macroBlend%d", detailIndex ) );
 807
 808   // Calculate the blend for this detail texture.
 809   meta->addStatement( new GenOp( "   @ = calcBlend( @.x, @.xy, @, @ );\r\n", 
 810                                    new DecOp( detailBlend ), detailInfo, inTex, layerSize, layerSample ) );
 811
 812   // Get a var and accumulate the blend amount.
 813   Var *blendTotal = (Var*)LangElement::find( "blendTotal" );
 814   if ( !blendTotal )
 815   {
 816      blendTotal = new Var;
 817      //blendTotal->setName( "blendTotal" );
 818      blendTotal->setName( "blendTotal" );
 819      blendTotal->setType( "float" );
 820      meta->addStatement( new GenOp( "   @ = 0;\r\n", new DecOp( blendTotal ) ) );
 821   }
 822
 823   // Add to the blend total.
 824   meta->addStatement(new GenOp("   @ = max( @, @ );\r\n", blendTotal, blendTotal, detailBlend));
 825
 826   Var *detailColor = (Var*)LangElement::find( "macroColor" ); 
 827   if ( !detailColor )
 828   {
 829      detailColor = new Var;
 830      detailColor->setType( "vec4" );
 831      detailColor->setName( "macroColor" );
 832      meta->addStatement( new GenOp( "   @;\r\n", new DecOp( detailColor ) ) );
 833   }
 834
 835   // Get the detail texture.
 836   Var *detailMap = new Var;
 837   detailMap->setType( "sampler2D" );
 838   detailMap->setName( String::ToString( "macroMap%d", detailIndex ) );
 839   detailMap->uniform = true;
 840   detailMap->sampler = true;
 841   detailMap->constNum = Var::getTexUnitNum();     // used as texture unit num here
 842
 843   // If we're using SM 3.0 then take advantage of 
 844   // dynamic branching to skip layers per-pixel.
 845   if ( GFX->getPixelShaderVersion() >= 3.0f )
 846      meta->addStatement( new GenOp( "   if ( @ > 0.0f )\r\n", detailBlend ) );
 847
 848   meta->addStatement( new GenOp( "   {\r\n" ) );
 849
 850   // Note that we're doing the standard greyscale detail 
 851   // map technique here which can darken and lighten the 
 852   // diffuse texture.
 853   //
 854   // We take two color samples and lerp between them for
 855   // side projection layers... else a single sample.
 856   //
 857   if ( fd.features.hasFeature( MFT_TerrainSideProject, detailIndex ) )
 858   {
 859      meta->addStatement( new GenOp( "      @ = ( lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z ) * 2.0 ) - 1.0;\r\n", 
 860                                                detailColor, detailMap, inDet, detailMap, inDet, inTex ) );
 861   }
 862   else
 863   {
 864      meta->addStatement( new GenOp( "      @ = ( tex2D( @, @.xy ) * 2.0 ) - 1.0;\r\n", 
 865                                       detailColor, detailMap, inDet ) );
 866   }
 867
 868   meta->addStatement( new GenOp( "      @ *= @.y * @.w;\r\n",
 869                                    detailColor, detailInfo, inDet ) );
 870   ShaderFeature::OutputTarget target = ShaderFeature::DefaultTarget;
 871
 872   if(fd.features.hasFeature(MFT_DeferredTerrainMacroMap))
 873      target= ShaderFeature::RenderTarget1;
 874
 875   Var *outColor = (Var*)LangElement::find( getOutputTargetVarName(target) );
 876
 877   meta->addStatement(new GenOp("      @ += @ * @;\r\n",
 878                                    outColor, detailColor, detailBlend));
 879
 880   meta->addStatement( new GenOp( "   }\r\n" ) );
 881
 882   output = meta;
 883}
 884
 885
 886
 887ShaderFeature::Resources TerrainMacroMapFeatGLSL::getResources( const MaterialFeatureData &fd )
 888{
 889   Resources res;
 890
 891   if ( getProcessIndex() == 0 )
 892   {
 893      // If this is the first detail pass then we 
 894      // samples from the layer tex.
 895         res.numTex += 1;
 896   }
 897
 898      res.numTex += 1;
 899
 900   // Finally we always send the detail texture 
 901   // coord to the pixel shader.
 902   res.numTexReg += 1;
 903
 904   return res;
 905}
 906
 907U32 TerrainMacroMapFeatGLSL::getOutputTargets( const MaterialFeatureData &fd ) const
 908{
 909   return fd.features[MFT_DeferredTerrainMacroMap] ? ShaderFeature::RenderTarget1 : ShaderFeature::DefaultTarget;
 910}
 911
 912void TerrainNormalMapFeatGLSL::processVert(  Vector<ShaderComponent*> &componentList, 
 913                                             const MaterialFeatureData &fd )
 914{
 915   // We only need to process normals during the prepass.
 916   if ( !fd.features.hasFeature( MFT_PrePassConditioner ) )
 917      return;
 918
 919   MultiLine *meta = new MultiLine;
 920
 921   // Make sure the world to tangent transform
 922   // is created and available for the pixel shader.
 923   getOutViewToTangent( componentList, meta, fd );
 924
 925   output = meta;
 926}
 927
 928void TerrainNormalMapFeatGLSL::processPix(   Vector<ShaderComponent*> &componentList, 
 929                                             const MaterialFeatureData &fd )
 930{
 931
 932   MultiLine *meta = new MultiLine;
 933
 934   Var *viewToTangent = getInViewToTangent( componentList );
 935
 936   // This var is read from GBufferConditionerGLSL and 
 937   // used in the prepass output.
 938   Var *gbNormal = (Var*)LangElement::find( "gbNormal" );
 939   if ( !gbNormal )
 940   {
 941      gbNormal = new Var;
 942      gbNormal->setName( "gbNormal" );
 943      gbNormal->setType( "vec3" );
 944      meta->addStatement( new GenOp( "   @ = tGetMatrix3Row(@, 2);\r\n", new DecOp( gbNormal ), viewToTangent ) );
 945   }
 946
 947   const S32 normalIndex = getProcessIndex();
 948
 949   Var *detailBlend = (Var*)LangElement::find( String::ToString( "detailBlend%d", normalIndex ) );
 950   AssertFatal( detailBlend, "The detail blend is missing!" );
 951
 952   // If we're using SM 3.0 then take advantage of 
 953   // dynamic branching to skip layers per-pixel.
 954   if ( GFX->getPixelShaderVersion() >= 3.0f )
 955      meta->addStatement( new GenOp( "   if ( @ > 0.0f )\r\n", detailBlend ) );
 956
 957   meta->addStatement( new GenOp( "   {\r\n" ) );
 958
 959   // Get the normal map texture.
 960   Var *normalMap = _getNormalMapTex();
 961
 962   /// Get the texture coord.
 963   Var *inDet = _getInDetailCoord( componentList );
 964   Var *inTex = getVertTexCoord( "texCoord" );
 965
 966   // Sample the normal map.
 967   //
 968   // We take two normal samples and lerp between them for
 969   // side projection layers... else a single sample.
 970   LangElement *texOp;
 971   if ( fd.features.hasFeature( MFT_TerrainSideProject, normalIndex ) )
 972   {
 973      texOp = new GenOp( "lerp( tex2D( @, @.yz ), tex2D( @, @.xz ), @.z )", 
 974         normalMap, inDet, normalMap, inDet, inTex );
 975   }
 976   else
 977      texOp = new GenOp( "tex2D(@, @.xy)", normalMap, inDet );
 978
 979   // create bump normal
 980   Var *bumpNorm = new Var;
 981   bumpNorm->setName( "bumpNormal" );
 982   bumpNorm->setType( "vec4" );
 983
 984   LangElement *bumpNormDecl = new DecOp( bumpNorm );
 985   meta->addStatement( expandNormalMap( texOp, bumpNormDecl, bumpNorm, fd ) );
 986
 987   // Normalize is done later... 
 988   // Note: The reverse mul order is intentional. Affine matrix.
 989   meta->addStatement( new GenOp( "      @ = lerp( @, tMul( @.xyz, @ ), min( @, @.w ) );\r\n", 
 990      gbNormal, gbNormal, bumpNorm, viewToTangent, detailBlend, inDet ) );
 991
 992   // End the conditional block.
 993   meta->addStatement( new GenOp( "   }\r\n" ) );
 994
 995   // If this is the last normal map then we 
 996   // can test to see the total blend value
 997   // to see if we should clip the result.
 998   //if ( fd.features.getNextFeatureIndex( MFT_TerrainNormalMap, normalIndex ) == -1 )
 999      //meta->addStatement( new GenOp( "   clip( @ - 0.0001f );\r\n", blendTotal ) );
1000
1001   output = meta;
1002}
1003
1004ShaderFeature::Resources TerrainNormalMapFeatGLSL::getResources( const MaterialFeatureData &fd )
1005{
1006   Resources res;
1007
1008   // We only need to process normals during the prepass.
1009   if ( fd.features.hasFeature( MFT_PrePassConditioner ) )
1010   {
1011      // If this is the first normal map and there
1012      // are no parallax features then we will 
1013      // generate the worldToTanget transform.
1014      if (  !fd.features.hasFeature( MFT_TerrainParallaxMap ) &&
1015            ( getProcessIndex() == 0 || !fd.features.hasFeature( MFT_TerrainNormalMap, getProcessIndex() - 1 ) ) )
1016         res.numTexReg = 3;
1017
1018      res.numTex = 1;
1019   }
1020
1021   return res;
1022}
1023
1024void TerrainLightMapFeatGLSL::processPix( Vector<ShaderComponent*> &componentList, 
1025                                          const MaterialFeatureData &fd )
1026{
1027   // grab connector texcoord register
1028   Var *inTex = (Var*)LangElement::find( "texCoord" );
1029   if ( !inTex )
1030      return;
1031
1032   // Get the lightmap texture.
1033   Var *lightMap = new Var;
1034   lightMap->setType( "sampler2D" );
1035   lightMap->setName( "lightMapTex" );
1036   lightMap->uniform = true;
1037   lightMap->sampler = true;
1038   lightMap->constNum = Var::getTexUnitNum();
1039
1040   MultiLine *meta = new MultiLine;
1041
1042   // Find or create the lightMask value which is read by
1043   // RTLighting to mask out the lights.
1044   //
1045   // The first light is always the sunlight so we apply
1046   // the shadow mask to only the first channel.
1047   //
1048   Var *lightMask = (Var*)LangElement::find( "lightMask" );
1049   if ( !lightMask )
1050   {
1051      lightMask = new Var( "lightMask", "vec4" );
1052      meta->addStatement( new GenOp( "   @ = vec4(1);\r\n", new DecOp( lightMask ) ) );
1053   }
1054
1055   meta->addStatement( new GenOp( "   @[0] = tex2D( @, @.xy ).r;\r\n", lightMask, lightMap, inTex ) );
1056   output = meta;
1057}
1058
1059ShaderFeature::Resources TerrainLightMapFeatGLSL::getResources( const MaterialFeatureData &fd )
1060{
1061   Resources res; 
1062   res.numTex = 1;
1063   return res;
1064}
1065
1066
1067void TerrainAdditiveFeatGLSL::processPix( Vector<ShaderComponent*> &componentList, 
1068                                          const MaterialFeatureData &fd )
1069{
1070   Var *color = NULL;
1071   Var *normal = NULL;
1072   if (fd.features[MFT_DeferredTerrainDetailMap])
1073   {
1074       color = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::RenderTarget1) );
1075       normal = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::DefaultTarget) );
1076   }
1077   else
1078       color = (Var*) LangElement::find( getOutputTargetVarName(ShaderFeature::DefaultTarget) );
1079
1080   Var *blendTotal = (Var*)LangElement::find( "blendTotal" );
1081   if ( !color || !blendTotal )
1082      return;
1083   
1084   MultiLine *meta = new MultiLine;
1085
1086   meta->addStatement( new GenOp( "   clip( @ - 0.0001 );\r\n", blendTotal ) );
1087   meta->addStatement( new GenOp( "   @.a = @;\r\n", color, blendTotal ) );
1088   if (normal)
1089      meta->addStatement(new GenOp("   @.a = @;\r\n", normal, blendTotal));
1090
1091   output = meta;
1092}
1093
1094//standard matInfo map contains data of the form .r = bitflags, .g = (will contain AO), 
1095//.b = specular strength, a= spec power. 
1096//here, it's merely a cutout for now, so that lightmapping (target3) doesn't get mangled.
1097//we'll most likely revisit that later. possibly several ways...
1098
1099U32 TerrainBlankInfoMapFeatGLSL::getOutputTargets(const MaterialFeatureData &fd) const
1100{
1101   return fd.features[MFT_isDeferred] ? ShaderFeature::RenderTarget2 : ShaderFeature::RenderTarget1;
1102}
1103
1104void TerrainBlankInfoMapFeatGLSL::processPix(Vector<ShaderComponent*> &componentList,
1105   const MaterialFeatureData &fd)
1106{
1107   // search for material var
1108   Var *material;
1109   OutputTarget targ = RenderTarget1;
1110   if (fd.features[MFT_isDeferred])
1111   {
1112      targ = RenderTarget2;
1113   }
1114   material = (Var*)LangElement::find(getOutputTargetVarName(targ));
1115
1116   MultiLine * meta = new MultiLine;
1117   if (!material)
1118   {
1119      // create color var
1120      material = new Var;
1121      material->setType("vec4");
1122      material->setName(getOutputTargetVarName(targ));
1123      material->setStructName("OUT");
1124   }
1125
1126   meta->addStatement(new GenOp("   @ = float4(0.0,0.0,0.0,0.0001);\r\n", material));
1127
1128   output = meta;
1129}
1130