Browse Source

Missed a few files.

Areloch 9 years ago
parent
commit
21be97d206

+ 1319 - 0
Engine/source/environment/VolumetricFog.cpp

@@ -0,0 +1,1319 @@
+//-----------------------------------------------------------------------------
+// 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 "environment/VolumetricFog.h"
+#include "windowManager/platformWindowMgr.h"
+#include "gfx/gfxTransformSaver.h"
+#include "renderInstance/renderPassManager.h"
+#include "math/mathIO.h"
+#include "materials/shaderData.h"
+#include "math/util/matrixSet.h"
+#include "core/resourceManager.h"
+#include "core/stream/bitStream.h"
+#include "T3D/gameBase/gameConnection.h"
+#include "T3D/shapeBase.h"
+#include "ts/tsShapeInstance.h"
+#include "console/engineAPI.h"
+#include "gui/core/guiCanvas.h"
+#include "VolumetricFogRTManager.h"
+#include "lighting/lightInfo.h"
+#include "lighting/lightManager.h"
+
+#define COLBOX_SCALE Point3F(1.02f, 1.02f, 1.02f)
+
+IMPLEMENT_CO_NETOBJECT_V1(VolumetricFog);
+
+ConsoleDocClass(VolumetricFog,
+"@brief Volumetric Fog Object class. Main class defining the Volumetric\n"
+"Fog objects in the scene. Used in conjunction with the VolumetricFogRTManager\n"
+"class which is responsible for the required rendertargets.\n\n"
+"Methods (exposed to script):\n"
+" setFogColorF(color) Changes the overall fog color (color.rgba range 0.0 - 1.0).\n;"
+" setFogColor(color) Changes the overall fog color color.rgba range 0 - 255).\n;"
+" setFogDensity(density) Changes the overall fog density.\n"
+" setFogModulation(strength, speed1, speed2) changes the strength\n"
+" and the speeds of the 2 animation layers.\n\n"
+"Callbacks:\n"
+"onEnterFog triggered whenever the controlobject (Player or Camera) enters the Fog.\n"
+" (current Fog object and the controlobject are exposed to script.\n"
+"onLeaveFog triggered whenever the controlobject (Player or Camera) left the Fog.\n"
+" (current Fog object and the controlobject are exposed to script.\n\n"
+"@tsexample\n"
+" new VolumetricFog()\n"
+" {\n"
+" shapeName = \"art/environment/FogRCube.dts\";\n"
+" fogColor = \"200 200 200 128\";\n"
+" fogDensity = \"0.2\";\n"
+" ignoreWater = \"0\";\n"
+" MinSize = \"250\";\n"
+" FadeSize = \"750\";\n"
+" texture = \"art/environment/FogMod_heavy.dds\";\n"
+" tiles = \"1.5\";\n"
+" modStrength = \"0.2\";\n"
+" PrimSpeed = \"-0.01 0.04\";\n"
+" SecSpeed = \"0.02 -0.02\";\n"
+" position = \"748.644 656.371 65.3506\"; \n"
+" rotation = \"0 0 1 20.354\";\n"
+" scale = \"40 30 6\";\n"
+" };\n"
+"@endtsexample\n"
+);
+
+IMPLEMENT_CALLBACK(VolumetricFog, onEnterFog, void, (SimObjectId obj), (obj),
+"@brief Called when an object enters the volume of the Fog instance.\n\n"
+
+"@param obj the controlobject entering the fog.");
+
+IMPLEMENT_CALLBACK(VolumetricFog, onLeaveFog, void, (SimObjectId obj), (obj),
+"@brief Called when an object left the volume of the Fog instance.\n\n"
+
+"@param obj the controlobject leaving the fog.");
+
+
+VolumetricFog::VolumetricFog()
+{
+   AssertFatal(VFRTM != NULL, "VolumetricFog Fatal Error: No Manager found");
+
+   if (!VFRTM->IsInitialized())
+   VFRTM->Init();
+
+   mNetFlags.set(Ghostable | ScopeAlways);
+
+   mTypeMask |= EnvironmentObjectType | StaticObjectType;
+
+   mPrepassTarget = NULL;
+   mDepthBufferTarget = NULL;
+   mFrontBufferTarget = NULL;
+
+   z_buf = NULL;
+   mTexture = NULL;
+
+   mIsVBDirty = false;
+   mIsPBDirty = false;
+
+   mFogColor.set(200, 200, 200, 255);
+   mFogDensity = 0.3f;
+   mIgnoreWater = false;
+   mReflect = false;
+   mCamInFog = false;
+   mResizing = false;
+   mFogReflStrength = 20.0;
+   mUseGlow = false;
+   mGlowStrength = 0.3f;
+   mGlowing = 0;
+   mModifLightRays = false;
+   mLightRayMod = 1.0f;
+   mOldLightRayStrength = 0.1f;
+
+   mShapeName = "";
+   mShapeLoaded = false;
+   mMinDisplaySize = 10.0f;
+   mFadeSize = 0.0f;
+   mCurDetailLevel = 0;
+   mNumDetailLevels = 0;
+   det_size.clear();
+
+   mTextureName = "";
+   mIsTextured = false;
+   mStrength = 0.5f;
+   mTexTiles = 1.0f;
+   mSpeed1.set(0.5f, 0.0f);
+   mSpeed2.set(0.1f, 0.1f);
+}
+
+VolumetricFog::~VolumetricFog()
+{
+   if (isClientObject())
+      return;
+
+   for (S32 i = 0; i < det_size.size(); i++)
+   {
+      if (det_size[i].indices != NULL)
+         delete(det_size[i].indices);
+      if (det_size[i].piArray != NULL)
+         delete(det_size[i].piArray);
+      if (det_size[i].verts != NULL)
+         delete(det_size[i].verts);
+   }
+   det_size.clear();
+
+   if (z_buf.isValid())
+      SAFE_DELETE(z_buf);
+
+   if (!mTexture.isNull())
+      mTexture.free();
+}
+
+void VolumetricFog::initPersistFields()
+{
+   addGroup("VolumetricFogData");
+   addField("shapeName", TypeShapeFilename, Offset(mShapeName, VolumetricFog),
+      "Path and filename of the model file (.DTS, .DAE) to use for this Volume.");
+   addField("FogColor", TypeColorI, Offset(mFogColor, VolumetricFog),
+      "Fog color RGBA (Alpha is ignored)");
+   addField("FogDensity", TypeF32, Offset(mFogDensity, VolumetricFog), 
+      "Overal fog density value (0 disables the fog).");
+   addField("IgnoreWater", TypeBool, Offset(mIgnoreWater, VolumetricFog), 
+      "Set to true if volumetric fog should continue while submerged.");
+   addField("MinSize", TypeF32, Offset(mMinDisplaySize, VolumetricFog), 
+      "Min size (in pixels) for fog to be rendered.");
+   addField("FadeSize", TypeF32, Offset(mFadeSize, VolumetricFog), 
+      "Object size in pixels at which the FX-fading kicks in (0 disables fading).");
+   endGroup("VolumetricFogData");
+
+   addGroup("VolumetricFogModulation");
+   addField("texture", TypeImageFilename, Offset(mTextureName, VolumetricFog),
+      "A texture which contains Fogdensity modulator in the red channel and color with 1-green channel. No texture disables modulation.");
+   addField("tiles", TypeF32, Offset(mTexTiles, VolumetricFog), 
+      "How many times the texture is mapped to the object.");
+   addField("modStrength", TypeF32, Offset(mStrength, VolumetricFog),
+      "Overall strength of the density modulation (0 disables modulation).");
+   addField("PrimSpeed", TypePoint2F, Offset(mSpeed1, VolumetricFog),
+      "Overall primary speed of the density modulation (x-speed(u) y-speed(v))");
+   addField("SecSpeed", TypePoint2F, Offset(mSpeed2, VolumetricFog),
+      "Overall secundary speed of the density modulation (x-speed(u) y-speed(v))");
+   endGroup("VolumetricFogModulation");
+
+   addGroup("Reflections");
+   addField("Reflectable", TypeBool, Offset(mReflect, VolumetricFog), 
+      "Set to true if volumetric fog should be reflected.");
+   addField("ReflectStrength", TypeF32, Offset(mFogReflStrength, VolumetricFog), 
+      "Strength of the reflections (0 disables the fog).");
+   endGroup("Reflections");
+
+   addGroup("PostFX");
+   addField("useGlow", TypeBool, Offset(mUseGlow, VolumetricFog), 
+      "Set to true if volumetric fog should use glow PostFX.");
+   addField("glowStrength", TypeF32, Offset(mGlowStrength, VolumetricFog),
+      "Overall strength of the glow PostFX.");
+   addField("modLightRay", TypeBool, Offset(mModifLightRays, VolumetricFog), 
+      "Set to true if volumetric fog should modify the brightness of the Lightrays.");
+   addField("lightRayMod", TypeF32, Offset(mLightRayMod, VolumetricFog),
+      "Modifier for LightRay PostFX when inside Fog.");
+   endGroup("PostFX");
+   Parent::initPersistFields();
+}
+
+void VolumetricFog::inspectPostApply()
+{
+   Parent::inspectPostApply();
+   mSpeed.set(mSpeed1.x, mSpeed1.y, mSpeed2.x, mSpeed2.y);
+   setMaskBits(VolumetricFogMask | FogColorMask | FogDensityMask | FogModulationMask | FogPostFXMask | FogShapeMask);
+}
+
+bool VolumetricFog::onAdd()
+{
+   if (!Parent::onAdd())
+      return false;
+
+   if (!VFRTM->IsInitialized())
+   {
+      Con::errorf("No VolumetricFogRTManager present!!");
+      return false;
+   }
+
+   resetWorldBox();
+
+   mShapeLoaded = LoadShape();
+
+   setRenderTransform(mObjToWorld);
+
+   addToScene();
+   ColBox.set(getTransform(), (mObjBox.getExtents() * getScale() * COLBOX_SCALE));
+   mObjSize = mWorldBox.getGreatestDiagonalLength();
+   mObjScale = getScale();
+   mTexTiles = mAbs(mTexTiles);
+   mSpeed.set(mSpeed1.x, mSpeed1.y, mSpeed2.x, mSpeed2.y);
+   mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
+
+   if (isClientObject())
+   {
+      conn = GameConnection::getConnectionToServer();
+      if (!conn)
+      {  
+         Con::errorf("VolumetricFog::onAdd - No Serverconnection");
+         return false;
+      }
+
+      glowFX = static_cast<PostEffect*>(Sim::findObject("VolFogGlowPostFx"));
+
+      mOldLightRayStrength = Con::getFloatVariable("$LightRayPostFX::brightScalar",1.0f);
+
+      GuiCanvas* cv = dynamic_cast<GuiCanvas*>(Sim::findObject("Canvas"));
+      if (cv == NULL)
+      {
+         Con::errorf("VolumetricFog::onAdd - Canvas not found!!");
+         return false;
+      }
+      mPlatformWindow = cv->getPlatformWindow();
+      VolumetricFogRTManager::getVolumetricFogRTMResizeSignal().notify(this, &VolumetricFog::handleResize);
+      GuiCanvas::getCanvasSizeChangeSignal().notify(this, &VolumetricFog::handleCanvasResize);
+
+      InitTexture();
+      return setupRenderer();
+   }
+
+   VFRTM->IncFogObjects();
+   
+   return true;
+}
+
+void VolumetricFog::onRemove()
+{
+   if (isClientObject())
+   {
+      if (isTicking())
+      {
+         setProcessTick(false);
+         if (mGlowing != 0)
+         {
+            mGlowing = 0;
+            glowFX->disable();
+         }
+         _leaveFog(static_cast<ShapeBase*>(conn->getControlObject()));
+      }
+      VolumetricFogRTManager::getVolumetricFogRTMResizeSignal().remove(this, &VolumetricFog::handleResize);
+      GuiCanvas::getCanvasSizeChangeSignal().remove(this, &VolumetricFog::handleCanvasResize);
+   }
+   removeFromScene();
+   VFRTM->DecFogObjects();
+   Parent::onRemove();
+}
+void VolumetricFog::handleCanvasResize(GuiCanvas* canvas)
+{
+   UpdateBuffers(0,true);
+}
+
+void VolumetricFog::handleResize(VolumetricFogRTManager *RTM, bool resize)
+{
+   if (resize)
+   {
+      mResizing = true;
+      RTM->FogAnswered();
+   }
+   else
+      mResizing = false;
+
+   if (mIsTextured)
+   {
+      F32 width = (F32)mPlatformWindow->getClientExtent().x;
+      F32 height = (F32)mPlatformWindow->getClientExtent().y;
+      if (!mPlatformWindow->isFullscreen())
+         height -= 20;//subtract caption bar from rendertarget size.
+      mTexScale.x = 2.0f - ((F32)mTexture.getWidth() / width);
+      mTexScale.y = 2.0f - ((F32)mTexture.getHeight() / height);
+   }
+
+   UpdateBuffers(0,true);
+}
+
+//-----------------------------------------------------------------------------
+// Loadshape extracted from TSMesh and TSShapeInstance
+//-----------------------------------------------------------------------------
+
+bool VolumetricFog::LoadShape()
+{
+   GFXPrimitiveType GFXdrawTypes[] = { GFXTriangleList, GFXTriangleStrip };
+   if (!mShapeName || mShapeName[0] == '\0')
+   {
+      Con::errorf("VolumetricFog::LoadShape() - No shape name! Volumetric Fog will not be rendered!");
+      return false;
+   }
+
+   // Load shape, server side only reads bounds and radius
+
+   Resource<TSShape> mShape;
+   mShape = ResourceManager::get().load(mShapeName);
+   if (bool(mShape) == false)
+   {
+      Con::errorf("VolumetricFog::LoadShape() - Unable to load shape: %s", mShapeName);
+      return false;
+   }
+
+   mObjBox = mShape->bounds;
+   mRadius = mShape->radius;
+   resetWorldBox();
+
+   if (!isClientObject())
+      return false;
+
+   TSShapeInstance *mShapeInstance = new TSShapeInstance(mShape, false);
+   meshes mesh_detail;
+
+   for (S32 i = 0; i < det_size.size(); i++)
+   {
+      if (det_size[i].indices != NULL)
+         delete(det_size[i].indices);
+      if (det_size[i].piArray != NULL)
+         delete(det_size[i].piArray);
+      if (det_size[i].verts != NULL)
+         delete(det_size[i].verts);
+   }
+   det_size.clear();
+
+   // browsing model for detail levels
+
+   for (U32 i = 0; i < mShape->details.size(); i++)
+   {
+      const TSDetail *detail = &mShape->details[i];
+      mesh_detail.det_size = detail->size;
+      mesh_detail.sub_shape = detail->subShapeNum;
+      mesh_detail.obj_det = detail->objectDetailNum;
+      mesh_detail.verts = NULL;
+      mesh_detail.piArray = NULL;
+      mesh_detail.indices = NULL;
+      if (detail->size >= 0.0f && detail->subShapeNum >= 0)
+         det_size.push_back(mesh_detail);
+   }
+
+   for (U32 i = 0; i < det_size.size(); i++)
+   {
+      const S32 ss = det_size[i].sub_shape;
+      if (ss >= 0)
+      {
+         const S32 start = mShape->subShapeFirstObject[ss];
+         const S32 end = start + mShape->subShapeNumObjects[ss];
+         for (S32 j = start; j < end; j++)
+         {
+            // Loading shape, only the first mesh for each detail will be used!
+            TSShapeInstance::MeshObjectInstance *meshObj = &mShapeInstance->mMeshObjects[j];
+            if (!meshObj)
+               continue;
+            TSMesh *mesh = meshObj->getMesh(det_size[i].obj_det);
+            if (mesh != NULL)
+            {
+               const U32 numNrms = mesh->mNumVerts;
+               GFXVertexPNTT *tmpVerts = NULL;
+               tmpVerts = new GFXVertexPNTT[numNrms];
+               mIsVBDirty = true;
+               for (U32 k = 0; k < numNrms; k++)
+                  {
+                     Point3F norm = mesh->mVertexData[k].normal();
+                     Point3F vert = mesh->mVertexData[k].vert();
+                     Point2F uv = mesh->mVertexData[k].tvert();
+                     tmpVerts[k].point = vert;
+                     tmpVerts[k].texCoord = uv;
+                     tmpVerts[k].normal = norm;
+                  }
+               det_size[i].verts = tmpVerts;
+               det_size[i].num_verts = numNrms;
+
+               det_size[i].piArray = new Vector<GFXPrimitive>();
+               GFXPrimitive pInfo;
+
+               det_size[i].indices = new Vector<U32>();
+
+               for (U32 k = 0; k < mesh->indices.size(); k++)
+                  det_size[i].indices->push_back(mesh->indices[k]);
+
+               U32 primitivesSize = mesh->primitives.size();
+               for (U32 k = 0; k < primitivesSize; k++)
+               {
+                  const TSDrawPrimitive & draw = mesh->primitives[k];
+                  GFXPrimitiveType drawType = GFXdrawTypes[draw.matIndex >> 30];
+                  switch (drawType)
+                  {
+                     case GFXTriangleList:
+                        pInfo.type = drawType;
+                        pInfo.numPrimitives = draw.numElements / 3;
+                        pInfo.startIndex = draw.start;
+                        // Use the first index to determine which 16-bit address space we are operating in
+                        pInfo.startVertex = mesh->indices[draw.start] & 0xFFFF0000;
+                        pInfo.minIndex = pInfo.startVertex;
+                        pInfo.numVertices = getMin((U32)0x10000, mesh->mNumVerts - pInfo.startVertex);
+                        break;
+                     case GFXTriangleStrip:
+                        pInfo.type = drawType;
+                        pInfo.numPrimitives = draw.numElements - 2;
+                        pInfo.startIndex = draw.start;
+                        // Use the first index to determine which 16-bit address space we are operating in
+                        pInfo.startVertex = mesh->indices[draw.start] & 0xFFFF0000;
+                        pInfo.minIndex = pInfo.startVertex;
+                        pInfo.numVertices = getMin((U32)0x10000, mesh->mNumVerts - pInfo.startVertex);
+                        break;
+                     default:
+                        Con::errorf("VolumetricFog::LoadShape Unknown drawtype!?!");
+                        return false;
+                        break;
+                  }
+               det_size[i].piArray->push_back(pInfo);
+               j = end;
+            }
+         }
+         else
+         {
+            Con::errorf("VolumetricFog::LoadShape Error loading mesh from shape!");
+            delete mShapeInstance;
+            return false;
+         }
+         mIsVBDirty = true;
+         mIsPBDirty = true;
+         }
+      }
+   }
+
+   mNumDetailLevels = det_size.size();
+   mCurDetailLevel = 0;
+   UpdateBuffers(mCurDetailLevel);
+   delete mShapeInstance;
+
+   return true;
+}
+
+//-----------------------------------------------------------------------------
+// UpdateBuffers called whenever detaillevel changes (LOD)
+//-----------------------------------------------------------------------------
+
+
+bool VolumetricFog::UpdateBuffers(U32 dl, bool force)
+{
+   if (mVB.isNull() || mIsVBDirty || dl != mCurDetailLevel || force)
+   {
+      mVB.set(GFX, det_size[dl].num_verts, GFXBufferTypeDynamic);
+      mIsVBDirty = false;
+   }
+   GFXVertexPNTT *vertPtr = mVB.lock();
+   if (!vertPtr)
+   {
+      mVB.unlock();
+      return false;
+   }
+   dMemcpy(vertPtr, det_size[dl].verts, sizeof (GFXVertexPNTT)* det_size[dl].num_verts);
+   mVB.unlock();
+
+   if (mIsPBDirty || mPB.isNull() || dl != mCurDetailLevel || force)
+   {
+      #ifdef TORQUE_DEBUG
+      mPB.set(GFX, det_size[dl].indices->size(), det_size[dl].piArray->size(), GFXBufferTypeDynamic, avar("%s() - VolFogPrimBuffer (line %d)", __FUNCTION__, __LINE__));
+      #else
+      mPB.set(GFX, det_size[dl].indices->size(), det_size[dl].piArray->size(), GFXBufferTypeDynamic);
+      #endif
+      U16 *ibIndices = NULL;
+      GFXPrimitive *piInput = NULL;
+      mPB.lock(&ibIndices, &piInput);
+      dCopyArray(ibIndices, det_size[dl].indices->address(), det_size[dl].indices->size());
+      dMemcpy(piInput, det_size[dl].piArray->address(), det_size[dl].piArray->size() * sizeof(GFXPrimitive));
+      mPB.unlock();
+      mIsPBDirty = false;
+   }
+   mCurDetailLevel = dl;
+   return true;
+}
+
+U32 VolumetricFog::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
+{
+   U32 retMask = Parent::packUpdate(con, mask, stream);
+   if (stream->writeFlag(mask & FogColorMask))
+      stream->write(mFogColor);
+   if (stream->writeFlag(mask & FogDensityMask))
+      stream->write(mFogDensity);
+   if (stream->writeFlag(mask & FogModulationMask))
+   {
+      stream->write(mTextureName);
+      mTexTiles = mFabs(mTexTiles);
+      stream->write(mTexTiles);
+      stream->write(mStrength);
+      mathWrite(*stream, mSpeed);
+   }
+   if (stream->writeFlag(mask & FogPostFXMask))
+   {
+      stream->writeFlag(mUseGlow);
+      stream->write(mGlowStrength);
+      stream->writeFlag(mModifLightRays);
+      stream->write(mLightRayMod);
+   }
+   if (stream->writeFlag(mask & VolumetricFogMask))
+   {
+      stream->writeFlag(mIgnoreWater);
+      stream->writeFlag(mReflect);
+      stream->write(mFogReflStrength);
+      stream->writeFlag(mResizing);
+      stream->write(mMinDisplaySize);
+      stream->write(mFadeSize);
+   }
+   if (stream->writeFlag(mask & FogShapeMask))
+   {
+      stream->writeString(mShapeName);
+      mathWrite(*stream, getTransform());
+      mathWrite(*stream, getScale());
+      if (!mShapeName || mShapeName[0] == '\0')
+         return retMask;
+      Resource<TSShape> mShape;
+      mShape = ResourceManager::get().load(mShapeName);
+      if (bool(mShape) == false)
+         return retMask;
+      mObjBox = mShape->bounds;
+      mRadius = mShape->radius;
+      resetWorldBox();
+      mObjSize = mWorldBox.getGreatestDiagonalLength();
+      mObjScale = getScale();
+      mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
+   }
+   return retMask;
+}
+
+void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream)
+{
+   Parent::unpackUpdate(con, stream);
+   MatrixF mat;
+   VectorF scale;
+   VectorF mOldScale = getScale();
+   String oldTextureName = mTextureName;
+   StringTableEntry oldShape = mShapeName;
+
+   if (stream->readFlag())// Fog color
+      stream->read(&mFogColor);
+   if (stream->readFlag())// Fog Density
+   {
+      stream->read(&mFogDensity);
+      if (isTicking())
+      {
+         char buf[20];
+         dSprintf(buf, sizeof(buf), "%3.7f", mFogDensity);
+         Con::setVariable("$VolumetricFog::density", buf);
+      }
+   }
+   if (stream->readFlag())// Fog Modulation
+   {
+      stream->read(&mTextureName);
+      stream->read(&mTexTiles);
+      mTexTiles = mFabs(mTexTiles);
+      stream->read(&mStrength);
+      mathRead(*stream, &mSpeed);
+      mSpeed1.set(mSpeed.x, mSpeed.y);
+      mSpeed2.set(mSpeed.z, mSpeed.w);
+
+      if (isProperlyAdded())
+      {
+         if (oldTextureName != mTextureName)
+            InitTexture();
+         if (oldTextureName.isNotEmpty() && mTextureName.isEmpty())
+         {
+            mIsTextured = false;
+            mTexture.free();
+         }
+      }
+   }
+   if (stream->readFlag())//Fog PostFX
+   {
+      mUseGlow = stream->readFlag();
+      stream->read(&mGlowStrength);
+      mModifLightRays = stream->readFlag();
+      stream->read(&mLightRayMod);
+      if (isTicking())
+      {
+         char buf[20];
+         dSprintf(buf, sizeof(buf), "%3.7f", mGlowStrength);
+         Con::setVariable("$VolFogGlowPostFx::glowStrength", buf);
+         if (mUseGlow && !glowFX->isEnabled())
+            glowFX->enable();
+         if (!mUseGlow && glowFX->isEnabled())
+            glowFX->disable();
+         if (mModifLightRays)
+         {
+            char buf[20];
+            dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength * mLightRayMod);
+            Con::setVariable("$LightRayPostFX::brightScalar", buf);
+         }
+         if (!mModifLightRays)
+         {
+            char buf[20];
+            dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength);
+            Con::setVariable("$LightRayPostFX::brightScalar", buf);
+         }
+      }
+   }
+   if (stream->readFlag())//Volumetric Fog
+   {
+      mIgnoreWater = stream->readFlag();
+      mReflect = stream->readFlag();
+      stream->read(&mFogReflStrength);
+      mResizing = stream->readFlag();
+      stream->read(&mMinDisplaySize);
+      stream->read(&mFadeSize);
+   }
+   if (stream->readFlag())//Fog shape
+   {
+      mShapeName = stream->readSTString();
+      mathRead(*stream, &mat);
+      mathRead(*stream, &scale);
+      if (strcmp(oldShape, mShapeName) != 0)
+      {
+         mIsVBDirty = true;
+         mShapeLoaded = LoadShape();
+      }
+      setScale(scale);
+      setTransform(mat);
+      ColBox.set(getTransform(), (mObjBox.getExtents() * getScale() * COLBOX_SCALE));
+      mObjSize = mWorldBox.getGreatestDiagonalLength();
+      mObjScale = getScale();
+      mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
+   }
+}
+
+void VolumetricFog::processTick(const Move* move)
+{
+   Parent::processTick(move);
+   mCounter++;
+   if ( mGlowing==1 && mCurGlow < mGlowStrength )
+   {
+      mCurGlow += (mGlowStrength / 10.0);
+      char buf[20];
+      dSprintf(buf, sizeof(buf), "%3.7f", mCurGlow);
+      Con::setVariable("$VolFogGlowPostFx::glowStrength", buf);
+   }
+   else if ( mGlowing == 2 && mCurGlow > 0.0f )
+   {
+      mCurGlow -= (mGlowStrength / 5.0f);
+      if (mCurGlow <= 0.0f)
+      {
+         glowFX->disable();
+         mGlowing = 0;
+         setProcessTick(false);
+         return;
+      }
+      else
+      {
+         char buf[20];
+         dSprintf(buf, sizeof(buf), "%3.7f", mCurGlow);
+         Con::setVariable("$VolFogGlowPostFx::glowStrength", buf);
+      }
+   }
+   if (mCounter == 3)
+   {
+      ShapeBase* control = static_cast<ShapeBase*>(conn->getControlObject());
+      MatrixF xfm;
+      control->getRenderEyeTransform(&xfm);
+      Point3F pos = xfm.getPosition();
+      if (!ColBox.isContained(pos))
+         _leaveFog(control);
+      mCounter = 0;
+   }
+}
+
+void VolumetricFog::_enterFog(ShapeBase *control)
+{
+   if (mUseGlow)
+   {
+      if (glowFX)
+      {
+         mCurGlow = 0.0f;
+         Con::setVariable("$VolFogGlowPostFx::glowStrength", "0.0");
+         glowFX->enable();
+         mGlowing = 1;
+      }
+   }
+   if (mModifLightRays)
+   {
+      char buf[20];
+      dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength * mLightRayMod);
+      Con::setVariable("$LightRayPostFX::brightScalar", buf);
+   }
+   mCounter = 0;
+   char buf[20];
+   dSprintf(buf, sizeof(buf), "%3.7f", mFogDensity);
+   Con::setVariable("$VolumetricFog::density", buf);
+   setProcessTick(true);
+   if (control)
+      onEnterFog_callback(control->getId());
+}
+
+void VolumetricFog::_leaveFog(ShapeBase *control)
+{
+   mCamInFog = false;
+   Con::setVariable("$VolumetricFog::density", "0.0");
+   if (mModifLightRays)
+   {
+      char buf[20];
+      dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength);
+      Con::setVariable("$LightRayPostFX::brightScalar", buf);
+   }
+   if (mUseGlow)
+   {
+      if (glowFX && mGlowing != 2)
+      {
+         mCurGlow = mGlowStrength;
+         mGlowing = 2;
+         if (control)
+            onLeaveFog_callback(control->getId());
+      }
+   }
+   else
+   {
+      setProcessTick(false);
+      if (control)
+         onLeaveFog_callback(control->getId());
+   }
+}
+
+//-----------------------------------------------------------------------------
+// Setting up the renderers
+//-----------------------------------------------------------------------------
+
+bool VolumetricFog::setupRenderer()
+{
+   // Search for the prepass rendertarget and shadermacros.
+   mPrepassTarget = NamedTexTarget::find("prepass");
+   if (!mPrepassTarget.isValid())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find PrepassTarget");
+      return false;
+   }
+
+   Vector<GFXShaderMacro> macros;
+   if (mPrepassTarget)
+      mPrepassTarget->getShaderMacros(&macros);
+
+   // Search the depth and frontbuffers which are created by the VolumetricFogRTManager
+
+   mDepthBufferTarget = NamedTexTarget::find("volfogdepth");
+   if (!mDepthBufferTarget.isValid())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find depthbuffer");
+      return false;
+   }
+
+   mFrontBufferTarget = NamedTexTarget::find("volfogfront");
+   if (!mFrontBufferTarget.isValid())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find frontbuffer");
+      return false;
+   }
+
+   // Find and setup the prepass Shader
+
+   ShaderData *shaderData;
+   mPrePassShader = Sim::findObject("VolumetricFogPrePassShader", shaderData) ?
+   shaderData->getShader() : NULL;
+   if (!mPrePassShader)
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogPrePassShader");
+      return false;
+   }
+
+   // Create ShaderConstBuffer and Handles
+
+   mPPShaderConsts = mPrePassShader->allocConstBuffer();
+   if (mPPShaderConsts.isNull())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants 1.");
+      return false;
+   }
+
+   mPPModelViewProjSC = mPrePassShader->getShaderConstHandle("$modelView");
+
+   // Find and setup the VolumetricFog Shader
+
+   shaderData = NULL;
+   mShader = Sim::findObject("VolumetricFogShader", shaderData) ?
+   shaderData->getShader(macros) : NULL;
+   if (!mShader)
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogShader");
+      return false;
+   }
+
+   // Create ShaderConstBuffer and Handles
+
+   mShaderConsts = mShader->allocConstBuffer();
+   if (mShaderConsts.isNull())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants 2.");
+      return false;
+   }
+
+   mModelViewProjSC = mShader->getShaderConstHandle("$modelView");
+   mFadeSizeSC = mShader->getShaderConstHandle("$fadesize");
+   mFogColorSC = mShader->getShaderConstHandle("$fogColor");
+   mFogDensitySC = mShader->getShaderConstHandle("$fogDensity");
+   mPreBias = mShader->getShaderConstHandle("$preBias");
+   mAccumTime = mShader->getShaderConstHandle("$accumTime");
+   mIsTexturedSC = mShader->getShaderConstHandle("$textured");
+   mTexTilesSC = mShader->getShaderConstHandle("$numtiles");
+   mModStrengthSC = mShader->getShaderConstHandle("$modstrength");
+   mModSpeedSC = mShader->getShaderConstHandle("$modspeed");
+   mViewPointSC = mShader->getShaderConstHandle("$viewpoint");
+   mTexScaleSC = mShader->getShaderConstHandle("$texscale");
+   mAmbientColorSC = mShader->getShaderConstHandle("$ambientColor");
+
+   // Find and setup the reflection Shader
+
+   shaderData = NULL;
+   mReflectionShader = Sim::findObject("VolumetricFogReflectionShader", shaderData) ?
+   shaderData->getShader() : NULL;
+   if (!mReflectionShader)
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogReflectionShader");
+      return false;
+   }
+
+   mReflShaderConsts = mReflectionShader->allocConstBuffer();
+   if (mReflShaderConsts.isNull())
+   {
+      Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants for VolumetricFogReflectionShader.");
+      return false;
+   }
+
+   mReflModelViewProjSC = mReflectionShader->getShaderConstHandle("$modelView");
+   mReflFogColorSC = mReflectionShader->getShaderConstHandle("$fogColor");
+   mReflFogDensitySC = mReflectionShader->getShaderConstHandle("$fogDensity");
+   mReflFogStrengthSC = mReflectionShader->getShaderConstHandle("$reflStrength");
+
+   // Create the prepass StateBlock
+
+   desc_preD.setCullMode(GFXCullCW);
+   desc_preD.setBlend(true);
+   desc_preD.setZReadWrite(false, false);
+   desc_preD.stencilEnable = false;
+   desc_preF.setCullMode(GFXCullCCW);
+   desc_preF.setBlend(true);
+   desc_preF.setZReadWrite(true, false);
+   desc_preF.stencilEnable = false;
+   
+   // Create the VolumetricFog StateBlock
+
+   descD.setCullMode(GFXCullCW);
+   descD.setBlend(true);
+   descD.setZReadWrite(false, false);// desc.setZReadWrite(true, false);
+
+   // prepassBuffer sampler
+   descD.samplersDefined = true;
+   descD.samplers[0].addressModeU = GFXAddressClamp;
+   descD.samplers[0].addressModeV = GFXAddressClamp;
+   descD.samplers[0].addressModeW = GFXAddressClamp;
+   descD.samplers[0].magFilter = GFXTextureFilterLinear;
+   descD.samplers[0].minFilter = GFXTextureFilterLinear;
+   descD.samplers[0].mipFilter = GFXTextureFilterLinear;
+   descD.samplers[0].textureColorOp = GFXTOPDisable;
+
+   // DepthBuffer sampler
+   descD.samplers[1].addressModeU = GFXAddressClamp;
+   descD.samplers[1].addressModeV = GFXAddressClamp;
+   descD.samplers[1].addressModeW = GFXAddressClamp;
+   descD.samplers[1].magFilter = GFXTextureFilterLinear;
+   descD.samplers[1].minFilter = GFXTextureFilterLinear;
+   descD.samplers[1].mipFilter = GFXTextureFilterLinear;
+   descD.samplers[1].textureColorOp = GFXTOPModulate;
+
+   // FrontBuffer sampler
+   descD.samplers[2].addressModeU = GFXAddressClamp;
+   descD.samplers[2].addressModeV = GFXAddressClamp;
+   descD.samplers[2].addressModeW = GFXAddressClamp;
+   descD.samplers[2].magFilter = GFXTextureFilterLinear;
+   descD.samplers[2].minFilter = GFXTextureFilterLinear;
+   descD.samplers[2].mipFilter = GFXTextureFilterLinear;
+   descD.samplers[2].textureColorOp = GFXTOPModulate;
+
+   // animated density modifier map sampler
+   descD.samplers[3].addressModeU = GFXAddressWrap;
+   descD.samplers[3].addressModeV = GFXAddressWrap;
+   descD.samplers[3].addressModeW = GFXAddressWrap;
+   descD.samplers[3].magFilter = GFXTextureFilterLinear;
+   descD.samplers[3].minFilter = GFXTextureFilterLinear;
+   descD.samplers[3].mipFilter = GFXTextureFilterLinear;
+   descD.samplers[3].textureColorOp = GFXTOPModulate;
+
+   dMemcpy(&descF, &descD, sizeof(GFXStateBlockDesc));
+   descF.setCullMode(GFXCullCCW);
+   descF.setBlend(true);
+   descF.setZReadWrite(true, false);
+
+   desc_refl.setCullMode(GFXCullCCW);
+   desc_refl.setBlend(true);
+   desc_refl.setZReadWrite(true, false);
+
+   mStateblock_preD = GFX->createStateBlock(desc_preD);
+   mStateblock_preF = GFX->createStateBlock(desc_preF);
+   mStateblockD = GFX->createStateBlock(descD);
+   mStateblockF = GFX->createStateBlock(descF);
+   mStateblock_refl = GFX->createStateBlock(desc_refl);
+
+   // Create Rendertarget
+
+   z_buf = GFX->allocRenderToTextureTarget();
+   if (z_buf == NULL)
+   {
+      Con::errorf("VolumetricFog::setupRenderer - Could not create Render Target");
+      return false;
+   }
+
+   return true;
+}
+
+void VolumetricFog::prepRenderImage(SceneRenderState *state)
+{
+   if (!mShapeLoaded || mFogDensity <= 0.0f || mResizing)
+      return;
+
+   if (!state->isDiffusePass())
+   {
+      if (!state->isReflectPass())
+      return;
+   }
+   
+   PROFILE_SCOPE(VolumetricFog_prepRenderImage);
+
+   // Time critical therefore static_cast
+   ShapeBase* control = static_cast<ShapeBase*>(conn->getControlObject());
+   if (control->getWaterCoverage() >= 0.9f && !mIgnoreWater)
+      return;
+
+   camPos = state->getCameraPosition();
+   F32 dist = (camPos - getBoxCenter()).len();
+   F32 scaleFactor = dist * mInvScale;
+   if (scaleFactor <= 0.0f)
+   {
+      if (mCurDetailLevel != 0)
+         UpdateBuffers(0);
+   }
+   const F32 pixelScale = state->getViewport().extent.y / 300.0f;
+
+   mPixelSize = (mRadius / scaleFactor) * state->getWorldToScreenScale().y * pixelScale;
+   if (mPixelSize < mMinDisplaySize)
+      return;
+   if (mNumDetailLevels > 1)
+   {
+      if ((det_size[mCurDetailLevel].det_size > mPixelSize) && (mCurDetailLevel < mNumDetailLevels - 1))
+         UpdateBuffers(mCurDetailLevel + 1);
+      else if (mCurDetailLevel > 0)
+      {
+         if (mPixelSize >= det_size[mCurDetailLevel - 1].det_size)
+            UpdateBuffers(mCurDetailLevel - 1);
+      }
+   }
+
+   if (state->isReflectPass() && mReflect)
+   {
+      ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
+      ri->renderDelegate.bind(this, &VolumetricFog::reflect_render);
+      ri->type = RenderPassManager::RIT_VolumetricFog;
+      ri->translucentSort = true;
+      ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint(camPos);
+      if (dist < 1.0f)
+         ri->defaultKey = 1;
+      else
+         ri->defaultKey = U32(dist);
+      state->getRenderPass()->addInst(ri);
+      return;
+   }
+   else if (state->isDiffusePass())
+   {
+      viewDist = state->getFarPlane();
+      mFOV = state->getCameraFrustum().getFov() / M_PI_F;
+      Point3F mEyeVec = state->getVectorEye() * viewDist;
+
+      mViewPoint.x = ((mAtan2(mEyeVec.x, mEyeVec.y) / M_PI_F) + 1.0f) * mTexTiles;
+      mViewPoint.y = (0.5f - (mAsin(mEyeVec.z) / M_PI_F)) * mTexTiles;
+
+      bool isInside = ColBox.isContained(camPos);
+      if (isInside && !mCamInFog)
+      {
+         mCamInFog = true;
+         _enterFog(control);
+      }
+      else if (!isInside && mCamInFog)
+         mCamInFog = false;
+
+      ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
+      ri->renderDelegate.bind(this, &VolumetricFog::render);
+      ri->type = RenderPassManager::RIT_VolumetricFog;
+      ri->translucentSort = true;
+      ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint(camPos);
+      if (dist < 1.0f)
+         ri->defaultKey = 1;
+      else
+         ri->defaultKey = U32(dist);
+      state->getRenderPass()->addInst(ri);
+      return;
+   }
+   return;
+}
+
+void VolumetricFog::render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat)
+{
+   if (overrideMat || !mShapeLoaded || !isClientObject() || mResizing)
+      return;
+
+   PROFILE_SCOPE(VolumetricFog_Render);
+
+   GFXTransformSaver saver;
+   GFX->setVertexBuffer(mVB);
+   GFX->setPrimitiveBuffer(mPB);
+
+   MatrixF mat = getRenderTransform();
+   mat.scale(mObjScale);
+   GFX->multWorld(mat);
+
+   GFX->setShader(mPrePassShader);
+   GFX->setShaderConstBuffer(mPPShaderConsts);
+   GFX->setStateBlock(mStateblock_preD);
+
+   // Set all the shader consts...
+
+   MatrixF xform(GFX->getProjectionMatrix());
+   xform *= GFX->getViewMatrix();
+   xform *= GFX->getWorldMatrix();
+
+   mPPShaderConsts->setSafe(mPPModelViewProjSC, xform);
+
+   LightInfo *lightinfo = LIGHTMGR->getSpecialLight(LightManager::slSunLightType);
+   const ColorF &sunlight = state->getAmbientLightColor();
+
+   Point3F ambientColor(sunlight.red, sunlight.green, sunlight.blue);
+   mShaderConsts->setSafe(mAmbientColorSC, ambientColor);
+
+   GFXTextureObject *mDepthBuffer = mDepthBufferTarget ? mDepthBufferTarget->getTexture(0) : NULL;
+   GFXTextureObject *mFrontBuffer = mFrontBufferTarget ? mFrontBufferTarget->getTexture(0) : NULL;
+
+   GFX->pushActiveRenderTarget();
+
+   //render backside to target mDepthBuffer
+   z_buf->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil);
+   z_buf->attachTexture(GFXTextureTarget::Color0, mDepthBuffer);
+
+   GFX->setActiveRenderTarget(z_buf);
+   GFX->clear(GFXClearStencil | GFXClearTarget , ColorI(0,0,0,0), 1.0f, 0);
+
+   GFX->drawPrimitive(0);
+   z_buf->resolve();
+
+   //render frontside to target mFrontBuffer
+   z_buf->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil);
+   z_buf->attachTexture(GFXTextureTarget::Color0, mFrontBuffer);
+   GFX->clear(GFXClearStencil | GFXClearTarget, ColorI(0, 0, 0, 0), 1.0f, 0);
+
+   GFX->setStateBlock(mStateblock_preF);
+
+   GFX->drawPrimitive(0);
+   z_buf->resolve();
+
+   GFX->popActiveRenderTarget();
+   z_buf->attachTexture(GFXTextureTarget::Color0, NULL);
+
+   //render Volumetric Fog
+   GFX->setShader(mShader);
+   GFX->setShaderConstBuffer(mShaderConsts);
+
+   mShaderConsts->setSafe(mModelViewProjSC, xform);
+   if (mFadeSize > 0.0f)
+      mShaderConsts->setSafe(mFadeSizeSC, mClampF(mPixelSize / mFadeSize, 0.0f, 1.0f));
+   else
+      mShaderConsts->setSafe(mFadeSizeSC, 1.0f);
+   mShaderConsts->setSafe(mFogColorSC, mFogColor);
+   mShaderConsts->setSafe(mFogDensitySC, mFogDensity);
+   mShaderConsts->setSafe(mPreBias, viewDist);
+   mShaderConsts->setSafe(mAccumTime, (F32)Sim::getCurrentTime() / 1000.0f);
+   mShaderConsts->setSafe(mModStrengthSC, mStrength);
+   mShaderConsts->setSafe(mModSpeedSC, mSpeed);
+   mShaderConsts->setSafe(mViewPointSC, mViewPoint);
+   mShaderConsts->setSafe(mTexScaleSC, mTexScale * mFOV);
+   mShaderConsts->setSafe(mTexTilesSC, mTexTiles);
+
+   GFXTextureObject *prepasstex = mPrepassTarget ? mPrepassTarget->getTexture(0) : NULL;
+
+   GFX->setTexture(0, prepasstex);
+   GFX->setTexture(1, mDepthBuffer);
+   GFX->setTexture(2, mFrontBuffer);
+
+   if (mIsTextured && mStrength > 0.0f)
+   {
+      GFX->setTexture(3, mTexture);
+      mShaderConsts->setSafe(mIsTexturedSC, 1.0f);
+   }
+   else
+      mShaderConsts->setSafe(mIsTexturedSC, 0.0f);
+
+   if (mCamInFog)
+   {
+      /*GFXLockedRect *rect=mDepthBuffer->lock();
+      U32 pixoffset = 0;// 1572864 + (512 * 4);
+      U8 red = rect->bits[pixoffset];
+      U8 green = rect->bits[pixoffset+1];
+      U8 blue = rect->bits[pixoffset+2];
+      U8 alpha = rect->bits[pixoffset+3];
+      mDepthBuffer->unlock();
+      S32 lval = ((alpha << 24) + (blue << 16) + (green << 8) + (red));
+      F32 fval = ((F32)lval / S32_MAX);
+      Con::printf("Color %d %d %d %d %d %f", red, green, blue, alpha, lval, fval);*/
+      GFX->setStateBlock(mStateblockD);
+   }
+   else
+      GFX->setStateBlock(mStateblockF);
+
+   GFX->drawPrimitive(0);
+}
+
+void VolumetricFog::reflect_render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat)
+{
+   if (overrideMat || !mShapeLoaded || !isClientObject() || mResizing || (mFogReflStrength==0.0f))
+      return;
+
+   GFXTransformSaver saver;
+   GFX->setVertexBuffer(mVB);
+   GFX->setPrimitiveBuffer(mPB);
+
+   MatrixF mat = getRenderTransform();
+   mat.scale(mObjScale);
+   GFX->multWorld(mat);
+
+   GFX->setShader(mReflectionShader);
+   GFX->setShaderConstBuffer(mReflShaderConsts);
+   GFX->setStateBlock(mStateblock_refl);
+
+   // Set all the shader consts...
+   MatrixF xform(GFX->getProjectionMatrix());
+   xform *= GFX->getViewMatrix();
+   xform *= GFX->getWorldMatrix();
+
+   mReflShaderConsts->setSafe(mReflModelViewProjSC, xform);
+   mReflShaderConsts->setSafe(mReflFogColorSC, mFogColor);
+   mReflShaderConsts->setSafe(mReflFogDensitySC, mFogDensity);
+   mReflShaderConsts->setSafe(mReflFogStrengthSC, mFogReflStrength);
+
+   GFX->drawPrimitive(0);
+}
+
+//-----------------------------------------------------------------------------
+// InitTexture is called whenever a modulation texture is added to the object
+//-----------------------------------------------------------------------------
+
+void VolumetricFog::InitTexture()
+{
+   mIsTextured = false;
+
+   if (mTextureName.isNotEmpty())
+      mTexture.set(mTextureName, &GFXDefaultStaticDiffuseProfile, "VolumetricFogMod");
+
+   if (!mTexture.isNull())
+   {
+      mIsTextured = true;
+
+      F32 width = (F32)mPlatformWindow->getClientExtent().x;
+      F32 height = (F32)mPlatformWindow->getClientExtent().y;
+
+      if (!mPlatformWindow->isFullscreen())
+         height -= 20;//subtract caption bar from rendertarget size.
+
+      mTexScale.x = 2.0f - ((F32)mTexture.getWidth() / width);
+      mTexScale.y = 2.0f - ((F32)mTexture.getHeight() / height);
+   }
+}
+
+void VolumetricFog::setFogColor(ColorF color)
+{
+   mFogColor.set(255 * color.red,255 * color.green,255 * color.blue);
+   setMaskBits(FogColorMask);
+}
+
+void VolumetricFog::setFogColor(ColorI color)
+{
+   mFogColor = color;
+   setMaskBits(FogColorMask);
+}
+
+void VolumetricFog::setFogDensity(F32 density)
+{
+   if (density < 0.0f)
+      density = 0.0f;
+   mFogDensity = density;
+   setMaskBits(FogDensityMask);
+}
+
+void VolumetricFog::setFogModulation(F32 strength,Point2F speed1,Point2F speed2)
+{
+   mStrength = strength;
+   mSpeed1 = speed1;
+   mSpeed2 = speed2;
+   mSpeed.set(speed1.x, speed1.y, speed2.x, speed2.y);
+   setMaskBits(FogModulationMask);
+}
+
+void VolumetricFog::setFogGlow(bool on_off, F32 strength)
+{
+   mUseGlow = on_off;
+   mGlowStrength = strength;
+   setMaskBits(FogPostFXMask);
+}
+
+void VolumetricFog::setFogLightray(bool on_off, F32 strength)
+{
+   mModifLightRays = on_off;
+   mLightRayMod = strength;
+   setMaskBits(FogPostFXMask);
+}
+
+bool VolumetricFog::isInsideFog()
+{
+   return mCamInFog;
+}
+
+DefineEngineMethod(VolumetricFog, SetFogColorF, void, (ColorF new_color), ,
+"@brief Changes the color of the fog\n\n."
+"@params new_color the new fog color (rgb 0.0 - 1.0, a is ignored.")
+{
+   object->setFogColor(new_color);
+}
+
+DefineEngineMethod(VolumetricFog, SetFogColor, void, (ColorI new_color), ,
+"@brief Changes the color of the fog\n\n."
+"@params new_color the new fog color (rgb 0-255, a is ignored.")
+{
+   object->setFogColor(new_color);
+}
+
+DefineEngineMethod(VolumetricFog, SetFogDensity, void, (F32 new_density), ,
+"@brief Changes the density of the fog\n\n."
+"@params new_density the new fog density.")
+{
+   object->setFogDensity(new_density);
+}
+
+DefineEngineMethod(VolumetricFog, SetFogModulation, void, (F32 new_strenght, Point2F new_speed1, Point2F new_speed2), ,
+"@brief Changes the modulation of the fog\n\n."
+"@params new_strenght the new strength of the modulation.\n"
+"@params new_speed1 the new speed (x y) of the modulation layer 1.\n"
+"@params new_speed2 the new speed (x y) of the modulation layer 2.\n")
+{
+   object->setFogModulation(new_strenght, new_speed1, new_speed2);
+}
+
+DefineEngineMethod(VolumetricFog, SetFogGlow, void, (bool on_off,F32 strength), ,
+"@brief Changes the glow postfx when inside the fog\n\n."
+"@params on_off set to true to enable glow.\n"
+"@params strength glow strength.\n")
+{
+   object->setFogGlow(on_off, strength);
+}
+
+DefineEngineMethod(VolumetricFog, SetFogLightray, void, (bool on_off, F32 strength), ,
+"@brief Changes the lightrays postfx when inside the fog\n\n."
+"@params on_off set to true to modification of the lightray postfx.\n"
+"@params strength lightray strength.\n")
+{
+   object->setFogLightray(on_off, strength);
+}
+
+DefineEngineMethod(VolumetricFog, isInsideFog, bool, (), ,
+"@brief returns true if control object is inside the fog\n\n.")
+{
+   return object->isInsideFog();
+}

