فهرست منبع

cleaned up variant of https://github.com/GarageGames/Torque3D/pull/768 alterations: opengl support, in-shader bug-reporting, direction vector fit to material slider-bar.

Azaezel 10 سال پیش
والد
کامیت
c6cdfafe4e
42فایلهای تغییر یافته به همراه2680 افزوده شده و 8 حذف شده
  1. 349 0
      Engine/source/T3D/accumulationVolume.cpp
  2. 104 0
      Engine/source/T3D/accumulationVolume.h
  3. 25 0
      Engine/source/T3D/tsStatic.cpp
  4. 74 1
      Engine/source/lighting/advanced/glsl/advancedLightingFeaturesGLSL.cpp
  5. 74 1
      Engine/source/lighting/advanced/hlsl/advancedLightingFeaturesHLSL.cpp
  6. 1 0
      Engine/source/materials/baseMatInstance.h
  7. 8 0
      Engine/source/materials/matInstance.cpp
  8. 1 0
      Engine/source/materials/matInstance.h
  9. 40 0
      Engine/source/materials/materialDefinition.cpp
  10. 10 0
      Engine/source/materials/materialDefinition.h
  11. 8 0
      Engine/source/materials/materialFeatureTypes.cpp
  12. 7 0
      Engine/source/materials/materialFeatureTypes.h
  13. 1 0
      Engine/source/materials/processedCustomMaterial.cpp
  14. 1 0
      Engine/source/materials/processedFFMaterial.cpp
  15. 1 0
      Engine/source/materials/processedMaterial.cpp
  16. 6 0
      Engine/source/materials/processedMaterial.h
  17. 51 0
      Engine/source/materials/processedShaderMaterial.cpp
  18. 5 0
      Engine/source/materials/processedShaderMaterial.h
  19. 1 0
      Engine/source/materials/sceneData.h
  20. 1 0
      Engine/source/renderInstance/renderBinManager.cpp
  21. 10 0
      Engine/source/renderInstance/renderMeshMgr.cpp
  22. 1 0
      Engine/source/renderInstance/renderPassManager.h
  23. 4 0
      Engine/source/scene/sceneObject.cpp
  24. 10 0
      Engine/source/scene/sceneObject.h
  25. 241 0
      Engine/source/shaderGen/GLSL/accuFeatureGLSL.cpp
  26. 185 0
      Engine/source/shaderGen/GLSL/accuFeatureGLSL.h
  27. 2 0
      Engine/source/shaderGen/GLSL/shaderGenGLSLInit.cpp
  28. 238 0
      Engine/source/shaderGen/HLSL/accuFeatureHLSL.cpp
  29. 185 0
      Engine/source/shaderGen/HLSL/accuFeatureHLSL.h
  30. 2 1
      Engine/source/shaderGen/HLSL/shaderGenHLSLInit.cpp
  31. 3 0
      Engine/source/ts/tsMesh.cpp
  32. 2 1
      Engine/source/ts/tsRenderState.cpp
  33. 13 1
      Engine/source/ts/tsRenderState.h
  34. 13 1
      Engine/source/ts/tsShapeInstance.cpp
  35. 6 0
      Engine/source/ts/tsShapeInstance.h
  36. 1 0
      Engine/source/util/imposterCapture.cpp
  37. 476 1
      Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui
  38. 21 0
      Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs
  39. 1 0
      Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs
  40. 476 1
      Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui
  41. 21 0
      Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs
  42. 1 0
      Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs

+ 349 - 0
Engine/source/T3D/accumulationVolume.cpp

@@ -0,0 +1,349 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "platform/platform.h"
+#include "T3D/accumulationVolume.h"
+
+#include "scene/sceneManager.h"
+#include "scene/sceneRenderState.h"
+#include "gfx/gfxDevice.h"
+#include "gfx/gfxDrawUtil.h"
+#include "gfx/sim/debugDraw.h"
+#include "util/tempAlloc.h"
+#include "materials/materialDefinition.h"
+#include "materials/materialManager.h"
+#include "materials/materialFeatureTypes.h"
+#include "materials/matInstance.h"
+#include "console/consoleTypes.h"
+#include "core/stream/bitStream.h"
+#include "gfx/gfxDevice.h"
+#include "console/console.h"
+#include "console/engineAPI.h"
+#include "gfx/gfxTextureHandle.h"
+#include "scene/sceneContainer.h"
+
+#include "math/mPolyhedron.impl.h"
+
+Vector< SimObjectPtr<SceneObject> > AccumulationVolume::smAccuObjects;
+Vector< SimObjectPtr<AccumulationVolume> > AccumulationVolume::smAccuVolumes;
+
+//#define DEBUG_DRAW
+
+IMPLEMENT_CO_NETOBJECT_V1( AccumulationVolume );
+
+ConsoleDocClass( AccumulationVolume,
+   "@brief An invisible shape that allow objects within it to have an accumulation map.\n\n"
+
+   "AccumulationVolume is used to add additional realism to a scene. It's main use is in outdoor scenes "
+   " where objects could benefit from overlaying environment accumulation textures such as sand, snow, etc.\n\n"
+
+   "Objects within the volume must have accumulation enabled in their material. \n\n"
+
+   "@ingroup enviroMisc"
+);
+
+//-----------------------------------------------------------------------------
+
+AccumulationVolume::AccumulationVolume()
+   : mTransformDirty( true ),
+     mSilhouetteExtractor( mPolyhedron )
+{
+   VECTOR_SET_ASSOCIATION( mWSPoints );
+   VECTOR_SET_ASSOCIATION( mVolumeQueryList );
+
+   //mObjectFlags.set( VisualOccluderFlag );
+   
+   mNetFlags.set( Ghostable | ScopeAlways );
+   mObjScale.set( 1.f, 1.f, 1.f );
+   mObjBox.set(
+      Point3F( -0.5f, -0.5f, -0.5f ),
+      Point3F( 0.5f, 0.5f, 0.5f )
+   );
+
+   mObjToWorld.identity();
+   mWorldToObj.identity();
+
+   // Accumulation Texture.
+   mTextureName = "";
+   mAccuTexture = NULL;
+
+   resetWorldBox();
+}
+
+AccumulationVolume::~AccumulationVolume()
+{
+   mAccuTexture = NULL;
+}
+
+void AccumulationVolume::initPersistFields()
+{
+   addProtectedField( "texture", TypeStringFilename, Offset( mTextureName, AccumulationVolume ),
+         &_setTexture, &defaultProtectedGetFn, "Accumulation texture." );
+
+   Parent::initPersistFields();
+}
+
+//-----------------------------------------------------------------------------
+
+void AccumulationVolume::consoleInit()
+{
+   // Disable rendering of occlusion volumes by default.
+   getStaticClassRep()->mIsRenderEnabled = false;
+}
+
+//-----------------------------------------------------------------------------
+
+bool AccumulationVolume::onAdd()
+{
+   if( !Parent::onAdd() )
+      return false;
+
+   // Prepare some client side things.
+   if ( isClientObject() )  
+   {
+      smAccuVolumes.push_back(this);
+      refreshVolumes();
+   }
+
+   // Set up the silhouette extractor.
+   mSilhouetteExtractor = SilhouetteExtractorType( mPolyhedron );
+
+   return true;
+}
+
+void AccumulationVolume::onRemove()
+{
+   if ( isClientObject() )  
+   {
+      smAccuVolumes.remove(this);
+      refreshVolumes();
+   }
+   Parent::onRemove();
+}
+
+//-----------------------------------------------------------------------------
+
+void AccumulationVolume::_renderObject( ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat )
+{
+   Parent::_renderObject( ri, state, overrideMat );
+
+   #ifdef DEBUG_DRAW
+   if( state->isDiffusePass() )
+      DebugDrawer::get()->drawPolyhedronDebugInfo( mPolyhedron, getTransform(), getScale() );
+   #endif
+}
+
+//-----------------------------------------------------------------------------
+
+void AccumulationVolume::setTransform( const MatrixF& mat )
+{
+   Parent::setTransform( mat );
+   mTransformDirty = true;
+   refreshVolumes();
+}
+
+//-----------------------------------------------------------------------------
+
+void AccumulationVolume::buildSilhouette( const SceneCameraState& cameraState, Vector< Point3F >& outPoints )
+{
+   // Extract the silhouette of the polyhedron.  This works differently
+   // depending on whether we project orthogonally or in perspective.
+
+   TempAlloc< U32 > indices( mPolyhedron.getNumPoints() );
+   U32 numPoints;
+
+   if( cameraState.getFrustum().isOrtho() )
+   {
+      // Transform the view direction into object space.
+
+      Point3F osViewDir;
+      getWorldTransform().mulV( cameraState.getViewDirection(), &osViewDir );
+
+      // And extract the silhouette.
+
+      SilhouetteExtractorOrtho< PolyhedronType > extractor( mPolyhedron );
+      numPoints = extractor.extractSilhouette( osViewDir, indices, indices.size );
+   }
+   else
+   {
+      // Create a transform to go from view space to object space.
+
+      MatrixF camView( true );
+      camView.scale( Point3F( 1.0f / getScale().x, 1.0f / getScale().y, 1.0f / getScale().z ) );
+      camView.mul( getRenderWorldTransform() );
+      camView.mul( cameraState.getViewWorldMatrix() );
+
+      // Do a perspective-correct silhouette extraction.
+
+      numPoints = mSilhouetteExtractor.extractSilhouette(
+         camView,
+         indices, indices.size );
+   }
+
+   // If we haven't yet, transform the polyhedron's points
+   // to world space.
+
+   if( mTransformDirty )
+   {
+      const U32 numPoints = mPolyhedron.getNumPoints();
+      const PolyhedronType::PointType* points = getPolyhedron().getPoints();
+
+      mWSPoints.setSize( numPoints );
+      for( U32 i = 0; i < numPoints; ++ i )
+      {
+         Point3F p = points[ i ];
+         p.convolve( getScale() );
+         getTransform().mulP( p, &mWSPoints[ i ] );
+      }
+
+      mTransformDirty = false;
+   }
+
+   // Now store the points.
+
+   outPoints.setSize( numPoints );
+   for( U32 i = 0; i < numPoints; ++ i )
+      outPoints[ i ] = mWSPoints[ indices[ i ] ];
+}
+
+//-----------------------------------------------------------------------------
+
+U32 AccumulationVolume::packUpdate( NetConnection *connection, U32 mask, BitStream *stream )
+{
+   U32 retMask = Parent::packUpdate( connection, mask, stream );
+
+   if (stream->writeFlag(mask & InitialUpdateMask))
+   {
+      stream->write( mTextureName );
+   }
+
+   return retMask;  
+}
+
+void AccumulationVolume::unpackUpdate( NetConnection *connection, BitStream *stream )
+{
+   Parent::unpackUpdate( connection, stream );
+
+   if (stream->readFlag())
+   {
+      stream->read( &mTextureName );
+      setTexture(mTextureName);
+   }
+}
+
+//-----------------------------------------------------------------------------
+
+void AccumulationVolume::inspectPostApply()
+{
+   Parent::inspectPostApply();
+   setMaskBits(U32(-1) );
+}
+
+void AccumulationVolume::setTexture( const String& name )
+{
+   mTextureName = name;
+   if ( isClientObject() && mTextureName.isNotEmpty() )
+   {
+      mAccuTexture.set(mTextureName, &GFXDefaultStaticDiffuseProfile, "AccumulationVolume::mAccuTexture");
+      if ( mAccuTexture.isNull() )
+         Con::warnf( "AccumulationVolume::setTexture - Unable to load texture: %s", mTextureName.c_str() );
+   }
+   refreshVolumes();
+}
+
+//-----------------------------------------------------------------------------
+// Static Functions
+//-----------------------------------------------------------------------------
+bool AccumulationVolume::_setTexture( void *object, const char *index, const char *data )
+{
+   AccumulationVolume* volume = reinterpret_cast< AccumulationVolume* >( object );
+   volume->setTexture( data );
+   return false;
+}
+
+void AccumulationVolume::refreshVolumes()
+{
+   // This function tests each accumulation object to
+   // see if it's within the bounds of an accumulation
+   // volume. If so, it will pass on the accumulation
+   // texture of the volume to the object.
+
+   // This function should only be called when something
+   // global like change of volume or material occurs.
+
+   // Clear old data.
+   for (S32 n = 0; n < smAccuObjects.size(); ++n)
+   {
+      SimObjectPtr<SceneObject> object = smAccuObjects[n];
+      if ( object.isValid() )
+         object->mAccuTex = GFXTexHandle::ZERO;
+   }
+
+   // 
+   for (S32 i = 0; i < smAccuVolumes.size(); ++i)
+   {
+      SimObjectPtr<AccumulationVolume> volume = smAccuVolumes[i];
+      if ( volume.isNull() ) continue;
+
+      for (S32 n = 0; n < smAccuObjects.size(); ++n)
+      {
+         SimObjectPtr<SceneObject> object = smAccuObjects[n];
+         if ( object.isNull() ) continue;
+
+         if ( volume->containsPoint(object->getPosition()) )
+            object->mAccuTex = volume->mAccuTexture;
+      }
+   }
+}
+
+// Accumulation Object Management.
+void AccumulationVolume::addObject(SimObjectPtr<SceneObject> object)
+{
+   smAccuObjects.push_back(object);
+   refreshVolumes();
+}
+
+void AccumulationVolume::removeObject(SimObjectPtr<SceneObject> object)
+{
+   smAccuObjects.remove(object);
+   refreshVolumes();
+}
+
+void AccumulationVolume::updateObject(SceneObject* object)
+{
+   // This function is called when an individual object
+   // has been moved. Tests to see if it's in any of the
+   // accumulation volumes.
+
+   // We use ZERO instead of NULL so the accumulation
+   // texture will be updated in renderMeshMgr.
+   object->mAccuTex = GFXTexHandle::ZERO;
+
+   for (S32 i = 0; i < smAccuVolumes.size(); ++i)
+   {
+      SimObjectPtr<AccumulationVolume> volume = smAccuVolumes[i];
+      if ( volume.isNull() ) continue;
+
+      if ( volume->containsPoint(object->getPosition()) )
+         object->mAccuTex = volume->mAccuTexture;
+   }
+}

