aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/fx_water.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/client/fx_water.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/client/fx_water.cpp')
-rw-r--r--mp/src/game/client/fx_water.cpp603
1 files changed, 603 insertions, 0 deletions
diff --git a/mp/src/game/client/fx_water.cpp b/mp/src/game/client/fx_water.cpp
new file mode 100644
index 00000000..f35e4f6b
--- /dev/null
+++ b/mp/src/game/client/fx_water.cpp
@@ -0,0 +1,603 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "clienteffectprecachesystem.h"
+#include "fx_sparks.h"
+#include "iefx.h"
+#include "c_te_effect_dispatch.h"
+#include "particles_ez.h"
+#include "decals.h"
+#include "engine/IEngineSound.h"
+#include "fx_quad.h"
+#include "tier0/vprof.h"
+#include "fx.h"
+#include "fx_water.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectSplash )
+CLIENTEFFECT_MATERIAL( "effects/splash1" )
+CLIENTEFFECT_MATERIAL( "effects/splash2" )
+CLIENTEFFECT_MATERIAL( "effects/splash4" )
+CLIENTEFFECT_MATERIAL( "effects/slime1" )
+CLIENTEFFECT_REGISTER_END()
+
+
+#define SPLASH_MIN_SPEED 50.0f
+#define SPLASH_MAX_SPEED 100.0f
+
+ConVar cl_show_splashes( "cl_show_splashes", "1" );
+
+static Vector s_vecSlimeColor( 46.0f/255.0f, 90.0f/255.0f, 36.0f/255.0f );
+
+// Each channel does not contribute to the luminosity equally, as represented here
+#define RED_CHANNEL_CONTRIBUTION 0.30f
+#define GREEN_CHANNEL_CONTRIBUTION 0.59f
+#define BLUE_CHANNEL_CONTRIBUTION 0.11f
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns a normalized tint and luminosity for a specified color
+// Input : &color - normalized input color to extract information from
+// *tint - normalized tint of that color
+// *luminosity - normalized luminosity of that color
+//-----------------------------------------------------------------------------
+void UTIL_GetNormalizedColorTintAndLuminosity( const Vector &color, Vector *tint, float *luminosity )
+{
+ // Give luminosity if requested
+ if ( luminosity != NULL )
+ {
+ // Each channel contributes differently than the others
+ *luminosity = ( color.x * RED_CHANNEL_CONTRIBUTION ) +
+ ( color.y * GREEN_CHANNEL_CONTRIBUTION ) +
+ ( color.z * BLUE_CHANNEL_CONTRIBUTION );
+ }
+
+ // Give tint if requested
+ if ( tint != NULL )
+ {
+ if ( color == vec3_origin )
+ {
+ *tint = vec3_origin;
+ }
+ else
+ {
+ float maxComponent = MAX( color.x, MAX( color.y, color.z ) );
+ *tint = color / maxComponent;
+ }
+ }
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &origin -
+// &normal -
+// scale -
+//-----------------------------------------------------------------------------
+void FX_WaterRipple( const Vector &origin, float scale, Vector *pColor, float flLifetime, float flAlpha )
+{
+ VPROF_BUDGET( "FX_WaterRipple", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+ trace_t tr;
+
+ Vector color = pColor ? *pColor : Vector( 0.8f, 0.8f, 0.75f );
+
+ Vector startPos = origin + Vector(0,0,8);
+ Vector endPos = origin + Vector(0,0,-64);
+
+ UTIL_TraceLine( startPos, endPos, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
+
+ if ( tr.fraction < 1.0f )
+ {
+ //Add a ripple quad to the surface
+ FX_AddQuad( tr.endpos + ( tr.plane.normal * 0.5f ),
+ tr.plane.normal,
+ 16.0f*scale,
+ 128.0f*scale,
+ 0.7f,
+ flAlpha, // start alpha
+ 0.0f, // end alpha
+ 0.25f,
+ random->RandomFloat( 0, 360 ),
+ random->RandomFloat( -16.0f, 16.0f ),
+ color,
+ flLifetime,
+ "effects/splashwake1",
+ (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &origin -
+// &normal -
+//-----------------------------------------------------------------------------
+void FX_GunshotSplash( const Vector &origin, const Vector &normal, float scale )
+{
+ VPROF_BUDGET( "FX_GunshotSplash", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+
+ if ( cl_show_splashes.GetBool() == false )
+ return;
+
+ Vector color;
+ float luminosity;
+
+ // Get our lighting information
+ FX_GetSplashLighting( origin + ( normal * scale ), &color, &luminosity );
+
+ float flScale = scale / 8.0f;
+
+ if ( flScale > 4.0f )
+ {
+ flScale = 4.0f;
+ }
+
+ // Setup our trail emitter
+ CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "splash" );
+
+ if ( !sparkEmitter )
+ return;
+
+ sparkEmitter->SetSortOrigin( origin );
+ sparkEmitter->m_ParticleCollision.SetGravity( 800.0f );
+ sparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
+ sparkEmitter->SetVelocityDampen( 2.0f );
+ sparkEmitter->GetBinding().SetBBox( origin - Vector( 32, 32, 32 ), origin + Vector( 32, 32, 32 ) );
+
+ PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/splash2" );
+
+ TrailParticle *tParticle;
+
+ Vector offDir;
+ Vector offset;
+ float colorRamp;
+
+ //Dump out drops
+ for ( int i = 0; i < 16; i++ )
+ {
+ offset = origin;
+ offset[0] += random->RandomFloat( -8.0f, 8.0f ) * flScale;
+ offset[1] += random->RandomFloat( -8.0f, 8.0f ) * flScale;
+
+ tParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
+
+ if ( tParticle == NULL )
+ break;
+
+ tParticle->m_flLifetime = 0.0f;
+ tParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
+
+ offDir = normal + RandomVector( -0.8f, 0.8f );
+
+ tParticle->m_vecVelocity = offDir * random->RandomFloat( SPLASH_MIN_SPEED * flScale * 3.0f, SPLASH_MAX_SPEED * flScale * 3.0f );
+ tParticle->m_vecVelocity[2] += random->RandomFloat( 32.0f, 64.0f ) * flScale;
+
+ tParticle->m_flWidth = random->RandomFloat( 1.0f, 3.0f );
+ tParticle->m_flLength = random->RandomFloat( 0.025f, 0.05f );
+
+ colorRamp = random->RandomFloat( 0.75f, 1.25f );
+
+ tParticle->m_color.r = MIN( 1.0f, color[0] * colorRamp ) * 255;
+ tParticle->m_color.g = MIN( 1.0f, color[1] * colorRamp ) * 255;
+ tParticle->m_color.b = MIN( 1.0f, color[2] * colorRamp ) * 255;
+ tParticle->m_color.a = luminosity * 255;
+ }
+
+ // Setup the particle emitter
+ CSmartPtr<CSplashParticle> pSimple = CSplashParticle::Create( "splish" );
+ pSimple->SetSortOrigin( origin );
+ pSimple->SetClipHeight( origin.z );
+ pSimple->SetParticleCullRadius( scale * 2.0f );
+ pSimple->GetBinding().SetBBox( origin - Vector( 32, 32, 32 ), origin + Vector( 32, 32, 32 ) );
+
+ SimpleParticle *pParticle;
+
+ //Main gout
+ for ( int i = 0; i < 8; i++ )
+ {
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, origin );
+
+ if ( pParticle == NULL )
+ break;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 2.0f; //NOTENOTE: We use a clip plane to realistically control our lifespan
+
+ pParticle->m_vecVelocity.Random( -0.2f, 0.2f );
+ pParticle->m_vecVelocity += ( normal * random->RandomFloat( 4.0f, 6.0f ) );
+
+ VectorNormalize( pParticle->m_vecVelocity );
+
+ pParticle->m_vecVelocity *= 50 * flScale * (8-i);
+
+ colorRamp = random->RandomFloat( 0.75f, 1.25f );
+
+ pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
+ pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
+ pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
+
+ pParticle->m_uchStartSize = 24 * flScale * RemapValClamped( i, 7, 0, 1, 0.5f );
+ pParticle->m_uchEndSize = MIN( 255, pParticle->m_uchStartSize * 2 );
+
+ pParticle->m_uchStartAlpha = RemapValClamped( i, 7, 0, 255, 32 ) * luminosity;
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
+ }
+
+ // Do a ripple
+ FX_WaterRipple( origin, flScale, &color, 1.5f, luminosity );
+
+ //Play a sound
+ CLocalPlayerFilter filter;
+
+ EmitSound_t ep;
+ ep.m_nChannel = CHAN_VOICE;
+ ep.m_pSoundName = "Physics.WaterSplash";
+ ep.m_flVolume = 1.0f;
+ ep.m_SoundLevel = SNDLVL_NORM;
+ ep.m_pOrigin = &origin;
+
+
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &origin -
+// &normal -
+// scale -
+// *pColor -
+//-----------------------------------------------------------------------------
+void FX_GunshotSlimeSplash( const Vector &origin, const Vector &normal, float scale )
+{
+ if ( cl_show_splashes.GetBool() == false )
+ return;
+
+ VPROF_BUDGET( "FX_GunshotSlimeSplash", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+
+#if 0
+
+ float colorRamp;
+ float flScale = MIN( 1.0f, scale / 8.0f );
+
+ PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/slime1" );
+ PMaterialHandle hMaterial2 = ParticleMgr()->GetPMaterial( "effects/splash4" );
+
+ Vector color;
+ float luminosity;
+
+ // Get our lighting information
+ FX_GetSplashLighting( origin + ( normal * scale ), &color, &luminosity );
+
+ Vector offDir;
+ Vector offset;
+
+ TrailParticle *tParticle;
+
+ CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "splash" );
+
+ if ( !sparkEmitter )
+ return;
+
+ sparkEmitter->SetSortOrigin( origin );
+ sparkEmitter->m_ParticleCollision.SetGravity( 800.0f );
+ sparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
+ sparkEmitter->SetVelocityDampen( 2.0f );
+ if ( IsXbox() )
+ {
+ sparkEmitter->GetBinding().SetBBox( origin - Vector( 32, 32, 64 ), origin + Vector( 32, 32, 64 ) );
+ }
+
+ //Dump out drops
+ for ( int i = 0; i < 24; i++ )
+ {
+ offset = origin;
+ offset[0] += random->RandomFloat( -16.0f, 16.0f ) * flScale;
+ offset[1] += random->RandomFloat( -16.0f, 16.0f ) * flScale;
+
+ tParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
+
+ if ( tParticle == NULL )
+ break;
+
+ tParticle->m_flLifetime = 0.0f;
+ tParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
+
+ offDir = normal + RandomVector( -0.6f, 0.6f );
+
+ tParticle->m_vecVelocity = offDir * random->RandomFloat( SPLASH_MIN_SPEED * flScale * 3.0f, SPLASH_MAX_SPEED * flScale * 3.0f );
+ tParticle->m_vecVelocity[2] += random->RandomFloat( 32.0f, 64.0f ) * flScale;
+
+ tParticle->m_flWidth = random->RandomFloat( 3.0f, 6.0f ) * flScale;
+ tParticle->m_flLength = random->RandomFloat( 0.025f, 0.05f ) * flScale;
+
+ colorRamp = random->RandomFloat( 0.75f, 1.25f );
+
+ tParticle->m_color.r = MIN( 1.0f, color.x * colorRamp ) * 255;
+ tParticle->m_color.g = MIN( 1.0f, color.y * colorRamp ) * 255;
+ tParticle->m_color.b = MIN( 1.0f, color.z * colorRamp ) * 255;
+ tParticle->m_color.a = 255 * luminosity;
+ }
+
+ // Setup splash emitter
+ CSmartPtr<CSplashParticle> pSimple = CSplashParticle::Create( "splish" );
+ pSimple->SetSortOrigin( origin );
+ pSimple->SetClipHeight( origin.z );
+ pSimple->SetParticleCullRadius( scale * 2.0f );
+
+ if ( IsXbox() )
+ {
+ pSimple->GetBinding().SetBBox( origin - Vector( 32, 32, 64 ), origin + Vector( 32, 32, 64 ) );
+ }
+
+ SimpleParticle *pParticle;
+
+ // Tint
+ colorRamp = random->RandomFloat( 0.75f, 1.0f );
+ color = Vector( 1.0f, 0.8f, 0.0f ) * color * colorRamp;
+
+ //Main gout
+ for ( int i = 0; i < 8; i++ )
+ {
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial2, origin );
+
+ if ( pParticle == NULL )
+ break;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 2.0f; //NOTENOTE: We use a clip plane to realistically control our lifespan
+
+ pParticle->m_vecVelocity.Random( -0.2f, 0.2f );
+ pParticle->m_vecVelocity += ( normal * random->RandomFloat( 4.0f, 6.0f ) );
+
+ VectorNormalize( pParticle->m_vecVelocity );
+
+ pParticle->m_vecVelocity *= 50 * flScale * (8-i);
+
+ colorRamp = random->RandomFloat( 0.75f, 1.25f );
+
+ pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
+ pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
+ pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
+
+ pParticle->m_uchStartSize = 24 * flScale * RemapValClamped( i, 7, 0, 1, 0.5f );
+ pParticle->m_uchEndSize = MIN( 255, pParticle->m_uchStartSize * 2 );
+
+ pParticle->m_uchStartAlpha = RemapValClamped( i, 7, 0, 255, 32 ) * luminosity;
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
+ }
+
+#else
+
+ QAngle vecAngles;
+ VectorAngles( normal, vecAngles );
+ if ( scale < 2.0f )
+ {
+ DispatchParticleEffect( "slime_splash_01", origin, vecAngles );
+ }
+ else if ( scale < 4.0f )
+ {
+ DispatchParticleEffect( "slime_splash_02", origin, vecAngles );
+ }
+ else
+ {
+ DispatchParticleEffect( "slime_splash_03", origin, vecAngles );
+ }
+
+#endif
+
+ //Play a sound
+ CLocalPlayerFilter filter;
+
+ EmitSound_t ep;
+ ep.m_nChannel = CHAN_VOICE;
+ ep.m_pSoundName = "Physics.WaterSplash";
+ ep.m_flVolume = 1.0f;
+ ep.m_SoundLevel = SNDLVL_NORM;
+ ep.m_pOrigin = &origin;
+
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void SplashCallback( const CEffectData &data )
+{
+ Vector normal;
+
+ AngleVectors( data.m_vAngles, &normal );
+
+ if ( data.m_fFlags & FX_WATER_IN_SLIME )
+ {
+ FX_GunshotSlimeSplash( data.m_vOrigin, Vector(0,0,1), data.m_flScale );
+ }
+ else
+ {
+ FX_GunshotSplash( data.m_vOrigin, Vector(0,0,1), data.m_flScale );
+ }
+}
+
+DECLARE_CLIENT_EFFECT( "watersplash", SplashCallback );
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &data -
+//-----------------------------------------------------------------------------
+void GunshotSplashCallback( const CEffectData &data )
+{
+ if ( data.m_fFlags & FX_WATER_IN_SLIME )
+ {
+ FX_GunshotSlimeSplash( data.m_vOrigin, Vector(0,0,1), data.m_flScale );
+ }
+ else
+ {
+ FX_GunshotSplash( data.m_vOrigin, Vector(0,0,1), data.m_flScale );
+ }
+}
+
+DECLARE_CLIENT_EFFECT( "gunshotsplash", GunshotSplashCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &data -
+//-----------------------------------------------------------------------------
+void RippleCallback( const CEffectData &data )
+{
+ float flScale = data.m_flScale / 8.0f;
+
+ Vector color;
+ float luminosity;
+
+ // Get our lighting information
+ FX_GetSplashLighting( data.m_vOrigin + ( Vector(0,0,1) * 4.0f ), &color, &luminosity );
+
+ FX_WaterRipple( data.m_vOrigin, flScale, &color, 1.5f, luminosity );
+}
+
+DECLARE_CLIENT_EFFECT( "waterripple", RippleCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pDebugName -
+// Output : WaterDebrisEffect*
+//-----------------------------------------------------------------------------
+WaterDebrisEffect* WaterDebrisEffect::Create( const char *pDebugName )
+{
+ return new WaterDebrisEffect( pDebugName );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pParticle -
+// timeDelta -
+// Output : float
+//-----------------------------------------------------------------------------
+float WaterDebrisEffect::UpdateAlpha( const SimpleParticle *pParticle )
+{
+ return ( ((float)pParticle->m_uchStartAlpha/255.0f) * sin( M_PI * (pParticle->m_flLifetime / pParticle->m_flDieTime) ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pParticle -
+// timeDelta -
+// Output : float
+//-----------------------------------------------------------------------------
+float CSplashParticle::UpdateRoll( SimpleParticle *pParticle, float timeDelta )
+{
+ pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
+
+ pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -4.0f );
+
+ //Cap the minimum roll
+ if ( fabs( pParticle->m_flRollDelta ) < 0.5f )
+ {
+ pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f;
+ }
+
+ return pParticle->m_flRoll;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pParticle -
+// timeDelta -
+//-----------------------------------------------------------------------------
+void CSplashParticle::UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
+{
+ //Decellerate
+ static float dtime;
+ static float decay;
+
+ if ( dtime != timeDelta )
+ {
+ dtime = timeDelta;
+ float expected = 3.0f;
+ decay = exp( log( 0.0001f ) * dtime / expected );
+ }
+
+ pParticle->m_vecVelocity *= decay;
+ pParticle->m_vecVelocity[2] -= ( 800.0f * timeDelta );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pParticle -
+// Output : float
+//-----------------------------------------------------------------------------
+float CSplashParticle::UpdateAlpha( const SimpleParticle *pParticle )
+{
+ if ( m_bUseClipHeight )
+ {
+ float flAlpha = pParticle->m_uchStartAlpha / 255.0f;
+
+ return flAlpha * RemapValClamped(pParticle->m_Pos.z,
+ m_flClipHeight,
+ m_flClipHeight - ( UpdateScale( pParticle ) * 0.5f ),
+ 1.0f,
+ 0.0f );
+ }
+
+ return (pParticle->m_uchStartAlpha/255.0f) + ( (float)(pParticle->m_uchEndAlpha/255.0f) - (float)(pParticle->m_uchStartAlpha/255.0f) ) * (pParticle->m_flLifetime / pParticle->m_flDieTime);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &clipPlane -
+//-----------------------------------------------------------------------------
+void CSplashParticle::SetClipHeight( float flClipHeight )
+{
+ m_bUseClipHeight = true;
+ m_flClipHeight = flClipHeight;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pIterator -
+//-----------------------------------------------------------------------------
+void CSplashParticle::SimulateParticles( CParticleSimulateIterator *pIterator )
+{
+ float timeDelta = pIterator->GetTimeDelta();
+
+ SimpleParticle *pParticle = (SimpleParticle*)pIterator->GetFirst();
+
+ while ( pParticle )
+ {
+ //Update velocity
+ UpdateVelocity( pParticle, timeDelta );
+ pParticle->m_Pos += pParticle->m_vecVelocity * timeDelta;
+
+ // Clip by height if requested
+ if ( m_bUseClipHeight )
+ {
+ // See if we're below, and therefore need to clip
+ if ( pParticle->m_Pos.z + UpdateScale( pParticle ) < m_flClipHeight )
+ {
+ pIterator->RemoveParticle( pParticle );
+ pParticle = (SimpleParticle*)pIterator->GetNext();
+ continue;
+ }
+ }
+
+ //Should this particle die?
+ pParticle->m_flLifetime += timeDelta;
+ UpdateRoll( pParticle, timeDelta );
+
+ if ( pParticle->m_flLifetime >= pParticle->m_flDieTime )
+ pIterator->RemoveParticle( pParticle );
+
+ pParticle = (SimpleParticle*)pIterator->GetNext();
+ }
+}