splash.cpp

Engine/source/T3D/fx/splash.cpp

More...

Public Functions

ConsoleDocClass(Splash , "@brief Manages the ring used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> a <a href="/coding/class/classsplash/">Splash</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effect.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" )
ConsoleDocClass(SplashData , "@brief Acts as the physical point in space in white a <a href="/coding/class/classsplash/">Splash</a> is created <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">from.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" )

Detailed Description

Public Functions

ConsoleDocClass(Splash , "@brief Manages the ring used <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> a <a href="/coding/class/classsplash/">Splash</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">effect.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" )

ConsoleDocClass(SplashData , "@brief Acts as the physical point in space in white a <a href="/coding/class/classsplash/">Splash</a> is created <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">from.\n</a>" "@ingroup <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">FX\n</a>" )

IMPLEMENT_CO_DATABLOCK_V1(SplashData )

IMPLEMENT_CO_NETOBJECT_V1(Splash )

  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 "T3D/fx/splash.h"
 25
 26#include "console/consoleTypes.h"
 27#include "gfx/primBuilder.h"
 28#include "gfx/gfxDrawUtil.h"
 29#include "sfx/sfxSystem.h"
 30#include "sfx/sfxProfile.h"
 31#include "scene/sceneManager.h"
 32#include "scene/sceneRenderState.h"
 33#include "core/stream/bitStream.h"
 34#include "math/mathIO.h"
 35#include "T3D/fx/explosion.h"
 36#include "T3D/fx/particle.h"
 37#include "T3D/fx/particleEmitter.h"
 38#include "T3D/fx/particleEmitterNode.h"
 39#include "T3D/gameBase/gameProcess.h"
 40#include "sim/netConnection.h"
 41#include "renderInstance/renderPassManager.h"
 42#include "console/engineAPI.h"
 43
 44namespace
 45{
 46
 47MRandomLCG sgRandom(0xdeadbeef);
 48
 49} // namespace {}
 50
 51//----------------------------------------------------------------------------
 52
 53IMPLEMENT_CO_DATABLOCK_V1(SplashData);
 54IMPLEMENT_CO_NETOBJECT_V1(Splash);
 55
 56ConsoleDocClass( SplashData,
 57   "@brief Acts as the physical point in space in white a Splash is created from.\n"
 58   "@ingroup FX\n"
 59);
 60
 61ConsoleDocClass( Splash,
 62   "@brief Manages the ring used for a Splash effect.\n"
 63   "@ingroup FX\n"
 64);
 65
 66//--------------------------------------------------------------------------
 67// Splash Data
 68//--------------------------------------------------------------------------
 69SplashData::SplashData()
 70{
 71   soundProfile      = NULL;
 72   soundProfileId    = 0;
 73
 74   scale.set(1, 1, 1);
 75
 76   dMemset( emitterList, 0, sizeof( emitterList ) );
 77   dMemset( emitterIDList, 0, sizeof( emitterIDList ) );
 78
 79   delayMS = 0;
 80   delayVariance = 0;
 81   lifetimeMS = 1000;
 82   lifetimeVariance = 0;
 83   width = 4.0;
 84   numSegments = 10;
 85   velocity = 5.0;
 86   height = 0.0;
 87   acceleration = 0.0;
 88   texWrap = 1.0;
 89   texFactor = 3.0;
 90   ejectionFreq = 5;
 91   ejectionAngle = 45.0;
 92   ringLifetime = 1.0;
 93   startRadius = 0.5;
 94   explosion = NULL;
 95   explosionId = 0;
 96
 97   dMemset( textureName, 0, sizeof( textureName ) );
 98
 99   U32 i;
100   for( i=0; i<NUM_TIME_KEYS; i++ )
101      times[i] = 1.0;
102
103   times[0] = 0.0;
104
105   for( i=0; i<NUM_TIME_KEYS; i++ )
106      colors[i].set( 1.0, 1.0, 1.0, 1.0 );
107
108}
109
110//--------------------------------------------------------------------------
111// Init fields
112//--------------------------------------------------------------------------
113   void SplashData::initPersistFields()
114{
115   addField("soundProfile",      TYPEID< SFXProfile >(),       Offset(soundProfile,       SplashData), "SFXProfile effect to play.\n");
116   addField("scale",             TypePoint3F,                  Offset(scale,              SplashData), "The scale of this splashing effect, defined as the F32 points X, Y, Z.\n");
117   addField("emitter",           TYPEID< ParticleEmitterData >(),   Offset(emitterList,        SplashData), NUM_EMITTERS, "List of particle emitters to create at the point of this Splash effect.\n");
118   addField("delayMS",           TypeS32,                      Offset(delayMS,            SplashData), "Time to delay, in milliseconds, before actually starting this effect.\n");
119   addField("delayVariance",     TypeS32,                      Offset(delayVariance,      SplashData), "Time variance for delayMS.\n");
120   addField("lifetimeMS",        TypeS32,                      Offset(lifetimeMS,         SplashData), "Lifetime for this effect, in milliseconds.\n");
121   addField("lifetimeVariance",  TypeS32,                      Offset(lifetimeVariance,   SplashData), "Time variance for lifetimeMS.\n");
122   addField("width",             TypeF32,                      Offset(width,              SplashData), "Width for the X and Y coordinates to create this effect within.");
123   addField("numSegments",       TypeS32,                      Offset(numSegments,        SplashData), "Number of ejection points in the splash ring.\n");
124   addField("velocity",          TypeF32,                      Offset(velocity,           SplashData), "Velocity for the splash effect to travel.\n");
125   addField("height",            TypeF32,                      Offset(height,             SplashData), "Height for the splash to reach.\n");
126   addField("acceleration",      TypeF32,                      Offset(acceleration,       SplashData), "Constant acceleration value to place upon the splash effect.\n");
127   addField("times",             TypeF32,                      Offset(times,              SplashData), NUM_TIME_KEYS, "Times to transition through the splash effect. Up to 4 allowed. Values are 0.0 - 1.0, and corrispond to the life of the particle where 0 is first created and 1 is end of lifespace.\n" );
128   addField("colors",            TypeColorF,                   Offset(colors,             SplashData), NUM_TIME_KEYS, "Color values to set the splash effect, rgba. Up to 4 allowed. Will transition through colors based on values set in the times value. Example: colors[0] = \"0.6 1.0 1.0 0.5\".\n" );
129   addField("texture",           TypeFilename,                 Offset(textureName,        SplashData), NUM_TEX, "Imagemap file to use as the texture for the splash effect.\n");
130   addField("texWrap",           TypeF32,                      Offset(texWrap,            SplashData), "Amount to wrap the texture around the splash ring, 0.0f - 1.0f.\n");
131   addField("texFactor",         TypeF32,                      Offset(texFactor,          SplashData), "Factor in which to apply the texture to the splash ring, 0.0f - 1.0f.\n");
132   addField("ejectionFreq",      TypeF32,                      Offset(ejectionFreq,       SplashData), "Frequency in which to emit splash rings.\n");
133   addField("ejectionAngle",     TypeF32,                      Offset(ejectionAngle,      SplashData), "Rotational angle to create a splash ring.\n");
134   addField("ringLifetime",      TypeF32,                      Offset(ringLifetime,       SplashData), "Lifetime, in milliseconds, for a splash ring.\n");
135   addField("startRadius",       TypeF32,                      Offset(startRadius,        SplashData), "Starting radius size of a splash ring.\n");
136   addField("explosion",         TYPEID< ExplosionData >(),    Offset(explosion,          SplashData), "ExplosionData object to create at the creation position of this splash effect.\n");
137
138   Parent::initPersistFields();
139}
140
141//--------------------------------------------------------------------------
142// On add - verify data settings
143//--------------------------------------------------------------------------
144bool SplashData::onAdd()
145{
146   if (Parent::onAdd() == false)
147      return false;
148
149   return true;
150}
151
152//--------------------------------------------------------------------------
153// Pack data
154//--------------------------------------------------------------------------
155void SplashData::packData(BitStream* stream)
156{
157   Parent::packData(stream);
158
159   mathWrite(*stream, scale);
160   stream->write(delayMS);
161   stream->write(delayVariance);
162   stream->write(lifetimeMS);
163   stream->write(lifetimeVariance);
164   stream->write(width);
165   stream->write(numSegments);
166   stream->write(velocity);
167   stream->write(height);
168   stream->write(acceleration);
169   stream->write(texWrap);
170   stream->write(texFactor);
171   stream->write(ejectionFreq);
172   stream->write(ejectionAngle);
173   stream->write(ringLifetime);
174   stream->write(startRadius);
175
176   if( stream->writeFlag( explosion ) )
177   {
178      stream->writeRangedU32(explosion->getId(), DataBlockObjectIdFirst, DataBlockObjectIdLast);
179   }
180
181   S32 i;
182   for( i=0; i<NUM_EMITTERS; i++ )
183   {
184      if( stream->writeFlag( emitterList[i] != NULL ) )
185      {
186         stream->writeRangedU32( emitterList[i]->getId(), DataBlockObjectIdFirst,  DataBlockObjectIdLast );
187      }
188   }
189
190   for( i=0; i<NUM_TIME_KEYS; i++ )
191   {
192      stream->write( colors[i] );
193   }
194
195   for( i=0; i<NUM_TIME_KEYS; i++ )
196   {
197      stream->write( times[i] );
198   }
199
200   for( i=0; i<NUM_TEX; i++ )
201   {
202      stream->writeString(textureName[i]);
203   }
204}
205
206//--------------------------------------------------------------------------
207// Unpack data
208//--------------------------------------------------------------------------
209void SplashData::unpackData(BitStream* stream)
210{
211   Parent::unpackData(stream);
212
213   mathRead(*stream, &scale);
214   stream->read(&delayMS);
215   stream->read(&delayVariance);
216   stream->read(&lifetimeMS);
217   stream->read(&lifetimeVariance);
218   stream->read(&width);
219   stream->read(&numSegments);
220   stream->read(&velocity);
221   stream->read(&height);
222   stream->read(&acceleration);
223   stream->read(&texWrap);
224   stream->read(&texFactor);
225   stream->read(&ejectionFreq);
226   stream->read(&ejectionAngle);
227   stream->read(&ringLifetime);
228   stream->read(&startRadius);
229
230   if( stream->readFlag() )
231   {
232      explosionId = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
233   }
234
235   U32 i;
236   for( i=0; i<NUM_EMITTERS; i++ )
237   {
238      if( stream->readFlag() )
239      {
240         emitterIDList[i] = stream->readRangedU32( DataBlockObjectIdFirst, DataBlockObjectIdLast );
241      }
242   }
243
244   for( i=0; i<NUM_TIME_KEYS; i++ )
245   {
246      stream->read( &colors[i] );
247   }
248
249   for( i=0; i<NUM_TIME_KEYS; i++ )
250   {
251      stream->read( &times[i] );
252   }
253
254   for( i=0; i<NUM_TEX; i++ )
255   {
256      textureName[i] = stream->readSTString();
257   }
258}
259
260//--------------------------------------------------------------------------
261// Preload data - load resources
262//--------------------------------------------------------------------------
263bool SplashData::preload(bool server, String &errorStr)
264{
265   if (Parent::preload(server, errorStr) == false)
266      return false;
267
268   if (!server)
269   {
270      S32 i;
271      for( i=0; i<NUM_EMITTERS; i++ )
272      {
273         if( !emitterList[i] && emitterIDList[i] != 0 )
274         {
275            if( Sim::findObject( emitterIDList[i], emitterList[i] ) == false)
276            {
277               Con::errorf( ConsoleLogEntry::General, "SplashData::onAdd: Invalid packet, bad datablockId(particle emitter): 0x%x", emitterIDList[i] );
278            }
279         }
280      }
281
282      for( i=0; i<NUM_TEX; i++ )
283      {
284         if (textureName[i] && textureName[i][0])
285         {
286            textureHandle[i] = GFXTexHandle(textureName[i], &GFXDefaultStaticDiffuseProfile, avar("%s() - textureHandle[%d] (line %d)", __FUNCTION__, i, __LINE__) );
287         }
288      }
289   }
290
291   if( !explosion && explosionId != 0 )
292   {
293      if( !Sim::findObject(explosionId, explosion) )
294      {
295         Con::errorf(ConsoleLogEntry::General, "SplashData::preload: Invalid packet, bad datablockId(explosion): %d", explosionId);
296      }
297   }
298
299   return true;
300}
301
302
303//--------------------------------------------------------------------------
304// Splash
305//--------------------------------------------------------------------------
306Splash::Splash()
307   : mDataBlock( NULL )
308{
309   dMemset( mEmitterList, 0, sizeof( mEmitterList ) );
310
311   mDelayMS = 0;
312   mCurrMS = 0;
313   mEndingMS = 1000;
314   mActive = false;
315   mRadius = 0.0;
316   mVelocity = 1.0;
317   mHeight = 0.0;
318   mTimeSinceLastRing = 0.0;
319   mDead = false;
320   mElapsedTime = 0.0;
321
322   mInitialNormal.set( 0.0, 0.0, 1.0 );
323
324   // Only allocated client side.
325   mNetFlags.set( IsGhost );
326}
327
328//--------------------------------------------------------------------------
329// Destructor
330//--------------------------------------------------------------------------
331Splash::~Splash()
332{
333}
334
335//--------------------------------------------------------------------------
336// Set initial state
337//--------------------------------------------------------------------------
338void Splash::setInitialState(const Point3F& point, const Point3F& normal, const F32 fade)
339{
340   mInitialPosition = point;
341   mInitialNormal   = normal;
342   mFade            = fade;
343   mFog             = 0.0f;
344}
345
346
347//--------------------------------------------------------------------------
348// OnAdd
349//--------------------------------------------------------------------------
350bool Splash::onAdd()
351{
352   // first check if we have a server connection, if we dont then this is on the server
353   //  and we should exit, then check if the parent fails to add the object
354   NetConnection* conn = NetConnection::getConnectionToServer();
355   if(!conn || !Parent::onAdd())
356      return false;
357
358   if( !mDataBlock )
359   {
360      Con::errorf("Splash::onAdd - Fail - No datablock");
361      return false;
362   }
363
364   mDelayMS = mDataBlock->delayMS + sgRandom.randI( -mDataBlock->delayVariance, mDataBlock->delayVariance );
365   mEndingMS = mDataBlock->lifetimeMS + sgRandom.randI( -mDataBlock->lifetimeVariance, mDataBlock->lifetimeVariance );
366
367   mVelocity = mDataBlock->velocity;
368   mHeight = mDataBlock->height;
369   mTimeSinceLastRing = 1.0 / mDataBlock->ejectionFreq;
370
371   for( U32 i=0; i<SplashData::NUM_EMITTERS; i++ )
372   {
373      if( mDataBlock->emitterList[i] != NULL )
374      {
375         ParticleEmitter * pEmitter = new ParticleEmitter;
376         pEmitter->onNewDataBlock( mDataBlock->emitterList[i], false );
377         if( !pEmitter->registerObject() )
378         {
379            Con::warnf( ConsoleLogEntry::General, "Could not register emitter for particle of class: %s", mDataBlock->getName() );
380            delete pEmitter;
381            pEmitter = NULL;
382         }
383         mEmitterList[i] = pEmitter;
384      }
385   }
386
387   spawnExplosion();
388
389   mObjBox.minExtents = Point3F( -1, -1, -1 );
390   mObjBox.maxExtents = Point3F(  1,  1,  1 );
391   resetWorldBox();
392
393   gClientSceneGraph->addObjectToScene(this);
394
395   removeFromProcessList();
396   ClientProcessList::get()->addObject(this);
397
398   conn->addObject(this);
399
400   return true;
401}
402
403//--------------------------------------------------------------------------
404// OnRemove
405//--------------------------------------------------------------------------
406void Splash::onRemove()
407{
408   for( U32 i=0; i<SplashData::NUM_EMITTERS; i++ )
409   {
410      if( mEmitterList[i] )
411      {
412         mEmitterList[i]->deleteWhenEmpty();
413         mEmitterList[i] = NULL;
414      }
415   }
416
417   ringList.clear();
418
419   removeFromScene();
420
421   Parent::onRemove();
422}
423
424
425//--------------------------------------------------------------------------
426// On New Data Block
427//--------------------------------------------------------------------------
428bool Splash::onNewDataBlock( GameBaseData *dptr, bool reload )
429{
430   mDataBlock = dynamic_cast<SplashData*>(dptr);
431   if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
432      return false;
433
434   scriptOnNewDataBlock();
435   return true;
436}
437
438
439//--------------------------------------------------------------------------
440// Process tick
441//--------------------------------------------------------------------------
442void Splash::processTick(const Move*)
443{
444   mCurrMS += TickMs;
445
446   if( isServerObject() )
447   {
448      if( mCurrMS >= mEndingMS )
449      {
450         mDead = true;
451         if( mCurrMS >= (mEndingMS + mDataBlock->ringLifetime * 1000) )
452         {
453            deleteObject();
454         }
455      }
456   }
457   else
458   {
459      if( mCurrMS >= mEndingMS )
460      {
461         mDead = true;
462      }
463   }
464}
465
466//--------------------------------------------------------------------------
467// Advance time
468//--------------------------------------------------------------------------
469void Splash::advanceTime(F32 dt)
470{
471   if (dt == 0.0)
472      return;
473
474   mElapsedTime += dt;
475
476   updateColor();
477   updateWave( dt );
478   updateEmitters( dt );
479   updateRings( dt );
480
481   if( !mDead )
482   {
483      emitRings( dt );
484   }
485}
486
487//----------------------------------------------------------------------------
488// Update emitters
489//----------------------------------------------------------------------------
490void Splash::updateEmitters( F32 dt )
491{
492   Point3F pos = getPosition();
493
494   for( U32 i=0; i<SplashData::NUM_EMITTERS; i++ )
495   {
496      if( mEmitterList[i] )
497      {
498         mEmitterList[i]->emitParticles( pos, pos, mInitialNormal, Point3F( 0.0, 0.0, 0.0 ), (S32) (dt * 1000) );
499      }
500   }
501
502}
503
504//----------------------------------------------------------------------------
505// Update wave
506//----------------------------------------------------------------------------
507void Splash::updateWave( F32 dt )
508{
509   mVelocity += mDataBlock->acceleration * dt;
510   mRadius += mVelocity * dt;
511
512}
513
514//----------------------------------------------------------------------------
515// Update color
516//----------------------------------------------------------------------------
517void Splash::updateColor()
518{
519   for(SplashRingList::Iterator ring = ringList.begin(); ring != ringList.end(); ++ring)
520   {
521      F32 t = F32(ring->elapsedTime) / F32(ring->lifetime);
522
523      for( U32 i = 1; i < SplashData::NUM_TIME_KEYS; i++ )
524      {
525         if( mDataBlock->times[i] >= t )
526         {
527            F32 firstPart =   t - mDataBlock->times[i-1];
528            F32 total     =   (mDataBlock->times[i] -
529                               mDataBlock->times[i-1]);
530
531            firstPart /= total;
532
533            ring->color.interpolate( mDataBlock->colors[i-1],
534                                     mDataBlock->colors[i],
535                                     firstPart);
536            break;
537         }
538      }
539   }
540}
541
542//----------------------------------------------------------------------------
543// Create ring
544//----------------------------------------------------------------------------
545SplashRing Splash::createRing()
546{
547   SplashRing ring;
548   U32 numPoints = mDataBlock->numSegments + 1;
549
550   Point3F ejectionAxis( 0.0, 0.0, 1.0 );
551
552   Point3F axisx;
553   if (mFabs(ejectionAxis.z) < 0.999f)
554      mCross(ejectionAxis, Point3F(0, 0, 1), &axisx);
555   else
556      mCross(ejectionAxis, Point3F(0, 1, 0), &axisx);
557   axisx.normalize();
558
559   for( U32 i=0; i<numPoints; i++ )
560   {
561      F32 t = F32(i) / F32(numPoints);
562
563      AngAxisF thetaRot( axisx, mDataBlock->ejectionAngle * (M_PI / 180.0));
564      AngAxisF phiRot(   ejectionAxis, t * (M_PI * 2.0));
565
566      Point3F pointAxis = ejectionAxis;
567
568      MatrixF temp;
569      thetaRot.setMatrix(&temp);
570      temp.mulP(pointAxis);
571      phiRot.setMatrix(&temp);
572      temp.mulP(pointAxis);
573
574      Point3F startOffset = axisx;
575      temp.mulV( startOffset );
576      startOffset *= mDataBlock->startRadius;
577
578      SplashRingPoint point;
579      point.position = getPosition() + startOffset;
580      point.velocity = pointAxis * mDataBlock->velocity;
581
582      ring.points.push_back( point );
583   }
584
585   ring.color = mDataBlock->colors[0];
586   ring.lifetime = mDataBlock->ringLifetime;
587   ring.elapsedTime = 0.0;
588   ring.v = mDataBlock->texFactor * mFmod( mElapsedTime, 1.0 );
589
590   return ring;
591}
592
593//----------------------------------------------------------------------------
594// Emit rings
595//----------------------------------------------------------------------------
596void Splash::emitRings( F32 dt )
597{
598   mTimeSinceLastRing += dt;
599
600   S32 numNewRings = (S32) (mTimeSinceLastRing * F32(mDataBlock->ejectionFreq));
601
602   mTimeSinceLastRing -= numNewRings / mDataBlock->ejectionFreq;
603
604   for( S32 i=numNewRings-1; i>=0; i-- )
605   {
606      F32 t = F32(i) / F32(numNewRings);
607      t *= dt;
608      t += mTimeSinceLastRing;
609
610      SplashRing ring = createRing();
611      updateRing( ring, t );
612
613      ringList.pushBack( ring );
614   }
615}
616
617//----------------------------------------------------------------------------
618// Update rings
619//----------------------------------------------------------------------------
620void Splash::updateRings( F32 dt )
621{
622   SplashRingList::Iterator ring;
623   for(SplashRingList::Iterator i = ringList.begin(); i != ringList.end(); /*Trickiness*/)
624   {
625      ring = i++;
626      ring->elapsedTime += dt;
627
628      if( !ring->isActive() )
629      {
630         ringList.erase( ring );
631      }
632      else
633      {
634         updateRing( *ring, dt );
635      }
636   }
637}
638
639//----------------------------------------------------------------------------
640// Update ring
641//----------------------------------------------------------------------------
642void Splash::updateRing( SplashRing& ring, F32 dt )
643{
644   for( U32 i=0; i<ring.points.size(); i++ )
645   {
646      if( mDead )
647      {
648         Point3F vel = ring.points[i].velocity;
649         vel.normalize();
650         vel *= mDataBlock->acceleration;
651         ring.points[i].velocity += vel * dt;
652      }
653
654      ring.points[i].velocity += Point3F( 0.0f, 0.0f, -9.8f ) * dt;
655      ring.points[i].position += ring.points[i].velocity * dt;
656   }
657}
658
659//----------------------------------------------------------------------------
660// Explode
661//----------------------------------------------------------------------------
662void Splash::spawnExplosion()
663{
664   if( !mDataBlock->explosion ) return;
665
666   Explosion* pExplosion = new Explosion;
667   pExplosion->onNewDataBlock(mDataBlock->explosion, false);
668
669   MatrixF trans = getTransform();
670   trans.setPosition( getPosition() );
671
672   pExplosion->setTransform( trans );
673   pExplosion->setInitialState( trans.getPosition(), VectorF(0,0,1), 1);
674   if (!pExplosion->registerObject())
675      delete pExplosion;
676}
677
678//--------------------------------------------------------------------------
679// packUpdate
680//--------------------------------------------------------------------------
681U32 Splash::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
682{
683   U32 retMask = Parent::packUpdate(con, mask, stream);
684
685   if( stream->writeFlag(mask & GameBase::InitialUpdateMask) )
686   {
687      mathWrite(*stream, mInitialPosition);
688   }
689
690   return retMask;
691}
692
693//--------------------------------------------------------------------------
694// unpackUpdate
695//--------------------------------------------------------------------------
696void Splash::unpackUpdate(NetConnection* con, BitStream* stream)
697{
698   Parent::unpackUpdate(con, stream);
699
700   if( stream->readFlag() )
701   {
702      mathRead(*stream, &mInitialPosition);
703      setPosition( mInitialPosition );
704   }
705}
706