+ 104 - 0
Engine/source/T3D/accumulationVolume.h

@@ -0,0 +1,104 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ACCUMULATIONVOLUME_H_
+#define _ACCUMULATIONVOLUME_H_
+
+#ifndef _SCENEPOLYHEDRALSPACE_H_
+#include "scene/scenePolyhedralSpace.h"
+#endif
+
+#ifndef _MSILHOUETTEEXTRACTOR_H_
+#include "math/mSilhouetteExtractor.h"
+#endif
+
+#ifndef _GFXDEVICE_H_
+#include "gfx/gfxDevice.h"
+#endif
+
+/// A volume in space that blocks visibility.
+class AccumulationVolume : public ScenePolyhedralSpace
+{
+   public:
+
+      typedef ScenePolyhedralSpace Parent;
+
+   protected:
+
+      typedef SilhouetteExtractorPerspective< PolyhedronType > SilhouetteExtractorType;
+
+      /// Whether the volume's transform has changed and we need to recompute
+      /// transform-based data.
+      bool mTransformDirty;
+
+      /// World-space points of the volume's polyhedron.
+      Vector< Point3F > mWSPoints;
+
+      /// Silhouette extractor when using perspective projections.
+      SilhouetteExtractorType mSilhouetteExtractor;
+      
+      mutable Vector< SceneObject* > mVolumeQueryList;
+
+      // Name (path) of the accumulation texture.
+      String mTextureName;
+      
+      // SceneSpace.
+      virtual void _renderObject( ObjectRenderInst* ri, SceneRenderState* state, BaseMatInstance* overrideMat );
+
+   public:
+
+      GFXTexHandle mAccuTexture;
+
+      AccumulationVolume();
+      ~AccumulationVolume();
+
+      // SimObject.
+      DECLARE_CONOBJECT( AccumulationVolume );
+      DECLARE_DESCRIPTION( "Allows objects in an area to have accumulation effect applied." );
+      DECLARE_CATEGORY( "3D Scene" );
+
+      virtual bool onAdd();
+      virtual void onRemove();
+      void inspectPostApply();
+      void setTexture( const String& name );
+
+      // Static Functions.
+      static void consoleInit();
+      static void initPersistFields();
+      static Vector< SimObjectPtr<SceneObject> > smAccuObjects;
+      static Vector< SimObjectPtr<AccumulationVolume> > smAccuVolumes;
+      static void addObject(SimObjectPtr<SceneObject> object);
+      static void removeObject(SimObjectPtr<SceneObject> object);
+      static void refreshVolumes();
+      static bool _setTexture( void *object, const char *index, const char *data );
+      static void updateObject(SceneObject* object);
+
+      // Network
+      U32 packUpdate( NetConnection *, U32 mask, BitStream *stream );
+      void unpackUpdate( NetConnection *, BitStream *stream );
+
+      // SceneObject.
+      virtual void buildSilhouette( const SceneCameraState& cameraState, Vector< Point3F >& outPoints );
+      virtual void setTransform( const MatrixF& mat );
+};
+
+#endif // !_AccumulationVolume_H_

+ 25 - 0
Engine/source/T3D/tsStatic.cpp

@@ -48,6 +48,7 @@
 #include "materials/materialFeatureData.h"
 #include "materials/materialFeatureTypes.h"
 #include "console/engineAPI.h"
+#include "T3D/accumulationVolume.h"
 
 using namespace Torque;
 
@@ -293,6 +294,13 @@ bool TSStatic::onAdd()
 
    _updateShouldTick();
 
+   // Accumulation
+   if ( isClientObject() && mShapeInstance )
+   {
+      if ( mShapeInstance->hasAccumulation() ) 
+         AccumulationVolume::addObject(this);
+   }
+
    return true;
 }
 
