Torque3D Documentation / _generateds / VolumetricFog.cpp

VolumetricFog.cpp

Engine/source/environment/VolumetricFog.cpp

More...

Public Defines

define
COLBOX_SCALE() (1.02f, 1.02f, 1.02f)

Public Functions

ConsoleDocClass(VolumetricFog , "@brief Volumetric Fog <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> class. Main class defining the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Volumetric\n</a>" "Fog objects in the scene. Used in conjunction with the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">VolumetricFogRTManager\n</a>" "class which is responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1a21625ca11566389388a748ad1acc0990">required</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rendertargets.\n\n</a>" "Methods (exposed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> script):\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " setFogColorF(color) Changes the overall fog color (color.rgba range 0.0 - 1.0).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>;" " setFogColor(color) Changes the overall fog color color.rgba range 0 - 255)
DefineEngineMethod(VolumetricFog , isInsideFog , bool , () , "@brief returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> object is inside the fog\n\n." )
DefineEngineMethod(VolumetricFog , SetFogColor , void , (ColorI new_color) )
DefineEngineMethod(VolumetricFog , SetFogColorF , void , (LinearColorF new_color) )
DefineEngineMethod(VolumetricFog , SetFogDensity , void , (F32 new_density) , "@brief Changes the density of the fog\n\n." "@params new_density the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> fog density." )
DefineEngineMethod(VolumetricFog , SetFogGlow , void , (bool on_off, F32 strength) , "@brief Changes the glow postfx when inside the fog\n\n." "@params on_off set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> enable <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">glow.\n</a>" "@params strength glow <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">strength.\n</a>" )
DefineEngineMethod(VolumetricFog , SetFogLightray , void , (bool on_off, F32 strength) , "@brief Changes the lightrays postfx when inside the fog\n\n." "@params on_off set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> modification of the lightray <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">postfx.\n</a>" "@params strength lightray <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">strength.\n</a>" )
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 <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> strength of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">modulation.\n</a>" "@params new_speed1 the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> speed (x y) of the modulation layer 1.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@params new_speed2 the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> speed (x y) of the modulation layer 2.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )
IMPLEMENT_CALLBACK(VolumetricFog , onEnterFog , void , (SimObjectId obj) , (obj) , "@brief Called when an object enters the volume of the Fog <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">instance.\n\n</a>" "@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 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">instance.\n\n</a>" "@param obj the controlobject leaving the fog." )

Detailed Description

Public Defines

COLBOX_SCALE() (1.02f, 1.02f, 1.02f)

Public Functions

ConsoleDocClass(VolumetricFog , "@brief Volumetric Fog <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> class. Main class defining the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Volumetric\n</a>" "Fog objects in the scene. Used in conjunction with the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">VolumetricFogRTManager\n</a>" "class which is responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> the <a href="/coding/file/tsshapeconstruct_8cpp/#tsshapeconstruct_8cpp_1a21625ca11566389388a748ad1acc0990">required</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">rendertargets.\n\n</a>" "Methods (exposed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> script):\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " setFogColorF(color) Changes the overall fog color (color.rgba range 0.0 - 1.0).\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>;" " setFogColor(color) Changes the overall fog color color.rgba range 0 - 255)

DefineEngineMethod(VolumetricFog , isInsideFog , bool , () , "@brief returns true <a href="/coding/file/tsmeshintrinsics_8cpp/#tsmeshintrinsics_8cpp_1a4e4fa7e3399708e0777b5308db01278c">if</a> <a href="/coding/file/guieditctrl_8cpp/#guieditctrl_8cpp_1abb04e3738c4c5a96b3ade6fa47013a6c">control</a> object is inside the fog\n\n." )

DefineEngineMethod(VolumetricFog , SetFogColor , void , (ColorI new_color) )

DefineEngineMethod(VolumetricFog , SetFogColorF , void , (LinearColorF new_color) )

DefineEngineMethod(VolumetricFog , SetFogDensity , void , (F32 new_density) , "@brief Changes the density of the fog\n\n." "@params new_density the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> fog density." )

DefineEngineMethod(VolumetricFog , SetFogGlow , void , (bool on_off, F32 strength) , "@brief Changes the glow postfx when inside the fog\n\n." "@params on_off set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> enable <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">glow.\n</a>" "@params strength glow <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">strength.\n</a>" )

DefineEngineMethod(VolumetricFog , SetFogLightray , void , (bool on_off, F32 strength) , "@brief Changes the lightrays postfx when inside the fog\n\n." "@params on_off set <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> true <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> modification of the lightray <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">postfx.\n</a>" "@params strength lightray <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">strength.\n</a>" )

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 <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> strength of the <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">modulation.\n</a>" "@params new_speed1 the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> speed (x y) of the modulation layer 1.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@params new_speed2 the <a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> speed (x y) of the modulation layer 2.\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" )

IMPLEMENT_CALLBACK(VolumetricFog , onEnterFog , void , (SimObjectId obj) , (obj) , "@brief Called when an object enters the volume of the Fog <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">instance.\n\n</a>" "@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 <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">instance.\n\n</a>" "@param obj the controlobject leaving the fog." )

