forestWindEmitter.cpp
Engine/source/forest/forestWindEmitter.cpp
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