@@ -403,6 +411,13 @@ void TSStatic::onRemove()
 {
    SAFE_DELETE( mPhysicsRep );
 
+   // Accumulation
+   if ( isClientObject() && mShapeInstance )
+   {
+      if ( mShapeInstance->hasAccumulation() ) 
+         AccumulationVolume::removeObject(this);
+   }
+
    mConvexList->nukeList();
 
    removeFromScene();
@@ -562,6 +577,9 @@ void TSStatic::prepRenderImage( SceneRenderState* state )
    rdata.setFadeOverride( 1.0f );
    rdata.setOriginSort( mUseOriginSort );
 
+   // Acculumation
+   rdata.setAccuTex(mAccuTex);
+
    // If we have submesh culling enabled then prepare
    // the object space frustum to pass to the shape.
    Frustum culler;
@@ -649,6 +667,13 @@ void TSStatic::setTransform(const MatrixF & mat)
    if ( mPhysicsRep )
       mPhysicsRep->setTransform( mat );
 
+   // Accumulation
+   if ( isClientObject() && mShapeInstance )
+   {
+      if ( mShapeInstance->hasAccumulation() ) 
+         AccumulationVolume::updateObject(this);
+   }
+
    // Since this is a static it's render transform changes 1
    // to 1 with it's collision transform... no interpolation.
    setRenderTransform(mat);

+ 74 - 1
Engine/source/lighting/advanced/glsl/advancedLightingFeaturesGLSL.cpp

@@ -330,6 +330,58 @@ void DeferredBumpFeatGLSL::processPix( Vector<ShaderComponent*> &componentList,
       output = meta;
       return;
    }
+
+   else if (fd.features[MFT_AccuMap])
+   {
+      Var *bumpSample = (Var *)LangElement::find("bumpSample");
+      if (bumpSample == NULL)
+      {
+         MultiLine *meta = new MultiLine;
+
+         Var *texCoord = getInTexCoord("texCoord", "vec2", true, componentList);
+
+         Var *bumpMap = getNormalMapTex();
+
+         bumpSample = new Var;
+         bumpSample->setType("vec4");
+         bumpSample->setName("bumpSample");
+         LangElement *bumpSampleDecl = new DecOp(bumpSample);
+
+         meta->addStatement(new GenOp("   @ = tex2D(@, @);\r\n", bumpSampleDecl, bumpMap, texCoord));
+
+         if (fd.features.hasFeature(MFT_DetailNormalMap))
+         {
+            Var *bumpMap = (Var*)LangElement::find("detailBumpMap");
+            if (!bumpMap) {
+               bumpMap = new Var;
+               bumpMap->setType("sampler2D");
+               bumpMap->setName("detailBumpMap");
+               bumpMap->uniform = true;
+               bumpMap->sampler = true;
+               bumpMap->constNum = Var::getTexUnitNum();
+            }
+
+            texCoord = getInTexCoord("detCoord", "vec2", true, componentList);
+            LangElement *texOp = new GenOp("tex2D(@, @)", bumpMap, texCoord);
+
+            Var *detailBump = new Var;
+            detailBump->setName("detailBump");
+            detailBump->setType("vec4");
+            meta->addStatement(expandNormalMap(texOp, new DecOp(detailBump), detailBump, fd));
+
+            Var *detailBumpScale = new Var;
+            detailBumpScale->setType("float");
+            detailBumpScale->setName("detailBumpStrength");
+            detailBumpScale->uniform = true;
+            detailBumpScale->constSortPos = cspPass;
+            meta->addStatement(new GenOp("   @.xy += @.xy * @;\r\n", bumpSample, detailBump, detailBumpScale));
+         }
+
+         output = meta;
+
+         return;
+      }
+   }
    else if (   fd.materialFeatures[MFT_NormalsOut] || 
                fd.features[MFT_ForwardShading] || 
                !fd.features[MFT_RTLighting] )
@@ -398,7 +450,20 @@ void DeferredBumpFeatGLSL::setTexData( Material::StageData &stageDat,
       return;
    }
 
-   if (  !fd.features[MFT_Parallax] && !fd.features[MFT_SpecularMap] &&
+   if (!fd.features[MFT_PrePassConditioner] && fd.features[MFT_AccuMap])
+   {
+      passData.mTexType[texIndex] = Material::Bump;
+      passData.mSamplerNames[texIndex] = "bumpMap";
+      passData.mTexSlot[texIndex++].texObject = stageDat.getTex(MFT_NormalMap);
+
+      if (fd.features.hasFeature(MFT_DetailNormalMap))
+      {
+         passData.mTexType[texIndex] = Material::DetailBump;
+         passData.mSamplerNames[texIndex] = "detailBumpMap";
+         passData.mTexSlot[texIndex++].texObject = stageDat.getTex(MFT_DetailNormalMap);
+      }
+   }
+   else if (!fd.features[MFT_Parallax] && !fd.features[MFT_SpecularMap] &&
          ( fd.features[MFT_PrePassConditioner] ||
            fd.features[MFT_PixSpecular] ) )
    {
@@ -481,6 +546,14 @@ void DeferredPixelSpecularGLSL::processPix(  Vector<ShaderComponent*> &component
    AssertFatal( lightInfoSamp && d_specular && d_NL_Att,
       "DeferredPixelSpecularGLSL::processPix - Something hosed the deferred features!" );
 
+   if (fd.features[MFT_AccuMap]) {
+      // change specularity where the accu texture is applied
+      Var *accuPlc = (Var*)LangElement::find("plc");
+      Var *accuSpecular = (Var*)LangElement::find("accuSpecular");
+      if (accuPlc != NULL && accuSpecular != NULL)
+         //d_specular = clamp(lerp( d_specular, accuSpecular * d_specular, plc.a), 0, 1)
+         meta->addStatement(new GenOp("   @ = clamp( lerp( @, @ * @, @.a), 0, 1);\r\n", d_specular, d_specular, accuSpecular, d_specular, accuPlc));
+   }
    // (a^m)^n = a^(m*n)
    meta->addStatement( new GenOp( "   @ = pow( abs(@), max((@ / AL_ConstantSpecularPower),1.0f)) * @;\r\n", 
       specDecl, d_specular, specPow, specStrength ) );

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

@@ -330,6 +330,57 @@ void DeferredBumpFeatHLSL::processPix( Vector<ShaderComponent*> &componentList,
       output = meta;
       return;
    }
+   else if (fd.features[MFT_AccuMap]) 
+   {
+      Var *bumpSample = (Var *)LangElement::find( "bumpSample" );
+      if( bumpSample == NULL )
+      {
+         MultiLine *meta = new MultiLine;
+
+         Var *texCoord = getInTexCoord( "texCoord", "float2", true, componentList );
+
+         Var *bumpMap = getNormalMapTex();
+
+         bumpSample = new Var;
+         bumpSample->setType( "float4" );
+         bumpSample->setName( "bumpSample" );
+         LangElement *bumpSampleDecl = new DecOp( bumpSample );
+
+         meta->addStatement( new GenOp( "   @ = tex2D(@, @);\r\n", bumpSampleDecl, bumpMap, texCoord ) );
+
+         if ( fd.features.hasFeature( MFT_DetailNormalMap ) )
+         {
+            Var *bumpMap = (Var*)LangElement::find( "detailBumpMap" );
+            if ( !bumpMap ) {
+               bumpMap = new Var;
+               bumpMap->setType( "sampler2D" );
+               bumpMap->setName( "detailBumpMap" );
+               bumpMap->uniform = true;
+               bumpMap->sampler = true;
+               bumpMap->constNum = Var::getTexUnitNum();
+            }
+
+            texCoord = getInTexCoord( "detCoord", "float2", true, componentList );
+            LangElement *texOp = new GenOp( "tex2D(@, @)", bumpMap, texCoord );
+
+            Var *detailBump = new Var;
+            detailBump->setName( "detailBump" );
+            detailBump->setType( "float4" );
+            meta->addStatement( expandNormalMap( texOp, new DecOp( detailBump ), detailBump, fd ) );
+
+            Var *detailBumpScale = new Var;
+            detailBumpScale->setType( "float" );
+            detailBumpScale->setName( "detailBumpStrength" );
+            detailBumpScale->uniform = true;
+            detailBumpScale->constSortPos = cspPass;
+            meta->addStatement( new GenOp( "   @.xy += @.xy * @;\r\n", bumpSample, detailBump, detailBumpScale ) );
+         }
+
+         output = meta;
+
+         return;
+      }
+   } 
    else if (   fd.materialFeatures[MFT_NormalsOut] || 
                fd.features[MFT_ForwardShading] || 
                !fd.features[MFT_RTLighting] )
@@ -398,7 +449,20 @@ void DeferredBumpFeatHLSL::setTexData( Material::StageData &stageDat,
       return;
    }
 
-   if (  !fd.features[MFT_Parallax] && !fd.features[MFT_SpecularMap] &&
+   if (  !fd.features[MFT_PrePassConditioner] && fd.features[MFT_AccuMap] )
+   {
+      passData.mTexType[ texIndex ] = Material::Bump;
+      passData.mSamplerNames[ texIndex ] = "bumpMap";
+      passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_NormalMap );
+
+      if (  fd.features.hasFeature( MFT_DetailNormalMap ) )
+      {
+         passData.mTexType[ texIndex ] = Material::DetailBump;
+         passData.mSamplerNames[texIndex] = "detailBumpMap";
+         passData.mTexSlot[ texIndex++ ].texObject = stageDat.getTex( MFT_DetailNormalMap );
+      }
+   }
+   else if (  !fd.features[MFT_Parallax] && !fd.features[MFT_SpecularMap] &&
          ( fd.features[MFT_PrePassConditioner] ||
            fd.features[MFT_PixSpecular] ) )
    {
@@ -481,6 +545,15 @@ void DeferredPixelSpecularHLSL::processPix(  Vector<ShaderComponent*> &component
    AssertFatal( lightInfoSamp && d_specular && d_NL_Att,
       "DeferredPixelSpecularHLSL::processPix - Something hosed the deferred features!" );
 
+   if (fd.features[ MFT_AccuMap ]) {
+      // change specularity where the accu texture is applied
+      Var *accuPlc = (Var*) LangElement::find( "plc" );
+      Var *accuSpecular = (Var*)LangElement::find( "accuSpecular" );
+      if(accuPlc != NULL && accuSpecular != NULL)
+         //d_specular = clamp(lerp( d_specular, accuSpecular * d_specular, plc.a), 0, 1)
+         meta->addStatement( new GenOp( "   @ = clamp( lerp( @, @ * @, @.a), 0, 1);\r\n", d_specular, d_specular, accuSpecular, d_specular, accuPlc ) );
+   }
+	  
    // (a^m)^n = a^(m*n)
    meta->addStatement( new GenOp( "   @ = pow( abs(@), max((@ / AL_ConstantSpecularPower),1.0f)) * @;\r\n", 
       specDecl, d_specular, specPow, specStrength ) );

+ 1 - 0
Engine/source/materials/baseMatInstance.h

@@ -185,6 +185,7 @@ public:
 
    // BTRTODO: This stuff below should probably not be in BaseMatInstance
    virtual bool hasGlow() = 0;
+   virtual bool hasAccumulation() = 0;
    
    virtual U32 getCurPass() = 0;
 

+ 8 - 0
Engine/source/materials/matInstance.cpp

@@ -497,6 +497,14 @@ bool MatInstance::hasGlow()
       return false;
 }
 
+bool MatInstance::hasAccumulation() 
+{ 
+   if( mProcessedMaterial )
+      return mProcessedMaterial->hasAccumulation(); 
+   else
+      return false;
+}
+
 const FeatureSet& MatInstance::getFeatures() const 
 {
    return mProcessedMaterial->getFeatures(); 

+ 1 - 0
Engine/source/materials/matInstance.h

@@ -75,6 +75,7 @@ public:
    virtual SimObject* getUserObject() const { return mUserObject; }
    virtual Material *getMaterial() { return mMaterial; }
    virtual bool hasGlow();
+   virtual bool hasAccumulation();
    virtual U32 getCurPass() { return getMax( mCurPass, 0 ); }
    virtual U32 getCurStageNum();
    virtual RenderPassData *getPass(U32 pass);   

+ 40 - 0
Engine/source/materials/materialDefinition.cpp

@@ -34,6 +34,7 @@
 #include "sfx/sfxTrack.h"
 #include "sfx/sfxTypes.h"
 #include "core/util/safeDelete.h"
+#include "T3D/accumulationVolume.h"
 
 
 IMPLEMENT_CONOBJECT( Material );
@@ -119,6 +120,13 @@ Material::Material()
       mSpecularStrength[i] = 1.0f;
       mPixelSpecular[i] = false;
 
+      mAccuEnabled[i]   = false;
+      mAccuScale[i]     = 1.0f;
+      mAccuDirection[i] = 1.0f;
+      mAccuStrength[i]  = 0.6f;
+      mAccuCoverage[i]  = 0.9f;
+      mAccuSpecular[i]  = 16.0f;
+	  
       mParallaxScale[i] = 0.0f;
 
       mVertLit[i] = false;
@@ -250,6 +258,24 @@ void Material::initPersistFields()
          "normal map texture.  Note that if pixel specular is enabled the DXTnm format will not "
          "work with your normal map, unless you are also using a specular map." );
 
+      addProtectedField( "accuEnabled", TYPEID< bool >(), Offset( mAccuEnabled, Material ),
+            &_setAccuEnabled, &defaultProtectedGetFn, MAX_STAGES, "Accumulation texture." );
+
+      addField("accuScale",      TypeF32, Offset(mAccuScale, Material), MAX_STAGES,
+         "The scale that is applied to the accu map texture. You can use this to fit the texture to smaller or larger objects.");
+		 
+      addField("accuDirection",  TypeF32, Offset(mAccuDirection, Material), MAX_STAGES,
+         "The direction of the accumulation. Chose whether you want the accu map to go from top to bottom (ie. snow) or upwards (ie. mold).");
+		 
+      addField("accuStrength",   TypeF32, Offset(mAccuStrength, Material), MAX_STAGES,
+         "The strength of the accu map. This changes the transparency of the accu map texture. Make it subtle or add more contrast.");
+		 
+      addField("accuCoverage",   TypeF32, Offset(mAccuCoverage, Material), MAX_STAGES,
+         "The coverage ratio of the accu map texture. Use this to make the entire shape pick up some of the accu map texture or none at all.");
+		 
+      addField("accuSpecular",   TypeF32, Offset(mAccuSpecular, Material), MAX_STAGES,
+         "Changes specularity to this value where the accumulated material is present.");
+
       addField( "specularMap", TypeImageFilename, Offset(mSpecularMapFilename, Material), MAX_STAGES,
          "The specular map texture. The RGB channels of this texture provide a per-pixel replacement for the 'specular' parameter on the material. "
          "If this texture contains alpha information, the alpha channel of the texture will be used as the gloss map. "
@@ -669,4 +695,18 @@ ConsoleMethod( Material, setAutoGenerated, void, 3, 3,
               "setAutoGenerated(bool isAutoGenerated): Set whether or not the Material is autogenerated." )
 {
    object->setAutoGenerated(dAtob(argv[2]));
+}
+
+// Accumulation
+bool Material::_setAccuEnabled( void *object, const char *index, const char *data )
+{
+   Material* mat = reinterpret_cast< Material* >( object );
+
+   if ( index )
+   {
+      U32 i = dAtoui(index);
+      mat->mAccuEnabled[i] = dAtob(data);
+      AccumulationVolume::refreshVolumes();
+   }
+   return true;
 }

+ 10 - 0
Engine/source/materials/materialDefinition.h

@@ -88,6 +88,7 @@ public:
       DynamicLightMask,
       NormalizeCube,
       TexTarget,
+      AccuMap,
    };
 
    enum BlendOp
@@ -198,6 +199,12 @@ public:
    // Data
    //-----------------------------------------------------------------------
    FileName mDiffuseMapFilename[MAX_STAGES];
+   bool     mAccuEnabled[MAX_STAGES];
+   F32      mAccuScale[MAX_STAGES];
+   F32      mAccuDirection[MAX_STAGES];
+   F32      mAccuStrength[MAX_STAGES];
+   F32      mAccuCoverage[MAX_STAGES];
+   F32      mAccuSpecular[MAX_STAGES];
    FileName mOverlayMapFilename[MAX_STAGES];
    FileName mLightMapFilename[MAX_STAGES];
    FileName mToneMapFilename[MAX_STAGES];
@@ -371,6 +378,9 @@ public:
    //
    static void initPersistFields();
 
+   // Accumulation
+   static bool _setAccuEnabled( void *object, const char *index, const char *data );
+
    DECLARE_CONOBJECT(Material);
 protected:
 

+ 8 - 0
Engine/source/materials/materialFeatureTypes.cpp

@@ -32,6 +32,12 @@ ImplementFeatureType( MFT_TexAnim, MFG_PreTexture, 1.0f, true );
 ImplementFeatureType( MFT_Parallax, MFG_PreTexture, 2.0f, true );
 ImplementFeatureType( MFT_DiffuseVertColor, MFG_PreTexture, 3.0f, true );
 
+ImplementFeatureType( MFT_AccuScale, MFG_PreTexture, 4.0f, true );
+ImplementFeatureType( MFT_AccuDirection, MFG_PreTexture, 4.0f, true );
+ImplementFeatureType( MFT_AccuStrength, MFG_PreTexture, 4.0f, true );
+ImplementFeatureType( MFT_AccuCoverage, MFG_PreTexture, 4.0f, true );
+ImplementFeatureType( MFT_AccuSpecular, MFG_PreTexture, 4.0f, true );
+
 ImplementFeatureType( MFT_DiffuseMap, MFG_Texture, 2.0f, true );
 ImplementFeatureType( MFT_OverlayMap, MFG_Texture, 3.0f, true );
 ImplementFeatureType( MFT_DetailMap, MFG_Texture, 4.0f, true );
@@ -41,6 +47,8 @@ ImplementFeatureType( MFT_SpecularMap, MFG_Texture, 8.0f, true );
 ImplementFeatureType( MFT_NormalMap, MFG_Texture, 9.0f, true );
 ImplementFeatureType( MFT_DetailNormalMap, MFG_Texture, 10.0f, true );
 
+ImplementFeatureType( MFT_AccuMap, MFG_PreLighting, 2.0f, true );
+
 ImplementFeatureType( MFT_RTLighting, MFG_Lighting, 2.0f, true );
 ImplementFeatureType( MFT_SubSurface, MFG_Lighting, 3.0f, true );
 ImplementFeatureType( MFT_LightMap, MFG_Lighting, 4.0f, true );

+ 7 - 0
Engine/source/materials/materialFeatureTypes.h

@@ -95,6 +95,13 @@ DeclareFeatureType( MFT_DetailMap );
 DeclareFeatureType( MFT_DiffuseColor );
 DeclareFeatureType( MFT_DetailNormalMap );
 
+DeclareFeatureType( MFT_AccuMap );
+DeclareFeatureType( MFT_AccuScale );
+DeclareFeatureType( MFT_AccuDirection );
+DeclareFeatureType( MFT_AccuStrength );
+DeclareFeatureType( MFT_AccuCoverage );
+DeclareFeatureType( MFT_AccuSpecular );
+
 /// This feature enables vertex coloring for the diffuse channel.
 DeclareFeatureType( MFT_DiffuseVertColor );
 

+ 1 - 0
Engine/source/materials/processedCustomMaterial.cpp

@@ -49,6 +49,7 @@ ProcessedCustomMaterial::ProcessedCustomMaterial(Material &mat)
    mCustomMaterial = static_cast<CustomMaterial*>(mMaterial);
    mHasSetStageData = false;
    mHasGlow = false;
+   mHasAccumulation = false;
    mMaxStages = 0;
    mMaxTex = 0;
 }

+ 1 - 0
Engine/source/materials/processedFFMaterial.cpp

@@ -67,6 +67,7 @@ void ProcessedFFMaterial::_construct()
 {   
    mHasSetStageData = false;
    mHasGlow = false;
+   mHasAccumulation = false;
    mIsLightingMaterial = false;
    mDefaultHandle = new FFMaterialParameterHandle();
    mDefaultParameters = new MaterialParameters();

+ 1 - 0
Engine/source/materials/processedMaterial.cpp

@@ -93,6 +93,7 @@ ProcessedMaterial::ProcessedMaterial()
    mCurrentParams( NULL ),
    mHasSetStageData( false ),
    mHasGlow( false ),   
+   mHasAccumulation( false ),   
    mMaxStages( 0 ),
    mVertexFormat( NULL ),
    mUserObject( NULL )

+ 6 - 0
Engine/source/materials/processedMaterial.h

@@ -197,6 +197,9 @@ public:
    /// Returns true if any pass glows
    bool hasGlow() const { return mHasGlow; }
 
+   /// Returns true if any pass accumulates
+   bool hasAccumulation() const { return mHasAccumulation; }
+
    /// Gets the stage number for a pass
    U32 getStageFromPass(U32 pass) const
    {
@@ -244,6 +247,9 @@ protected:
    /// If we glow
    bool mHasGlow;
 
+   /// If we have accumulation.
+   bool mHasAccumulation;
+
    /// Number of stages (not to be confused with number of passes)
    U32 mMaxStages;
 

+ 51 - 0
Engine/source/materials/processedShaderMaterial.cpp

@@ -55,6 +55,11 @@ void ShaderConstHandles::init( GFXShader *shader, CustomMaterial* mat /*=NULL*/
    mSpecularColorSC = shader->getShaderConstHandle(ShaderGenVars::specularColor);
    mSpecularPowerSC = shader->getShaderConstHandle(ShaderGenVars::specularPower);
    mSpecularStrengthSC = shader->getShaderConstHandle(ShaderGenVars::specularStrength);
+   mAccuScaleSC = shader->getShaderConstHandle("$accuScale");
+   mAccuDirectionSC = shader->getShaderConstHandle("$accuDirection");
+   mAccuStrengthSC = shader->getShaderConstHandle("$accuStrength");
+   mAccuCoverageSC = shader->getShaderConstHandle("$accuCoverage");
+   mAccuSpecularSC = shader->getShaderConstHandle("$accuSpecular");
    mParallaxInfoSC = shader->getShaderConstHandle("$parallaxInfo");
    mFogDataSC = shader->getShaderConstHandle(ShaderGenVars::fogData);
    mFogColorSC = shader->getShaderConstHandle(ShaderGenVars::fogColor);
@@ -423,6 +428,34 @@ void ProcessedShaderMaterial::_determineFeatures(  U32 stageNum,
          fd.features.addFeature( MFT_GlossMap );
    }
 
+   if ( mMaterial->mAccuEnabled[stageNum] )
+   {
+      fd.features.addFeature( MFT_AccuMap );
+      mHasAccumulation = true;
+   }
+
+   // we need both diffuse and normal maps + sm3 to have an accu map
+   if(   fd.features[ MFT_AccuMap ] && 
+       ( !fd.features[ MFT_DiffuseMap ] || 
+         !fd.features[ MFT_NormalMap ] ||
+         GFX->getPixelShaderVersion() < 3.0f ) ) {
+      AssertWarn(false, "SAHARA: Using an Accu Map requires SM 3.0 and a normal map.");
+      fd.features.removeFeature( MFT_AccuMap );
+      mHasAccumulation = false;
+   }
+
+   // if we still have the AccuMap feature, we add all accu constant features
+   if ( fd.features[ MFT_AccuMap ] ) {
+      // add the dependencies of the accu map
+      fd.features.addFeature( MFT_AccuScale );
+      fd.features.addFeature( MFT_AccuDirection );
+      fd.features.addFeature( MFT_AccuStrength );
+      fd.features.addFeature( MFT_AccuCoverage );
+      fd.features.addFeature( MFT_AccuSpecular );
+      // now remove some features that are not compatible with this
+      fd.features.removeFeature( MFT_UseInstancing );
+   }
+
    // Without a base texture use the diffuse color
    // feature to ensure some sort of output.
    if (!fd.features[MFT_DiffuseMap])
@@ -809,6 +842,13 @@ void ProcessedShaderMaterial::setTextureStages( SceneRenderState *state, const S
          case Material::BackBuff:
             GFX->setTexture( i, sgData.backBuffTex );
             break;
+
+         case Material::AccuMap:
+            if ( sgData.accuTex )
+               GFX->setTexture( i, sgData.accuTex );
+            else
+               GFX->setTexture( i, GFXTexHandle::ZERO );
+            break;
             
          case Material::TexTarget:
             {
@@ -1137,6 +1177,17 @@ void ProcessedShaderMaterial::_setShaderConstants(SceneRenderState * state, cons
          0.0f, 0.0f ); // TODO: Wrap mode flags?
       shaderConsts->setSafe(handles->mBumpAtlasTileSC, atlasTileParams);
    }
+   
+   if( handles->mAccuScaleSC->isValid() )
+      shaderConsts->set( handles->mAccuScaleSC, mMaterial->mAccuScale[stageNum] );
+   if( handles->mAccuDirectionSC->isValid() )
+      shaderConsts->set( handles->mAccuDirectionSC, mMaterial->mAccuDirection[stageNum] );
+   if( handles->mAccuStrengthSC->isValid() )
+      shaderConsts->set( handles->mAccuStrengthSC, mMaterial->mAccuStrength[stageNum] );
+   if( handles->mAccuCoverageSC->isValid() )
+      shaderConsts->set( handles->mAccuCoverageSC, mMaterial->mAccuCoverage[stageNum] );
+   if( handles->mAccuSpecularSC->isValid() )
+      shaderConsts->set( handles->mAccuSpecularSC, mMaterial->mAccuSpecular[stageNum] );
 }
 
 bool ProcessedShaderMaterial::_hasCubemap(U32 pass)

+ 5 - 0
Engine/source/materials/processedShaderMaterial.h

@@ -48,6 +48,11 @@ public:
    GFXShaderConstHandle* mSpecularPowerSC;
    GFXShaderConstHandle* mSpecularStrengthSC;
    GFXShaderConstHandle* mParallaxInfoSC;
+   GFXShaderConstHandle* mAccuScaleSC;
+   GFXShaderConstHandle* mAccuDirectionSC;
+   GFXShaderConstHandle* mAccuStrengthSC;
+   GFXShaderConstHandle* mAccuCoverageSC;
+   GFXShaderConstHandle* mAccuSpecularSC;
    GFXShaderConstHandle* mFogDataSC;
    GFXShaderConstHandle* mFogColorSC;   
    GFXShaderConstHandle* mDetailScaleSC;

+ 1 - 0
Engine/source/materials/sceneData.h

@@ -64,6 +64,7 @@ struct SceneData
    GFXTextureObject *backBuffTex;
    GFXTextureObject *reflectTex;
    GFXTextureObject *miscTex;
+   GFXTextureObject *accuTex;
    
    /// The current lights to use in rendering
    /// in order of the light importance.

+ 1 - 0
Engine/source/renderInstance/renderBinManager.cpp

@@ -164,6 +164,7 @@ void RenderBinManager::setupSGData( MeshRenderInst *ri, SceneData &data )
    data.cubemap      = ri->cubemap;
    data.miscTex      = ri->miscTex;
    data.reflectTex   = ri->reflectTex;
+   data.accuTex      = ri->accuTex;
    data.lightmap     = ri->lightmap;
    data.visibility   = ri->visibility;
    data.materialHint = ri->materialHint;

+ 10 - 0
Engine/source/renderInstance/renderMeshMgr.cpp

@@ -115,6 +115,7 @@ void RenderMeshMgr::render(SceneRenderState * state)
    GFXCubemap *lastCubemap = NULL;
    GFXTextureObject *lastReflectTex = NULL;
    GFXTextureObject *lastMiscTex = NULL;
+   GFXTextureObject *lastAccuTex = NULL;
 
    SceneData sgData;
    sgData.init( state );
@@ -225,6 +226,15 @@ void RenderMeshMgr::render(SceneRenderState * state)
                dirty = true;
             }
 
+            // Update accumulation texture if it changed.
+            // Note: accumulation texture can be NULL, and must be updated.
+            if ( passRI->accuTex != lastAccuTex )
+            {
+               sgData.accuTex = passRI->accuTex;
+               lastAccuTex = lastAccuTex;
+               dirty = true;
+            }
+
             if ( dirty )
                mat->setTextureStages( state, sgData );
 

+ 1 - 0
Engine/source/renderInstance/renderPassManager.h

@@ -366,6 +366,7 @@ struct MeshRenderInst : public RenderInst
    GFXTextureObject *backBuffTex;
    GFXTextureObject *reflectTex;
    GFXTextureObject *miscTex;
+   GFXTextureObject *accuTex;
    GFXCubemap   *cubemap;
 
    void clear();

+ 4 - 0
Engine/source/scene/sceneObject.cpp

@@ -43,6 +43,7 @@
 #include "math/mTransform.h"
 #include "T3D/gameBase/gameProcess.h"
 #include "T3D/gameBase/gameConnection.h"
+#include "T3D/accumulationVolume.h"
 
 IMPLEMENT_CONOBJECT(SceneObject);
 
@@ -141,6 +142,8 @@ SceneObject::SceneObject()
 
    mObjectFlags.set( RenderEnabledFlag | SelectionEnabledFlag );
    mIsScopeAlways = false;
+
+   mAccuTex = NULL;
 }
 
 //-----------------------------------------------------------------------------
@@ -152,6 +155,7 @@ SceneObject::~SceneObject()
    AssertFatal( !mSceneObjectLinks,
       "SceneObject::~SceneObject() - object is still linked to SceneTrackers" );
 
+   mAccuTex = NULL;
    unlink();
 }
 

+ 10 - 0
Engine/source/scene/sceneObject.h

@@ -51,6 +51,10 @@
 #include "scene/sceneContainer.h"
 #endif
 
+#ifndef _GFXDEVICE_H_
+#include "gfx/gfxDevice.h"
+#endif
+
 
 class SceneManager;
 class SceneRenderState;
@@ -765,8 +769,14 @@ class SceneObject : public NetObject, private SceneContainer::Link, public Proce
       static bool _setFieldRotation( void *object, const char *index, const char *data );
       static bool _setFieldScale( void *object, const char *index, const char *data );
       static bool _setMountPID( void* object, const char* index, const char* data );
+      static bool _setAccuEnabled( void *object, const char *index, const char *data );
 
       /// @}
+
+   // Accumulation Texture
+   // Note: This was placed in SceneObject to both ShapeBase and TSStatic could support it.
+   public:
+      GFXTextureObject* mAccuTex;
 };
 
 #endif  // _SCENEOBJECT_H_

+ 241 - 0
Engine/source/shaderGen/GLSL/accuFeatureGLSL.cpp

@@ -0,0 +1,241 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "shaderGen/GLSL/accuFeatureGLSL.h"
+#include "shaderGen/shaderFeature.h"
+#include "shaderGen/shaderOp.h"
+#include "shaderGen/featureMgr.h"
+#include "materials/materialFeatureTypes.h"
+#include "gfx/gfxDevice.h"
+#include "materials/processedMaterial.h"
+
+//****************************************************************************
+// Accu Texture
+//****************************************************************************
+void AccuTexFeatGLSL::processVert(Vector<ShaderComponent*> &componentList,
+                                    const MaterialFeatureData &fd )
+{
+   MultiLine *meta = new MultiLine;
+   getOutTexCoord(   "texCoord", 
+                     "vec2", 
+                     true, 
+                     false, 
+                     meta, 
+                     componentList );
+   
+   getOutObjToTangentSpace( componentList, meta, fd );
+   addOutAccuVec( componentList, meta );
+
+   output = meta;
+}
+
+void AccuTexFeatGLSL::processPix(Vector<ShaderComponent*> &componentList,
+                                    const MaterialFeatureData &fd )
+{
+   MultiLine *meta = new MultiLine;
+
+   output = meta;
+
+   // OUT.col
+   Var *color = (Var*) LangElement::find( "col" );
+   if (!color)
+   {
+      output = new GenOp("   //NULL COLOR!");
+      return;
+   }
+
+   // accu map
+   Var *accuMap = new Var;
+   accuMap->setType( "sampler2D" );
+   accuMap->setName( "accuMap" );
+   accuMap->uniform = true;
+   accuMap->sampler = true;
+   accuMap->constNum = Var::getTexUnitNum();     // used as texture unit num here
+
+   // accuColor var
+   Var *accuColor = new Var;
+   accuColor->setType( "vec4" );
+   accuColor->setName( "accuColor" );
+   LangElement *colorAccuDecl = new DecOp( accuColor );
+
+   // plc (placement)
+   Var *accuPlc = new Var;
+   accuPlc->setType( "vec4" );
+   accuPlc->setName( "plc" );
+   LangElement *plcAccu = new DecOp( accuPlc );
+
+   // accu constants
+   Var *accuScale = (Var*)LangElement::find( "accuScale" );
+   if ( !accuScale ) {
+      accuScale = new Var;
+      accuScale->setType( "float" );
+      accuScale->setName( "accuScale" );
+      accuScale->uniform = true;
+      accuScale->sampler = false;
+      accuScale->constSortPos = cspPotentialPrimitive;
+   }
+   Var *accuDirection = (Var*)LangElement::find( "accuDirection" );
+   if ( !accuDirection ) {
+      accuDirection = new Var;
+      accuDirection->setType( "float" );
+      accuDirection->setName( "accuDirection" );
+      accuDirection->uniform = true;
+      accuDirection->sampler = false;
+      accuDirection->constSortPos = cspPotentialPrimitive;
+   }
+   Var *accuStrength = (Var*)LangElement::find( "accuStrength" );
+   if ( !accuStrength ) {
+      accuStrength = new Var;
+      accuStrength->setType( "float" );
+      accuStrength->setName( "accuStrength" );
+      accuStrength->uniform = true;
+      accuStrength->sampler = false;
+      accuStrength->constSortPos = cspPotentialPrimitive;
+   }
+   Var *accuCoverage = (Var*)LangElement::find( "accuCoverage" );
+   if ( !accuCoverage ) {
+      accuCoverage = new Var;
+      accuCoverage->setType( "float" );
+      accuCoverage->setName( "accuCoverage" );
+      accuCoverage->uniform = true;
+      accuCoverage->sampler = false;
+      accuCoverage->constSortPos = cspPotentialPrimitive;
+   }
+   Var *accuSpecular = (Var*)LangElement::find( "accuSpecular" );
+   if ( !accuSpecular ) {
+      accuSpecular = new Var;
+      accuSpecular->setType( "float" );
+      accuSpecular->setName( "accuSpecular" );
+      accuSpecular->uniform = true;
+      accuSpecular->sampler = false;
+      accuSpecular->constSortPos = cspPotentialPrimitive;
+   }
+
+   Var *inTex = getInTexCoord( "texCoord", "vec2", true, componentList );
+   Var *accuVec = getInTexCoord( "accuVec", "vec3", true, componentList );
+   Var *bumpNorm = (Var *)LangElement::find( "bumpSample" );
+   if( bumpNorm == NULL ) {
+      bumpNorm = (Var *)LangElement::find( "bumpNormal" );
+      if (!bumpNorm)
+      {
+         output = new GenOp("   //NULL bumpNormal!");
+         return;
+      }
+   }
+
+   // get the accu pixel color
+   meta->addStatement( new GenOp( "   @ = tex2D(@, @ * @);\r\n", colorAccuDecl, accuMap, inTex, accuScale ) );
+
+   // scale up normals
+   meta->addStatement( new GenOp( "   @.xyz = @.xyz * 2.0 - 0.5;\r\n", bumpNorm, bumpNorm ) );
+
+   // assign direction
+   meta->addStatement( new GenOp( "   @.z *= @*2.0;\r\n", accuVec, accuDirection ) );
+
+   // saturate based on strength
+   meta->addStatement( new GenOp( "   @ = saturate( float4(dot( float3(@), @.xyz * pow(@, 5) ) ));\r\n", plcAccu, bumpNorm, accuVec, accuStrength ) );
+
+   // add coverage
+   meta->addStatement( new GenOp( "   @.a += (2 * pow(@/2, 5)) - 0.5;\r\n", accuPlc, accuCoverage ) );
+
+   // clamp to a sensible value
+   meta->addStatement( new GenOp( "   @.a = clamp(@.a, 0, 1);\r\n", accuPlc, accuPlc ) );
+
+   // light
+   Var *lightColor = (Var*) LangElement::find( "d_lightcolor" );
+   if(lightColor != NULL)
+      meta->addStatement( new GenOp( "   @ *= float4(@, 1.0);\r\n\r\n", accuColor, lightColor ) );
+
+   // lerp with current pixel - use the accu alpha as well
+   meta->addStatement( new GenOp( "   @ = mix( @, @, @.a * @.a);\r\n", color, color, accuColor, accuPlc, accuColor ) );
+
+   // the result should always be opaque
+   meta->addStatement( new GenOp( "   @.a = 1.0;\r\n", color ) );
+}
+
+void AccuTexFeatGLSL::setTexData(Material::StageData &stageDat,
+                                    const MaterialFeatureData &fd,
+                                    RenderPassData &passData,
+                                    U32 &texIndex )
+{
+   //GFXTextureObject *tex = stageDat.getTex( MFT_AccuMap );
+   //if ( tex )
+   //{
+   passData.mSamplerNames[texIndex] = "accuMap";
+   passData.mTexType[ texIndex++ ] = Material::AccuMap;
+      //passData.mTexSlot[ texIndex++ ].texObject = tex;
+   //}
+}
+
+
+void AccuTexFeatGLSL::getAccuVec(MultiLine *meta, LangElement *accuVec)
+{
+   // Get the transform to world space.
+   Var *objTrans = (Var*)LangElement::find( "objTrans" );
+   if ( !objTrans )
+   {
+      objTrans = new Var;
+      objTrans->setType( "float4x4" );
+      objTrans->setName( "objTrans" );
+      objTrans->uniform = true;
+      objTrans->constSortPos = cspPrimitive;      
+   }
+
+   // accu obj trans
+   Var *aobjTrans = new Var;
+   aobjTrans->setType( "float4x4" );
+   aobjTrans->setName( "accuObjTrans" );
+   LangElement *accuObjTransDecl = new DecOp( aobjTrans );
+
+   Var *outObjToTangentSpace = (Var*)LangElement::find( "objToTangentSpace" );
+
+   Var *tav = new Var;
+   tav->setType( "float4" );
+   tav->setName( "tAccuVec" );
+   LangElement *tavDecl = new DecOp( tav );
+
+   meta->addStatement( new GenOp( "   @ = float4(0,0,1,0);\r\n", tavDecl ) );
+   meta->addStatement( new GenOp( "   @ = transpose(@);\r\n", accuObjTransDecl, objTrans ) );
+   meta->addStatement( new GenOp( "   @ = tMul(@, @);\r\n", tav, aobjTrans, tav ) );
+   meta->addStatement( new GenOp( "   @.xyz = tMul(@, @.xyz);\r\n", tav, outObjToTangentSpace, tav ) );
+   meta->addStatement( new GenOp( "   @.y *= -1;\r\n", tav ) );
+   meta->addStatement( new GenOp( "   @ = @.xyz;\r\n", accuVec, tav ) );
+}
+
+Var* AccuTexFeatGLSL::addOutAccuVec(Vector<ShaderComponent*> &componentList, MultiLine *meta)
+{
+   Var *outAccuVec = (Var*)LangElement::find( "accuVec" );
+   if ( !outAccuVec )
+   {
+      // Setup the connector.
+      ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
+      outAccuVec = connectComp->getElement( RT_TEXCOORD );
+      outAccuVec->setName( "accuVec" );
+      outAccuVec->setStructName( "OUT" );
+      outAccuVec->setType( "float3" );
+      outAccuVec->mapsToSampler = false;
+
+      getAccuVec( meta, outAccuVec );
+   }
+
+   return outAccuVec;
+}

+ 185 - 0
Engine/source/shaderGen/GLSL/accuFeatureGLSL.h

@@ -0,0 +1,185 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ACCUFEATUREGLSL_H_
+#define _ACCUFEATUREGLSL_H_
+
+#ifndef _SHADERGEN_GLSL_SHADERFEATUREGLSL_H_
+#include "shaderGen/GLSL/shaderFeatureGLSL.h"
+#endif
+#ifndef _LANG_ELEMENT_H_
+#include "shaderGen/langElement.h"
+#endif
+#ifndef _GFXDEVICE_H_
+#include "gfx/gfxDevice.h"
+#endif
+#ifndef _FEATUREMGR_H_
+#include "shaderGen/featureMgr.h"
+#endif
+#ifndef _MATERIALFEATURETYPES_H_
+#include "materials/materialFeatureTypes.h"
+#endif
+#ifndef _MATERIALFEATUREDATA_H_
+#include "materials/materialFeatureData.h"
+#endif
+
+/// Accu texture
+class AccuTexFeatGLSL : public ShaderFeatureGLSL
+{
+public:
+
+   //****************************************************************************
+   // Accu Texture
+   //****************************************************************************
+   virtual void processVert(  Vector<ShaderComponent*> &componentList, 
+                              const MaterialFeatureData &fd );
+
+   virtual void processPix(   Vector<ShaderComponent*> &componentList, 
+                              const MaterialFeatureData &fd );
+
+   void getAccuVec( MultiLine *meta, LangElement *accuVec );
+
+   Var* addOutAccuVec( Vector<ShaderComponent*> &componentList, MultiLine *meta );
+
+   virtual Material::BlendOp getBlendOp(){ return Material::LerpAlpha; }
+
+   virtual Resources getResources( const MaterialFeatureData &fd )
+   {
+      Resources res; 
+      res.numTex = 1;
+      res.numTexReg = 1;
+      return res;
+   }
+
+   virtual void setTexData(   Material::StageData &stageDat,
+                              const MaterialFeatureData &fd,
+                              RenderPassData &passData,
+                              U32 &texIndex );
+
+   virtual String getName()
+   {
+      return "Accu Texture";
+   }
+};
+
+class AccuScaleFeature : public ShaderFeatureGLSL
+{
+public:
+   virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+   {
+      // Find the constant value
+      Var *accuScale = (Var *)( LangElement::find("accuScale") );
+      if( accuScale == NULL )
+      {
+         accuScale = new Var;
+         accuScale->setType( "float" );
+         accuScale->setName( "accuScale" );
+         accuScale->constSortPos = cspPotentialPrimitive;
+         accuScale->uniform = true;
+      }
+   }
+
+   virtual String getName() { return "Accu Scale"; }
+};
+
+class AccuDirectionFeature : public ShaderFeatureGLSL
+{
+public:
+   virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+   {
+      // Find the constant value
+      Var *accuDirection = (Var *)( LangElement::find("accuDirection") );
+      if( accuDirection == NULL )
+      {
+         accuDirection = new Var;
+         accuDirection->setType( "float" );
+         accuDirection->setName( "accuDirection" );
+         accuDirection->constSortPos = cspPotentialPrimitive;
+         accuDirection->uniform = true;
+      }
+   }
+
+   virtual String getName() { return "Accu Direction"; }
+};
+
+class AccuStrengthFeature : public ShaderFeatureGLSL
+{
+public:
+   virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+   {
+      // Find the constant value
+      Var *accuStrength = (Var *)( LangElement::find("accuStrength") );
+      if( accuStrength == NULL )
+      {
+         accuStrength = new Var;
+         accuStrength->setType( "float" );
+         accuStrength->setName( "accuStrength" );
+         accuStrength->constSortPos = cspPotentialPrimitive;
+         accuStrength->uniform = true;
+      }
+   }
+
+   virtual String getName() { return "Accu Strength"; }
+};
+
+class AccuCoverageFeature : public ShaderFeatureGLSL
+{
+public:
+   virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+   {
+      // Find the constant value
+      Var *accuCoverage = (Var *)( LangElement::find("accuCoverage") );
+      if( accuCoverage == NULL )
+      {
+         accuCoverage = new Var;
+         accuCoverage->setType( "float" );
+         accuCoverage->setName( "accuCoverage" );
+         accuCoverage->constSortPos = cspPotentialPrimitive;
+         accuCoverage->uniform = true;
+      }
+   }
+
+   virtual String getName() { return "Accu Coverage"; }
+};
+
+
+class AccuSpecularFeature : public ShaderFeatureGLSL
+{
+public:
+   virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+   {
+      // Find the constant value
+      Var *accuSpecular = (Var *)( LangElement::find("accuSpecular") );
+      if( accuSpecular == NULL )
+      {
+         accuSpecular = new Var;
+         accuSpecular->setType( "float" );
+         accuSpecular->setName( "accuSpecular" );
+         accuSpecular->constSortPos = cspPotentialPrimitive;
+         accuSpecular->uniform = true;
+      }
+   }
+
+   virtual String getName() { return "Accu Specular"; }
+};
+
+#endif

+ 2 - 0
Engine/source/shaderGen/GLSL/shaderGenGLSLInit.cpp

@@ -32,6 +32,7 @@
 #include "shaderGen/GLSL/paraboloidGLSL.h"
 #include "materials/materialFeatureTypes.h"
 #include "core/module.h"
+#include "shaderGen/GLSL/accuFeatureGLSL.h"
 
 
 static ShaderGen::ShaderGenInitDelegate sInitDelegate;
@@ -62,6 +63,7 @@ void _initShaderGenGLSL( ShaderGen *shaderGen )
    FEATUREMGR->registerFeature( MFT_CubeMap, new ReflectCubeFeatGLSL );
    FEATUREMGR->registerFeature( MFT_PixSpecular, new PixelSpecularGLSL );
    FEATUREMGR->registerFeature( MFT_SpecularMap, new SpecularMapGLSL );
+   FEATUREMGR->registerFeature( MFT_AccuMap, new AccuTexFeatGLSL );
    FEATUREMGR->registerFeature( MFT_GlossMap, new NamedFeatureGLSL( "Gloss Map" ) );
    FEATUREMGR->registerFeature( MFT_IsTranslucent, new NamedFeatureGLSL( "Translucent" ) );
    FEATUREMGR->registerFeature( MFT_Visibility, new VisibilityFeatGLSL );

+ 238 - 0
Engine/source/shaderGen/HLSL/accuFeatureHLSL.cpp

@@ -0,0 +1,238 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "shaderGen/HLSL/accuFeatureHLSL.h"
+#include "shaderGen/shaderFeature.h"
+#include "shaderGen/shaderOp.h"
+#include "shaderGen/featureMgr.h"
+#include "materials/materialFeatureTypes.h"
+#include "gfx/gfxDevice.h"
+#include "materials/processedMaterial.h"
+
+//****************************************************************************
+// Accu Texture
+//****************************************************************************
+void AccuTexFeatHLSL::processVert(  Vector<ShaderComponent*> &componentList, 
+                                    const MaterialFeatureData &fd )
+{
+   MultiLine *meta = new MultiLine;
+   getOutTexCoord(   "texCoord", 
+                     "float2", 
+                     true, 
+                     false, 
+                     meta, 
+                     componentList );
+   
+   getOutObjToTangentSpace( componentList, meta, fd );
+   addOutAccuVec( componentList, meta );
+
+   output = meta;
+}
+
+void AccuTexFeatHLSL::processPix(   Vector<ShaderComponent*> &componentList, 
+                                    const MaterialFeatureData &fd )
+{
+   MultiLine *meta = new MultiLine;
+
+   output = meta;
+
+   // OUT.col
+   Var *color = (Var*) LangElement::find( "col" );
+   if (!color)
+   {
+      output = new GenOp("   //NULL COLOR!");
+      return;
+   }
+
+   // accu map
+   Var *accuMap = new Var;
+   accuMap->setType( "sampler2D" );
+   accuMap->setName( "accuMap" );
+   accuMap->uniform = true;
+   accuMap->sampler = true;
+   accuMap->constNum = Var::getTexUnitNum();     // used as texture unit num here
+
+   // accuColor var
+   Var *accuColor = new Var;
+   accuColor->setType( "float4" );
+   accuColor->setName( "accuColor" );
+   LangElement *colorAccuDecl = new DecOp( accuColor );
+
+   // plc (placement)
+   Var *accuPlc = new Var;
+   accuPlc->setType( "float4" );
+   accuPlc->setName( "plc" );
+   LangElement *plcAccu = new DecOp( accuPlc );
+
+   // accu constants
+   Var *accuScale = (Var*)LangElement::find( "accuScale" );
+   if ( !accuScale ) {
+      accuScale = new Var;
+      accuScale->setType( "float" );
+      accuScale->setName( "accuScale" );
+      accuScale->uniform = true;
+      accuScale->sampler = false;
+      accuScale->constSortPos = cspPotentialPrimitive;
+   }
+   Var *accuDirection = (Var*)LangElement::find( "accuDirection" );
+   if ( !accuDirection ) {
+      accuDirection = new Var;
+      accuDirection->setType( "float" );
+      accuDirection->setName( "accuDirection" );
+      accuDirection->uniform = true;
+      accuDirection->sampler = false;
+      accuDirection->constSortPos = cspPotentialPrimitive;
+   }
+   Var *accuStrength = (Var*)LangElement::find( "accuStrength" );
+   if ( !accuStrength ) {
+      accuStrength = new Var;
+      accuStrength->setType( "float" );
+      accuStrength->setName( "accuStrength" );
+      accuStrength->uniform = true;
+      accuStrength->sampler = false;
+      accuStrength->constSortPos = cspPotentialPrimitive;
+   }
+   Var *accuCoverage = (Var*)LangElement::find( "accuCoverage" );
+   if ( !accuCoverage ) {
+      accuCoverage = new Var;
+      accuCoverage->setType( "float" );
+      accuCoverage->setName( "accuCoverage" );
+      accuCoverage->uniform = true;
+      accuCoverage->sampler = false;
+      accuCoverage->constSortPos = cspPotentialPrimitive;
+   }
+   Var *accuSpecular = (Var*)LangElement::find( "accuSpecular" );
+   if ( !accuSpecular ) {
+      accuSpecular = new Var;
+      accuSpecular->setType( "float" );
+      accuSpecular->setName( "accuSpecular" );
+      accuSpecular->uniform = true;
+      accuSpecular->sampler = false;
+      accuSpecular->constSortPos = cspPotentialPrimitive;
+   }
+
+   Var *inTex = getInTexCoord( "texCoord", "float2", true, componentList );
+   Var *accuVec = getInTexCoord( "accuVec", "float3", true, componentList );
+   Var *bumpNorm = (Var *)LangElement::find( "bumpSample" );
+   if( bumpNorm == NULL ) {
+      bumpNorm = (Var *)LangElement::find( "bumpNormal" );
+      if (!bumpNorm)
+        return;
+   }
+
+   // get the accu pixel color
+   meta->addStatement( new GenOp( "   @ = tex2D(@, @ * @);\r\n", colorAccuDecl, accuMap, inTex, accuScale ) );
+
+   // scale up normals
+   meta->addStatement( new GenOp( "   @.xyz = @.xyz * 2.0 - 0.5;\r\n", bumpNorm, bumpNorm ) );
+
+   // assign direction
+   meta->addStatement( new GenOp( "   @.z *= @*2.0;\r\n", accuVec, accuDirection ) );
+
+   // saturate based on strength
+   meta->addStatement( new GenOp( "   @ = saturate( dot( @, @.xyz * pow(@, 5) ) );\r\n", plcAccu, bumpNorm, accuVec, accuStrength ) );
+
+   // add coverage
+   meta->addStatement( new GenOp( "   @.a += (2 * pow(@/2, 5)) - 0.5;\r\n", accuPlc, accuCoverage ) );
+
+   // clamp to a sensible value
+   meta->addStatement( new GenOp( "   @.a = clamp(@.a, 0, 1);\r\n", accuPlc, accuPlc ) );
+
+   // light
+   Var *lightColor = (Var*) LangElement::find( "d_lightcolor" );
+   if(lightColor != NULL)
+      meta->addStatement( new GenOp( "   @ *= float4(@, 1.0);\r\n\r\n", accuColor, lightColor ) );
+
+   // lerp with current pixel - use the accu alpha as well
+   meta->addStatement( new GenOp( "   @ = lerp( @, @, @.a * @.a);\r\n", color, color, accuColor, accuPlc, accuColor ) );
+
+   // the result should always be opaque
+   meta->addStatement( new GenOp( "   @.a = 1.0;\r\n", color ) );
+
+}
+
+void AccuTexFeatHLSL::setTexData(   Material::StageData &stageDat,
+                                    const MaterialFeatureData &fd,
+                                    RenderPassData &passData,
+                                    U32 &texIndex )
+{
+   //GFXTextureObject *tex = stageDat.getTex( MFT_AccuMap );
+   //if ( tex )
+   //{
+   passData.mSamplerNames[ texIndex ] = "AccuMap";
+   passData.mTexType[ texIndex++ ] = Material::AccuMap;
+   //}
+}
+
+
+void AccuTexFeatHLSL::getAccuVec( MultiLine *meta, LangElement *accuVec )
+{
+   // Get the transform to world space.
+   Var *objTrans = (Var*)LangElement::find( "objTrans" );
+   if ( !objTrans )
+   {
+      objTrans = new Var;
+      objTrans->setType( "float4x4" );
+      objTrans->setName( "objTrans" );
+      objTrans->uniform = true;
+      objTrans->constSortPos = cspPrimitive;      
+   }
+
+   // accu obj trans
+   Var *aobjTrans = new Var;
+   aobjTrans->setType( "float4x4" );
+   aobjTrans->setName( "accuObjTrans" );
+   LangElement *accuObjTransDecl = new DecOp( aobjTrans );
+
+   Var *outObjToTangentSpace = (Var*)LangElement::find( "objToTangentSpace" );
+
+   Var *tav = new Var;
+   tav->setType( "float4" );
+   tav->setName( "tAccuVec" );
+   LangElement *tavDecl = new DecOp( tav );
+
+   meta->addStatement( new GenOp( "   @ = float4(0,0,1,0);\r\n", tavDecl ) );
+   meta->addStatement( new GenOp( "   @ = transpose(@);\r\n", accuObjTransDecl, objTrans ) );
+   meta->addStatement( new GenOp( "   @ = mul(@, @);\r\n", tav, aobjTrans, tav ) );
+   meta->addStatement( new GenOp( "   @.xyz = mul(@, @.xyz);\r\n", tav, outObjToTangentSpace, tav ) );
+   meta->addStatement( new GenOp( "   @.y *= -1;\r\n", tav ) );
+   meta->addStatement( new GenOp( "   @ = @.xyz;\r\n", accuVec, tav ) );
+}
+
+Var* AccuTexFeatHLSL::addOutAccuVec( Vector<ShaderComponent*> &componentList, MultiLine *meta )
+{
+   Var *outAccuVec = (Var*)LangElement::find( "accuVec" );
+   if ( !outAccuVec )
+   {
+      // Setup the connector.
+      ShaderConnector *connectComp = dynamic_cast<ShaderConnector *>( componentList[C_CONNECTOR] );
+      outAccuVec = connectComp->getElement( RT_TEXCOORD );
+      outAccuVec->setName( "accuVec" );
+      outAccuVec->setStructName( "OUT" );
+      outAccuVec->setType( "float3" );
+      outAccuVec->mapsToSampler = false;
+
+      getAccuVec( meta, outAccuVec );
+   }
+
+   return outAccuVec;
+}

+ 185 - 0
Engine/source/shaderGen/HLSL/accuFeatureHLSL.h

@@ -0,0 +1,185 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#ifndef _ACCUFEATUREHLSL_H_
+#define _ACCUFEATUREHLSL_H_
+
+#ifndef _SHADERGEN_HLSL_SHADERFEATUREHLSL_H_
+#include "shaderGen/HLSL/shaderFeatureHLSL.h"
+#endif
+#ifndef _LANG_ELEMENT_H_
+#include "shaderGen/langElement.h"
+#endif
+#ifndef _GFXDEVICE_H_
+#include "gfx/gfxDevice.h"
+#endif
+#ifndef _FEATUREMGR_H_
+#include "shaderGen/featureMgr.h"
+#endif
+#ifndef _MATERIALFEATURETYPES_H_
+#include "materials/materialFeatureTypes.h"
+#endif
+#ifndef _MATERIALFEATUREDATA_H_
+#include "materials/materialFeatureData.h"
+#endif
+
+/// Accu texture
+class AccuTexFeatHLSL : public ShaderFeatureHLSL
+{
+public:
+
+   //****************************************************************************
+   // Accu Texture
+   //****************************************************************************
+   virtual void processVert(  Vector<ShaderComponent*> &componentList, 
+                              const MaterialFeatureData &fd );
+
+   virtual void processPix(   Vector<ShaderComponent*> &componentList, 
+                              const MaterialFeatureData &fd );
+
+   void getAccuVec( MultiLine *meta, LangElement *accuVec );
+
+   Var* addOutAccuVec( Vector<ShaderComponent*> &componentList, MultiLine *meta );
+
+   virtual Material::BlendOp getBlendOp(){ return Material::LerpAlpha; }
+
+   virtual Resources getResources( const MaterialFeatureData &fd )
+   {
+      Resources res; 
+      res.numTex = 1;
+      res.numTexReg = 1;
+      return res;
+   }
+
+   virtual void setTexData(   Material::StageData &stageDat,
+                              const MaterialFeatureData &fd,
+                              RenderPassData &passData,
+                              U32 &texIndex );
+
+   virtual String getName()
+   {
+      return "Accu Texture";
+   }
+};
+
+class AccuScaleFeature : public ShaderFeatureHLSL
+{
+public:
+   virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+   {
+      // Find the constant value
+      Var *accuScale = (Var *)( LangElement::find("accuScale") );
+      if( accuScale == NULL )
+      {
+         accuScale = new Var;
+         accuScale->setType( "float" );
+         accuScale->setName( "accuScale" );
+         accuScale->constSortPos = cspPotentialPrimitive;
+         accuScale->uniform = true;
+      }
+   }
+
+   virtual String getName() { return "Accu Scale"; }
+};
+
+class AccuDirectionFeature : public ShaderFeatureHLSL
+{
+public:
+   virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+   {
+      // Find the constant value
+      Var *accuDirection = (Var *)( LangElement::find("accuDirection") );
+      if( accuDirection == NULL )
+      {
+         accuDirection = new Var;
+         accuDirection->setType( "float" );
+         accuDirection->setName( "accuDirection" );
+         accuDirection->constSortPos = cspPotentialPrimitive;
+         accuDirection->uniform = true;
+      }
+   }
+
+   virtual String getName() { return "Accu Direction"; }
+};
+
+class AccuStrengthFeature : public ShaderFeatureHLSL
+{
+public:
+   virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+   {
+      // Find the constant value
+      Var *accuStrength = (Var *)( LangElement::find("accuStrength") );
+      if( accuStrength == NULL )
+      {
+         accuStrength = new Var;
+         accuStrength->setType( "float" );
+         accuStrength->setName( "accuStrength" );
+         accuStrength->constSortPos = cspPotentialPrimitive;
+         accuStrength->uniform = true;
+      }
+   }
+
+   virtual String getName() { return "Accu Strength"; }
+};
+
+class AccuCoverageFeature : public ShaderFeatureHLSL
+{
+public:
+   virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+   {
+      // Find the constant value
+      Var *accuCoverage = (Var *)( LangElement::find("accuCoverage") );
+      if( accuCoverage == NULL )
+      {
+         accuCoverage = new Var;
+         accuCoverage->setType( "float" );
+         accuCoverage->setName( "accuCoverage" );
+         accuCoverage->constSortPos = cspPotentialPrimitive;
+         accuCoverage->uniform = true;
+      }
+   }
+
+   virtual String getName() { return "Accu Coverage"; }
+};
+
+
+class AccuSpecularFeature : public ShaderFeatureHLSL
+{
+public:
+   virtual void processPix( Vector<ShaderComponent*> &componentList, const MaterialFeatureData &fd )
+   {
+      // Find the constant value
+      Var *accuSpecular = (Var *)( LangElement::find("accuSpecular") );
+      if( accuSpecular == NULL )
+      {
+         accuSpecular = new Var;
+         accuSpecular->setType( "float" );
+         accuSpecular->setName( "accuSpecular" );
+         accuSpecular->constSortPos = cspPotentialPrimitive;
+         accuSpecular->uniform = true;
+      }
+   }
+
+   virtual String getName() { return "Accu Specular"; }
+};
+
+#endif

+ 2 - 1
Engine/source/shaderGen/HLSL/shaderGenHLSLInit.cpp

@@ -32,7 +32,7 @@
 #include "shaderGen/HLSL/paraboloidHLSL.h"
 #include "materials/materialFeatureTypes.h"
 #include "core/module.h"
-
+#include "shaderGen/HLSL/accuFeatureHLSL.h"
 
 static ShaderGen::ShaderGenInitDelegate sInitDelegate;
 
@@ -66,6 +66,7 @@ void _initShaderGenHLSL( ShaderGen *shaderGen )
    FEATUREMGR->registerFeature( MFT_Visibility, new VisibilityFeatHLSL );
    FEATUREMGR->registerFeature( MFT_Fog, new FogFeatHLSL );
    FEATUREMGR->registerFeature( MFT_SpecularMap, new SpecularMapHLSL );
+   FEATUREMGR->registerFeature( MFT_AccuMap, new AccuTexFeatHLSL );
    FEATUREMGR->registerFeature( MFT_GlossMap, new NamedFeatureHLSL( "Gloss Map" ) );
    FEATUREMGR->registerFeature( MFT_LightbufferMRT, new NamedFeatureHLSL( "Lightbuffer MRT" ) );
    FEATUREMGR->registerFeature( MFT_RenderTarget1_Zero, new RenderTargetZeroHLSL( ShaderFeature::RenderTarget1 ) );

+ 3 - 0
Engine/source/ts/tsMesh.cpp

@@ -165,6 +165,9 @@ void TSMesh::innerRender( TSMaterialList *materials, const TSRenderState &rdata,
    MeshRenderInst *coreRI = renderPass->allocInst<MeshRenderInst>();
    coreRI->type = RenderPassManager::RIT_Mesh;
 
+   // Pass accumulation texture along.
+   coreRI->accuTex = rdata.getAccuTex();
+
    const MatrixF &objToWorld = GFX->getWorldMatrix();
 
    // Sort by the center point or the bounds.

+ 2 - 1
Engine/source/ts/tsRenderState.cpp

@@ -33,7 +33,8 @@ TSRenderState::TSRenderState()
       mMaterialHint( NULL ),
       mCuller( NULL ),
       mLightQuery( NULL ),
-      mUseOriginSort( false )
+      mUseOriginSort( false ),
+      mAccuTex( NULL )
 {
 }
 

+ 13 - 1
Engine/source/ts/tsRenderState.h

@@ -27,7 +27,9 @@
 #include "math/mMatrix.h"
 #endif
 
-
+#ifndef _GFXDEVICE_H_
+#include "gfx/gfxDevice.h"
+#endif
 
 class SceneRenderState;
 class GFXCubemap;
@@ -103,8 +105,14 @@ protected:
    /// are forward lit and need lights.
    LightQuery *mLightQuery;
 
+   // The accumulation texture provided by an accumulation
+   // volume. This is passed down per-object.
+   GFXTextureObject* mAccuTex;
+
 public:
 
+   
+
    TSRenderState();
    TSRenderState( const TSRenderState &state );
 
@@ -147,6 +155,10 @@ public:
    void setLightQuery( LightQuery *query ) { mLightQuery = query; }
    LightQuery* getLightQuery() const { return mLightQuery; }
 
+   ///@see mAccuTex
+   void setAccuTex( GFXTextureObject* query ) { mAccuTex = query; }
+   GFXTextureObject* getAccuTex() const { return mAccuTex; }
+
    /// @}
 };
 

+ 13 - 1
Engine/source/ts/tsShapeInstance.cpp

@@ -39,7 +39,6 @@
 #include "gfx/gfxDrawUtil.h"
 #include "core/module.h"
 
-
 MODULE_BEGIN( TSShapeInstance )
 
    MODULE_INIT
@@ -783,3 +782,16 @@ void TSShapeInstance::prepCollision()
    }
 }
 
+// Returns true is the shape contains any materials with accumulation enabled.
+bool TSShapeInstance::hasAccumulation()
+{
+   bool result = false;
+   for ( U32 i = 0; i < mMaterialList->size(); ++i )
+   {
+      BaseMatInstance* mat = mMaterialList->getMaterialInst(i);
+      if ( mat->hasAccumulation() )
+         result = true;
+   }
+   return result;
+}
+

+ 6 - 0
Engine/source/ts/tsShapeInstance.h

@@ -671,6 +671,12 @@ protected:
    void *mData; ///< available for use by app...initialized to 0
 
    void prepCollision();
+
+//-------------------------------------------------------------------------------------
+// accumulation
+//-------------------------------------------------------------------------------------
+
+   bool hasAccumulation();
 };
 
 