+ 243 - 0
Engine/source/environment/VolumetricFog.h

@@ -0,0 +1,243 @@
+//-----------------------------------------------------------------------------
+// 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 _VolumetricFog_H_
+#define _VolumetricFog_H_
+   
+#ifndef _SCENEOBJECT_H_
+#include "scene/sceneObject.h"
+#endif
+#ifndef _MATTEXTURETARGET_H_
+#include "materials/matTextureTarget.h"
+#endif
+#ifndef _GFXSHADER_H_
+#include "gfx/gfxShader.h"
+#endif
+#ifndef _GFXTARGET_H_
+#include "gfx/gfxTarget.h"
+#endif
+#ifndef _GFXVERTEXBUFFER_H_
+#include "gfx/gfxVertexBuffer.h"
+#endif
+#ifndef _TSSHAPE_H_
+#include "ts/tsShape.h"
+#endif
+#ifndef _POST_EFFECT_H_
+#include "postFx/postEffect.h"
+#endif
+   
+#include "gui/core/guiCanvas.h"
+   
+class VolumetricFogRTManager;
+   
+class VolumetricFog : public SceneObject
+{
+   typedef SceneObject Parent;
+   
+   // Maskbits for updating
+   enum
+   {
+      VolumetricFogMask = Parent::NextFreeMask,
+      FogColorMask = Parent::NextFreeMask << 1,
+      FogDensityMask = Parent::NextFreeMask << 2,
+      FogModulationMask = Parent::NextFreeMask << 3,
+      FogPostFXMask = Parent::NextFreeMask << 4,
+      FogShapeMask = Parent::NextFreeMask << 5,
+      NextFreeMask = Parent::NextFreeMask << 6
+   };
+   
+// Struct which holds the shape details
+   struct meshes
+   {
+      F32 det_size;
+      S32 sub_shape;
+      S32 obj_det;
+      U32 num_verts;
+      GFXVertexPNTT *verts;
+      Vector <GFXPrimitive> *piArray;
+      Vector <U32> *indices;
+   };
+   
+   protected:
+      // Rendertargets;
+      GFXTextureTargetRef z_buf;
+      NamedTexTargetRef mPrepassTarget;
+      NamedTexTargetRef mDepthBufferTarget;
+      NamedTexTargetRef mFrontBufferTarget;
+   
+      // Fog Modulation texture
+      GFXTexHandle mTexture;
+   
+      // Shaders
+      GFXShaderRef mShader;
+      GFXShaderRef mPrePassShader;
+      GFXShaderRef mReflectionShader;
+   
+      // Stateblocks
+      GFXStateBlockDesc descD;
+      GFXStateBlockDesc descF;
+      GFXStateBlockDesc desc_preD;
+      GFXStateBlockDesc desc_preF;
+      GFXStateBlockDesc desc_refl;
+   
+      GFXStateBlockRef mStateblockD;
+      GFXStateBlockRef mStateblockF;
+      GFXStateBlockRef mStateblock_preD;
+      GFXStateBlockRef mStateblock_preF;
+      GFXStateBlockRef mStateblock_refl;
+   
+      // Shaderconstants
+      GFXShaderConstBufferRef mShaderConsts;
+      GFXShaderConstHandle *mModelViewProjSC;
+      GFXShaderConstHandle *mFadeSizeSC;
+      GFXShaderConstHandle *mFogColorSC;
+      GFXShaderConstHandle *mFogDensitySC;
+      GFXShaderConstHandle *mPreBias;
+      GFXShaderConstHandle *mAccumTime;
+      GFXShaderConstHandle *mIsTexturedSC;
+      GFXShaderConstHandle *mModSpeedSC;
+      GFXShaderConstHandle *mModStrengthSC;
+      GFXShaderConstHandle *mViewPointSC;
+      GFXShaderConstHandle *mTexScaleSC;
+      GFXShaderConstHandle *mTexTilesSC;
+   
+      GFXShaderConstBufferRef mPPShaderConsts;
+      GFXShaderConstHandle *mPPModelViewProjSC;
+
+      GFXShaderConstHandle *mAmbientColorSC;
+   
+      GFXShaderConstBufferRef mReflShaderConsts;
+      GFXShaderConstHandle *mReflModelViewProjSC;
+      GFXShaderConstHandle *mReflFogColorSC;
+      GFXShaderConstHandle *mReflFogDensitySC;
+      GFXShaderConstHandle *mReflFogStrengthSC;
+   
+      // Vertex and Prim. Buffer
+      GFXVertexBufferHandle<GFXVertexPNTT> mVB;
+      GFXPrimitiveBufferHandle mPB;
+   
+      // Fog volume data;
+      StringTableEntry mShapeName;
+      ColorI mFogColor;
+      F32 mFogDensity;
+      bool mIgnoreWater;
+      bool mReflect;
+      Vector<meshes> det_size;
+      bool mShapeLoaded;
+      F32 mPixelSize;
+      F32 mFadeSize;
+      U32 mCurDetailLevel;
+      U32 mNumDetailLevels;
+      F32 mObjSize;
+      F32 mRadius;
+      OrientedBox3F ColBox;
+      VectorF mObjScale;
+      F32 mMinDisplaySize;
+      F32 mInvScale;
+   
+      // Fog Modulation data
+      String mTextureName;
+      bool mIsTextured;
+      F32 mTexTiles;
+      F32 mStrength;
+      Point2F mSpeed1;
+      Point2F mSpeed2;
+      Point4F mSpeed;
+      Point2F mTexScale;
+   
+      // Fog Rendering data
+      Point3F camPos;
+      Point2F mViewPoint;
+      F32 mFOV;
+      F32 viewDist;
+      bool mIsVBDirty;
+      bool mIsPBDirty;
+      bool mCamInFog;
+      bool mResizing;
+      PlatformWindow *mPlatformWindow;
+   
+      // Reflections
+      F32 mFogReflStrength;
+   
+      // PostFX
+      PostEffect *glowFX;
+      bool mUseGlow;
+      F32 mGlowStrength;
+      U8 mGlowing;
+      F32 mCurGlow;
+   
+      bool mModifLightRays;
+      F32 mLightRayMod;
+      F32 mOldLightRayStrength;
+   
+      GameConnection* conn;
+      U32 mCounter;
+   
+      void ResizeRT(PlatformWindow *win, bool resize);
+   
+   protected:
+      // Protected methods
+      bool onAdd();
+      void onRemove();
+      void handleResize(VolumetricFogRTManager *RTM, bool resize);
+      void handleCanvasResize(GuiCanvas* canvas);
+   
+      bool LoadShape();
+      bool setupRenderer();
+      void InitTexture();
+      bool UpdateBuffers(U32 dl,bool force=true);
+   
+      void processTick(const Move *move);
+      void _enterFog(ShapeBase *control);
+      void _leaveFog(ShapeBase *control);
+   
+   public:
+      // Public methods
+      VolumetricFog();
+      ~VolumetricFog();
+   
+      static void initPersistFields();
+      virtual void inspectPostApply();
+   
+      U32 packUpdate(NetConnection *conn, U32 mask, BitStream *stream);
+      void unpackUpdate(NetConnection *conn, BitStream *stream);
+   
+      void prepRenderImage(SceneRenderState* state);
+      void render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat);
+      void reflect_render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat);
+   
+      // Methods for modifying & networking various fog elements
+      // Used in script
+      void setFogColor(ColorF color);
+      void setFogColor(ColorI color);
+      void setFogDensity(F32 density);
+      void setFogModulation(F32 strength, Point2F speed1, Point2F speed2);
+      void setFogGlow(bool on_off, F32 strength);
+      void setFogLightray(bool on_off, F32 strength);
+      bool isInsideFog();
+   
+      DECLARE_CONOBJECT(VolumetricFog);
+   
+      DECLARE_CALLBACK(void, onEnterFog, (SimObjectId obj));
+      DECLARE_CALLBACK(void, onLeaveFog, (SimObjectId obj));
+};
+#endif

