forestWindMgr.cpp
Engine/source/forest/forestWindMgr.cpp
Public Variables
Detailed Description
Public Variables
MODULE_END
MODULE_INIT
MODULE_SHUTDOWN
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/forestWindMgr.h" 26 27#include "platform/profiler.h" 28#include "core/tAlgorithm.h" 29#include "core/module.h" 30#include "console/consoleTypes.h" 31#include "math/mathUtils.h" 32#include "T3D/gameBase/gameConnection.h" 33#include "forest/forest.h" 34#include "forest/forestWindAccumulator.h" 35#include "T3D/fx/particleEmitter.h" 36 37 38MODULE_BEGIN( ForestWindMgr ) 39 40 MODULE_INIT 41 { 42 ManagedSingleton< ForestWindMgr >::createSingleton(); 43 ForestWindMgr::initConsole(); 44 } 45 46 MODULE_SHUTDOWN 47 { 48 ManagedSingleton< ForestWindMgr >::deleteSingleton(); 49 } 50 51MODULE_END; 52 53 54ForestWindMgr::WindAdvanceSignal ForestWindMgr::smAdvanceSignal; 55 56F32 ForestWindMgr::smWindEffectRadius = 25.0f; 57 58 59ForestWindMgr::ForestWindMgr() 60{ 61 setProcessTicks( true ); 62 mSources = new IdToWindMap(); 63 mPrevSources = new IdToWindMap(); 64} 65 66ForestWindMgr::~ForestWindMgr() 67{ 68 IdToWindMap::Iterator sourceIter = mSources->begin(); 69 for (; sourceIter != mSources->end(); ++sourceIter) 70 delete (*sourceIter).value; 71 72 delete mSources; 73 delete mPrevSources; 74} 75 76void ForestWindMgr::initConsole() 77{ 78 Con::addVariable( "$pref::windEffectRadius", TypeF32, &smWindEffectRadius, "Radius to affect the wind.\n" 79 "@ingroup Rendering\n"); 80} 81 82void ForestWindMgr::addEmitter( ForestWindEmitter *emitter ) 83{ 84 mEmitters.push_back( emitter ); 85} 86 87void ForestWindMgr::removeEmitter( ForestWindEmitter *emitter ) 88{ 89 ForestWindEmitterList::iterator iter = T3D::find( mEmitters.begin(), 90 mEmitters.end(), 91 emitter ); 92 93 AssertFatal( iter != mEmitters.end(), 94 "SpeedTreeWindMgr::removeEmitter() - Bad emitter!" ); 95 96 mEmitters.erase( iter ); 97} 98 99void ForestWindMgr::processTick() 100{ 101 const F32 timeDelta = 0.032f; 102 103 if ( mEmitters.empty() ) 104 return; 105 106 PROFILE_SCOPE(ForestWindMgr_AdvanceTime); 107 108 // Advance all ForestWinds. 109 { 110 PROFILE_SCOPE(ForestWindMgr_AdvanceTime_ForestWind_ProcessTick); 111 112 ForestWindEmitterList::iterator iter = mEmitters.begin(); 113 for ( ; iter != mEmitters.end(); iter++ ) 114 { 115 if ( (*iter)->getWind() && 116 (*iter)->isEnabled() ) 117 { 118 (*iter)->updateMountPosition(); 119 120 ForestWind *wind = (*iter)->getWind(); 121 if ( wind ) 122 wind->processTick(); 123 } 124 } 125 } 126 127 // Assign the new global wind value used by the particle system. 128 { 129 ForestWindEmitter *pWindEmitter = getGlobalWind(); 130 if ( pWindEmitter == NULL ) 131 ParticleEmitter::setWindVelocity( Point3F::Zero ); 132 else 133 { 134 ForestWind *pWind = pWindEmitter->getWind(); 135 ParticleEmitter::setWindVelocity( pWind->getDirection() * pWind->getStrength() ); 136 } 137 } 138 139 // Get the game connection and camera object 140 // in order to retrieve the camera position. 141 GameConnection *conn = GameConnection::getConnectionToServer(); 142 if ( !conn ) 143 return; 144 145 GameBase *cam = conn->getCameraObject(); 146 if ( !cam ) 147 return; 148 149 const Point3F &camPos = cam->getPosition(); 150 151 152 153 // Gather TreePlacementInfo for trees near the camera. 154 { 155 PROFILE_SCOPE( ForestWindMgr_AdvanceTime_GatherTreePlacementInfo ); 156 157 smAdvanceSignal.trigger( camPos, smWindEffectRadius, &mPlacementInfo ); 158 } 159 160 // Prepare to build a new local source map. 161 { 162 PROFILE_SCOPE( ForestWindMgr_AdvanceTime_SwapSources ); 163 AssertFatal( mPrevSources->isEmpty(), "prev sources not empty!" ); 164 165 T3D::swap( mSources, mPrevSources ); 166 167 AssertFatal( mSources->isEmpty(), "swap failed!" ); 168 } 169 170 // Update wind for each TreePlacementInfo 171 { 172 PROFILE_SCOPE( ForestWindMgr_AdvanceTime_UpdateWind ); 173 174 for( S32 i = 0; i < mPlacementInfo.size(); i++ ) 175 { 176 const TreePlacementInfo &info = mPlacementInfo[i]; 177 updateWind( camPos, info, timeDelta ); 178 } 179 180 mPlacementInfo.clear(); 181 } 182 183 // Clean up any accumulators in the 184 // previous local source map. 185 { 186 PROFILE_SCOPE( ForestWindMgr_AdvanceTime_Cleanup ); 187 188 IdToWindMap::Iterator sourceIter = mPrevSources->begin(); 189 for (; sourceIter != mPrevSources->end(); ++sourceIter) 190 { 191 ForestWindAccumulator *accum = (*sourceIter).value; 192 193 AssertFatal( accum, "Got null accumulator!" ); 194 delete accum; 195 } 196 197 mPrevSources->clear(); 198 } 199} 200 201ForestWindAccumulator* ForestWindMgr::getLocalWind( ForestItemKey key ) 202{ 203 PROFILE_SCOPE( ForestWindMgr_getLocalWind ); 204 205 ForestWindAccumulator *accumulator = NULL; 206 IdToWindMap::Iterator iter = mSources->find( key ); 207 if ( iter != mSources->end() ) 208 accumulator = iter->value; 209 210 if ( accumulator ) 211 return accumulator; 212 else 213 { 214 /* 215 ForestWindEmitterList::iterator iter = mEmitters.begin(); 216 for ( ; iter != mEmitters.end(); iter++ ) 217 { 218 if ( (*iter)->getWind() && 219 (*iter)->isEnabled() && 220 !(*iter)->isLocalWind() ) 221 { 222 return (*iter)->getWind(); 223 } 224 } 225 */ 226 return NULL; 227 } 228} 229 230ForestWindEmitter* ForestWindMgr::getGlobalWind() 231{ 232 ForestWindEmitterList::iterator itr = mEmitters.begin(); 233 for ( ; itr != mEmitters.end(); itr++ ) 234 { 235 if ( !(*itr)->isRadialEmitter() ) 236 return *itr; 237 } 238 239 return NULL; 240} 241 242void ForestWindMgr::updateWind( const Point3F &camPos, 243 const TreePlacementInfo &info, 244 F32 timeDelta ) 245{ 246 PROFILE_SCOPE(ForestWindMgr_updateWind); 247 248 // See if we have the blended source available. 249 ForestWindAccumulator *blendDest = NULL; 250 { 251 IdToWindMap::Iterator iter = mPrevSources->find( info.itemKey ); 252 if ( iter != mPrevSources->end() ) 253 { 254 blendDest = iter->value; 255 mPrevSources->erase( iter ); 256 } 257 } 258 259 // Get some stuff we'll need for finding the emitters. 260 F32 treeHeight = info.scale * info.dataBlock->getObjBox().len_z(); 261 Point3F top = info.pos; 262 top.z += treeHeight; 263 if ( blendDest ) 264 top += ( 1.0f / info.scale ) * blendDest->getDirection(); 265 266 // Go thru the emitters to accumulate the total wind force. 267 VectorF windForce( 0, 0, 0 ); 268 269 F32 time = Sim::getCurrentTime() / 1000.0f; 270 271 ForestWindEmitterList::iterator iter = mEmitters.begin(); 272 for ( ; iter != mEmitters.end(); iter++ ) 273 { 274 ForestWindEmitter *emitter = (*iter); 275 276 // If disabled or no wind object... skip it. 277 if ( !emitter->isEnabled() || !emitter->getWind() ) 278 continue; 279 280 ForestWind *wind = emitter->getWind(); 281 282 F32 strength = wind->getStrength(); 283 284 if ( emitter->isRadialEmitter() ) 285 { 286 Point3F closest = MathUtils::mClosestPointOnSegment( info.pos, top, emitter->getPosition() ); 287 Point3F dir = closest - emitter->getPosition(); 288 F32 lenSquared = dir.lenSquared(); 289 if ( lenSquared > emitter->getWindRadiusSquared() ) 290 continue; 291 292 dir *= 1.0f / mSqrt( lenSquared ); 293 294 F32 att = lenSquared / emitter->getWindRadiusSquared(); 295 strength *= 1.0f - att; 296 windForce += dir * strength; 297 } 298 else 299 { 300 F32 d = mDot( info.pos, Point3F::One ); //PlaneF( Point3F::Zero, wind->getDirection() ).distToPlane( Point3F( info.pos.x, info.pos.y, 0 ) ); 301 //F32 d = PlaneF( Point3F::Zero, wind->getDirection() ).distToPlane( Point3F( info.pos.x, info.pos.y, 0 ) ); 302 F32 scale = 1.0f + ( mSin( d + ( time / 10.0 ) ) * 0.5f ); 303 windForce += wind->getDirection() * strength * scale; 304 } 305 } 306 307 // If we need a accumulator then we also need to presimulate. 308 if ( !blendDest ) 309 { 310 blendDest = new ForestWindAccumulator( info ); 311 blendDest->presimulate( windForce, 4.0f / TickSec ); 312 } 313 else 314 blendDest->updateWind( windForce, timeDelta ); 315 316 mSources->insertUnique( info.itemKey, blendDest ); 317} 318