+ 1 - 0
Engine/source/util/imposterCapture.cpp

@@ -121,6 +121,7 @@ void ImposterCaptureMaterialHook::init( BaseMatInstance *inMat )
    features.addFeature( MFT_IsDXTnm );
    features.addFeature( MFT_NormalMap );
    features.addFeature( MFT_NormalsOut );
+   features.addFeature( MFT_AccuMap );
    mNormalsMatInst = MATMGR->createMatInstance( matName );
    mNormalsMatInst->getFeaturesDelegate().bind( &ImposterCaptureMaterialHook::_overrideFeatures );
    mNormalsMatInst->init( features, inMat->getVertexFormat() );

+ 476 - 1
Templates/Empty/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui

@@ -654,7 +654,6 @@
                            bitmap = "tools/gui/images/delete";
                         };
                      };
-                  
                   };
                };
                new GuiRolloutCtrl(advancedTextureMapsRollout) {
@@ -1483,6 +1482,482 @@
                      };
                   };
                };
+               new GuiRolloutCtrl() {
+                  class = "BehaviorQuickEditRollout";
+                  superclass = LBQuickEditRollout;
+                  Profile = "GuiRolloutProfile";
+                  HorizSizing = "width";
+                  VertSizing = "bottom";
+                  Position = "0 0";
+                  Extent = "195 0";
+                  Caption = "Accumulation Properties";
+                  Margin = "-1 0 0 0";
+                  DragSizable = false;
+                  container = true;
+                  parentRollout = %this.rollout;
+                  object = %behavior;
+                  
+                  new GuiStackControl() {
+                     StackingType = "Vertical";
+                     HorizStacking = "Left to Right";
+                     VertStacking = "Top to Bottom";
+                     Padding = "0";
+                     canSaveDynamicFields = "0";
+                     Enabled = "1";
+                     isContainer = "1";
+                     Profile = "GuiDefaultProfile";
+                     HorizSizing = "width";
+                     VertSizing = "bottom";
+                     Position = "1 3";
+                     Extent = "195 16";
+                     MinExtent = "16 16";
+                     canSave = "1";
+                     isDecoy = "0";
+                     Visible = "1";
+                     tooltipprofile = "GuiToolTipProfile";
+                     hovertime = "1000";
+                     
+                     new GuiContainer(){ // enable/disable
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiCheckBoxCtrl() {
+                           canSaveDynamicFields = "0";
+                           internalName = "accuCheckbox";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "ToolsGuiCheckBoxProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 7";
+                           Extent = "57 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           Command = "MaterialEditorGui.updateAccuCheckbox($ThisControl.getValue());";
+                           tooltipprofile = "ToolsGuiDefaultProfile";
+                           ToolTip = "Enables the use of Pixel Specular for this layer.";
+                           hovertime = "1000";
+                           text = "Enable";
+                           groupNum = "-1";
+                           buttonType = "ToggleButton";
+                           useMouseEvents = "0";
+                           useInactiveState = "0";
+                        };  
+                     };
+                  
+                     new GuiContainer(){ // scale
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiTextCtrl() {
+                           canSaveDynamicFields = "0";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "GuiTextRightProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 3";
+                           Extent = "54 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           hovertime = "1000";
+                           Margin = "0 0 0 0";
+                           Padding = "0 0 0 0";
+                           AnchorTop = "1";
+                           AnchorBottom = "0";
+                           AnchorLeft = "1";
+                           AnchorRight = "0";
+                           text = "Scale";
+                           maxLength = "1024";
+                        };
+
+								new GuiControl() {
+                           class = "AggregateControl";
+                           position = "70 3";
+                           Extent = "96 20";
+                           
+                           new GuiSliderCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuScaleSlider";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiSliderProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "0 2";
+                              Extent = "61 14";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "MaterialEditorGui.updateActiveMaterial(\"accuScale[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, true);";
+                              AltCommand = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuScale[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, false);";
+                              tooltipprofile = "GuiDefaultProfile";
+                              ToolTip = "Sets the scale of the accu map.";
+                              hovertime = "1000";
+                              range = "0.03125 32";
+                              ticks = "0";
+                              value = "1";
+                           };
+                           new GuiTextEditCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuScaleTextEdit";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiTextEditProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "64 0";
+                              Extent = "29 18";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuScale[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
+                              hovertime = "1000";
+                              AnchorTop = "1";
+                              AnchorBottom = "0";
+                              AnchorLeft = "1";
+                              AnchorRight = "0";
+                              text = "1";
+                              maxLength = "3";
+                           };
+                        };
+                     };
+
+                     new GuiContainer(){ // direction
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiTextCtrl() {
+                           canSaveDynamicFields = "0";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "GuiTextRightProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 3";
+                           Extent = "54 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           hovertime = "1000";
+                           Margin = "0 0 0 0";
+                           Padding = "0 0 0 0";
+                           AnchorTop = "1";
+                           AnchorBottom = "0";
+                           AnchorLeft = "1";
+                           AnchorRight = "0";
+                           text = "Direction";
+                           maxLength = "1024";
+                        };
+
+								new GuiControl() {
+                           class = "AggregateControl";
+                           position = "70 3";
+                           Extent = "96 20";
+                           
+                           new GuiSliderCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuDirectionSlider";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiSliderProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "0 2";
+                              Extent = "61 14";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "MaterialEditorGui.updateActiveMaterial(\"accuDirection[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, true);";
+                              AltCommand = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuDirection[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, false);";
+                              tooltipprofile = "GuiDefaultProfile";
+                              ToolTip = "Sets the direction of the accu map.";
+                              hovertime = "1000";
+                              range = "-1 1";
+                              ticks = "0";
+                              value = "-1";
+                           };
+                           new GuiTextEditCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuDirectionTextEdit";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiTextEditProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "64 0";
+                              Extent = "29 18";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuDirection[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
+                              hovertime = "1000";
+                              AnchorTop = "1";
+                              AnchorBottom = "0";
+                              AnchorLeft = "1";
+                              AnchorRight = "0";
+                              text = "-1";
+                              maxLength = "3";
+                           };
+                        };
+                     };
+                     new GuiContainer(){ // strength
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiTextCtrl() {
+                           canSaveDynamicFields = "0";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "GuiTextRightProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 3";
+                           Extent = "54 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           hovertime = "1000";
+                           Margin = "0 0 0 0";
+                           Padding = "0 0 0 0";
+                           AnchorTop = "1";
+                           AnchorBottom = "0";
+                           AnchorLeft = "1";
+                           AnchorRight = "0";
+                           text = "Strength";
+                           maxLength = "1024";
+                        };
+
+								new GuiControl() {
+                           class = "AggregateControl";
+                           position = "70 3";
+                           Extent = "96 20";
+                           
+                           new GuiSliderCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuStrengthSlider";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiSliderProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "0 2";
+                              Extent = "61 14";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "MaterialEditorGui.updateActiveMaterial(\"accuStrength[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, true);";
+                              AltCommand = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuStrength[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, false);";
+                              tooltipprofile = "GuiDefaultProfile";
+                              ToolTip = "Sets the strength of the accu map.";
+                              hovertime = "1000";
+                              range = "0 1";
+                              ticks = "0";
+                              value = "0.6";
+                           };
+                           new GuiTextEditCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuStrengthTextEdit";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiTextEditProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "64 0";
+                              Extent = "29 18";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuStrength[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
+                              hovertime = "1000";
+                              AnchorTop = "1";
+                              AnchorBottom = "0";
+                              AnchorLeft = "1";
+                              AnchorRight = "0";
+                              text = "0.6";
+                              maxLength = "3";
+                           };
+                        };
+                     };
+                     new GuiContainer(){ // coverage
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiTextCtrl() {
+                           canSaveDynamicFields = "0";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "GuiTextRightProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 3";
+                           Extent = "54 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           hovertime = "1000";
+                           Margin = "0 0 0 0";
+                           Padding = "0 0 0 0";
+                           AnchorTop = "1";
+                           AnchorBottom = "0";
+                           AnchorLeft = "1";
+                           AnchorRight = "0";
+                           text = "Coverage";
+                           maxLength = "1024";
+                        };
+
+								new GuiControl() {
+                           class = "AggregateControl";
+                           position = "70 3";
+                           Extent = "96 20";
+                           
+                           new GuiSliderCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuCoverageSlider";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiSliderProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "0 2";
+                              Extent = "61 14";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "MaterialEditorGui.updateActiveMaterial(\"accuCoverage[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, true);";
+                              AltCommand = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuCoverage[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, false);";
+                              tooltipprofile = "GuiDefaultProfile";
+                              ToolTip = "Sets the coverage of the accu map.";
+                              hovertime = "1000";
+                              range = "0 2";
+                              ticks = "0";
+                              value = "1";
+                           };
+                           new GuiTextEditCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuCoverageTextEdit";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiTextEditProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "64 0";
+                              Extent = "29 18";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuCoverage[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
+                              hovertime = "1000";
+                              AnchorTop = "1";
+                              AnchorBottom = "0";
+                              AnchorLeft = "1";
+                              AnchorRight = "0";
+                              text = "1";
+                              maxLength = "3";
+                           };
+                        };
+                     };
+                     new GuiContainer(){ // specular
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiTextCtrl() {
+                           canSaveDynamicFields = "0";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "GuiTextRightProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 3";
+                           Extent = "54 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           hovertime = "1000";
+                           Margin = "0 0 0 0";
+                           Padding = "0 0 0 0";
+                           AnchorTop = "1";
+                           AnchorBottom = "0";
+                           AnchorLeft = "1";
+                           AnchorRight = "0";
+                           text = "Specular scale";
+                           maxLength = "1024";
+                        };
+
+								new GuiControl() {
+                           class = "AggregateControl";
+                           position = "70 3";
+                           Extent = "96 20";
+                           
+                           new GuiSliderCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuSpecularSlider";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiSliderProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "0 2";
+                              Extent = "61 14";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "MaterialEditorGui.updateActiveMaterial(\"accuSpecular[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, true);";
+                              AltCommand = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuSpecular[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, false);";
+                              tooltipprofile = "GuiDefaultProfile";
+                              ToolTip = "Sets the specular scale over the accu map.";
+                              hovertime = "1000";
+                              range = "0 2";
+                              ticks = "0";
+                              value = "1";
+                           };
+                           new GuiTextEditCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuSpecularTextEdit";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiTextEditProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "64 0";
+                              Extent = "29 18";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuSpecular[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
+                              hovertime = "1000";
+                              AnchorTop = "1";
+                              AnchorBottom = "0";
+                              AnchorLeft = "1";
+                              AnchorRight = "0";
+                              text = "1";
+                              maxLength = "3";
+                           };
+                        };
+                     };
+
+                  };
+               };
                new GuiRolloutCtrl() {
                   class = "BehaviorQuickEditRollout";
                   superclass = LBQuickEditRollout;

+ 21 - 0
Templates/Empty/game/tools/materialEditor/scripts/materialEditor.ed.cs

@@ -886,6 +886,17 @@ function MaterialEditorGui::guiSync( %this, %material )
       MaterialEditorPropertiesWindow-->specMapDisplayBitmap.setBitmap( (%material).specularMap[%layer] );
    }
    
