Torque3D Documentation / _generateds / forestWindMgr.cpp

forestWindMgr.cpp

Engine/source/forest/forestWindMgr.cpp

More...

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