+ 299 - 0
Engine/source/environment/VolumetricFogRTManager.cpp

@@ -0,0 +1,299 @@
+//-----------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+   
+//-----------------------------------------------------------------------------
+// Volumetric Fog Rendertarget Manager
+//
+// Creates and maintains one set of rendertargets to be used by every
+// VolumetricFog object in the scene.
+//
+// Will be loaded at startup end removed when ending game.
+//
+//-----------------------------------------------------------------------------
+   
+#include "VolumetricFogRTManager.h"
+#include "core/module.h"
+#include "scene/sceneManager.h"
+#include "windowManager/platformWindowMgr.h"
+#include "console/engineAPI.h"
+#include "gui/core/guiCanvas.h"
+   
+MODULE_BEGIN(VolumetricFogRTManager)
+   
+MODULE_INIT_AFTER(Scene)
+MODULE_SHUTDOWN_BEFORE(Scene)
+   
+MODULE_INIT
+{
+   gVolumetricFogRTManager = new VolumetricFogRTManager;
+   gClientSceneGraph->addObjectToScene(gVolumetricFogRTManager);
+}
+   
+MODULE_SHUTDOWN
+{
+   gClientSceneGraph->removeObjectFromScene(gVolumetricFogRTManager);
+   SAFE_DELETE(gVolumetricFogRTManager);
+}
+   
+MODULE_END;
+   
+ConsoleDocClass( VolumetricFogRTManager,
+"@brief Creates and maintains one set of rendertargets to be used by every\n"
+"VolumetricFog object in the scene.\n\n"
+"Will be loaded at startup end removed when ending game.\n\n"
+"Methods:\n"
+" get() returns the currently loaded VolumetricFogRTManager, also accessible\n"
+" through VFRTM define.\n"
+" Init() Initializes the rendertargets, called when a VolumetricFog object is\n"
+" added to the scene.\n"
+" isInitialed() returns true if Rendertargets are present, false if not, then\n"
+" Init() should be called to create the rendertargets.\n"
+" setQuality(U32 Quality) Normally a rendertarget has the same size as the view,\n"
+" with this method you can scale down the size of it.\n"
+" Be aware that scaling down will introduce renderartefacts.\n"
+"@ingroup Atmosphere"
+);
+   
+VolumetricFogRTMResizeSignal VolumetricFogRTManager::smVolumetricFogRTMResizeSignal;
+   
+VolumetricFogRTManager *gVolumetricFogRTManager = NULL;
+
+S32 VolumetricFogRTManager::mTargetScale = 1;
+   
+IMPLEMENT_CONOBJECT(VolumetricFogRTManager);
+   
+VolumetricFogRTManager::VolumetricFogRTManager()
+{
+   setGlobalBounds();
+   mTypeMask |= EnvironmentObjectType;
+   mNetFlags.set(IsGhost);
+   mIsInitialized = false;
+   mNumFogObjects = 0;
+}
+   
+VolumetricFogRTManager::~VolumetricFogRTManager()
+{
+   if (mFrontTarget.isRegistered())
+      mFrontTarget.unregister();
+   
+   if (mDepthTarget.isRegistered())
+      mDepthTarget.unregister();
+   
+   if (mDepthBuffer.isValid())
+      mDepthBuffer->kill();
+   
+   if (mFrontBuffer.isValid())
+      mFrontBuffer->kill();
+}
+   
+void VolumetricFogRTManager::onSceneRemove()
+{
+   if (mIsInitialized)
+      mPlatformWindow->getScreenResChangeSignal().remove(this, &VolumetricFogRTManager::ResizeRT);
+}
+   
+void VolumetricFogRTManager::onRemove()
+{
+   removeFromScene();
+   Parent::onRemove();
+}
+   
+void VolumetricFogRTManager::consoleInit()
+{
+   Con::addVariable("$pref::VolumetricFog::Quality", TypeS32, &mTargetScale,
+   "The scale of the rendertargets.\n"
+   "@ingroup Rendering\n");
+}
+   
+bool VolumetricFogRTManager::Init()
+{
+   if (mIsInitialized)
+      {
+      Con::errorf("VolumetricFogRTManager allready initialized!!");
+      return true;
+      }
+   
+   GuiCanvas* cv = dynamic_cast<GuiCanvas*>(Sim::findObject("Canvas"));
+   if (cv == NULL)
+   {
+      Con::errorf("VolumetricFogRTManager::Init() - Canvas not found!!");
+      return false;
+   }
+   
+   mPlatformWindow = cv->getPlatformWindow();
+   mPlatformWindow->getScreenResChangeSignal().notify(this,&VolumetricFogRTManager::ResizeRT);
+   
+   if (mTargetScale < 1)
+      mTargetScale = 1;
+   
+   mWidth = mFloor(mPlatformWindow->getClientExtent().x / mTargetScale);
+   mHeight = mPlatformWindow->getClientExtent().y;
+   mFullScreen = mPlatformWindow->isFullscreen();
+   if (!mFullScreen)
+      mHeight -= 20;//subtract caption bar from rendertarget size.
+   mHeight = mFloor(mHeight / mTargetScale);
+   
+   mDepthBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F,
+   &GFXDefaultRenderTargetProfile, avar("%s() - mDepthBuffer (line %d)", __FUNCTION__, __LINE__));
+   if (!mDepthBuffer.isValid())
+   {
+      Con::errorf("VolumetricFogRTManager Fatal Error: Unable to create Depthbuffer");
+      return false;
+   }
+   if (!mDepthTarget.registerWithName("volfogdepth"))
+   {
+      Con::errorf("VolumetricFogRTManager Fatal Error : Unable to register Depthbuffer");
+      return false;
+   }
+   mDepthTarget.setTexture(mDepthBuffer);
+   
+   mFrontBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F,
+   &GFXDefaultRenderTargetProfile, avar("%s() - mFrontBuffer (line %d)", __FUNCTION__, __LINE__));
+   if (!mFrontBuffer.isValid())
+   {
+      Con::errorf("VolumetricFogRTManager Fatal Error: Unable to create front buffer");
+      return false;
+   }
+   if (!mFrontTarget.registerWithName("volfogfront"))
+   {
+      Con::errorf("VolumetricFogRTManager Fatal Error : Unable to register Frontbuffer");
+      return false;
+   }
+   
+   mFrontTarget.setTexture(mFrontBuffer);
+   
+   Con::setVariable("$VolumetricFog::density", "0.0");
+   
+   mIsInitialized = true;
+   
+   return true;
+}
+   
+U32 VolumetricFogRTManager::IncFogObjects()
+{
+   mNumFogObjects++;
+   return mNumFogObjects;
+}
+   
+U32 VolumetricFogRTManager::DecFogObjects()
+{
+   if (mNumFogObjects > 0)
+      mNumFogObjects--;
+   return mNumFogObjects;
+}
+   
+void VolumetricFogRTManager::ResizeRT(PlatformWindow* win,bool resize)
+{
+   mFogHasAnswered = 0;
+   smVolumetricFogRTMResizeSignal.trigger(this, true);
+}
+   
+void VolumetricFogRTManager::FogAnswered()
+{
+   mFogHasAnswered++;
+   if (mFogHasAnswered == mNumFogObjects)
+   {
+      if (Resize())
+         smVolumetricFogRTMResizeSignal.trigger(this, false);
+      else
+         Con::errorf("VolumetricFogRTManager::FogAnswered - Error resizing rendertargets!");
+   }
+}
+   
+bool VolumetricFogRTManager::Resize()
+{
+   if (mTargetScale < 1)
+      mTargetScale = 1;
+   mWidth = mFloor(mPlatformWindow->getClientExtent().x / mTargetScale);
+   mHeight = mPlatformWindow->getClientExtent().y;
+     
+   if (!mPlatformWindow->isFullscreen())
+      mHeight -= 20;//subtract caption bar from rendertarget size.
+   mHeight = mFloor(mHeight / mTargetScale);
+   
+   if (mWidth < 16 || mHeight < 16)
+      return false;
+   
+   if (mFrontTarget.isRegistered())
+      mFrontTarget.setTexture(NULL);
+   
+   if (mDepthTarget.isRegistered())
+      mDepthTarget.setTexture(NULL);
+   
+   if (mDepthBuffer.isValid())
+      mDepthBuffer->kill();
+   
+   if (mFrontBuffer.isValid())
+      mFrontBuffer->kill();
+   
+   mFrontBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F,
+   &GFXDefaultRenderTargetProfile, avar("%s() - mFrontBuffer (line %d)", __FUNCTION__, __LINE__));
+   if (!mFrontBuffer.isValid())
+      {
+      Con::errorf("VolumetricFogRTManager::Resize() Fatal Error: Unable to create front buffer");
+      return false;
+      }
+   mFrontTarget.setTexture(mFrontBuffer);
+   
+   mDepthBuffer = GFXTexHandle(mWidth, mHeight, GFXFormatR32F,
+   &GFXDefaultRenderTargetProfile, avar("%s() - mDepthBuffer (line %d)", __FUNCTION__, __LINE__));
+   if (!mDepthBuffer.isValid())
+      {
+         Con::errorf("VolumetricFogRTManager::Resize() Fatal Error: Unable to create Depthbuffer");
+         return false;
+      }
+   mDepthTarget.setTexture(mDepthBuffer);
+   return true;
+}
+   
+S32 VolumetricFogRTManager::setQuality(U32 Quality)
+{
+   if (!mIsInitialized)
+      return (mTargetScale = Quality);
+      
+   if (Quality < 1)
+      Quality = 1;
+   
+   if (Quality == mTargetScale)
+      return mTargetScale;
+   
+   mTargetScale = Quality;
+   
+   mFogHasAnswered = 0;
+   smVolumetricFogRTMResizeSignal.trigger(this, true);
+   
+   return mTargetScale;
+}
+   
+VolumetricFogRTManager* VolumetricFogRTManager::get()
+{
+   return gVolumetricFogRTManager;
+}
+   
+DefineConsoleFunction(SetFogVolumeQuality, S32, (U32 new_quality), ,
+"@brief Resizes the rendertargets of the Volumetric Fog object.\n"
+"@params new_quality new quality for the rendertargets 1 = full size, 2 = halfsize, 3 = 1/3, 4 = 1/4 ...")
+{
+   if (VFRTM == NULL)
+      return -1;
+   return VFRTM->setQuality(new_quality);
+}