+   MaterialEditorPropertiesWindow-->accuScaleTextEdit.setText((%material).accuScale[%layer]);
+   MaterialEditorPropertiesWindow-->accuScaleTextEdit.setText((%material).accuScale[%layer]);
+   MaterialEditorPropertiesWindow-->accuDirectionTextEdit.setText((%material).accuDirection[%layer]);
+   MaterialEditorPropertiesWindow-->accuDirectionTextEdit.setText((%material).accuDirection[%layer]);
+   MaterialEditorPropertiesWindow-->accuStrengthTextEdit.setText((%material).accuStrength[%layer]);
+   MaterialEditorPropertiesWindow-->accuStrengthTextEdit.setText((%material).accuStrength[%layer]);
+   MaterialEditorPropertiesWindow-->accuCoverageTextEdit.setText((%material).accuCoverage[%layer]);
+   MaterialEditorPropertiesWindow-->accuCoverageTextEdit.setText((%material).accuCoverage[%layer]);
+   MaterialEditorPropertiesWindow-->accuSpecularTextEdit.setText((%material).accuSpecular[%layer]);
+   MaterialEditorPropertiesWindow-->accuSpecularTextEdit.setText((%material).accuSpecular[%layer]);
+   
    MaterialEditorPropertiesWindow-->detailScaleTextEdit.setText( getWord((%material).detailScale[%layer], 0) );
    MaterialEditorPropertiesWindow-->detailNormalStrengthTextEdit.setText( getWord((%material).detailNormalMapStrength[%layer], 0) );
    
