Torque3D Documentation / _generateds / forestWindEmitter.cpp

forestWindEmitter.cpp

Engine/source/forest/forestWindEmitter.cpp

More...

Public Variables

bool

For frame signal.

Public Functions

ConsoleDocClass(ForestWindEmitter , "@brief <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> simulating wind in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">level.\n\n</a>" "When placed in the level, <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classforestwindemitter/">ForestWindEmitter</a> will cause tree branches <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> bend and sway, leaves " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> flutter, and create vertical bending on the tree 's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">trunk.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//The following is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> full declaration of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> wind <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">emitter\n</a>" "<a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classforestwindemitter/">ForestWindEmitter</a>()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " position=\"497.739 765.821 102.395\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   windEnabled = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   radialEmitter = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   strength = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   radius = \"3\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gustStrength = \"0.5\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gustFrequency = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gustYawAngle = \"10\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gustYawFrequency = \"4\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gustWobbleStrength = \"2\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   turbulenceStrength = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   turbulenceFrequency = \"2\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   hasMount = \"0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   scale = \"3 3 3\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   canSave = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   canSaveDynamicFields = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   rotation = \"1 0 0 0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Forest\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Atmosphere\n</a>" )
DefineEngineMethod(ForestWindEmitter , attachToObject , void , (U32 objectID) , "@brief Mounts the wind emitter <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> another scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n\n</a>" "@param objectID Unique ID of the object wind emitter should attach <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Wind emitter previously created and named %<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">windEmitter\n</a>" "// Going <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> attach it <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the player, making him <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> walking wind <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">storm\n</a>" "%windEmitter.attachToObject(%player);\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" )

Detailed Description

Public Variables

bool gEditingMission 

For frame signal.

Public Functions

ConsoleDocClass(ForestWindEmitter , "@brief <a href="/coding/file/gizmo_8h/#gizmo_8h_1a10fcd3bee2ea25191e31795e36bdeba1a5df911aaca43421a25e32c3002befbc4">Object</a> responsible <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> simulating wind in <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">level.\n\n</a>" "When placed in the level, <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classforestwindemitter/">ForestWindEmitter</a> will cause tree branches <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> bend and sway, leaves " "<a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> flutter, and create vertical bending on the tree 's <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">trunk.\n\n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "//The following is <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> full declaration of <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> wind <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">emitter\n</a>" "<a href="/coding/file/tmm__on_8h/#tmm__on_8h_1a1ac41480eb2e4aadd52252ee550b630a">new</a> <a href="/coding/class/classforestwindemitter/">ForestWindEmitter</a>()\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "{\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " position=\"497.739 765.821 102.395\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   windEnabled = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   radialEmitter = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   strength = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   radius = \"3\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gustStrength = \"0.5\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gustFrequency = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gustYawAngle = \"10\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gustYawFrequency = \"4\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   gustWobbleStrength = \"2\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   turbulenceStrength = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   turbulenceFrequency = \"2\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   hasMount = \"0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   scale = \"3 3 3\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   canSave = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   canSaveDynamicFields = \"1\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "   rotation = \"1 0 0 0\";\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "};\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Forest\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Atmosphere\n</a>" )

DefineEngineMethod(ForestWindEmitter , attachToObject , void , (U32 objectID) , "@brief Mounts the wind emitter <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> another scene <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">object\n\n</a>" "@param objectID Unique ID of the object wind emitter should attach <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a>" "@<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">tsexample\n</a>" "// Wind emitter previously created and named %<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">windEmitter\n</a>" "// Going <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> attach it <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the player, making him <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> walking wind <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">storm\n</a>" "%windEmitter.attachToObject(%player);\<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">n</a>" " @<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">endtsexample\n\n</a>" )

IMPLEMENT_CO_NETOBJECT_V1(ForestWindEmitter )

  1
  2//-----------------------------------------------------------------------------
  3// Copyright (c) 2012 GarageGames, LLC
  4//
  5// Permission is hereby granted, free of charge, to any person obtaining a copy
  6// of this software and associated documentation files (the "Software"), to
  7// deal in the Software without restriction, including without limitation the
  8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  9// sell copies of the Software, and to permit persons to whom the Software is
 10// furnished to do so, subject to the following conditions:
 11//
 12// The above copyright notice and this permission notice shall be included in
 13// all copies or substantial portions of the Software.
 14//
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 21// IN THE SOFTWARE.
 22//-----------------------------------------------------------------------------
 23
 24#include "platform/platform.h"
 25#include "forest/forestWindEmitter.h"
 26
 27#include "forest/forestWindMgr.h"
 28#include "console/consoleInternal.h"
 29#include "core/stream/bitStream.h"
 30#include "core/util/safeDelete.h"
 31#include "platform/profiler.h"
 32#include "math/mathIO.h"
 33#include "math/mRandom.h"
 34#include "scene/sceneManager.h"
 35#include "scene/sceneRenderState.h"
 36#include "renderInstance/renderPassManager.h"
 37#include "gfx/gfxDrawUtil.h"
 38#include "gfx/gfxTransformSaver.h"
 39#include "sim/netConnection.h"
 40#include "T3D/gameBase/processList.h"
 41#include "console/engineAPI.h"
 42
 43#include "T3D/gameBase/gameConnection.h"
 44
 45ConsoleDocClass( ForestWindEmitter,
 46   "@brief Object responsible for simulating wind in a level.\n\n"
 47
 48   "When placed in the level, a ForestWindEmitter will cause tree branches to bend and sway, leaves "
 49   "to flutter, and create vertical bending on the tree's trunk.\n\n"
 50
 51   "@tsexample\n"
 52   "// The following is a full declaration of a wind emitter\n"
 53   "new ForestWindEmitter()\n"
 54   "{\n"
 55   "   position = \"497.739 765.821 102.395\";\n"
 56   "   windEnabled = \"1\";\n"
 57   "   radialEmitter = \"1\";\n"
 58   "   strength = \"1\";\n"
 59   "   radius = \"3\";\n"
 60   "   gustStrength = \"0.5\";\n"
 61   "   gustFrequency = \"1\";\n"
 62   "   gustYawAngle = \"10\";\n"
 63   "   gustYawFrequency = \"4\";\n"
 64   "   gustWobbleStrength = \"2\";\n"
 65   "   turbulenceStrength = \"1\";\n"
 66   "   turbulenceFrequency = \"2\";\n"
 67   "   hasMount = \"0\";\n"
 68   "   scale = \"3 3 3\";\n"
 69   "   canSave = \"1\";\n"
 70   "   canSaveDynamicFields = \"1\";\n"
 71   "   rotation = \"1 0 0 0\";\n"
 72   "};\n"
 73   "@endtsexample\n\n"
 74
 75   "@ingroup FX\n"
 76   "@ingroup Forest\n"
 77   "@ingroup Atmosphere\n"
 78);
 79
 80// We need to know when the mission editor is enabled.
 81extern bool gEditingMission;
 82
 83ForestWind::ForestWind(  ForestWindEmitter *emitter )
 84   :  mStrength( 0.0f ),
 85      mDirection( 1.0f, 0, 0 ),
 86      mLastGustTime( 0 ),
 87      mLastYawTime( 0 ),
 88      mTargetYawAngle( 0 ),
 89      mCurrentInterp( 0 ),
 90      mCurrentTarget( 0, 0 ),
 91      mParent( emitter ),
 92      mRandom( Platform::getRealMilliseconds() + 1 ),
 93      mIsDirty( false )
 94{
 95}
 96
 97ForestWind::~ForestWind()
 98{
 99}
100
101void ForestWind::processTick()
102{
103   PROFILE_SCOPE( ForestWind_ProcessTick );
104
105   const F32 deltaTime = 0.032f;
106   const U32 simTime = Sim::getCurrentTime();
107   
108   Point2F finalVec( 0, 0 );
109   Point2F windDir( mParent->mWindDirection.x, mParent->mWindDirection.y );
110
111   if ( mLastGustTime < simTime )
112   {
113      Point2F turbVec( 0, 0 );
114      if ( mLastGustTime < simTime + (mParent->mWindTurbulenceFrequency * 1000.0f) )
115         turbVec = (mRandom.randF() * mParent->mWindTurbulenceStrength) * windDir;
116
117      mLastGustTime = simTime + (mParent->mWindGustFrequency * 1000.0f);
118      Point2F gustVec = (mRandom.randF() * mParent->mWindGustStrength + mRandom.randF() * mParent->mWindGustWobbleStrength) * windDir;
119
120      finalVec += gustVec + turbVec;
121      //finalVec.normalizeSafe();
122   }
123   
124   //bool rotationChange = false;
125
126   if ( mLastYawTime < simTime )
127   {
128      mLastYawTime = simTime + (mParent->mWindGustYawFrequency * 1000.0f);
129      F32 rotateAmt = mRandom.randF() * mParent->mWindGustYawAngle + mRandom.randF() * mParent->mWindGustWobbleStrength;
130      
131      if ( mRandom.randF() <= 0.5f )
132         rotateAmt = -rotateAmt;
133
134      rotateAmt = mDegToRad( rotateAmt );
135
136      if ( rotateAmt > M_2PI_F )
137         rotateAmt -= M_2PI_F;
138      else if ( rotateAmt < -M_2PI_F )
139         rotateAmt += M_2PI_F;
140
141      mTargetYawAngle = rotateAmt;
142
143      //finalVec.rotate( rotateAmt );
144      mCurrentTarget.rotate( rotateAmt );
145   }
146   
147   //mCurrentTarget.normalizeSafe();
148
149   if ( mCurrentTarget.isZero() || mCurrentInterp >= 1.0f )
150   {
151      mCurrentInterp = 0;
152      mCurrentTarget.set( 0, 0 );
153   
154      Point2F windNorm( mDirection.x, mDirection.y );
155     windNorm.normalizeSafe();
156
157      mCurrentTarget = finalVec + windNorm;
158   }
159   else
160   {
161      mCurrentInterp += deltaTime;
162      mCurrentInterp = mClampF( mCurrentInterp, 0.0f, 1.0f );
163      mDirection.interpolate( mDirection, Point3F( mCurrentTarget.x, mCurrentTarget.y, 0 ), mCurrentInterp );
164      //F32 rotateAmt = mLerp( 0, mTargetYawAngle, mCurrentInterp );
165
166      //mTargetYawAngle -= rotateAmt;
167
168      //Point2F dir( mDirection.x, mDirection.y );
169      //if ( mTargetYawAngle > 0.0f )
170        // dir.rotate( rotateAmt );
171
172      //mDirection.set( dir.x, dir.y, 0 );
173   }
174}
175
176void ForestWind::setStrengthAndDirection( F32 strength, const VectorF &direction )
177{
178   if (  mStrength != strength ||
179         mDirection != direction )
180   {
181      mStrength = strength;
182      mDirection = direction;
183      mCurrentTarget.zero();
184      mIsDirty = true;
185   }
186}
187
188void ForestWind::setStrength( F32 strength )
189{
190   if ( mStrength != strength )
191   {
192      mStrength = strength;
193      mIsDirty = true;
194   }
195}
196
197void ForestWind::setDirection( const VectorF &direction )
198{
199   if ( mDirection != direction )
200   {
201      mDirection = direction;
202      mIsDirty = true;
203   }
204}
205
206IMPLEMENT_CO_NETOBJECT_V1(ForestWindEmitter);
207
208ForestWindEmitter::ForestWindEmitter( bool makeClientObject )
209   :  
210      mAddedToScene( false ),
211      mEnabled( true ),
212      mWind( NULL ),
213      mWindStrength( 1 ),
214      mWindDirection( 1, 0, 0 ),
215      mWindGustFrequency( 3.0f ),
216      mWindGustStrength( 0.25f ),
217      mWindGustYawAngle( 10.0f ),
218      mWindGustYawFrequency( 4.0f ),
219      mWindGustWobbleStrength( 2.0f ),
220      mWindTurbulenceFrequency( 2.0f ),
221      mWindTurbulenceStrength( 0.25f ),
222      mWindRadius( 0 ),
223      mRadialEmitter( false ),
224      mHasMount( false ),
225      mIsMounted( false ),
226      mMountObject( NULL )
227{
228   mTypeMask |= StaticObjectType | EnvironmentObjectType;
229
230   if ( makeClientObject )
231      mNetFlags.set( IsGhost );
232   else
233      mNetFlags.set( Ghostable | ScopeAlways );
234}
235
236ForestWindEmitter::~ForestWindEmitter()
237{
238}
239
240void ForestWindEmitter::initPersistFields()
241{
242   // Initialise parents' persistent fields.
243   Parent::initPersistFields();
244
245   addGroup( "ForestWind" );
246      addField( "windEnabled",         TypeBool,      Offset( mEnabled, ForestWindEmitter ), "Determines if the emitter will be counted in wind calculations." );
247      addField( "radialEmitter",       TypeBool,      Offset( mRadialEmitter, ForestWindEmitter ), "Determines if the emitter is a global direction or local radial emitter." );
248      addField( "strength",            TypeF32,       Offset( mWindStrength, ForestWindEmitter ), "The strength of the wind force." );
249      addField( "radius",              TypeF32,       Offset( mWindRadius, ForestWindEmitter ), "The radius of the emitter for local radial emitters." );
250      addField( "gustStrength",        TypeF32,       Offset( mWindGustStrength, ForestWindEmitter ), "The maximum strength of a gust." );
251      addField( "gustFrequency",       TypeF32,       Offset( mWindGustFrequency, ForestWindEmitter ), "The frequency of gusting in seconds." );
252      addField( "gustYawAngle",        TypeF32,       Offset( mWindGustYawAngle, ForestWindEmitter ), "The amount of degrees the wind direction can drift (both positive and negative)." );
253      addField( "gustYawFrequency",    TypeF32,       Offset( mWindGustYawFrequency, ForestWindEmitter ), "The frequency of wind yaw drift, in seconds." );
254      addField( "gustWobbleStrength",  TypeF32,       Offset( mWindGustWobbleStrength, ForestWindEmitter ), "The amount of random wobble added to gust and turbulence vectors." );
255      addField( "turbulenceStrength",  TypeF32,       Offset( mWindTurbulenceStrength, ForestWindEmitter ), "The strength of gust turbulence." ); 
256      addField( "turbulenceFrequency", TypeF32,       Offset( mWindTurbulenceFrequency, ForestWindEmitter ), "The frequency of gust turbulence, in seconds." ); 
257      addField( "hasMount", TypeBool, Offset( mHasMount, ForestWindEmitter ), "Determines if the emitter is mounted to another object." );
258   endGroup( "ForestWind" );
259}
260
261U32 ForestWindEmitter::packUpdate(NetConnection * con, U32 mask, BitStream * stream)
262{
263   U32 retMask = Parent::packUpdate( con, mask, stream );
264
265   mathWrite( *stream, mObjToWorld );
266
267   if ( stream->writeFlag( mask & EnabledMask ) )
268      stream->writeFlag( mEnabled );
269
270   if ( stream->writeFlag( mask & WindMask ) )
271   {
272      stream->write( mWindStrength );
273
274      stream->write( mWindRadius );
275      stream->writeFlag( mRadialEmitter );
276
277      stream->write( mWindGustStrength );
278      stream->write( mWindGustFrequency );
279
280      stream->write( mWindGustYawAngle );
281      stream->write( mWindGustYawFrequency );
282      stream->write( mWindGustWobbleStrength );
283
284      stream->write( mWindTurbulenceStrength );
285      stream->write( mWindTurbulenceFrequency );
286
287      // The wind direction should be normalized!
288      if ( mWindDirection.isZero() )
289      {
290         VectorF forwardVec( 0, 0, 0 );
291         mWorldToObj.getColumn( 1, &mWindDirection );
292      }
293      else
294         mWindDirection.normalize();
295
296      stream->writeNormalVector( mWindDirection, 8 );  
297
298      stream->writeFlag( mHasMount );
299   } 
300
301   return retMask;
302}
303
304void ForestWindEmitter::unpackUpdate(NetConnection * con, BitStream * stream)
305{
306   // Unpack Parent.
307   Parent::unpackUpdate( con, stream );
308
309   MatrixF xfm;
310   mathRead( *stream, &xfm );
311   Parent::setTransform( xfm );
312
313   U32 windMask = 0;
314
315   if ( stream->readFlag() ) // EnabledMask
316      mEnabled = stream->readFlag();
317
318   if ( stream->readFlag() ) // WindMask
319   {
320      stream->read( &mWindStrength );
321      stream->read( &mWindRadius );
322      
323      mRadialEmitter = stream->readFlag();
324
325      stream->read( &mWindGustStrength );
326      stream->read( &mWindGustFrequency );
327      
328      stream->read( &mWindGustYawAngle );
329      stream->read( &mWindGustYawFrequency );
330      stream->read( &mWindGustWobbleStrength );
331
332      stream->read( &mWindTurbulenceStrength );
333      stream->read( &mWindTurbulenceFrequency );
334
335      stream->readNormalVector( &mWindDirection, 8 );
336      windMask |= WindMask;
337
338      mHasMount = stream->readFlag();
339   }
340
341   // This does nothing if the masks are not set!
342   if ( windMask != 0 && isProperlyAdded() )
343   {
344      Point3F boxRad( 0, 0, 0 );
345
346      if ( !isRadialEmitter() )
347         boxRad.set( 10000.0f, 10000.0f, 10000.0f );
348      else
349         boxRad.set( mWindRadius, mWindRadius, mWindRadius ); 
350         
351      mObjBox.set( -boxRad, boxRad );
352      resetWorldBox();
353      
354      _initWind( windMask );
355   }
356}
357
358bool ForestWindEmitter::onAdd()
359{
360   if ( !Parent::onAdd() )
361      return false;
362  
363   // Only the client side actually does wind.
364   if ( isClientObject() )
365   {
366      // TODO: wasn't this a big hack we already fixed better?
367      //Projectile::getGhostReceivedSignal().notify( this, &ForestWindEmitter::_onMountObjectGhostReceived );
368   
369      _initWind();
370      WINDMGR->addEmitter( this );
371   }
372
373   Point3F boxRad( 0, 0, 0 );
374
375   if ( !isRadialEmitter() )
376      boxRad.set( 10000.0f, 10000.0f, 10000.0f );
377   else
378      boxRad.set( mWindRadius, mWindRadius, mWindRadius ); 
379      
380   mObjBox.set( -boxRad, boxRad );
381   resetWorldBox();
382
383   enableCollision();
384
385   // If we are we editing the mission then
386   // be sure to add us to the scene.
387   if ( gEditingMission || mHasMount )
388   {
389      addToScene();
390      mAddedToScene = true;
391   }
392
393   return true;
394} 
395
396void ForestWindEmitter::onRemove()
397{
398   // Only the client side actually does wind.
399   if ( isClientObject() )
400   {
401      //Projectile::getGhostReceivedSignal().remove( this, &ForestWindEmitter::_onMountObjectGhostReceived );
402
403      WINDMGR->removeEmitter( this );
404      SAFE_DELETE( mWind );
405   }
406
407   // If we are editing the mission then remove
408   // us from the scene graph.
409   if ( gEditingMission || mHasMount )
410   {
411      removeFromScene();
412      mAddedToScene = false;
413   }
414
415   // Do Parent.
416   Parent::onRemove();
417}
418
419void ForestWindEmitter::_onMountObjectGhostReceived( SceneObject *object )
420{
421   if ( !object )
422      return;
423
424   attachToObject( object );
425}
426
427void ForestWindEmitter::inspectPostApply()
428{
429   // Force the client update!
430   setMaskBits(0xffffffff);
431}
432
433void ForestWindEmitter::onEditorEnable()
434{
435   if ( !mAddedToScene )
436   {
437      addToScene();
438      mAddedToScene = true;
439   }
440}
441
442void ForestWindEmitter::onEditorDisable()
443{
444   // Remove us from the scene.
445   if ( mAddedToScene )
446   {
447      removeFromScene();
448      mAddedToScene = false;
449   }
450}
451
452void ForestWindEmitter::_initWind( U32 mask )
453{
454   AssertFatal( !isServerObject(), "SpeedWind is never updated on the server!" );
455
456   // If we don't have a wind 
457   // object create one now.
458   if ( !mWind ) 
459      mWind = new ForestWind( this );
460
461   // Do we need to apply a new direction and strength?
462   if ( mask & WindMask )
463   {
464      mWorldToObj.getColumn( 1, &mWindDirection );
465      mWind->setStrengthAndDirection( mWindStrength, mWindDirection );
466   }
467}
468
469void ForestWindEmitter::setTransform( const MatrixF &mat )
470{
471   Parent::setTransform( mat );
472
473   // Force the client update!
474   setMaskBits(0xffffffff);
475
476   if ( isClientObject() )
477      _initWind();
478}
479
480void ForestWindEmitter::prepRenderImage( SceneRenderState* state )
481{
482   PROFILE_SCOPE( ForestWindEmitter_PrepRenderImage );
483
484   // Only render the radius and
485   // direction if we're in the editor.
486   // Don't render them if this is a reflect pass.
487   if ( !state->isDiffusePass() || !gEditingMission )
488      return;
489
490   // This should be sufficient for most objects that don't manage zones, and
491   // don't need to return a specialized RenderImage...
492   ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
493   ri->renderDelegate.bind( this, &ForestWindEmitter::_renderEmitterInfo );
494   ri->type = RenderPassManager::RIT_Editor;
495   state->getRenderPass()->addInst( ri );
496}
497
498void ForestWindEmitter::_renderEmitterInfo( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat )
499{
500   if ( overrideMat )
501      return;
502
503   GFXTransformSaver saver;
504
505   GFXDrawUtil *drawer = GFX->getDrawUtil();
506
507   AssertFatal( drawer, "Got NULL GFXDrawUtil!" );
508
509   const Point3F &pos = getPosition();
510   const VectorF &windVec = mWind->getDirection();
511
512   GFXStateBlockDesc desc;
513   desc.setBlend( true );
514   desc.setZReadWrite( true, false );
515
516   // Draw an arrow pointing
517   // in the wind direction.
518   drawer->drawArrow( desc, pos, pos + (windVec * mWindStrength), ColorI( 0, 0, 255, 255 ) );//Point3F( -235.214, 219.589, 34.0991 ), Point3F( -218.814, 244.731, 37.5587 ), ColorI( 255, 255, 0, 255 ) );//
519   drawer->drawArrow( desc, pos, pos + (mWind->getTarget() * mWindStrength ), ColorI( 255, 0, 0, 85 ) );
520
521   S32 useRadius = mWindRadius;
522   // Draw a 2D circle for the wind radius.
523   if ( isRadialEmitter() )
524   {
525      // If the camera is close to the sphere, shrink the sphere so it remains visible.
526      GameConnection* gc = GameConnection::getConnectionToServer();
527      GameBase *gb = gc ? gc->getCameraObject() : NULL;
528      if (gb)
529      {
530         F32 camDist = (gb->getPosition() - getPosition()).len();
531         if ( camDist < mWindRadius )
532            useRadius = camDist;
533      }
534      drawer->drawSphere( desc, useRadius, pos, ColorI( 255, 0, 0, 80 ) );
535   }
536}
537
538F32 ForestWindEmitter::getStrength() const
539{ 
540   return mWind->getStrength(); 
541}
542
543void ForestWindEmitter::setStrength( F32 strength )
544{
545   mWindStrength = strength;
546   mWind->setStrength( mWindStrength );
547}
548
549void ForestWindEmitter::attachToObject( SceneObject *obj )
550{
551   if ( !obj )
552      return;
553
554   mMountObject = obj;
555   mIsMounted = true;
556
557   if ( isServerObject() )
558      deleteNotify( mMountObject );
559}
560
561void ForestWindEmitter::updateMountPosition()
562{
563   AssertFatal( isClientObject(), "ForestWindEmitter::updateMountPosition - This should only happen on the client!" );
564
565   if ( !mHasMount || !mMountObject )
566      return;
567
568   MatrixF mat( true ); 
569   mat.setPosition( mMountObject->getPosition() );
570   Parent::setTransform( mat );
571}
572
573void ForestWindEmitter::onDeleteNotify(SimObject *object)
574{
575   AssertFatal( isServerObject(), "ForestWindEmitter::onDeleteNotify - This should never happen on the client!" );
576   safeDeleteObject();
577}
578
579DefineEngineMethod( ForestWindEmitter, attachToObject, void, ( U32 objectID ),,
580   "@brief Mounts the wind emitter to another scene object\n\n"
581
582   "@param objectID Unique ID of the object wind emitter should attach to"
583   
584   "@tsexample\n"
585   "// Wind emitter previously created and named %windEmitter\n"
586   "// Going to attach it to the player, making him a walking wind storm\n"
587   "%windEmitter.attachToObject(%player);\n"
588   "@endtsexample\n\n")
589{
590   SceneObject *obj = dynamic_cast<SceneObject*>( Sim::findObject( objectID ) );
591   if ( !obj )
592      Con::warnf( "ForestWindEmitter::attachToObject - failed to find object with ID: %d", objectID );
593
594   object->attachToObject( obj );
595}
596