forestWindMgr.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "forest/forestWindMgr.h"
  24. #include "platform/profiler.h"
  25. #include "core/tAlgorithm.h"
  26. #include "core/module.h"
  27. #include "console/consoleTypes.h"
  28. #include "math/mathUtils.h"
  29. #include "T3D/gameBase/gameConnection.h"
  30. #include "forest/forest.h"
  31. #include "forest/forestWindAccumulator.h"
  32. #include "T3D/fx/particleEmitter.h"
  33. MODULE_BEGIN( ForestWindMgr )
  34. MODULE_INIT
  35. {
  36. ManagedSingleton< ForestWindMgr >::createSingleton();
  37. ForestWindMgr::initConsole();
  38. }
  39. MODULE_SHUTDOWN
  40. {
  41. ManagedSingleton< ForestWindMgr >::deleteSingleton();
  42. }
  43. MODULE_END;
  44. ForestWindMgr::WindAdvanceSignal ForestWindMgr::smAdvanceSignal;
  45. F32 ForestWindMgr::smWindEffectRadius = 25.0f;
  46. ForestWindMgr::ForestWindMgr()
  47. {
  48. setProcessTicks( true );
  49. mSources = new IdToWindMap();
  50. mPrevSources = new IdToWindMap();
  51. }
  52. ForestWindMgr::~ForestWindMgr()
  53. {
  54. IdToWindMap::Iterator sourceIter = mSources->begin();
  55. for (; sourceIter != mSources->end(); ++sourceIter)
  56. delete (*sourceIter).value;
  57. delete mSources;
  58. delete mPrevSources;
  59. }
  60. void ForestWindMgr::initConsole()
  61. {
  62. Con::addVariable( "$pref::windEffectRadius", TypeF32, &smWindEffectRadius, "Radius to affect the wind.\n"
  63. "@ingroup Rendering\n");
  64. }
  65. void ForestWindMgr::addEmitter( ForestWindEmitter *emitter )
  66. {
  67. mEmitters.push_back( emitter );
  68. }
  69. void ForestWindMgr::removeEmitter( ForestWindEmitter *emitter )
  70. {
  71. ForestWindEmitterList::iterator iter = T3D::find( mEmitters.begin(),
  72. mEmitters.end(),
  73. emitter );
  74. AssertFatal( iter != mEmitters.end(),
  75. "SpeedTreeWindMgr::removeEmitter() - Bad emitter!" );
  76. mEmitters.erase( iter );
  77. }
  78. void ForestWindMgr::processTick()
  79. {
  80. const F32 timeDelta = 0.032f;
  81. if ( mEmitters.empty() )
  82. return;
  83. PROFILE_SCOPE(ForestWindMgr_AdvanceTime);
  84. // Advance all ForestWinds.
  85. {
  86. PROFILE_SCOPE(ForestWindMgr_AdvanceTime_ForestWind_ProcessTick);
  87. ForestWindEmitterList::iterator iter = mEmitters.begin();
  88. for ( ; iter != mEmitters.end(); iter++ )
  89. {
  90. if ( (*iter)->getWind() &&
  91. (*iter)->isEnabled() )
  92. {
  93. (*iter)->updateMountPosition();
  94. ForestWind *wind = (*iter)->getWind();
  95. if ( wind )
  96. wind->processTick();
  97. }
  98. }
  99. }
  100. // Assign the new global wind value used by the particle system.
  101. {
  102. ForestWindEmitter *pWindEmitter = getGlobalWind();
  103. if ( pWindEmitter == NULL )
  104. ParticleEmitter::setWindVelocity( Point3F::Zero );
  105. else
  106. {
  107. ForestWind *pWind = pWindEmitter->getWind();
  108. ParticleEmitter::setWindVelocity( pWind->getDirection() * pWind->getStrength() );
  109. }
  110. }
  111. // Get the game connection and camera object
  112. // in order to retrieve the camera position.
  113. GameConnection *conn = GameConnection::getConnectionToServer();
  114. if ( !conn )
  115. return;
  116. GameBase *cam = conn->getCameraObject();
  117. if ( !cam )
  118. return;
  119. const Point3F &camPos = cam->getPosition();
  120. // Gather TreePlacementInfo for trees near the camera.
  121. {
  122. PROFILE_SCOPE( ForestWindMgr_AdvanceTime_GatherTreePlacementInfo );
  123. smAdvanceSignal.trigger( camPos, smWindEffectRadius, &mPlacementInfo );
  124. }
  125. // Prepare to build a new local source map.
  126. {
  127. PROFILE_SCOPE( ForestWindMgr_AdvanceTime_SwapSources );
  128. AssertFatal( mPrevSources->isEmpty(), "prev sources not empty!" );
  129. T3D::swap( mSources, mPrevSources );
  130. AssertFatal( mSources->isEmpty(), "swap failed!" );
  131. }
  132. // Update wind for each TreePlacementInfo
  133. {
  134. PROFILE_SCOPE( ForestWindMgr_AdvanceTime_UpdateWind );
  135. for( S32 i = 0; i < mPlacementInfo.size(); i++ )
  136. {
  137. const TreePlacementInfo &info = mPlacementInfo[i];
  138. updateWind( camPos, info, timeDelta );
  139. }
  140. mPlacementInfo.clear();
  141. }
  142. // Clean up any accumulators in the
  143. // previous local source map.
  144. {
  145. PROFILE_SCOPE( ForestWindMgr_AdvanceTime_Cleanup );
  146. IdToWindMap::Iterator sourceIter = mPrevSources->begin();
  147. for (; sourceIter != mPrevSources->end(); ++sourceIter)
  148. {
  149. ForestWindAccumulator *accum = (*sourceIter).value;
  150. AssertFatal( accum, "Got null accumulator!" );
  151. delete accum;
  152. }
  153. mPrevSources->clear();
  154. }
  155. }
  156. ForestWindAccumulator* ForestWindMgr::getLocalWind( ForestItemKey key )
  157. {
  158. PROFILE_SCOPE( ForestWindMgr_getLocalWind );
  159. ForestWindAccumulator *accumulator = NULL;
  160. IdToWindMap::Iterator iter = mSources->find( key );
  161. if ( iter != mSources->end() )
  162. accumulator = iter->value;
  163. if ( accumulator )
  164. return accumulator;
  165. else
  166. {
  167. /*
  168. ForestWindEmitterList::iterator iter = mEmitters.begin();
  169. for ( ; iter != mEmitters.end(); iter++ )
  170. {
  171. if ( (*iter)->getWind() &&
  172. (*iter)->isEnabled() &&
  173. !(*iter)->isLocalWind() )
  174. {
  175. return (*iter)->getWind();
  176. }
  177. }
  178. */
  179. return NULL;
  180. }
  181. }
  182. ForestWindEmitter* ForestWindMgr::getGlobalWind()
  183. {
  184. ForestWindEmitterList::iterator itr = mEmitters.begin();
  185. for ( ; itr != mEmitters.end(); itr++ )
  186. {
  187. if ( !(*itr)->isRadialEmitter() )
  188. return *itr;
  189. }
  190. return NULL;
  191. }
  192. void ForestWindMgr::updateWind( const Point3F &camPos,
  193. const TreePlacementInfo &info,
  194. F32 timeDelta )
  195. {
  196. PROFILE_SCOPE(ForestWindMgr_updateWind);
  197. // See if we have the blended source available.
  198. ForestWindAccumulator *blendDest = NULL;
  199. {
  200. IdToWindMap::Iterator iter = mPrevSources->find( info.itemKey );
  201. if ( iter != mPrevSources->end() )
  202. {
  203. blendDest = iter->value;
  204. mPrevSources->erase( iter );
  205. }
  206. }
  207. // Get some stuff we'll need for finding the emitters.
  208. F32 treeHeight = info.scale * info.dataBlock->getObjBox().len_z();
  209. Point3F top = info.pos;
  210. top.z += treeHeight;
  211. if ( blendDest )
  212. top += ( 1.0f / info.scale ) * blendDest->getDirection();
  213. // Go thru the emitters to accumulate the total wind force.
  214. VectorF windForce( 0, 0, 0 );
  215. F32 time = Sim::getCurrentTime() / 1000.0f;
  216. ForestWindEmitterList::iterator iter = mEmitters.begin();
  217. for ( ; iter != mEmitters.end(); iter++ )
  218. {
  219. ForestWindEmitter *emitter = (*iter);
  220. // If disabled or no wind object... skip it.
  221. if ( !emitter->isEnabled() || !emitter->getWind() )
  222. continue;
  223. ForestWind *wind = emitter->getWind();
  224. F32 strength = wind->getStrength();
  225. if ( emitter->isRadialEmitter() )
  226. {
  227. Point3F closest = MathUtils::mClosestPointOnSegment( info.pos, top, emitter->getPosition() );
  228. Point3F dir = closest - emitter->getPosition();
  229. F32 lenSquared = dir.lenSquared();
  230. if ( lenSquared > emitter->getWindRadiusSquared() )
  231. continue;
  232. dir *= 1.0f / mSqrt( lenSquared );
  233. F32 att = lenSquared / emitter->getWindRadiusSquared();
  234. strength *= 1.0f - att;
  235. windForce += dir * strength;
  236. }
  237. else
  238. {
  239. F32 d = mDot( info.pos, Point3F::One ); //PlaneF( Point3F::Zero, wind->getDirection() ).distToPlane( Point3F( info.pos.x, info.pos.y, 0 ) );
  240. //F32 d = PlaneF( Point3F::Zero, wind->getDirection() ).distToPlane( Point3F( info.pos.x, info.pos.y, 0 ) );
  241. F32 scale = 1.0f + ( mSin( d + ( time / 10.0 ) ) * 0.5f );
  242. windForce += wind->getDirection() * strength * scale;
  243. }
  244. }
  245. // If we need a accumulator then we also need to presimulate.
  246. if ( !blendDest )
  247. {
  248. blendDest = new ForestWindAccumulator( info );
  249. blendDest->presimulate( windForce, 4.0f / TickSec );
  250. }
  251. else
  252. blendDest->updateWind( windForce, timeDelta );
  253. mSources->insertUnique( info.itemKey, blendDest );
  254. }