@@ -966,6 +977,9 @@ function MaterialEditorGui::guiSync( %this, %material )
    MaterialEditorPropertiesWindow-->SequenceSliderFPS.setValue( (%material).sequenceFramePerSec[%layer] );
    MaterialEditorPropertiesWindow-->SequenceSliderSSS.setValue( %numFrames );
    
+   // Accumulation
+   MaterialEditorPropertiesWindow-->accuCheckbox.setValue((%material).accuEnabled[%layer]);   
+   
    %this.preventUndo = false;
 }
 
@@ -2249,3 +2263,10 @@ function MaterialEditorMapThumbnail::onRightClick( %this )
    
    %popup.showPopup( Canvas );
 }
+
+// Accumulation
+function MaterialEditorGui::updateAccuCheckbox(%this, %value)
+{
+   MaterialEditorGui.updateActiveMaterial("accuEnabled[" @ MaterialEditorGui.currentLayer @ "]", %value);   
+   MaterialEditorGui.guiSync( materialEd_previewMaterial );
+}

+ 1 - 0
Templates/Empty/game/tools/worldEditor/scripts/editors/creator.ed.cs

@@ -83,6 +83,7 @@ function EWCreatorWindow::init( %this )
       %this.registerMissionObject( "SpawnSphere",  "Observer Spawn Sphere", "ObserverDropPoint" );
       %this.registerMissionObject( "SFXSpace",      "Sound Space" );
       %this.registerMissionObject( "OcclusionVolume", "Occlusion Volume" );