IMPLEMENT_CO_NETOBJECT_V1(VolumetricFog )

   1
   2//-----------------------------------------------------------------------------
   3// Copyright (c) 2012 GarageGames, LLC
   4//
   5// Permission is hereby granted, free of charge, to any person obtaining a copy
   6// of this software and associated documentation files (the "Software"), to
   7// deal in the Software without restriction, including without limitation the
   8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   9// sell copies of the Software, and to permit persons to whom the Software is
  10// furnished to do so, subject to the following conditions:
  11//
  12// The above copyright notice and this permission notice shall be included in
  13// all copies or substantial portions of the Software.
  14//
  15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21// IN THE SOFTWARE.
  22//-----------------------------------------------------------------------------
  23
  24#include "environment/VolumetricFog.h"
  25#include "windowManager/platformWindowMgr.h"
  26#include "gfx/gfxTransformSaver.h"
  27#include "renderInstance/renderPassManager.h"
  28#include "math/mathIO.h"
  29#include "materials/shaderData.h"
  30#include "math/util/matrixSet.h"
  31#include "core/resourceManager.h"
  32#include "core/stream/bitStream.h"
  33#include "T3D/gameBase/gameConnection.h"
  34#include "T3D/shapeBase.h"
  35#include "ts/tsShapeInstance.h"
  36#include "console/engineAPI.h"
  37#include "gui/core/guiCanvas.h"
  38#include "VolumetricFogRTManager.h"
  39#include "lighting/lightInfo.h"
  40#include "lighting/lightManager.h"
  41
  42#define COLBOX_SCALE Point3F(1.02f, 1.02f, 1.02f)
  43
  44IMPLEMENT_CO_NETOBJECT_V1(VolumetricFog);
  45
  46ConsoleDocClass(VolumetricFog,
  47"@brief Volumetric Fog Object class. Main class defining the Volumetric\n"
  48"Fog objects in the scene. Used in conjunction with the VolumetricFogRTManager\n"
  49"class which is responsible for the required rendertargets.\n\n"
  50"Methods (exposed to script):\n"
  51" setFogColorF(color) Changes the overall fog color (color.rgba range 0.0 - 1.0).\n;"
  52" setFogColor(color) Changes the overall fog color color.rgba range 0 - 255).\n;"
  53" setFogDensity(density) Changes the overall fog density.\n"
  54" setFogModulation(strength, speed1, speed2) changes the strength\n"
  55" and the speeds of the 2 animation layers.\n\n"
  56"Callbacks:\n"
  57"onEnterFog triggered whenever the controlobject (Player or Camera) enters the Fog.\n"
  58" (current Fog object and the controlobject are exposed to script.\n"
  59"onLeaveFog triggered whenever the controlobject (Player or Camera) left the Fog.\n"
  60" (current Fog object and the controlobject are exposed to script.\n\n"
  61"@tsexample\n"
  62" new VolumetricFog()\n"
  63" {\n"
  64" shapeName = \"art/environment/FogRCube.dts\";\n"
  65" fogColor = \"200 200 200 128\";\n"
  66" fogDensity = \"0.2\";\n"
  67" ignoreWater = \"0\";\n"
  68" MinSize = \"250\";\n"
  69" FadeSize = \"750\";\n"
  70" texture = \"art/environment/FogMod_heavy.dds\";\n"
  71" tiles = \"1.5\";\n"
  72" modStrength = \"0.2\";\n"
  73" PrimSpeed = \"-0.01 0.04\";\n"
  74" SecSpeed = \"0.02 -0.02\";\n"
  75" position = \"748.644 656.371 65.3506\"; \n"
  76" rotation = \"0 0 1 20.354\";\n"
  77" scale = \"40 30 6\";\n"
  78" };\n"
  79"@endtsexample\n"
  80);
  81
  82IMPLEMENT_CALLBACK(VolumetricFog, onEnterFog, void, (SimObjectId obj), (obj),
  83"@brief Called when an object enters the volume of the Fog instance.\n\n"
  84
  85"@param obj the controlobject entering the fog.");
  86
  87IMPLEMENT_CALLBACK(VolumetricFog, onLeaveFog, void, (SimObjectId obj), (obj),
  88"@brief Called when an object left the volume of the Fog instance.\n\n"
  89
  90"@param obj the controlobject leaving the fog.");
  91
  92
  93VolumetricFog::VolumetricFog()
  94{
  95   AssertFatal(VFRTM != NULL, "VolumetricFog Fatal Error: No Manager found");
  96
  97   if (!VFRTM->IsInitialized())
  98   VFRTM->Init();
  99
 100   mNetFlags.set(Ghostable | ScopeAlways);
 101
 102   mTypeMask |= EnvironmentObjectType | StaticObjectType;
 103
 104   mDeferredTarget = NULL;
 105   mDepthBufferTarget = NULL;
 106   mFrontBufferTarget = NULL;
 107
 108   z_buf = NULL;
 109   mTexture = NULL;
 110
 111   mIsVBDirty = false;
 112   mIsPBDirty = false;
 113
 114   mFogColor.set(200, 200, 200, 255);
 115   mFogDensity = 0.3f;
 116   mIgnoreWater = false;
 117   mReflect = false;
 118   mCamInFog = false;
 119   mResizing = false;
 120   mFogReflStrength = 20.0;
 121   mUseGlow = false;
 122   mGlowStrength = 0.3f;
 123   mGlowing = 0;
 124   mModifLightRays = false;
 125   mLightRayMod = 1.0f;
 126   mOldLightRayStrength = 0.1f;
 127
 128   mShapeName = "";
 129   mShapeLoaded = false;
 130   mMinDisplaySize = 10.0f;
 131   mFadeSize = 0.0f;
 132   mCurDetailLevel = 0;
 133   mNumDetailLevels = 0;
 134   det_size.clear();
 135
 136   mTextureName = "";
 137   mIsTextured = false;
 138   mStrength = 0.5f;
 139   mTexTiles = 1.0f;
 140   mSpeed1.set(0.5f, 0.0f);
 141   mSpeed2.set(0.1f, 0.1f);
 142
 143   mShapeAsset = StringTable->EmptyString();
 144   mShapeAssetId = StringTable->EmptyString();
 145}
 146
 147VolumetricFog::~VolumetricFog()
 148{
 149   if (!isClientObject())
 150      return;
 151
 152   for (S32 i = 0; i < det_size.size(); i++)
 153   {
 154      if (det_size[i].indices != NULL)
 155         delete(det_size[i].indices);
 156      if (det_size[i].piArray != NULL)
 157         delete(det_size[i].piArray);
 158      if (det_size[i].verts != NULL)
 159         delete [] (det_size[i].verts);
 160   }
 161   det_size.clear();
 162
 163   z_buf = NULL;
 164
 165   if (!mTexture.isNull())
 166      mTexture.free();
 167}
 168
 169void VolumetricFog::initPersistFields()
 170{
 171   addGroup("VolumetricFogData");
 172   addProtectedField("shapeAsset", TypeShapeAssetPtr, Offset(mShapeAsset, VolumetricFog),
 173      &VolumetricFog::_setShapeAsset, &defaultProtectedGetFn, "The source shape asset.");
 174
 175   addField("shapeName", TypeShapeFilename, Offset(mShapeName, VolumetricFog),
 176      "Path and filename of the model file (.DTS, .DAE) to use for this Volume.", AbstractClassRep::FieldFlags::FIELD_HideInInspectors );
 177
 178   addField("FogColor", TypeColorI, Offset(mFogColor, VolumetricFog),
 179      "Fog color RGBA (Alpha is ignored)");
 180   addField("FogDensity", TypeF32, Offset(mFogDensity, VolumetricFog), 
 181      "Overal fog density value (0 disables the fog).");
 182   addField("IgnoreWater", TypeBool, Offset(mIgnoreWater, VolumetricFog), 
 183      "Set to true if volumetric fog should continue while submerged.");
 184   addField("MinSize", TypeF32, Offset(mMinDisplaySize, VolumetricFog), 
 185      "Min size (in pixels) for fog to be rendered.");
 186   addField("FadeSize", TypeF32, Offset(mFadeSize, VolumetricFog), 
 187      "Object size in pixels at which the FX-fading kicks in (0 disables fading).");
 188   endGroup("VolumetricFogData");
 189
 190   addGroup("VolumetricFogModulation");
 191   addField("texture", TypeImageFilename, Offset(mTextureName, VolumetricFog),
 192      "A texture which contains Fogdensity modulator in the red channel and color with 1-green channel. No texture disables modulation.");
 193   addField("tiles", TypeF32, Offset(mTexTiles, VolumetricFog), 
 194      "How many times the texture is mapped to the object.");
 195   addField("modStrength", TypeF32, Offset(mStrength, VolumetricFog),
 196      "Overall strength of the density modulation (0 disables modulation).");
 197   addField("PrimSpeed", TypePoint2F, Offset(mSpeed1, VolumetricFog),
 198      "Overall primary speed of the density modulation (x-speed(u) y-speed(v))");
 199   addField("SecSpeed", TypePoint2F, Offset(mSpeed2, VolumetricFog),
 200      "Overall secundary speed of the density modulation (x-speed(u) y-speed(v))");
 201   endGroup("VolumetricFogModulation");
 202
 203   addGroup("Reflections");
 204   addField("Reflectable", TypeBool, Offset(mReflect, VolumetricFog), 
 205      "Set to true if volumetric fog should be reflected.");
 206   addField("ReflectStrength", TypeF32, Offset(mFogReflStrength, VolumetricFog), 
 207      "Strength of the reflections (0 disables the fog).");
 208   endGroup("Reflections");
 209
 210   addGroup("PostFX");
 211   addField("useGlow", TypeBool, Offset(mUseGlow, VolumetricFog), 
 212      "Set to true if volumetric fog should use glow PostFX.");
 213   addField("glowStrength", TypeF32, Offset(mGlowStrength, VolumetricFog),
 214      "Overall strength of the glow PostFX.");
 215   addField("modLightRay", TypeBool, Offset(mModifLightRays, VolumetricFog), 
 216      "Set to true if volumetric fog should modify the brightness of the Lightrays.");
 217   addField("lightRayMod", TypeF32, Offset(mLightRayMod, VolumetricFog),
 218      "Modifier for LightRay PostFX when inside Fog.");
 219   endGroup("PostFX");
 220   Parent::initPersistFields();
 221}
 222
 223bool VolumetricFog::_setShapeAsset(void* obj, const char* index, const char* data)
 224{
 225   VolumetricFog* fog = static_cast<VolumetricFog*>(obj);// ->setFile(FileName(data));
 226
 227   fog->setShapeAsset(StringTable->insert(data));
 228
 229   return false;
 230}
 231
 232void VolumetricFog::inspectPostApply()
 233{
 234   Parent::inspectPostApply();
 235   mSpeed.set(mSpeed1.x, mSpeed1.y, mSpeed2.x, mSpeed2.y);
 236   setMaskBits(VolumetricFogMask | FogColorMask | FogDensityMask | FogModulationMask | FogPostFXMask | FogShapeMask);
 237}
 238
 239bool VolumetricFog::onAdd()
 240{
 241   if (!Parent::onAdd())
 242      return false;
 243
 244   if (!VFRTM->IsInitialized())
 245   {
 246      Con::errorf("No VolumetricFogRTManager present!!");
 247      return false;
 248   }
 249
 250   resetWorldBox();
 251
 252   mShapeLoaded = LoadShape();
 253
 254   setRenderTransform(mObjToWorld);
 255
 256   addToScene();
 257   ColBox.set(getTransform(), (mObjBox.getExtents() * getScale() * COLBOX_SCALE));
 258   mObjSize = mWorldBox.getGreatestDiagonalLength();
 259   mObjScale = getScale();
 260   mTexTiles = mAbs(mTexTiles);
 261   mSpeed.set(mSpeed1.x, mSpeed1.y, mSpeed2.x, mSpeed2.y);
 262   mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
 263
 264   VFRTM->IncFogObjects();
 265
 266   if (isClientObject())
 267   {
 268      conn = GameConnection::getConnectionToServer();
 269      if (!conn)
 270      {  
 271         Con::errorf("VolumetricFog::onAdd - No Serverconnection");
 272         return false;
 273      }
 274
 275      glowFX = static_cast<PostEffect*>(Sim::findObject("VolFogGlowPostFx"));
 276
 277      mOldLightRayStrength = Con::getFloatVariable("$LightRayPostFX::brightScalar",1.0f);
 278
 279      GuiCanvas* cv = dynamic_cast<GuiCanvas*>(Sim::findObject("Canvas"));
 280      if (cv == NULL)
 281      {
 282         Con::errorf("VolumetricFog::onAdd - Canvas not found!!");
 283         return false;
 284      }
 285      mPlatformWindow = cv->getPlatformWindow();
 286      VolumetricFogRTManager::getVolumetricFogRTMResizeSignal().notify(this, &VolumetricFog::handleResize);
 287      GuiCanvas::getCanvasSizeChangeSignal().notify(this, &VolumetricFog::handleCanvasResize);
 288
 289      InitTexture();
 290      return setupRenderer();
 291   }
 292   
 293   return true;
 294}
 295
 296void VolumetricFog::onRemove()
 297{
 298   if (isClientObject())
 299   {
 300      if (isTicking())
 301      {
 302         setProcessTick(false);
 303         if (mGlowing != 0)
 304         {
 305            mGlowing = 0;
 306            glowFX->disable();
 307         }
 308         _leaveFog(dynamic_cast<ShapeBase*>(conn->getControlObject()));
 309      }
 310      VolumetricFogRTManager::getVolumetricFogRTMResizeSignal().remove(this, &VolumetricFog::handleResize);
 311      GuiCanvas::getCanvasSizeChangeSignal().remove(this, &VolumetricFog::handleCanvasResize);
 312   }
 313   removeFromScene();
 314   VFRTM->DecFogObjects();
 315   Parent::onRemove();
 316}
 317void VolumetricFog::handleCanvasResize(GuiCanvas* canvas)
 318{
 319   UpdateBuffers(0,true);
 320}
 321
 322void VolumetricFog::handleResize(VolumetricFogRTManager *RTM, bool resize)
 323{
 324   if (resize)
 325   {
 326      mResizing = true;
 327      RTM->FogAnswered();
 328   }
 329   else
 330      mResizing = false;
 331
 332   if (mIsTextured)
 333   {
 334      F32 width = (F32)mPlatformWindow->getClientExtent().x;
 335      F32 height = (F32)mPlatformWindow->getClientExtent().y;
 336
 337      mTexScale.x = 2.0f - ((F32)mTexture.getWidth() / width);
 338      mTexScale.y = 2.0f - ((F32)mTexture.getHeight() / height);
 339   }
 340
 341   UpdateBuffers(0,true);
 342}
 343
 344//-----------------------------------------------------------------------------
 345// Loadshape extracted from TSMesh and TSShapeInstance
 346//-----------------------------------------------------------------------------
 347
 348bool VolumetricFog::setShapeAsset(const StringTableEntry shapeAssetId)
 349{
 350   mShapeAssetId = shapeAssetId;
 351
 352   LoadShape();
 353   return true;
 354}
 355
 356bool VolumetricFog::LoadShape()
 357{
 358   GFXPrimitiveType GFXdrawTypes[] = { GFXTriangleList, GFXTriangleStrip };
 359
 360   Resource<TSShape> mShape;
 361   if (mShapeAssetId != StringTable->EmptyString())
 362   {
 363      mShapeAsset = mShapeAssetId;
 364
 365      if (mShapeAsset.isNull())
 366      {
 367         Con::errorf("[TSStatic] Failed to load shape asset.");
 368         return false;
 369      }
 370
 371      mShape = mShapeAsset->getShapeResource();
 372
 373      if (!mShape)
 374      {
 375         Con::errorf("TSStatic::_createShape() - Shape Asset had no valid shape!");
 376         return false;
 377      }
 378   }
 379   else
 380   {
 381      if (!mShapeName || mShapeName[0] == '\0')
 382      {
 383         Con::errorf("VolumetricFog::LoadShape() - No shape name! Volumetric Fog will not be rendered!");
 384         return false;
 385      }
 386
 387      // Load shape, server side only reads bounds and radius
 388      mShape = ResourceManager::get().load(mShapeName);
 389   }
 390
 391   if (bool(mShape) == false)
 392   {
 393      Con::errorf("VolumetricFog::LoadShape() - Unable to load shape: %s", mShapeName);
 394      return false;
 395   }
 396
 397   mObjBox = mShape->mBounds;
 398   mRadius = mShape->mRadius;
 399   resetWorldBox();
 400
 401   if (!isClientObject())
 402      return false;
 403
 404   TSShapeInstance *mShapeInstance = new TSShapeInstance(mShape, false);
 405   meshes mesh_detail;
 406
 407   for (S32 i = 0; i < det_size.size(); i++)
 408   {
 409      if (det_size[i].indices != NULL)
 410         delete(det_size[i].indices);
 411      if (det_size[i].piArray != NULL)
 412         delete(det_size[i].piArray);
 413      if (det_size[i].verts != NULL)
 414         delete [] (det_size[i].verts);
 415   }
 416   det_size.clear();
 417
 418   // browsing model for detail levels
 419
 420   for (U32 i = 0; i < mShape->details.size(); i++)
 421   {
 422      const TSDetail *detail = &mShape->details[i];
 423      mesh_detail.det_size = detail->size;
 424      mesh_detail.sub_shape = detail->subShapeNum;
 425      mesh_detail.obj_det = detail->objectDetailNum;
 426      mesh_detail.verts = NULL;
 427      mesh_detail.piArray = NULL;
 428      mesh_detail.indices = NULL;
 429      if (detail->size >= 0.0f && detail->subShapeNum >= 0)
 430         det_size.push_back(mesh_detail);
 431   }
 432
 433   for (U32 i = 0; i < det_size.size(); i++)
 434   {
 435      const S32 ss = det_size[i].sub_shape;
 436      if (ss >= 0)
 437      {
 438         const S32 start = mShape->subShapeFirstObject[ss];
 439         const S32 end = start + mShape->subShapeNumObjects[ss];
 440         for (S32 j = start; j < end; j++)
 441         {
 442            // Loading shape, only the first mesh for each detail will be used!
 443            TSShapeInstance::MeshObjectInstance *meshObj = &mShapeInstance->mMeshObjects[j];
 444            if (!meshObj)
 445               continue;
 446            TSMesh *mesh = meshObj->getMesh(det_size[i].obj_det);
 447            if (mesh != NULL)
 448            {
 449               const U32 numNrms = mesh->mNumVerts;
 450               GFXVertexPNTT *tmpVerts = NULL;
 451               tmpVerts = new GFXVertexPNTT[numNrms];
 452               mIsVBDirty = true;
 453               for (U32 k = 0; k < numNrms; k++)
 454                  {
 455                     const TSMesh::__TSMeshVertexBase &vd = mesh->mVertexData.getBase(k);
 456                     Point3F norm = vd.normal();
 457                     Point3F vert = vd.vert();
 458                     Point2F uv = vd.tvert();
 459                     tmpVerts[k].point = vert;
 460                     tmpVerts[k].texCoord = uv;
 461                     tmpVerts[k].normal = norm;
 462                  }
 463               det_size[i].verts = tmpVerts;
 464               det_size[i].num_verts = numNrms;
 465
 466               det_size[i].piArray = new Vector<GFXPrimitive>();
 467               GFXPrimitive pInfo;
 468
 469               det_size[i].indices = new Vector<U32>();
 470
 471               for (U32 k = 0; k < mesh->mIndices.size(); k++)
 472                  det_size[i].indices->push_back(mesh->mIndices[k]);
 473
 474               U32 primitivesSize = mesh->mPrimitives.size();
 475               for (U32 k = 0; k < primitivesSize; k++)
 476               {
 477                  const TSDrawPrimitive & draw = mesh->mPrimitives[k];
 478                  GFXPrimitiveType drawType = GFXdrawTypes[draw.matIndex >> 30];
 479                  switch (drawType)
 480                  {
 481                     case GFXTriangleList:
 482                        pInfo.type = drawType;
 483                        pInfo.numPrimitives = draw.numElements / 3;
 484                        pInfo.startIndex = draw.start;
 485                        // Use the first index to determine which 16-bit address space we are operating in
 486                        pInfo.startVertex = mesh->mIndices[draw.start] & 0xFFFF0000;
 487                        pInfo.minIndex = pInfo.startVertex;
 488                        pInfo.numVertices = getMin((U32)0x10000, mesh->mNumVerts - pInfo.startVertex);
 489                        break;
 490                     case GFXTriangleStrip:
 491                        pInfo.type = drawType;
 492                        pInfo.numPrimitives = draw.numElements - 2;
 493                        pInfo.startIndex = draw.start;
 494                        // Use the first index to determine which 16-bit address space we are operating in
 495                        pInfo.startVertex = mesh->mIndices[draw.start] & 0xFFFF0000;
 496                        pInfo.minIndex = pInfo.startVertex;
 497                        pInfo.numVertices = getMin((U32)0x10000, mesh->mNumVerts - pInfo.startVertex);
 498                        break;
 499                     default:
 500                        Con::errorf("VolumetricFog::LoadShape Unknown drawtype!?!");
 501                        return false;
 502                        break;
 503                  }
 504               det_size[i].piArray->push_back(pInfo);
 505               j = end;
 506            }
 507         }
 508         else
 509         {
 510            Con::errorf("VolumetricFog::LoadShape Error loading mesh from shape!");
 511            delete mShapeInstance;
 512            return false;
 513         }
 514         mIsVBDirty = true;
 515         mIsPBDirty = true;
 516         }
 517      }
 518   }
 519
 520   mNumDetailLevels = det_size.size();
 521   mCurDetailLevel = 0;
 522   UpdateBuffers(mCurDetailLevel);
 523   delete mShapeInstance;
 524
 525   return true;
 526}
 527
 528//-----------------------------------------------------------------------------
 529// UpdateBuffers called whenever detaillevel changes (LOD)
 530//-----------------------------------------------------------------------------
 531
 532
 533bool VolumetricFog::UpdateBuffers(U32 dl, bool force)
 534{
 535   if (mVB.isNull() || mIsVBDirty || dl != mCurDetailLevel || force)
 536   {
 537      mVB.set(GFX, det_size[dl].num_verts, GFXBufferTypeDynamic);
 538      mIsVBDirty = false;
 539   }
 540   GFXVertexPNTT *vertPtr = mVB.lock();
 541   if (!vertPtr)
 542   {
 543      mVB.unlock();
 544      return false;
 545   }
 546   dMemcpy(vertPtr, det_size[dl].verts, sizeof (GFXVertexPNTT)* det_size[dl].num_verts);
 547   mVB.unlock();
 548
 549   if (mIsPBDirty || mPB.isNull() || dl != mCurDetailLevel || force)
 550   {
 551      #ifdef TORQUE_DEBUG
 552      mPB.set(GFX, det_size[dl].indices->size(), det_size[dl].piArray->size(), GFXBufferTypeDynamic, avar("%s() - VolFogPrimBuffer (line %d)", __FUNCTION__, __LINE__));
 553      #else
 554      mPB.set(GFX, det_size[dl].indices->size(), det_size[dl].piArray->size(), GFXBufferTypeDynamic);
 555      #endif
 556      U16 *ibIndices = NULL;
 557      GFXPrimitive *piInput = NULL;
 558      mPB.lock(&ibIndices, &piInput);
 559      dCopyArray(ibIndices, det_size[dl].indices->address(), det_size[dl].indices->size());
 560      dMemcpy(piInput, det_size[dl].piArray->address(), det_size[dl].piArray->size() * sizeof(GFXPrimitive));
 561      mPB.unlock();
 562      mIsPBDirty = false;
 563   }
 564   mCurDetailLevel = dl;
 565   return true;
 566}
 567
 568U32 VolumetricFog::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
 569{
 570   U32 retMask = Parent::packUpdate(con, mask, stream);
 571   if (stream->writeFlag(mask & FogColorMask))
 572      stream->write(mFogColor);
 573   if (stream->writeFlag(mask & FogDensityMask))
 574      stream->write(mFogDensity);
 575   if (stream->writeFlag(mask & FogModulationMask))
 576   {
 577      stream->write(mTextureName);
 578      mTexTiles = mFabs(mTexTiles);
 579      stream->write(mTexTiles);
 580      stream->write(mStrength);
 581      mathWrite(*stream, mSpeed);
 582   }
 583   if (stream->writeFlag(mask & FogPostFXMask))
 584   {
 585      stream->writeFlag(mUseGlow);
 586      stream->write(mGlowStrength);
 587      stream->writeFlag(mModifLightRays);
 588      stream->write(mLightRayMod);
 589   }
 590   if (stream->writeFlag(mask & VolumetricFogMask))
 591   {
 592      stream->writeFlag(mIgnoreWater);
 593      stream->writeFlag(mReflect);
 594      stream->write(mFogReflStrength);
 595      stream->writeFlag(mResizing);
 596      stream->write(mMinDisplaySize);
 597      stream->write(mFadeSize);
 598   }
 599   if (stream->writeFlag(mask & FogShapeMask))
 600   {
 601      stream->writeString(mShapeAssetId);
 602      stream->writeString(mShapeName);
 603      mathWrite(*stream, getTransform());
 604      mathWrite(*stream, getScale());
 605
 606      Resource<TSShape> mShape;
 607
 608      if (mShapeAssetId != StringTable->EmptyString())
 609      {
 610         mShape = mShapeAsset->getShapeResource();
 611      }
 612      else if (mShapeName && mShapeName[0] != '\0')
 613      {
 614         mShape = ResourceManager::get().load(mShapeName);
 615      }
 616
 617      if (bool(mShape) == false)
 618         return retMask;
 619
 620      mObjBox = mShape->mBounds;
 621      mRadius = mShape->mRadius;
 622      resetWorldBox();
 623      mObjSize = mWorldBox.getGreatestDiagonalLength();
 624      mObjScale = getScale();
 625      mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
 626   }
 627   return retMask;
 628}
 629
 630void VolumetricFog::unpackUpdate(NetConnection *con, BitStream *stream)
 631{
 632   Parent::unpackUpdate(con, stream);
 633   MatrixF mat;
 634   VectorF scale;
 635   VectorF mOldScale = getScale();
 636   String oldTextureName = mTextureName;
 637   StringTableEntry oldShapeAsset = mShapeAssetId;
 638   StringTableEntry oldShape = mShapeName;
 639
 640   if (stream->readFlag())// Fog color
 641      stream->read(&mFogColor);
 642   if (stream->readFlag())// Fog Density
 643   {
 644      stream->read(&mFogDensity);
 645      if (isTicking())
 646      {
 647         char buf[20];
 648         dSprintf(buf, sizeof(buf), "%3.7f", mFogDensity);
 649         Con::setVariable("$VolumetricFog::density", buf);
 650      }
 651   }
 652   if (stream->readFlag())// Fog Modulation
 653   {
 654      stream->read(&mTextureName);
 655      stream->read(&mTexTiles);
 656      mTexTiles = mFabs(mTexTiles);
 657      stream->read(&mStrength);
 658      mathRead(*stream, &mSpeed);
 659      mSpeed1.set(mSpeed.x, mSpeed.y);
 660      mSpeed2.set(mSpeed.z, mSpeed.w);
 661
 662      if (isProperlyAdded())
 663      {
 664         if (oldTextureName != mTextureName)
 665            InitTexture();
 666         if (oldTextureName.isNotEmpty() && mTextureName.isEmpty())
 667         {
 668            mIsTextured = false;
 669            mTexture.free();
 670         }
 671      }
 672   }
 673   if (stream->readFlag())//Fog PostFX
 674   {
 675      mUseGlow = stream->readFlag();
 676      stream->read(&mGlowStrength);
 677      mModifLightRays = stream->readFlag();
 678      stream->read(&mLightRayMod);
 679      if (isTicking())
 680      {
 681         char glowStrBuf[20];
 682         dSprintf(glowStrBuf, sizeof(glowStrBuf), "%3.7f", mGlowStrength);
 683         Con::setVariable("$VolFogGlowPostFx::glowStrength", glowStrBuf);
 684         if (mUseGlow && !glowFX->isEnabled())
 685            glowFX->enable();
 686         if (!mUseGlow && glowFX->isEnabled())
 687            glowFX->disable();
 688
 689       F32 rayStrength = mOldLightRayStrength;
 690       if (mModifLightRays)
 691          rayStrength *= mLightRayMod;
 692       char rayStrBuf[20];
 693       dSprintf(rayStrBuf, sizeof(rayStrBuf), "%3.7f", rayStrength);
 694       Con::setVariable("$LightRayPostFX::brightScalar", rayStrBuf);
 695      }
 696   }
 697   if (stream->readFlag())//Volumetric Fog
 698   {
 699      mIgnoreWater = stream->readFlag();
 700      mReflect = stream->readFlag();
 701      stream->read(&mFogReflStrength);
 702      mResizing = stream->readFlag();
 703      stream->read(&mMinDisplaySize);
 704      stream->read(&mFadeSize);
 705   }
 706   if (stream->readFlag())//Fog shape
 707   {
 708      char buffer[256];
 709      stream->readString(buffer);
 710      mShapeAssetId = StringTable->insert(buffer);
 711
 712      mShapeName = stream->readSTString();
 713      mathRead(*stream, &mat);
 714      mathRead(*stream, &scale);
 715      if (strcmp(oldShapeAsset, mShapeAssetId) != 0 || strcmp(oldShape, mShapeName) != 0)
 716      {
 717         mIsVBDirty = true;
 718         mShapeLoaded = LoadShape();
 719      }
 720      setScale(scale);
 721      setTransform(mat);
 722      ColBox.set(getTransform(), (mObjBox.getExtents() * getScale() * COLBOX_SCALE));
 723      mObjSize = mWorldBox.getGreatestDiagonalLength();
 724      mObjScale = getScale();
 725      mInvScale = (1.0f / getMax(getMax(mObjScale.x, mObjScale.y), mObjScale.z));
 726   }
 727}
 728
 729void VolumetricFog::processTick(const Move* move)
 730{
 731   Parent::processTick(move);
 732   mCounter++;
 733   if ( mGlowing==1 && mCurGlow < mGlowStrength )
 734   {
 735      mCurGlow += (mGlowStrength / 10.0);
 736      char buf[20];
 737      dSprintf(buf, sizeof(buf), "%3.7f", mCurGlow);
 738      Con::setVariable("$VolFogGlowPostFx::glowStrength", buf);
 739   }
 740   else if ( mGlowing == 2 && mCurGlow > 0.0f )
 741   {
 742      mCurGlow -= (mGlowStrength / 5.0f);
 743      if (mCurGlow <= 0.0f)
 744      {
 745         glowFX->disable();
 746         mGlowing = 0;
 747         setProcessTick(false);
 748         return;
 749      }
 750      else
 751      {
 752         char buf[20];
 753         dSprintf(buf, sizeof(buf), "%3.7f", mCurGlow);
 754         Con::setVariable("$VolFogGlowPostFx::glowStrength", buf);
 755      }
 756   }
 757   if (mCounter == 3)
 758   {
 759      ShapeBase* control = dynamic_cast<ShapeBase*>(conn->getControlObject());
 760      if (!control)
 761         return;
 762      MatrixF xfm;
 763      control->getRenderEyeTransform(&xfm);
 764      Point3F pos = xfm.getPosition();
 765      if (!ColBox.isContained(pos))
 766         _leaveFog(control);
 767      mCounter = 0;
 768   }
 769}
 770
 771void VolumetricFog::_enterFog(ShapeBase *control)
 772{
 773   if (mUseGlow)
 774   {
 775      if (glowFX)
 776      {
 777         mCurGlow = 0.0f;
 778         Con::setVariable("$VolFogGlowPostFx::glowStrength", "0.0");
 779         glowFX->enable();
 780         mGlowing = 1;
 781      }
 782   }
 783   if (mModifLightRays)
 784   {
 785      char buf[20];
 786      dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength * mLightRayMod);
 787      Con::setVariable("$LightRayPostFX::brightScalar", buf);
 788   }
 789   mCounter = 0;
 790   char buf[20];
 791   dSprintf(buf, sizeof(buf), "%3.7f", mFogDensity);
 792   Con::setVariable("$VolumetricFog::density", buf);
 793   setProcessTick(true);
 794   if (control)
 795      onEnterFog_callback(control->getId());
 796}
 797
 798void VolumetricFog::_leaveFog(ShapeBase *control)
 799{
 800   mCamInFog = false;
 801   Con::setVariable("$VolumetricFog::density", "0.0");
 802   if (mModifLightRays)
 803   {
 804      char buf[20];
 805      dSprintf(buf, sizeof(buf), "%3.7f", mOldLightRayStrength);
 806      Con::setVariable("$LightRayPostFX::brightScalar", buf);
 807   }
 808   if (mUseGlow)
 809   {
 810      if (glowFX && mGlowing != 2)
 811      {
 812         mCurGlow = mGlowStrength;
 813         mGlowing = 2;
 814         if (control)
 815            onLeaveFog_callback(control->getId());
 816      }
 817   }
 818   else
 819   {
 820      setProcessTick(false);
 821      if (control)
 822         onLeaveFog_callback(control->getId());
 823   }
 824}
 825
 826//-----------------------------------------------------------------------------
 827// Setting up the renderers
 828//-----------------------------------------------------------------------------
 829
 830bool VolumetricFog::setupRenderer()
 831{
 832   // Search for the deferred rendertarget and shadermacros.
 833   mDeferredTarget = NamedTexTarget::find("deferred");
 834   if (!mDeferredTarget.isValid())
 835   {
 836      Con::errorf("VolumetricFog::setupRenderer - could not find DeferredTarget");
 837      return false;
 838   }
 839
 840   Vector<GFXShaderMacro> macros;
 841   if (mDeferredTarget)
 842      mDeferredTarget->getShaderMacros(&macros);
 843
 844   // Search the depth and frontbuffers which are created by the VolumetricFogRTManager
 845
 846   mDepthBufferTarget = NamedTexTarget::find("volfogdepth");
 847   if (!mDepthBufferTarget.isValid())
 848   {
 849      Con::errorf("VolumetricFog::setupRenderer - could not find depthbuffer");
 850      return false;
 851   }
 852
 853   mFrontBufferTarget = NamedTexTarget::find("volfogfront");
 854   if (!mFrontBufferTarget.isValid())
 855   {
 856      Con::errorf("VolumetricFog::setupRenderer - could not find frontbuffer");
 857      return false;
 858   }
 859
 860   // Find and setup the deferred Shader
 861
 862   ShaderData *shaderData;
 863   mDeferredShader = Sim::findObject("VolumetricFogDeferredShader", shaderData) ?
 864   shaderData->getShader() : NULL;
 865   if (!mDeferredShader)
 866   {
 867      Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogDeferredShader");
 868      return false;
 869   }
 870
 871   // Create ShaderConstBuffer and Handles
 872
 873   mPPShaderConsts = mDeferredShader->allocConstBuffer();
 874   if (mPPShaderConsts.isNull())
 875   {
 876      Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants 1.");
 877      return false;
 878   }
 879
 880   mPPModelViewProjSC = mDeferredShader->getShaderConstHandle("$modelView");
 881
 882   // Find and setup the VolumetricFog Shader
 883
 884   shaderData = NULL;
 885   mShader = Sim::findObject("VolumetricFogShader", shaderData) ?
 886   shaderData->getShader(macros) : NULL;
 887   if (!mShader)
 888   {
 889      Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogShader");
 890      return false;
 891   }
 892
 893   // Create ShaderConstBuffer and Handles
 894
 895   mShaderConsts = mShader->allocConstBuffer();
 896   if (mShaderConsts.isNull())
 897   {
 898      Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants 2.");
 899      return false;
 900   }
 901
 902   mModelViewProjSC = mShader->getShaderConstHandle("$modelView");
 903   mFadeSizeSC = mShader->getShaderConstHandle("$fadesize");
 904   mFogColorSC = mShader->getShaderConstHandle("$fogColor");
 905   mFogDensitySC = mShader->getShaderConstHandle("$fogDensity");
 906   mPreBias = mShader->getShaderConstHandle("$preBias");
 907   mAccumTime = mShader->getShaderConstHandle("$accumTime");
 908   mIsTexturedSC = mShader->getShaderConstHandle("$textured");
 909   mTexTilesSC = mShader->getShaderConstHandle("$numtiles");
 910   mModStrengthSC = mShader->getShaderConstHandle("$modstrength");
 911   mModSpeedSC = mShader->getShaderConstHandle("$modspeed");
 912   mViewPointSC = mShader->getShaderConstHandle("$viewpoint");
 913   mTexScaleSC = mShader->getShaderConstHandle("$texscale");
 914   mAmbientColorSC = mShader->getShaderConstHandle("$ambientColor");
 915
 916   // Find and setup the reflection Shader
 917
 918   shaderData = NULL;
 919   mReflectionShader = Sim::findObject("VolumetricFogReflectionShader", shaderData) ?
 920   shaderData->getShader() : NULL;
 921   if (!mReflectionShader)
 922   {
 923      Con::errorf("VolumetricFog::setupRenderer - could not find VolumetricFogReflectionShader");
 924      return false;
 925   }
 926
 927   mReflShaderConsts = mReflectionShader->allocConstBuffer();
 928   if (mReflShaderConsts.isNull())
 929   {
 930      Con::errorf("VolumetricFog::setupRenderer - could not allocate ShaderConstants for VolumetricFogReflectionShader.");
 931      return false;
 932   }
 933
 934   mReflModelViewProjSC = mReflectionShader->getShaderConstHandle("$modelView");
 935   mReflFogColorSC = mReflectionShader->getShaderConstHandle("$fogColor");
 936   mReflFogDensitySC = mReflectionShader->getShaderConstHandle("$fogDensity");
 937   mReflFogStrengthSC = mReflectionShader->getShaderConstHandle("$reflStrength");
 938
 939   // Create the deferred StateBlock
 940
 941   desc_preD.setCullMode(GFXCullCW);
 942   desc_preD.setBlend(true);
 943   desc_preD.setZReadWrite(false, false);
 944   desc_preD.stencilEnable = false;
 945   desc_preF.setCullMode(GFXCullCCW);
 946   desc_preF.setBlend(true);
 947   desc_preF.setZReadWrite(true, false);
 948   desc_preF.stencilEnable = false;
 949   
 950   // Create the VolumetricFog StateBlock
 951
 952   descD.setCullMode(GFXCullCW);
 953   descD.setBlend(true);
 954   descD.setZReadWrite(false, false);// desc.setZReadWrite(true, false);
 955
 956   // deferredBuffer sampler
 957   descD.samplersDefined = true;
 958   descD.samplers[0].addressModeU = GFXAddressClamp;
 959   descD.samplers[0].addressModeV = GFXAddressClamp;
 960   descD.samplers[0].addressModeW = GFXAddressClamp;
 961   descD.samplers[0].magFilter = GFXTextureFilterLinear;
 962   descD.samplers[0].minFilter = GFXTextureFilterLinear;
 963   descD.samplers[0].mipFilter = GFXTextureFilterLinear;
 964
 965   // DepthBuffer sampler
 966   descD.samplers[1].addressModeU = GFXAddressClamp;
 967   descD.samplers[1].addressModeV = GFXAddressClamp;
 968   descD.samplers[1].addressModeW = GFXAddressClamp;
 969   descD.samplers[1].magFilter = GFXTextureFilterLinear;
 970   descD.samplers[1].minFilter = GFXTextureFilterLinear;
 971   descD.samplers[1].mipFilter = GFXTextureFilterLinear;
 972
 973   // FrontBuffer sampler
 974   descD.samplers[2].addressModeU = GFXAddressClamp;
 975   descD.samplers[2].addressModeV = GFXAddressClamp;
 976   descD.samplers[2].addressModeW = GFXAddressClamp;
 977   descD.samplers[2].magFilter = GFXTextureFilterLinear;
 978   descD.samplers[2].minFilter = GFXTextureFilterLinear;
 979   descD.samplers[2].mipFilter = GFXTextureFilterLinear;
 980
 981   // animated density modifier map sampler
 982   descD.samplers[3].addressModeU = GFXAddressWrap;
 983   descD.samplers[3].addressModeV = GFXAddressWrap;
 984   descD.samplers[3].addressModeW = GFXAddressWrap;
 985   descD.samplers[3].magFilter = GFXTextureFilterLinear;
 986   descD.samplers[3].minFilter = GFXTextureFilterLinear;
 987   descD.samplers[3].mipFilter = GFXTextureFilterLinear;
 988
 989   dMemcpy(&descF, &descD, sizeof(GFXStateBlockDesc));
 990   descF.setCullMode(GFXCullCCW);
 991   descF.setBlend(true);
 992   descF.setZReadWrite(true, false);
 993
 994   desc_refl.setCullMode(GFXCullCCW);
 995   desc_refl.setBlend(true);
 996   desc_refl.setZReadWrite(true, false);
 997
 998   mStateblock_preD = GFX->createStateBlock(desc_preD);
 999   mStateblock_preF = GFX->createStateBlock(desc_preF);
1000   mStateblockD = GFX->createStateBlock(descD);
1001   mStateblockF = GFX->createStateBlock(descF);
1002   mStateblock_refl = GFX->createStateBlock(desc_refl);
1003
1004   // Create Rendertarget
1005
1006   z_buf = GFX->allocRenderToTextureTarget();
1007   if (z_buf == NULL)
1008   {
1009      Con::errorf("VolumetricFog::setupRenderer - Could not create Render Target");
1010      return false;
1011   }
1012
1013   return true;
1014}
1015
1016void VolumetricFog::prepRenderImage(SceneRenderState *state)
1017{
1018   if (!mShapeLoaded || mFogDensity <= 0.0f || mResizing)
1019      return;
1020
1021   if (!state->isDiffusePass())
1022   {
1023      if (!state->isReflectPass())
1024      return;
1025   }
1026   
1027   PROFILE_SCOPE(VolumetricFog_prepRenderImage);
1028
1029   ShapeBase* control = dynamic_cast<ShapeBase*>(conn->getControlObject());
1030   if (!control || (control->getWaterCoverage() >= 0.9f && !mIgnoreWater))
1031      return;
1032
1033   camPos = state->getCameraPosition();
1034   F32 dist = (camPos - getBoxCenter()).len();
1035   F32 scaleFactor = dist * mInvScale;
1036   if (scaleFactor <= 0.0f)
1037   {
1038      if (mCurDetailLevel != 0)
1039         UpdateBuffers(0);
1040   }
1041   const F32 pixelScale = state->getViewport().extent.y / 300.0f;
1042
1043   mPixelSize = (mRadius / scaleFactor) * state->getWorldToScreenScale().y * pixelScale;
1044   if (mPixelSize < mMinDisplaySize)
1045      return;
1046   if (mNumDetailLevels > 1)
1047   {
1048      if ((mCurDetailLevel < mNumDetailLevels - 1) && (det_size[mCurDetailLevel].det_size > mPixelSize))
1049         UpdateBuffers(mCurDetailLevel + 1);
1050      else if (mCurDetailLevel > 0)
1051      {
1052         if (mPixelSize >= det_size[mCurDetailLevel - 1].det_size)
1053            UpdateBuffers(mCurDetailLevel - 1);
1054      }
1055   }
1056
1057   if (state->isReflectPass() && mReflect)
1058   {
1059      ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
1060      ri->renderDelegate.bind(this, &VolumetricFog::reflect_render);
1061      ri->type = RenderPassManager::RIT_VolumetricFog;
1062      ri->translucentSort = true;
1063      ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint(camPos);
1064      if (dist < 1.0f)
1065         ri->defaultKey = 1;
1066      else
1067         ri->defaultKey = U32(dist);
1068      state->getRenderPass()->addInst(ri);
1069      return;
1070   }
1071   else if (state->isDiffusePass())
1072   {
1073      viewDist = state->getFarPlane();
1074      mFOV = state->getCameraFrustum().getFov() / M_PI_F;
1075      Point3F mEyeVec = state->getVectorEye() * viewDist;
1076
1077      mViewPoint.x = ((mAtan2(mEyeVec.x, mEyeVec.y) / M_PI_F) + 1.0f) * mTexTiles;
1078      mViewPoint.y = (0.5f - (mAsin(mEyeVec.z) / M_PI_F)) * mTexTiles;
1079
1080      bool isInside = ColBox.isContained(camPos);
1081      if (isInside && !mCamInFog)
1082      {
1083         mCamInFog = true;
1084         _enterFog(control);
1085      }
1086      else if (!isInside && mCamInFog)
1087         mCamInFog = false;
1088
1089      ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
1090      ri->renderDelegate.bind(this, &VolumetricFog::render);
1091      ri->type = RenderPassManager::RIT_VolumetricFog;
1092      ri->translucentSort = true;
1093      ri->sortDistSq = getRenderWorldBox().getSqDistanceToPoint(camPos);
1094      if (dist < 1.0f)
1095         ri->defaultKey = 1;
1096      else
1097         ri->defaultKey = U32(dist);
1098      state->getRenderPass()->addInst(ri);
1099      return;
1100   }
1101   return;
1102}
1103
1104void VolumetricFog::render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat)
1105{
1106   if (overrideMat || !mShapeLoaded || !isClientObject() || mResizing)
1107      return;
1108
1109   PROFILE_SCOPE(VolumetricFog_Render);
1110
1111   GFXTransformSaver saver;
1112   GFX->setVertexBuffer(mVB);
1113   GFX->setPrimitiveBuffer(mPB);
1114
1115   MatrixF mat = getRenderTransform();
1116   mat.scale(mObjScale);
1117   GFX->multWorld(mat);
1118
1119   GFX->setShader(mDeferredShader);
1120   GFX->setShaderConstBuffer(mPPShaderConsts);
1121   GFX->setStateBlock(mStateblock_preD);
1122
1123   // Set all the shader consts...
1124
1125   MatrixF xform(GFX->getProjectionMatrix());
1126   xform *= GFX->getViewMatrix();
1127   xform *= GFX->getWorldMatrix();
1128
1129   mPPShaderConsts->setSafe(mPPModelViewProjSC, xform);
1130
1131   const LinearColorF &sunlight = state->getAmbientLightColor();
1132
1133   Point3F ambientColor(sunlight.red, sunlight.green, sunlight.blue);
1134   mShaderConsts->setSafe(mAmbientColorSC, ambientColor);
1135
1136   GFXTextureObject *mDepthBuffer = mDepthBufferTarget ? mDepthBufferTarget->getTexture(0) : NULL;
1137   GFXTextureObject *mFrontBuffer = mFrontBufferTarget ? mFrontBufferTarget->getTexture(0) : NULL;
1138
1139   GFX->pushActiveRenderTarget();
1140
1141   //render backside to target mDepthBuffer
1142   z_buf->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil);
1143   z_buf->attachTexture(GFXTextureTarget::Color0, mDepthBuffer);
1144
1145   GFX->setActiveRenderTarget(z_buf);
1146   GFX->clear(GFXClearStencil | GFXClearTarget , ColorI(0,0,0,0), 1.0f, 0);
1147
1148   GFX->drawPrimitive(0);
1149   z_buf->resolve();
1150
1151   //render frontside to target mFrontBuffer
1152   z_buf->attachTexture(GFXTextureTarget::DepthStencil, GFXTextureTarget::sDefaultDepthStencil);
1153   z_buf->attachTexture(GFXTextureTarget::Color0, mFrontBuffer);
1154   GFX->clear(GFXClearStencil | GFXClearTarget, ColorI(0, 0, 0, 0), 1.0f, 0);
1155
1156   GFX->setStateBlock(mStateblock_preF);
1157
1158   GFX->drawPrimitive(0);
1159   z_buf->resolve();
1160
1161   GFX->popActiveRenderTarget();
1162   z_buf->attachTexture(GFXTextureTarget::Color0, NULL);
1163
1164   //render Volumetric Fog
1165   GFX->setShader(mShader);
1166   GFX->setShaderConstBuffer(mShaderConsts);
1167
1168   mShaderConsts->setSafe(mModelViewProjSC, xform);
1169   if (mFadeSize > 0.0f)
1170      mShaderConsts->setSafe(mFadeSizeSC, mClampF(mPixelSize / mFadeSize, 0.0f, 1.0f));
1171   else
1172      mShaderConsts->setSafe(mFadeSizeSC, 1.0f);
1173   mShaderConsts->setSafe(mFogColorSC, mFogColor);
1174   mShaderConsts->setSafe(mFogDensitySC, mFogDensity);
1175   mShaderConsts->setSafe(mPreBias, viewDist);
1176   mShaderConsts->setSafe(mAccumTime, (F32)Sim::getCurrentTime() / 1000.0f);
1177   mShaderConsts->setSafe(mModStrengthSC, mStrength);
1178   mShaderConsts->setSafe(mModSpeedSC, mSpeed);
1179   mShaderConsts->setSafe(mViewPointSC, mViewPoint);
1180   mShaderConsts->setSafe(mTexScaleSC, mTexScale * mFOV);
1181   mShaderConsts->setSafe(mTexTilesSC, mTexTiles);
1182
1183   GFXTextureObject *deferredtex = mDeferredTarget ? mDeferredTarget->getTexture(0) : NULL;
1184
1185   GFX->setTexture(0, deferredtex);
1186   GFX->setTexture(1, mDepthBuffer);
1187   GFX->setTexture(2, mFrontBuffer);
1188
1189   if (mIsTextured && mStrength > 0.0f)
1190   {
1191      GFX->setTexture(3, mTexture);
1192      mShaderConsts->setSafe(mIsTexturedSC, 1.0f);
1193   }
1194   else
1195      mShaderConsts->setSafe(mIsTexturedSC, 0.0f);
1196
1197   if (mCamInFog)
1198   {
1199      /*GFXLockedRect *rect=mDepthBuffer->lock();
1200      U32 pixoffset = 0;// 1572864 + (512 * 4);
1201      U8 red = rect->bits[pixoffset];
1202      U8 green = rect->bits[pixoffset+1];
1203      U8 blue = rect->bits[pixoffset+2];
1204      U8 alpha = rect->bits[pixoffset+3];
1205      mDepthBuffer->unlock();
1206      S32 lval = ((alpha << 24) + (blue << 16) + (green << 8) + (red));
1207      F32 fval = ((F32)lval / S32_MAX);
1208      Con::printf("Color %d %d %d %d %d %f", red, green, blue, alpha, lval, fval);*/
1209      GFX->setStateBlock(mStateblockD);
1210   }
1211   else
1212      GFX->setStateBlock(mStateblockF);
1213
1214   GFX->drawPrimitive(0);
1215
1216   // Ensure these two textures are NOT bound to the pixel shader input on the second run as they are used as pixel shader outputs (render targets).
1217   GFX->clearTextureStateImmediate(1); //mDepthBuffer
1218   GFX->clearTextureStateImmediate(2); //mFrontBuffer
1219}
1220
1221void VolumetricFog::reflect_render(ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat)
1222{
1223   if (overrideMat || !mShapeLoaded || !isClientObject() || mResizing || (mFogReflStrength==0.0f))
1224      return;
1225
1226   GFXTransformSaver saver;
1227   GFX->setVertexBuffer(mVB);
1228   GFX->setPrimitiveBuffer(mPB);
1229
1230   MatrixF mat = getRenderTransform();
1231   mat.scale(mObjScale);
1232   GFX->multWorld(mat);
1233
1234   GFX->setShader(mReflectionShader);
1235   GFX->setShaderConstBuffer(mReflShaderConsts);
1236   GFX->setStateBlock(mStateblock_refl);
1237
1238   // Set all the shader consts...
1239   MatrixF xform(GFX->getProjectionMatrix());
1240   xform *= GFX->getViewMatrix();
1241   xform *= GFX->getWorldMatrix();
1242
1243   mReflShaderConsts->setSafe(mReflModelViewProjSC, xform);
1244   mReflShaderConsts->setSafe(mReflFogColorSC, mFogColor);
1245   mReflShaderConsts->setSafe(mReflFogDensitySC, mFogDensity);
1246   mReflShaderConsts->setSafe(mReflFogStrengthSC, mFogReflStrength);
1247
1248   GFX->drawPrimitive(0);
1249}
1250
1251//-----------------------------------------------------------------------------
1252// InitTexture is called whenever a modulation texture is added to the object
1253//-----------------------------------------------------------------------------
1254
1255void VolumetricFog::InitTexture()
1256{
1257   mIsTextured = false;
1258
1259   if (mTextureName.isNotEmpty())
1260      mTexture.set(mTextureName, &GFXStaticTextureSRGBProfile, "VolumetricFogMod");
1261
1262   if (!mTexture.isNull())
1263   {
1264      mIsTextured = true;
1265
1266      F32 width = (F32)mPlatformWindow->getClientExtent().x;
1267      F32 height = (F32)mPlatformWindow->getClientExtent().y;
1268
1269      mTexScale.x = 2.0f - ((F32)mTexture.getWidth() / width);
1270      mTexScale.y = 2.0f - ((F32)mTexture.getHeight() / height);
1271   }
1272}
1273
1274void VolumetricFog::setFogColor(LinearColorF color)
1275{
1276   mFogColor.set(255 * color.red,255 * color.green,255 * color.blue);
1277   setMaskBits(FogColorMask);
1278}
1279
1280void VolumetricFog::setFogColor(ColorI color)
1281{
1282   mFogColor = color;
1283   setMaskBits(FogColorMask);
1284}
1285
1286void VolumetricFog::setFogDensity(F32 density)
1287{
1288   if (density < 0.0f)
1289      density = 0.0f;
1290   mFogDensity = density;
1291   setMaskBits(FogDensityMask);
1292}
1293
1294void VolumetricFog::setFogModulation(F32 strength,Point2F speed1,Point2F speed2)
1295{
1296   mStrength = strength;
1297   mSpeed1 = speed1;
1298   mSpeed2 = speed2;
1299   mSpeed.set(speed1.x, speed1.y, speed2.x, speed2.y);
1300   setMaskBits(FogModulationMask);
1301}
1302
1303void VolumetricFog::setFogGlow(bool on_off, F32 strength)
1304{
1305   mUseGlow = on_off;
1306   mGlowStrength = strength;
1307   setMaskBits(FogPostFXMask);
1308}
1309
1310void VolumetricFog::setFogLightray(bool on_off, F32 strength)
1311{
1312   mModifLightRays = on_off;
1313   mLightRayMod = strength;
1314   setMaskBits(FogPostFXMask);
1315}
1316
1317bool VolumetricFog::isInsideFog()
1318{
1319   return mCamInFog;
1320}
1321
1322DefineEngineMethod(VolumetricFog, SetFogColorF, void, (LinearColorF new_color), ,
1323"@brief Changes the color of the fog\n\n."
1324"@params new_color the new fog color (rgb 0.0 - 1.0, a is ignored.")
1325{
1326   object->setFogColor(new_color);
1327}
1328
1329DefineEngineMethod(VolumetricFog, SetFogColor, void, (ColorI new_color), ,
1330"@brief Changes the color of the fog\n\n."
1331"@params new_color the new fog color (rgb 0-255, a is ignored.")
1332{
1333   object->setFogColor(new_color);
1334}
1335
1336DefineEngineMethod(VolumetricFog, SetFogDensity, void, (F32 new_density), ,
1337"@brief Changes the density of the fog\n\n."
1338"@params new_density the new fog density.")
1339{
1340   object->setFogDensity(new_density);
1341}
1342
1343DefineEngineMethod(VolumetricFog, SetFogModulation, void, (F32 new_strenght, Point2F new_speed1, Point2F new_speed2), ,
1344"@brief Changes the modulation of the fog\n\n."
1345"@params new_strenght the new strength of the modulation.\n"
1346"@params new_speed1 the new speed (x y) of the modulation layer 1.\n"
1347"@params new_speed2 the new speed (x y) of the modulation layer 2.\n")
1348{
1349   object->setFogModulation(new_strenght, new_speed1, new_speed2);
1350}
1351
1352DefineEngineMethod(VolumetricFog, SetFogGlow, void, (bool on_off,F32 strength), ,
1353"@brief Changes the glow postfx when inside the fog\n\n."
1354"@params on_off set to true to enable glow.\n"
1355"@params strength glow strength.\n")
1356{
1357   object->setFogGlow(on_off, strength);
1358}
1359
1360DefineEngineMethod(VolumetricFog, SetFogLightray, void, (bool on_off, F32 strength), ,
1361"@brief Changes the lightrays postfx when inside the fog\n\n."
1362"@params on_off set to true to modification of the lightray postfx.\n"
1363"@params strength lightray strength.\n")
1364{
1365   object->setFogLightray(on_off, strength);
1366}
1367
1368DefineEngineMethod(VolumetricFog, isInsideFog, bool, (), ,
1369"@brief returns true if control object is inside the fog\n\n.")
1370{
1371   return object->isInsideFog();
1372}
1373