+ 92 - 0
Engine/source/environment/VolumetricFogRTManager.h

@@ -0,0 +1,92 @@
+//-----------------------------------------------------------------------------
+// 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 _VolumetricFogRTManager_H_
+#define _VolumetricFogRTManager_H_
+   
+#ifndef _SCENEOBJECT_H_
+#include "scene/sceneObject.h"
+#endif
+#ifndef _MATTEXTURETARGET_H_
+#include "materials/matTextureTarget.h"
+#endif
+#ifndef _GFXTARGET_H_
+#include "gfx/gfxTarget.h"
+#endif
+#ifndef _SIGNAL_H_
+#include "core/util/tSignal.h"
+#endif
+   
+class VolumetricFogRTManager;
+   
+typedef Signal<void(VolumetricFogRTManager *VolumetricFogRTManager, bool resize)> VolumetricFogRTMResizeSignal;
+   
+#define VFRTM VolumetricFogRTManager::get()
+   
+class VolumetricFogRTManager : public SceneObject
+{
+   public:
+      typedef SceneObject Parent;
+   
+   protected:
+      GFXTexHandle mDepthBuffer;
+      GFXTexHandle mFrontBuffer;
+   
+      NamedTexTarget mDepthTarget;
+      NamedTexTarget mFrontTarget;
+   
+      PlatformWindow* mPlatformWindow;
+   
+      static S32 mTargetScale;
+      bool mIsInitialized;
+      U32 mNumFogObjects;
+      U32 mFogHasAnswered;
+      U32 mWidth;
+      U32 mHeight;
+      bool mFullScreen;
+   
+      void onRemove();
+      void onSceneRemove();
+      void ResizeRT(PlatformWindow *win, bool resize);
+   
+      static VolumetricFogRTMResizeSignal smVolumetricFogRTMResizeSignal;
+
+   public:
+      VolumetricFogRTManager();
+      ~VolumetricFogRTManager();
+      static VolumetricFogRTManager *get();
+      bool Init();
+      bool IsInitialized() { return mIsInitialized; }
+      static void consoleInit();
+      static VolumetricFogRTMResizeSignal& getVolumetricFogRTMResizeSignal() { return smVolumetricFogRTMResizeSignal; }
+      void FogAnswered();
+      S32 setQuality(U32 Quality);
+      bool Resize();
+      U32 IncFogObjects();
+      U32 DecFogObjects();
+   
+   DECLARE_CONOBJECT(VolumetricFogRTManager);
+};
+   
+extern VolumetricFogRTManager* gVolumetricFogRTManager;
+   
+#endif