+      %this.registerMissionObject( "AccumulationVolume", "Accumulation Volume" );
       %this.registerMissionObject("NavMesh", "Navigation mesh");
       %this.registerMissionObject("NavPath", "Path");
       

+ 476 - 1
Templates/Full/game/tools/materialEditor/gui/guiMaterialPropertiesWindow.ed.gui

@@ -654,7 +654,6 @@
                            bitmap = "tools/gui/images/delete";
                         };
                      };
-                  
                   };
                };
                new GuiRolloutCtrl(advancedTextureMapsRollout) {
@@ -1483,6 +1482,482 @@
                      };
                   };
                };
+               new GuiRolloutCtrl() {
+                  class = "BehaviorQuickEditRollout";
+                  superclass = LBQuickEditRollout;
+                  Profile = "GuiRolloutProfile";
+                  HorizSizing = "width";
+                  VertSizing = "bottom";
+                  Position = "0 0";
+                  Extent = "195 0";
+                  Caption = "Accumulation Properties";
+                  Margin = "-1 0 0 0";
+                  DragSizable = false;
+                  container = true;
+                  parentRollout = %this.rollout;
+                  object = %behavior;
+                  
+                  new GuiStackControl() {
+                     StackingType = "Vertical";
+                     HorizStacking = "Left to Right";
+                     VertStacking = "Top to Bottom";
+                     Padding = "0";
+                     canSaveDynamicFields = "0";
+                     Enabled = "1";
+                     isContainer = "1";
+                     Profile = "GuiDefaultProfile";
+                     HorizSizing = "width";
+                     VertSizing = "bottom";
+                     Position = "1 3";
+                     Extent = "195 16";
+                     MinExtent = "16 16";
+                     canSave = "1";
+                     isDecoy = "0";
+                     Visible = "1";
+                     tooltipprofile = "GuiToolTipProfile";
+                     hovertime = "1000";
+                     
+                     new GuiContainer(){ // enable/disable
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiCheckBoxCtrl() {
+                           canSaveDynamicFields = "0";
+                           internalName = "accuCheckbox";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "ToolsGuiCheckBoxProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 7";
+                           Extent = "57 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           Command = "MaterialEditorGui.updateAccuCheckbox($ThisControl.getValue());";
+                           tooltipprofile = "ToolsGuiDefaultProfile";
+                           ToolTip = "Enables the use of Pixel Specular for this layer.";
+                           hovertime = "1000";
+                           text = "Enable";
+                           groupNum = "-1";
+                           buttonType = "ToggleButton";
+                           useMouseEvents = "0";
+                           useInactiveState = "0";
+                        };  
+                     };
+                  
+                     new GuiContainer(){ // scale
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiTextCtrl() {
+                           canSaveDynamicFields = "0";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "GuiTextRightProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 3";
+                           Extent = "54 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           hovertime = "1000";
+                           Margin = "0 0 0 0";
+                           Padding = "0 0 0 0";
+                           AnchorTop = "1";
+                           AnchorBottom = "0";
+                           AnchorLeft = "1";
+                           AnchorRight = "0";
+                           text = "Scale";
+                           maxLength = "1024";
+                        };
+
+								new GuiControl() {
+                           class = "AggregateControl";
+                           position = "70 3";
+                           Extent = "96 20";
+                           
+                           new GuiSliderCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuScaleSlider";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiSliderProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "0 2";
+                              Extent = "61 14";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "MaterialEditorGui.updateActiveMaterial(\"accuScale[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, true);";
+                              AltCommand = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuScale[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, false);";
+                              tooltipprofile = "GuiDefaultProfile";
+                              ToolTip = "Sets the scale of the accu map.";
+                              hovertime = "1000";
+                              range = "0.03125 32";
+                              ticks = "0";
+                              value = "1";
+                           };
+                           new GuiTextEditCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuScaleTextEdit";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiTextEditProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "64 0";
+                              Extent = "29 18";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuScale[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
+                              hovertime = "1000";
+                              AnchorTop = "1";
+                              AnchorBottom = "0";
+                              AnchorLeft = "1";
+                              AnchorRight = "0";
+                              text = "1";
+                              maxLength = "3";
+                           };
+                        };
+                     };
+
+                     new GuiContainer(){ // direction
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiTextCtrl() {
+                           canSaveDynamicFields = "0";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "GuiTextRightProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 3";
+                           Extent = "54 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           hovertime = "1000";
+                           Margin = "0 0 0 0";
+                           Padding = "0 0 0 0";
+                           AnchorTop = "1";
+                           AnchorBottom = "0";
+                           AnchorLeft = "1";
+                           AnchorRight = "0";
+                           text = "Direction";
+                           maxLength = "1024";
+                        };
+
+								new GuiControl() {
+                           class = "AggregateControl";
+                           position = "70 3";
+                           Extent = "96 20";
+                           
+                           new GuiSliderCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuDirectionSlider";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiSliderProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "0 2";
+                              Extent = "61 14";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "MaterialEditorGui.updateActiveMaterial(\"accuDirection[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, true);";
+                              AltCommand = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuDirection[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, false);";
+                              tooltipprofile = "GuiDefaultProfile";
+                              ToolTip = "Sets the direction of the accu map.";
+                              hovertime = "1000";
+                              range = "-1 1";
+                              ticks = "0";
+                              value = "-1";
+                           };
+                           new GuiTextEditCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuDirectionTextEdit";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiTextEditProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "64 0";
+                              Extent = "29 18";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuDirection[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
+                              hovertime = "1000";
+                              AnchorTop = "1";
+                              AnchorBottom = "0";
+                              AnchorLeft = "1";
+                              AnchorRight = "0";
+                              text = "-1";
+                              maxLength = "3";
+                           };
+                        };
+                     };
+                     new GuiContainer(){ // strength
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiTextCtrl() {
+                           canSaveDynamicFields = "0";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "GuiTextRightProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 3";
+                           Extent = "54 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           hovertime = "1000";
+                           Margin = "0 0 0 0";
+                           Padding = "0 0 0 0";
+                           AnchorTop = "1";
+                           AnchorBottom = "0";
+                           AnchorLeft = "1";
+                           AnchorRight = "0";
+                           text = "Strength";
+                           maxLength = "1024";
+                        };
+
+								new GuiControl() {
+                           class = "AggregateControl";
+                           position = "70 3";
+                           Extent = "96 20";
+                           
+                           new GuiSliderCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuStrengthSlider";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiSliderProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "0 2";
+                              Extent = "61 14";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "MaterialEditorGui.updateActiveMaterial(\"accuStrength[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, true);";
+                              AltCommand = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuStrength[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, false);";
+                              tooltipprofile = "GuiDefaultProfile";
+                              ToolTip = "Sets the strength of the accu map.";
+                              hovertime = "1000";
+                              range = "0 1";
+                              ticks = "0";
+                              value = "0.6";
+                           };
+                           new GuiTextEditCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuStrengthTextEdit";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiTextEditProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "64 0";
+                              Extent = "29 18";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuStrength[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
+                              hovertime = "1000";
+                              AnchorTop = "1";
+                              AnchorBottom = "0";
+                              AnchorLeft = "1";
+                              AnchorRight = "0";
+                              text = "0.6";
+                              maxLength = "3";
+                           };
+                        };
+                     };
+                     new GuiContainer(){ // coverage
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiTextCtrl() {
+                           canSaveDynamicFields = "0";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "GuiTextRightProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 3";
+                           Extent = "54 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           hovertime = "1000";
+                           Margin = "0 0 0 0";
+                           Padding = "0 0 0 0";
+                           AnchorTop = "1";
+                           AnchorBottom = "0";
+                           AnchorLeft = "1";
+                           AnchorRight = "0";
+                           text = "Coverage";
+                           maxLength = "1024";
+                        };
+
+								new GuiControl() {
+                           class = "AggregateControl";
+                           position = "70 3";
+                           Extent = "96 20";
+                           
+                           new GuiSliderCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuCoverageSlider";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiSliderProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "0 2";
+                              Extent = "61 14";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "MaterialEditorGui.updateActiveMaterial(\"accuCoverage[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, true);";
+                              AltCommand = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuCoverage[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, false);";
+                              tooltipprofile = "GuiDefaultProfile";
+                              ToolTip = "Sets the coverage of the accu map.";
+                              hovertime = "1000";
+                              range = "0 2";
+                              ticks = "0";
+                              value = "1";
+                           };
+                           new GuiTextEditCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuCoverageTextEdit";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiTextEditProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "64 0";
+                              Extent = "29 18";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuCoverage[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
+                              hovertime = "1000";
+                              AnchorTop = "1";
+                              AnchorBottom = "0";
+                              AnchorLeft = "1";
+                              AnchorRight = "0";
+                              text = "1";
+                              maxLength = "3";
+                           };
+                        };
+                     };
+                     new GuiContainer(){ // specular
+                        profile="GuiTransparentProfile";
+                        isContainer = "1";
+                        position = "0 0";
+                        Extent = "195 24";
+                        HorizSizing = "width";
+                        
+                        new GuiTextCtrl() {
+                           canSaveDynamicFields = "0";
+                           Enabled = "1";
+                           isContainer = "0";
+                           Profile = "GuiTextRightProfile";
+                           HorizSizing = "right";
+                           VertSizing = "bottom";
+                           position = "8 3";
+                           Extent = "54 16";
+                           MinExtent = "8 2";
+                           canSave = "1";
+                           Visible = "1";
+                           hovertime = "1000";
+                           Margin = "0 0 0 0";
+                           Padding = "0 0 0 0";
+                           AnchorTop = "1";
+                           AnchorBottom = "0";
+                           AnchorLeft = "1";
+                           AnchorRight = "0";
+                           text = "Specular scale";
+                           maxLength = "1024";
+                        };
+
+								new GuiControl() {
+                           class = "AggregateControl";
+                           position = "70 3";
+                           Extent = "96 20";
+                           
+                           new GuiSliderCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuSpecularSlider";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiSliderProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "0 2";
+                              Extent = "61 14";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "MaterialEditorGui.updateActiveMaterial(\"accuSpecular[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, true);";
+                              AltCommand = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuSpecular[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue(), true, false);";
+                              tooltipprofile = "GuiDefaultProfile";
+                              ToolTip = "Sets the specular scale over the accu map.";
+                              hovertime = "1000";
+                              range = "0 2";
+                              ticks = "0";
+                              value = "1";
+                           };
+                           new GuiTextEditCtrl() {
+                              canSaveDynamicFields = "0";
+                              internalName = "accuSpecularTextEdit";
+                              Enabled = "1";
+                              isContainer = "0";
+                              Profile = "GuiTextEditProfile";
+                              HorizSizing = "right";
+                              VertSizing = "bottom";
+                              position = "64 0";
+                              Extent = "29 18";
+                              MinExtent = "8 2";
+                              canSave = "1";
+                              Visible = "1";
+                              Command = "$ThisControl.getParent().updateFromChild($ThisControl); MaterialEditorGui.updateActiveMaterial(\"accuSpecular[\" @ MaterialEditorGui.currentLayer @ \"]\", $ThisControl.getValue());";
+                              hovertime = "1000";
+                              AnchorTop = "1";
+                              AnchorBottom = "0";
+                              AnchorLeft = "1";
+                              AnchorRight = "0";
+                              text = "1";
+                              maxLength = "3";
+                           };
+                        };
+                     };
+
+                  };
+               };
                new GuiRolloutCtrl() {
                   class = "BehaviorQuickEditRollout";
                   superclass = LBQuickEditRollout;

+ 21 - 0
Templates/Full/game/tools/materialEditor/scripts/materialEditor.ed.cs

@@ -886,6 +886,17 @@ function MaterialEditorGui::guiSync( %this, %material )
       MaterialEditorPropertiesWindow-->specMapDisplayBitmap.setBitmap( (%material).specularMap[%layer] );
    }
    
