| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 | //-----------------------------------------------------------------------------// Copyright (c) 2012 GarageGames, LLC//// Permission is hereby granted, free of charge, to any person obtaining a copy// of this software and associated documentation files (the "Software"), to// deal in the Software without restriction, including without limitation the// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or// sell copies of the Software, and to permit persons to whom the Software is// furnished to do so, subject to the following conditions://// The above copyright notice and this permission notice shall be included in// all copies or substantial portions of the Software.//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS// IN THE SOFTWARE.//-----------------------------------------------------------------------------#include "platform/platform.h"#include "forest/forestWindMgr.h"#include "platform/profiler.h"#include "core/tAlgorithm.h"#include "core/module.h"#include "console/consoleTypes.h"#include "math/mathUtils.h"#include "T3D/gameBase/gameConnection.h"#include "forest/forest.h"#include "forest/forestWindAccumulator.h"#include "T3D/fx/particleEmitter.h"MODULE_BEGIN( ForestWindMgr )   MODULE_INIT   {      ManagedSingleton< ForestWindMgr >::createSingleton();      ForestWindMgr::initConsole();   }      MODULE_SHUTDOWN   {      ManagedSingleton< ForestWindMgr >::deleteSingleton();   }MODULE_END;ForestWindMgr::WindAdvanceSignal ForestWindMgr::smAdvanceSignal;  F32 ForestWindMgr::smWindEffectRadius = 25.0f;ForestWindMgr::ForestWindMgr(){   setProcessTicks( true );   mSources = new IdToWindMap();   mPrevSources = new IdToWindMap();}ForestWindMgr::~ForestWindMgr(){   IdToWindMap::Iterator sourceIter = mSources->begin();   for (; sourceIter != mSources->end(); ++sourceIter)      delete (*sourceIter).value;   delete mSources;   delete mPrevSources;}void ForestWindMgr::initConsole(){   Con::addVariable( "$pref::windEffectRadius", TypeF32, &smWindEffectRadius, "Radius to affect the wind.\n"	   "@ingroup Rendering\n");}void ForestWindMgr::addEmitter( ForestWindEmitter *emitter ){   mEmitters.push_back( emitter );}void ForestWindMgr::removeEmitter( ForestWindEmitter *emitter ){   ForestWindEmitterList::iterator iter = T3D::find( mEmitters.begin(),                                                mEmitters.end(),                                                 emitter );   AssertFatal( iter != mEmitters.end(),       "SpeedTreeWindMgr::removeEmitter() - Bad emitter!" );   mEmitters.erase( iter );}void ForestWindMgr::processTick(){   const F32 timeDelta = 0.032f;   if ( mEmitters.empty() )      return;   PROFILE_SCOPE(ForestWindMgr_AdvanceTime);   // Advance all ForestWinds.   {      PROFILE_SCOPE(ForestWindMgr_AdvanceTime_ForestWind_ProcessTick);      ForestWindEmitterList::iterator iter = mEmitters.begin();      for ( ; iter != mEmitters.end(); iter++ )      {         if (  (*iter)->getWind() &&               (*iter)->isEnabled() )         {            (*iter)->updateMountPosition();            ForestWind *wind = (*iter)->getWind();            if ( wind )               wind->processTick();         }      }   }      // Assign the new global wind value used by the particle system.   {      ForestWindEmitter *pWindEmitter = getGlobalWind();      if ( pWindEmitter == NULL )               ParticleEmitter::setWindVelocity( Point3F::Zero );      else      {         ForestWind *pWind = pWindEmitter->getWind();         ParticleEmitter::setWindVelocity( pWind->getDirection() * pWind->getStrength() );      }   }   // Get the game connection and camera object   // in order to retrieve the camera position.   GameConnection *conn = GameConnection::getConnectionToServer();   if ( !conn )      return;   GameBase *cam = conn->getCameraObject();   if ( !cam )      return;      const Point3F &camPos = cam->getPosition();         // Gather TreePlacementInfo for trees near the camera.   {      PROFILE_SCOPE( ForestWindMgr_AdvanceTime_GatherTreePlacementInfo );            smAdvanceSignal.trigger( camPos, smWindEffectRadius, &mPlacementInfo );   }   // Prepare to build a new local source map.   {      PROFILE_SCOPE( ForestWindMgr_AdvanceTime_SwapSources );      AssertFatal( mPrevSources->isEmpty(), "prev sources not empty!" );      	  T3D::swap( mSources, mPrevSources );      AssertFatal( mSources->isEmpty(), "swap failed!" );   }   // Update wind for each TreePlacementInfo   {      PROFILE_SCOPE( ForestWindMgr_AdvanceTime_UpdateWind );      for( S32 i = 0; i < mPlacementInfo.size(); i++ )      {         const TreePlacementInfo &info = mPlacementInfo[i];               updateWind( camPos, info, timeDelta );          }      mPlacementInfo.clear();   }   // Clean up any accumulators in the   // previous local source map.   {      PROFILE_SCOPE( ForestWindMgr_AdvanceTime_Cleanup );      IdToWindMap::Iterator sourceIter = mPrevSources->begin();      for (; sourceIter != mPrevSources->end(); ++sourceIter)      {         ForestWindAccumulator *accum = (*sourceIter).value;         AssertFatal( accum, "Got null accumulator!" );         delete accum;      }      mPrevSources->clear();   }}ForestWindAccumulator* ForestWindMgr::getLocalWind( ForestItemKey key ){   PROFILE_SCOPE( ForestWindMgr_getLocalWind );   ForestWindAccumulator *accumulator = NULL;   IdToWindMap::Iterator iter = mSources->find( key );   if ( iter != mSources->end() )      accumulator = iter->value;   if ( accumulator )      return accumulator;   else   {      /*      ForestWindEmitterList::iterator iter = mEmitters.begin();      for ( ; iter != mEmitters.end(); iter++ )      {         if (  (*iter)->getWind() &&               (*iter)->isEnabled() &&               !(*iter)->isLocalWind() )         {            return (*iter)->getWind();         }      }      */      return NULL;   }}ForestWindEmitter* ForestWindMgr::getGlobalWind(){   ForestWindEmitterList::iterator itr = mEmitters.begin();   for ( ; itr != mEmitters.end(); itr++ )   {      if ( !(*itr)->isRadialEmitter() )         return *itr;   }   return NULL;}void ForestWindMgr::updateWind(  const Point3F &camPos,                                  const TreePlacementInfo &info,                                  F32 timeDelta ){   PROFILE_SCOPE(ForestWindMgr_updateWind);   // See if we have the blended source available.   ForestWindAccumulator *blendDest = NULL;   {      IdToWindMap::Iterator iter = mPrevSources->find( info.itemKey );      if ( iter != mPrevSources->end() )      {         blendDest = iter->value;         mPrevSources->erase( iter );      }   }   // Get some stuff we'll need for finding the emitters.   F32 treeHeight = info.scale * info.dataBlock->getObjBox().len_z();   Point3F top = info.pos;   top.z += treeHeight;   if ( blendDest )      top += ( 1.0f / info.scale ) * blendDest->getDirection();   // Go thru the emitters to accumulate the total wind force.   VectorF windForce( 0, 0, 0 );   F32 time = Sim::getCurrentTime() / 1000.0f;   ForestWindEmitterList::iterator iter = mEmitters.begin();   for ( ; iter != mEmitters.end(); iter++ )   {      ForestWindEmitter *emitter = (*iter);      // If disabled or no wind object... skip it.      if ( !emitter->isEnabled() || !emitter->getWind() )         continue;      ForestWind *wind = emitter->getWind();      F32 strength = wind->getStrength();            if ( emitter->isRadialEmitter() )      {         Point3F closest = MathUtils::mClosestPointOnSegment( info.pos, top, emitter->getPosition() );         Point3F dir = closest - emitter->getPosition();         F32 lenSquared = dir.lenSquared();         if ( lenSquared > emitter->getWindRadiusSquared() )            continue;         dir *= 1.0f / mSqrt( lenSquared );         F32 att = lenSquared / emitter->getWindRadiusSquared();         strength *= 1.0f - att;         windForce += dir * strength;      }      else      {         F32 d = mDot( info.pos, Point3F::One ); //PlaneF( Point3F::Zero, wind->getDirection() ).distToPlane( Point3F( info.pos.x, info.pos.y, 0 ) );         //F32 d = PlaneF( Point3F::Zero, wind->getDirection() ).distToPlane( Point3F( info.pos.x, info.pos.y, 0 ) );         F32 scale = 1.0f + ( mSin( d + ( time / 10.0 ) ) * 0.5f );         windForce += wind->getDirection() * strength * scale;      }   }   // If we need a accumulator then we also need to presimulate.   if ( !blendDest )   {      blendDest = new ForestWindAccumulator( info );      blendDest->presimulate( windForce, 4.0f / TickSec );   }   else      blendDest->updateWind( windForce, timeDelta );   mSources->insertUnique( info.itemKey, blendDest );}
 |