timeOfDay.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745
  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 "environment/timeOfDay.h"
  24. #include "console/consoleTypes.h"
  25. #include "core/stream/bitStream.h"
  26. #include "T3D/gameBase/gameConnection.h"
  27. #include "environment/sun.h"
  28. #include "console/engineAPI.h"
  29. TimeOfDayUpdateSignal TimeOfDay::smTimeOfDayUpdateSignal;
  30. IMPLEMENT_CO_NETOBJECT_V1(TimeOfDay);
  31. ConsoleDocClass( TimeOfDay,
  32. "@brief Environmental object that triggers a day/night cycle in level.\n\n"
  33. "@note TimeOfDay only works in Advanced Lighting with a Sub object or ScatterSky\n\n"
  34. "@tsexample\n"
  35. "new TimeOfDay(tod)\n"
  36. "{\n"
  37. " axisTilt = \"23.44\";\n"
  38. " dayLength = \"120\";\n"
  39. " startTime = \"0.15\";\n"
  40. " time = \"0.15\";\n"
  41. " play = \"0\";\n"
  42. " azimuthOverride = \"572.958\";\n"
  43. " dayScale = \"1\";\n"
  44. " nightScale = \"1.5\";\n"
  45. " position = \"598.399 550.652 196.297\";\n"
  46. " rotation = \"1 0 0 0\";\n"
  47. " scale = \"1 1 1\";\n"
  48. " canSave = \"1\";\n"
  49. " canSaveDynamicFields = \"1\";\n"
  50. "};\n"
  51. "@endtsexample\n\n"
  52. "@ingroup enviroMisc"
  53. );
  54. TimeOfDay::TimeOfDay()
  55. : mStartTimeOfDay( 0.5f ), // High noon
  56. mDayLen( 120.0f ), // 2 minutes
  57. mAxisTilt( 23.44f ), // 35 degree tilt
  58. mAzimuth( 0.0f ),
  59. mElevation( 0.0f ),
  60. mTimeOfDay( 0.0f ), // initialized to StartTimeOfDay in onAdd
  61. mDayScale( 1.0f ),
  62. mPlay( true ),
  63. mNightScale( 1.5f ),
  64. mAnimateTime( 0.0f ),
  65. mAnimateSpeed( 0.0f ),
  66. mAnimate( false )
  67. {
  68. mNetFlags.set( Ghostable | ScopeAlways );
  69. mTypeMask = EnvironmentObjectType;
  70. // Sets the sun vector directly overhead for lightmap generation
  71. // The value of mSunVector is grabbed by the terrain lighting stuff.
  72. /*
  73. F32 ele, azi;
  74. ele = azi = TORADIANS(90);
  75. MathUtils::getVectorFromAngles(mSunVector, azi, ele);
  76. */
  77. mPrevElevation = 0;
  78. mNextElevation = 0;
  79. mAzimuthOverride = 1.0f;
  80. _initColors();
  81. }
  82. TimeOfDay::~TimeOfDay()
  83. {
  84. }
  85. bool TimeOfDay::setTimeOfDay( void *object, const char *index, const char *data )
  86. {
  87. TimeOfDay *tod = static_cast<TimeOfDay*>(object);
  88. tod->setTimeOfDay( dAtof( data ) );
  89. return false;
  90. }
  91. bool TimeOfDay::setPlay( void *object, const char *index, const char *data )
  92. {
  93. TimeOfDay *tod = static_cast<TimeOfDay*>(object);
  94. tod->setPlay( dAtob( data ) );
  95. return false;
  96. }
  97. bool TimeOfDay::setDayLength( void *object, const char *index, const char *data )
  98. {
  99. TimeOfDay *tod = static_cast<TimeOfDay*>(object);
  100. F32 length = dAtof( data );
  101. if( length != 0 )
  102. tod->setDayLength( length );
  103. return false;
  104. }
  105. void TimeOfDay::initPersistFields()
  106. {
  107. addGroup( "TimeOfDay" );
  108. addField( "axisTilt", TypeF32, Offset( mAxisTilt, TimeOfDay ),
  109. "The angle in degrees between global equator and tropic." );
  110. addProtectedField( "dayLength", TypeF32, Offset( mDayLen, TimeOfDay ), &setDayLength, &defaultProtectedGetFn,
  111. "The length of a virtual day in real world seconds." );
  112. addField( "startTime", TypeF32, Offset( mStartTimeOfDay, TimeOfDay ),
  113. "" );
  114. addProtectedField( "time", TypeF32, Offset( mTimeOfDay, TimeOfDay ), &setTimeOfDay, &defaultProtectedGetFn, "Current time of day." );
  115. addProtectedField( "play", TypeBool, Offset( mPlay, TimeOfDay ), &setPlay, &defaultProtectedGetFn, "True when the TimeOfDay object is operating." );
  116. addField( "azimuthOverride", TypeF32, Offset( mAzimuthOverride, TimeOfDay ), "" );
  117. addField( "dayScale", TypeF32, Offset( mDayScale, TimeOfDay ), "Scalar applied to time that elapses while the sun is up." );
  118. addField( "nightScale", TypeF32, Offset( mNightScale, TimeOfDay ), "Scalar applied to time that elapses while the sun is down." );
  119. endGroup( "TimeOfDay" );
  120. Parent::initPersistFields();
  121. }
  122. void TimeOfDay::consoleInit()
  123. {
  124. Parent::consoleInit();
  125. //addVariable( "$TimeOfDay::currentTime", &TimeOfDay::smCurrentTime );
  126. //addVariable( "$TimeOfDay::timeScale", TypeF32, &TimeOfDay::smTimeScale );
  127. }
  128. void TimeOfDay::inspectPostApply()
  129. {
  130. _updatePosition();
  131. setMaskBits( OrbitMask );
  132. }
  133. void TimeOfDay::_onGhostAlwaysDone()
  134. {
  135. _updatePosition();
  136. }
  137. bool TimeOfDay::onAdd()
  138. {
  139. if ( !Parent::onAdd() )
  140. return false;
  141. // The server initializes to the specified starting values.
  142. // The client initializes itself to the server time from
  143. // unpackUpdate.
  144. if ( isServerObject() )
  145. {
  146. mTimeOfDay = mStartTimeOfDay;
  147. _updatePosition();
  148. }
  149. // We don't use a bounds.
  150. setGlobalBounds();
  151. resetWorldBox();
  152. addToScene();
  153. // Lets receive ghost events so we can resolve
  154. // the sun object.
  155. if ( isClientObject() )
  156. NetConnection::smGhostAlwaysDone.notify( this, &TimeOfDay::_onGhostAlwaysDone );
  157. if ( isServerObject() )
  158. Con::executef( this, "onAdd" );
  159. setProcessTick( true );
  160. return true;
  161. }
  162. void TimeOfDay::onRemove()
  163. {
  164. if ( isClientObject() )
  165. NetConnection::smGhostAlwaysDone.remove( this, &TimeOfDay::_onGhostAlwaysDone );
  166. removeFromScene();
  167. Parent::onRemove();
  168. }
  169. U32 TimeOfDay::packUpdate(NetConnection *conn, U32 mask, BitStream *stream )
  170. {
  171. U32 retMask = Parent::packUpdate( conn, mask, stream );
  172. if ( stream->writeFlag( mask & OrbitMask ) )
  173. {
  174. stream->write( mStartTimeOfDay );
  175. stream->write( mDayLen );
  176. stream->write( mTimeOfDay );
  177. stream->write( mAxisTilt );
  178. stream->write( mAzimuthOverride );
  179. stream->write( mDayScale );
  180. stream->write( mNightScale );
  181. stream->writeFlag( mPlay );
  182. }
  183. if ( stream->writeFlag( mask & AnimateMask ) )
  184. {
  185. stream->write( mAnimateTime );
  186. stream->write( mAnimateSpeed );
  187. }
  188. return retMask;
  189. }
  190. void TimeOfDay::unpackUpdate( NetConnection *conn, BitStream *stream )
  191. {
  192. Parent::unpackUpdate( conn, stream );
  193. if ( stream->readFlag() ) // OrbitMask
  194. {
  195. stream->read( &mStartTimeOfDay );
  196. stream->read( &mDayLen );
  197. stream->read( &mTimeOfDay );
  198. stream->read( &mAxisTilt );
  199. stream->read( &mAzimuthOverride );
  200. stream->read( &mDayScale );
  201. stream->read( &mNightScale );
  202. mPlay = stream->readFlag();
  203. _updatePosition();
  204. }
  205. if ( stream->readFlag() ) // AnimateMask
  206. {
  207. F32 time, speed;
  208. stream->read( &time );
  209. stream->read( &speed );
  210. if( isProperlyAdded() )
  211. animate( time, speed );
  212. }
  213. }
  214. void TimeOfDay::processTick( const Move *move )
  215. {
  216. if ( mAnimate )
  217. {
  218. F32 current = mTimeOfDay * 360.0f;
  219. F32 next = current + (mAnimateSpeed * TickSec);
  220. // Protect for wrap around.
  221. while ( next > 360.0f )
  222. next -= 360.0f;
  223. // Clamp to make sure we don't pass the target time.
  224. if ( next >= mAnimateTime )
  225. {
  226. next = mAnimateTime;
  227. mAnimate = false;
  228. }
  229. // Set the new time of day.
  230. mTimeOfDay = next / 360.0f;
  231. _updatePosition();
  232. _updateTimeEvents();
  233. if ( !mAnimate && isServerObject() )
  234. Con::executef( this, "onAnimateDone" );
  235. }
  236. else if ( mPlay )
  237. {
  238. F32 dt = TickSec;
  239. F32 current = mRadToDeg( mNextElevation );
  240. if ( current > 350.0f || ( 0.0f <= current && current < 190.0f ) )
  241. dt *= mDayScale;
  242. else
  243. dt *= mNightScale;
  244. mTimeOfDay += dt / mDayLen;
  245. // It could be possible for more than a full day to
  246. // pass in a single advance time, so I put this inside a loop
  247. // but timeEvents will not actually be called for the
  248. // skipped day.
  249. while ( mTimeOfDay > 1.0f )
  250. mTimeOfDay -= 1.0f;
  251. _updatePosition();
  252. _updateTimeEvents();
  253. }
  254. else
  255. _updatePosition();
  256. }
  257. void TimeOfDay::_updatePosition()
  258. {
  259. mPrevElevation = mNextElevation;
  260. if ( mFabs( mAzimuthOverride ) )
  261. {
  262. mElevation = mDegToRad( mTimeOfDay * 360.0f );
  263. mAzimuth = mAzimuthOverride;
  264. mNextElevation = mElevation; // already normalized
  265. }
  266. else
  267. {
  268. //// Full azimuth/elevation calculation.
  269. //// calculate sun decline and meridian angle (in radians)
  270. //F32 sunDecline = mSin( M_2PI * mTimeOfYear ) * mDegToRad( mAxisTilt );
  271. //F32 meridianAngle = mTimeOfDay * M_2PI - mDegToRad( mLongitude );
  272. //// calculate the elevation and azimuth (in radians)
  273. //mElevation = _calcElevation( mDegToRad( mLatitude ), sunDecline, meridianAngle );
  274. //mAzimuth = _calcAzimuth( mDegToRad( mLatitude ), sunDecline, meridianAngle );
  275. // Simplified azimuth/elevation calculation.
  276. // calculate sun decline and meridian angle (in radians)
  277. F32 sunDecline = mDegToRad( mAxisTilt );
  278. F32 meridianAngle = mTimeOfDay * M_2PI;
  279. // calculate the elevation and azimuth (in radians)
  280. mElevation = _calcElevation( 0.0f, sunDecline, meridianAngle );
  281. mAzimuth = _calcAzimuth( 0.0f, sunDecline, meridianAngle );
  282. // calculate 'normalized' elevation (0=sunrise, PI/2=zenith, PI=sunset, 3PI/4=nadir)
  283. F32 normElevation = M_PI_F * mElevation / ( 2 * _calcElevation( 0.0f, sunDecline, 0.0f ) );
  284. if ( mAzimuth > M_PI_F )
  285. normElevation = M_PI_F - normElevation;
  286. else if ( mElevation < 0 )
  287. normElevation = M_2PI_F + normElevation;
  288. mNextElevation = normElevation;
  289. }
  290. // Only the client updates the sun position!
  291. if ( isClientObject() )
  292. smTimeOfDayUpdateSignal.trigger( this, mTimeOfDay );
  293. }
  294. F32 TimeOfDay::_calcElevation( F32 lat, F32 dec, F32 mer )
  295. {
  296. return mAsin( mSin(lat) * mSin(dec) + mCos(lat) * mCos(dec) * mCos(mer) );
  297. }
  298. F32 TimeOfDay::_calcAzimuth( F32 lat, F32 dec, F32 mer )
  299. {
  300. // Add PI to normalize this from the range of -PI/2 to PI/2 to 0 to 2 * PI;
  301. return mAtan2( mSin(mer), mCos(mer) * mSin(lat) - mTan(dec) * mCos(lat) ) + M_PI_F;
  302. }
  303. void TimeOfDay::_getSunColor( LinearColorF *outColor ) const
  304. {
  305. const COLOR_TARGET *ct = NULL;
  306. F32 ele = mClampF( M_2PI_F - mNextElevation, 0.0f, M_PI_F );
  307. F32 phase = -1.0f;
  308. F32 div;
  309. if (!mColorTargets.size())
  310. {
  311. outColor->set(1.0f,1.0f,1.0f);
  312. return;
  313. }
  314. if (mColorTargets.size() == 1)
  315. {
  316. ct = &mColorTargets[0];
  317. outColor->set(ct->color.red, ct->color.green, ct->color.blue);
  318. return;
  319. }
  320. //simple check
  321. if ( mColorTargets[0].elevation != 0.0f )
  322. {
  323. AssertFatal(0, "TimeOfDay::GetColor() - First elevation must be 0.0 radians");
  324. outColor->set(1.0f, 1.0f, 1.0f);
  325. //mBandMod = 1.0f;
  326. //mCurrentBandColor = color;
  327. return;
  328. }
  329. if ( mColorTargets[mColorTargets.size()-1].elevation != M_PI_F )
  330. {
  331. AssertFatal(0, "Celestails::GetColor() - Last elevation must be PI");
  332. outColor->set(1.0f, 1.0f, 1.0f);
  333. //mBandMod = 1.0f;
  334. //mCurrentBandColor = color;
  335. return;
  336. }
  337. //we need to find the phase and interp... also loop back around
  338. U32 count=0;
  339. for (;count < mColorTargets.size() - 1; count++)
  340. {
  341. const COLOR_TARGET *one = &mColorTargets[count];
  342. const COLOR_TARGET *two = &mColorTargets[count+1];
  343. if (ele >= one->elevation && ele <= two->elevation)
  344. {
  345. div = two->elevation - one->elevation;
  346. //catch bad input divide by zero
  347. if ( mFabs( div ) < 0.01f )
  348. div = 0.01f;
  349. phase = (ele - one->elevation) / div;
  350. outColor->interpolate( one->color, two->color, phase );
  351. //mCurrentBandColor.interpolate(one->bandColor, two->bandColor, phase);
  352. //mBandMod = one->bandMod * (1.0f - phase) + two->bandMod * phase;
  353. return;
  354. }
  355. }
  356. AssertFatal(0,"This isn't supposed to happen");
  357. }
  358. void TimeOfDay::_initColors()
  359. {
  360. // NOTE: The elevation targets represent distances
  361. // from PI/2 radians (strait up).
  362. LinearColorF c;
  363. LinearColorF bc;
  364. // e is for elevation
  365. F32 e = M_PI_F / 13.0f; // (semicircle in radians)/(number of color target entries);
  366. // Day
  367. c.set(1.0f,1.0f,1.0f);
  368. _addColorTarget(0, c, 1.0f, c); // High noon at equanox
  369. c.set(.9f,.9f,.9f);
  370. _addColorTarget(e * 1.0f, c, 1.0f, c);
  371. c.set(.9f,.9f,.9f);
  372. _addColorTarget(e * 2.0f, c, 1.0f, c);
  373. c.set(.8f,.75f,.75f);
  374. _addColorTarget(e * 3.0f, c, 1.0f, c);
  375. c.set(.7f,.65f,.65f);
  376. _addColorTarget(e * 4.0f, c, 1.0f, c);
  377. //Dawn and Dusk (3 entries)
  378. c.set(.7f,.65f,.65f);
  379. bc.set(.8f,.6f,.3f);
  380. _addColorTarget(e * 5.0f, c, 3.0f, bc);
  381. c.set(.65f,.54f,.4f);
  382. bc.set(.75f,.5f,.4f);
  383. _addColorTarget(e * 6.0f, c, 2.75f, bc);
  384. c.set(.55f,.45f,.25f);
  385. bc.set(.65f,.3f,.3f);
  386. _addColorTarget(e * 7.0f, c, 2.5f, bc);
  387. //NIGHT
  388. c.set(.3f,.3f,.3f);
  389. bc.set(.7f,.4f,.2f);
  390. _addColorTarget(e * 8.0f, c, 1.25f, bc);
  391. c.set(.25f,.25f,.3f);
  392. bc.set(.8f,.3f,.2f);
  393. _addColorTarget(e * 9.0f, c, 1.00f, bc);
  394. c.set(.25f,.25f,.4f);
  395. _addColorTarget(e * 10.0f, c, 1.0f, c);
  396. c.set(.2f,.2f,.35f);
  397. _addColorTarget(e * 11.0f, c, 1.0f, c);
  398. c.set(.15f,.15f,.2f);
  399. _addColorTarget(M_PI_F, c, 1.0f, c); // Midnight at equanox.
  400. }
  401. void TimeOfDay::_addColorTarget( F32 ele, const LinearColorF &color, F32 bandMod, const LinearColorF &bandColor )
  402. {
  403. COLOR_TARGET newTarget;
  404. newTarget.elevation = ele;
  405. newTarget.color = color;
  406. newTarget.bandMod = bandMod;
  407. newTarget.bandColor = bandColor;
  408. mColorTargets.push_back(newTarget);
  409. }
  410. void TimeOfDay::_updateTimeEvents()
  411. {
  412. if ( mTimeEvents.empty() )
  413. return;
  414. // Get the prev, next elevation in degrees since TimeOfDayEvent is specified
  415. // in degrees.
  416. F32 prevElevation = mRadToDeg( mPrevElevation );
  417. F32 nextElevation = mRadToDeg( mNextElevation );
  418. // If prevElevation is less than nextElevation then its the next day.
  419. // Unroll it so we can just loop forward in time and simplify our loop.
  420. if ( nextElevation < prevElevation )
  421. nextElevation += 360.0f;
  422. const U32 evtCount = mTimeEvents.size();
  423. // Find where in the event list we need to start...
  424. // The first timeEvent with elevation greater than our previous elevation.
  425. U32 start = 0;
  426. for ( ; start < evtCount; start++ )
  427. {
  428. if ( mTimeEvents[start].triggerElevation > prevElevation )
  429. break;
  430. }
  431. bool onNextDay = false;
  432. // Nothing between prevElevation and the end of the day...
  433. // Check between start of the day and nextElevation...
  434. if ( start == evtCount )
  435. {
  436. start = 0;
  437. for ( ; start < evtCount; start++ )
  438. {
  439. if ( mTimeEvents[start].triggerElevation <= nextElevation )
  440. {
  441. onNextDay = true;
  442. break;
  443. }
  444. }
  445. }
  446. // No events were hit...
  447. if ( start == evtCount )
  448. return;
  449. U32 itr = start;
  450. while ( true )
  451. {
  452. TimeOfDayEvent &timeEvent = mTimeEvents[itr];
  453. F32 elev = timeEvent.triggerElevation;
  454. if ( onNextDay )
  455. elev += 360.0f;
  456. // Hit an event that happens later after nextElevation so we
  457. // have checked everything within the range and are done.
  458. if ( elev > nextElevation )
  459. break;
  460. // If its not greater than the nextElevation it must be less, and if
  461. // we are here we already know its greater than prevElevation.
  462. AssertFatal( elev >= prevElevation && elev <= nextElevation, "TimeOfDay::_updateTimeEvents - Logical error in here!" );
  463. AssertFatal( !timeEvent.deleteMe, "TimeOfDay::_updateTimeEvents - tried to fire the same event twice!" );
  464. _onTimeEvent( timeEvent.identifier );
  465. if ( timeEvent.oneShot )
  466. timeEvent.deleteMe = true;
  467. // On to the next time event...
  468. itr++;
  469. // We hit the end of the day?
  470. if ( itr == evtCount )
  471. {
  472. // We are already on the next day so we have checked everything.
  473. if ( onNextDay )
  474. break;
  475. // Check events for the next day
  476. else
  477. {
  478. itr = 0;
  479. onNextDay = true;
  480. }
  481. }
  482. }
  483. // Cleanup one-shot events that fired...
  484. for ( S32 i = 0; i < mTimeEvents.size(); i++ )
  485. {
  486. if ( mTimeEvents[i].deleteMe )
  487. {
  488. // Don't use erase_fast, there are ordered.
  489. mTimeEvents.erase( i );
  490. i--;
  491. }
  492. }
  493. }
  494. void TimeOfDay::addTimeEvent( F32 triggerElevation, const UTF8 *identifier )
  495. {
  496. // Insert in ascending order of elevation.
  497. // Note that having more than one TimeEvent with the same triggerElevation
  498. // may cause undefined behavior.
  499. TimeOfDayEvent *pEvent = NULL;
  500. if ( mTimeEvents.empty() || mTimeEvents.last().triggerElevation <= triggerElevation )
  501. {
  502. mTimeEvents.increment();
  503. pEvent = &mTimeEvents.last();
  504. }
  505. else
  506. {
  507. for ( S32 i = 0; i < mTimeEvents.size(); i++ )
  508. {
  509. if ( mTimeEvents[i].triggerElevation > triggerElevation )
  510. {
  511. mTimeEvents.insert( i );
  512. pEvent = &mTimeEvents[i];
  513. break;
  514. }
  515. }
  516. }
  517. AssertFatal( pEvent, "TimeOfDay::addTimeEvent - could not find place to insert event." );
  518. pEvent->triggerElevation = triggerElevation;
  519. pEvent->identifier = identifier;
  520. pEvent->oneShot = false;
  521. pEvent->deleteMe = false;
  522. }
  523. void TimeOfDay::setTimeOfDay( F32 time )
  524. {
  525. mTimeOfDay = time;
  526. while ( mTimeOfDay > 1.0f )
  527. mTimeOfDay -= 1.0f;
  528. while ( mTimeOfDay < 0.0f )
  529. mTimeOfDay += 1.0f;
  530. _updatePosition();
  531. //if ( isServerObject() )
  532. _updateTimeEvents();
  533. setMaskBits( OrbitMask );
  534. }
  535. void TimeOfDay::_onTimeEvent( const String &identifier )
  536. {
  537. // Client doesn't do onTimeEvent callbacks.
  538. if ( isClientObject() )
  539. return;
  540. String strCurrentTime = String::ToString( "%g", mTimeOfDay );
  541. F32 elevation = mRadToDeg( mNextElevation );
  542. while( elevation < 0 )
  543. elevation += 360.0f;
  544. while( elevation > 360.0f )
  545. elevation -= 360.0f;
  546. String strCurrentElevation = String::ToString( "%g", elevation );
  547. Con::executef( this, "onTimeEvent", identifier.c_str(), strCurrentTime.c_str(), strCurrentElevation.c_str() );
  548. }
  549. void TimeOfDay::animate( F32 time, F32 speed )
  550. {
  551. // Stop any existing animation... this one
  552. // becomes the new one.
  553. mAnimate = false;
  554. // Set the target time to hit.
  555. mAnimateTime = mClamp(time, 0.0f, 360.0f);
  556. F32 current = mTimeOfDay * 360.0f;
  557. F32 target = mAnimateTime;
  558. if ( target < current )
  559. target += 360.0f;
  560. // If we're already at the current time then
  561. // we have nothing more to do... the animation is here.
  562. F32 dif = target - current;
  563. if ( mIsZero( dif ) )
  564. return;
  565. // Start playback.
  566. mAnimateSpeed = speed;
  567. mAnimate = true;
  568. if ( isServerObject() )
  569. {
  570. Con::executef( this, "onAnimateStart" );
  571. setMaskBits( AnimateMask );
  572. }
  573. }
  574. DefineEngineMethod( TimeOfDay, addTimeOfDayEvent, void, (F32 elevation, const char *identifier ),,
  575. "" )
  576. {
  577. object->addTimeEvent( elevation, identifier );
  578. }
  579. DefineEngineMethod( TimeOfDay, setTimeOfDay, void, ( F32 time ),,
  580. "" )
  581. {
  582. object->setTimeOfDay( time );
  583. }
  584. DefineEngineMethod( TimeOfDay, setPlay, void, ( bool enabled ),,
  585. "")
  586. {
  587. object->setPlay( enabled );
  588. }
  589. DefineEngineMethod( TimeOfDay, setDayLength, void, ( F32 seconds ),,
  590. "" )
  591. {
  592. if ( seconds > 0.0f )
  593. object->setDayLength( seconds );
  594. }
  595. DefineEngineMethod( TimeOfDay, animate, void, ( F32 elevation, F32 degreesPerSecond ),,
  596. "")
  597. {
  598. object->animate( elevation, degreesPerSecond );
  599. }