+   MaterialEditorPropertiesWindow-->accuScaleTextEdit.setText((%material).accuScale[%layer]);
+   MaterialEditorPropertiesWindow-->accuScaleTextEdit.setText((%material).accuScale[%layer]);
+   MaterialEditorPropertiesWindow-->accuDirectionTextEdit.setText((%material).accuDirection[%layer]);
+   MaterialEditorPropertiesWindow-->accuDirectionTextEdit.setText((%material).accuDirection[%layer]);
+   MaterialEditorPropertiesWindow-->accuStrengthTextEdit.setText((%material).accuStrength[%layer]);
+   MaterialEditorPropertiesWindow-->accuStrengthTextEdit.setText((%material).accuStrength[%layer]);
+   MaterialEditorPropertiesWindow-->accuCoverageTextEdit.setText((%material).accuCoverage[%layer]);
+   MaterialEditorPropertiesWindow-->accuCoverageTextEdit.setText((%material).accuCoverage[%layer]);
+   MaterialEditorPropertiesWindow-->accuSpecularTextEdit.setText((%material).accuSpecular[%layer]);
+   MaterialEditorPropertiesWindow-->accuSpecularTextEdit.setText((%material).accuSpecular[%layer]);
+   
    MaterialEditorPropertiesWindow-->detailScaleTextEdit.setText( getWord((%material).detailScale[%layer], 0) );
    MaterialEditorPropertiesWindow-->detailNormalStrengthTextEdit.setText( getWord((%material).detailNormalMapStrength[%layer], 0) );
    
@@ -966,6 +977,9 @@ function MaterialEditorGui::guiSync( %this, %material )
    MaterialEditorPropertiesWindow-->SequenceSliderFPS.setValue( (%material).sequenceFramePerSec[%layer] );
    MaterialEditorPropertiesWindow-->SequenceSliderSSS.setValue( %numFrames );
    
+   // Accumulation
+   MaterialEditorPropertiesWindow-->accuCheckbox.setValue((%material).accuEnabled[%layer]);   
+   
    %this.preventUndo = false;
 }
 
@@ -2249,3 +2263,10 @@ function MaterialEditorMapThumbnail::onRightClick( %this )
    
    %popup.showPopup( Canvas );
 }
+
+// Accumulation
+function MaterialEditorGui::updateAccuCheckbox(%this, %value)
+{
+   MaterialEditorGui.updateActiveMaterial("accuEnabled[" @ MaterialEditorGui.currentLayer @ "]", %value);   
+   MaterialEditorGui.guiSync( materialEd_previewMaterial );
+}

+ 1 - 0
Templates/Full/game/tools/worldEditor/scripts/editors/creator.ed.cs

@@ -83,6 +83,7 @@ function EWCreatorWindow::init( %this )
       %this.registerMissionObject( "SpawnSphere",  "Observer Spawn Sphere", "ObserverDropPoint" );
       %this.registerMissionObject( "SFXSpace",      "Sound Space" );
       %this.registerMissionObject( "OcclusionVolume", "Occlusion Volume" );
+      %this.registerMissionObject( "AccumulationVolume", "Accumulation Volume" );
       %this.registerMissionObject("NavMesh", "Navigation mesh");
       %this.registerMissionObject("NavPath", "Path");