bool C_ParticleFire::SimulateAndRender(Particle *pInParticle, ParticleDraw *pDraw, float &sortKey)
{
	FireParticle *pParticle = (FireParticle*)pInParticle;

	// Should this particle die?
	pParticle->m_Lifetime += pDraw->GetTimeDelta();
	if(pParticle->m_Lifetime > FIRE_PARTICLE_LIFETIME)
		return false;

	float smooth01 = 1 - (cos(pParticle->m_Lifetime * 3.14159 / FIRE_PARTICLE_LIFETIME) * 0.5 + 0.5);
	float smooth00 = 1 - (cos(pParticle->m_Lifetime * 3.14159 * 2 / FIRE_PARTICLE_LIFETIME) * 0.5 + 0.5);
	pParticle->m_Pos = pParticle->m_StartPos + pParticle->m_Direction * smooth01;
	
	FireRamp *pRamp = &g_FireRamps[pParticle->m_iRamp];
	Vector curColor = pRamp->m_Start + (pRamp->m_End - pRamp->m_Start) * smooth01;
	
	// Render.
	Vector tPos;
	TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos);
	sortKey = (int)tPos.z;

	RenderParticle_ColorSize(
		pDraw,
		tPos,
		curColor,
		smooth00,
		size);

	return true;
}
void CLitSmokeEmitter::RenderParticles( CParticleRenderIterator *pIterator )
{
	const LitSmokeParticle *pParticle = (const LitSmokeParticle*)pIterator->GetFirst();
	while ( pParticle )
	{
		float	tLifetime = pParticle->m_flLifetime / pParticle->m_flDieTime;

		// Transform.						   
		Vector tPos;

		TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos );
		float sortKey = tPos.z;
		
		float alpha255 = ( ( (float) pParticle->m_uchColor[3]/255.0f ) * sin( M_PI_F * tLifetime ) ) * 255.0f;

		Vector	color01 = Vector( pParticle->m_uchColor[0], pParticle->m_uchColor[1], pParticle->m_uchColor[2] ) * (tLifetime / 255.0f);

		m_Renderer.RenderParticle_AddColor (
			pIterator->GetParticleDraw(),
			pParticle->m_Pos,
			tPos,
			alpha255,
			FLerp( pParticle->m_uchStartSize, pParticle->m_uchEndSize, tLifetime ),
			color01
		);
		
		pParticle = (const LitSmokeParticle*)pIterator->GetNext( sortKey );
	}
}
void C_SmokeStack::RenderParticles( CParticleRenderIterator *pIterator )
{
	const SmokeStackParticle *pParticle = (const SmokeStackParticle*)pIterator->GetFirst();
	while ( pParticle )
	{
		// Transform.						   
		Vector tPos;
		TransformParticle( m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos );

		// Figure out its alpha. Squaring it after it gets halfway through its lifetime
		// makes it get translucent and fade out for a longer time.
		//float alpha = cosf( -M_PI_F + tLifetime * M_PI_F * 2.f ) * 0.5f + 0.5f;
		float tLifetime = pParticle->m_Lifetime * m_InvLifetime;
		float alpha = TableCos( -M_PI_F + tLifetime * M_PI_F * 2.f ) * 0.5f + 0.5f;
		if( tLifetime > 0.5f )
			alpha *= alpha;

		m_Renderer.RenderParticle(
			pIterator->GetParticleDraw(),
			pParticle->m_Pos,
			tPos,
			alpha * m_flAlphaScale,
			FLerp(m_StartSize, m_EndSize, tLifetime),
			DEG2RAD( pParticle->m_flAngle )
		);
		
		pParticle = (const SmokeStackParticle*)pIterator->GetNext( pParticle->m_flSortPos );
	}
}
void CLocalSpaceEmitter::RenderParticles( CParticleRenderIterator *pIterator )
{
	const matrix3x4_t &mLocalToWorld = GetTransformMatrix();
	const VMatrix &mModelView = ParticleMgr()->GetModelView();

	const SimpleParticle *pParticle = (const SimpleParticle *)pIterator->GetFirst();
	while ( pParticle )
	{
		// Transform it
		Vector screenPos, worldPos;
		VectorTransform( pParticle->m_Pos, mLocalToWorld, worldPos );
		
		// Correct viewmodel squashing
		if ( m_fFlags & FLE_VIEWMODEL )
		{
			FormatViewModelAttachment( NULL, worldPos, false );
		}

		TransformParticle( mModelView, worldPos, screenPos );
		
		float sortKey = (int) screenPos.z;

		// Render it
		RenderParticle_ColorSizeAngle(
			pIterator->GetParticleDraw(),
			screenPos,
			UpdateColor( pParticle ),
			UpdateAlpha( pParticle ) * GetAlphaDistanceFade( screenPos, m_flNearClipMin, m_flNearClipMax ),
			UpdateScale( pParticle ),
			pParticle->m_flRoll 
			);

		pParticle = (const SimpleParticle *)pIterator->GetNext( sortKey );
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pInParticle - 
//			*pDraw - 
//			&sortKey - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool C_PerfTest::SimulateAndRender(Particle *pInParticle, ParticleDraw *pDraw, float &sortKey)
{
	PerfTestParticle *pParticle = (PerfTestParticle*)pInParticle;

	// Render.
	Vector tPos;
	TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos);
	sortKey = tPos.z;

	Vector vColor( 0, 0, 0 );
	for( int i=0; i < NUM_LIGHTS; i++ )
	{
		float fDist = pParticle->m_Pos.DistToSqr( m_LightPos[i] );
		float fAmt;
		if( fDist > 0.0001f )
			fAmt = m_LightIntensity[i] / fDist;
		else
			fAmt = 1000;

		vColor += m_LightColor[i] * fAmt;
	}
	vColor = vColor.Min( Vector(255.1,255.1,255.1) );

	RenderParticle_Color255Size(
		pDraw,
		tPos,
		vColor,		// color
		255,		// alpha
		1			// size
		);

	return true;
}
//-----------------------------------------------------------------------------
// Purpose: Simulate motion and render all child particles
// Input  : *pInParticle - 
//			*pDraw - 
//			&sortKey - 
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CSimpleEmitter::SimulateAndRender( Particle *pInParticle, ParticleDraw *pDraw, float &sortKey)
{
	SimpleParticle *pParticle = (SimpleParticle *) pInParticle;
	float timeDelta = pDraw->GetTimeDelta();

	//Render
	Vector	tPos;

	TransformParticle( g_ParticleMgr.GetModelView(), pParticle->m_Pos, tPos );
	sortKey = (int) tPos.z;

	//Render it
	RenderParticle_ColorSizeAngle(
		pDraw,
		tPos,
		UpdateColor( pParticle, timeDelta ),
		UpdateAlpha( pParticle, timeDelta ) * GetAlphaDistanceFade( tPos, m_flNearClipMin, m_flNearClipMax ),
		UpdateScale( pParticle, timeDelta ),
		UpdateRoll( pParticle, timeDelta ) );

	//Update velocity
	UpdateVelocity( pParticle, timeDelta );
	pParticle->m_Pos += pParticle->m_vecVelocity * timeDelta;

	//Should this particle die?
	pParticle->m_flLifetime += timeDelta;

	if ( pParticle->m_flLifetime >= pParticle->m_flDieTime )
		return false;

	return true;
}
void C_MovieExplosion::RenderParticles( CParticleRenderIterator *pIterator )
{
	const StandardParticle_t *pParticle = (const StandardParticle_t*)pIterator->GetFirst();
	while ( pParticle )
	{
		// Draw.
		Vector tPos;
		TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos);
		float sortKey = tPos.z;

		float lifetimePercent = pParticle->m_Lifetime / EMITTED_PARTICLE_LIFETIME;
		Vector color;
		color.x = sin(lifetimePercent * 3.14159);
		color.y = color.x * 0.5f;
		color.z = 0;
		RenderParticle_ColorSize(
			pIterator->GetParticleDraw(),
			tPos,
			color,
			m_EmitterAlpha * sin(3.14159 * lifetimePercent),
			10);

		pParticle = (const StandardParticle_t*)pIterator->GetNext( sortKey );
	}
}
void C_SteamJet::RenderParticles( CParticleRenderIterator *pIterator )
{
	const SteamJetParticle *pParticle = (const SteamJetParticle*)pIterator->GetFirst();
	while ( pParticle )
	{
		// Render.
		Vector tPos;
		TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos);
		float sortKey = tPos.z;

		float lifetimeT = pParticle->m_Lifetime / (pParticle->m_DieTime + 0.001);
		float fRamp = lifetimeT * (STEAMJET_NUMRAMPS-1);
		int iRamp = (int)fRamp;
		float fraction = fRamp - iRamp;
		
		Vector vRampColor = m_Ramps[iRamp] + (m_Ramps[iRamp+1] - m_Ramps[iRamp]) * fraction;

		vRampColor[0] = min( 1.0f, vRampColor[0] );
		vRampColor[1] = min( 1.0f, vRampColor[1] );
		vRampColor[2] = min( 1.0f, vRampColor[2] );

#ifdef GE_DLL
		// Determine a linear alpha falloff based on our limits
		float alphamod = 1.0f;
		float fadetime = gpGlobals->curtime - m_flStartFadeTime;
		if ( m_bIsForExplosion && fadetime > 0 && m_flStartFadeTime > 0 )
			alphamod = RemapValClamped( fadetime, 0, m_flFadeDuration, 1.0f, 0 );

		float sinLifetime = sin(pParticle->m_Lifetime * 3.14159f / pParticle->m_DieTime) * alphamod;
#else
		float sinLifetime = sin(pParticle->m_Lifetime * 3.14159f / pParticle->m_DieTime);
#endif

		if ( m_nType == STEAM_HEATWAVE )
		{
			RenderParticle_ColorSizePerturbNormal(
				pIterator->GetParticleDraw(),
				tPos,
				vRampColor,
				sinLifetime * (m_clrRender->a/255.0f),
				FLerp(m_StartSize, m_EndSize, pParticle->m_Lifetime));
		}
		else
		{
			RenderParticle_ColorSizeAngle(
				pIterator->GetParticleDraw(),
				tPos,
				vRampColor,
				sinLifetime * (m_clrRender->a/255.0f),
				FLerp(pParticle->m_uchStartSize, pParticle->m_uchEndSize, pParticle->m_Lifetime),
				pParticle->m_flRoll );
		}

		pParticle = (const SteamJetParticle*)pIterator->GetNext( sortKey );
	}
}
void C_FuncSmokeVolume::RenderParticles( CParticleRenderIterator *pIterator )
{
	if ( m_CurrentDensity == 0 )
		return;

	const SmokeGrenadeParticle *pParticle = (const SmokeGrenadeParticle*)pIterator->GetFirst();
	while ( pParticle )
	{
		Vector renderPos = pParticle->m_Pos;

		// Fade out globally.
		float alpha = m_CurrentDensity;

		// Apply the precalculated fade alpha from world geometry.
		alpha *= pParticle->m_FadeAlpha;
		
		// TODO: optimize this whole routine!
		Vector color = m_MinColor + (m_MaxColor - m_MinColor) * (pParticle->m_ColorInterp / 255.1f);
		if ( IsEmissive() )
		{
			color.x += pParticle->m_Color[0] / 255.0f;
			color.y += pParticle->m_Color[1] / 255.0f;
			color.z += pParticle->m_Color[2] / 255.0f;

			color.x = clamp( color.x, 0.0f, 1.0f );
			color.y = clamp( color.y, 0.0f, 1.0f );
			color.z = clamp( color.z, 0.0f, 1.0f );
		}
		else
		{
			color.x *= pParticle->m_Color[0] / 255.0f;
			color.y *= pParticle->m_Color[1] / 255.0f;
			color.z *= pParticle->m_Color[2] / 255.0f;
		}
		
		Vector tRenderPos;
		TransformParticle( ParticleMgr()->GetModelView(), renderPos, tRenderPos );
		float sortKey = 1;//tRenderPos.z;

		RenderParticle_ColorSizeAngle(
			pIterator->GetParticleDraw(),
			tRenderPos,
			color,
			alpha * GetAlphaDistanceFade(tRenderPos, 10, 30),	// Alpha
			m_ParticleRadius,
			pParticle->m_CurRotation
			);

		pParticle = (const SmokeGrenadeParticle*)pIterator->GetNext( sortKey );
	}
}
//-----------------------------------------------------------------------------
// Simulate the particles
//-----------------------------------------------------------------------------
void C_EnvParticleScript::RenderParticles( CParticleRenderIterator *pIterator )
{
	const ParticleScriptParticle_t* pParticle = (const ParticleScriptParticle_t*)pIterator->GetFirst();
	while ( pParticle )
	{
		Vector vecRenderPos;
		TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, vecRenderPos );
		float sortKey = vecRenderPos.z;

		Vector color( 1, 1, 1 );
		RenderParticle_ColorSize( pIterator->GetParticleDraw(), vecRenderPos, color, 1.0f, pParticle->m_flSize );
		
		pParticle = (const ParticleScriptParticle_t*)pIterator->GetNext( sortKey );
	}
}
Exemple #11
0
void CTrailParticles::RenderParticles(CParticleRenderIterator *pIterator)
{
    const TrailParticle *pParticle = (const TrailParticle*) pIterator->GetFirst();
    while (pParticle)
    {
        //Get our remaining time
        float lifePerc = 1.0f - (pParticle->m_flLifetime / pParticle->m_flDieTime);
        float scale = (pParticle->m_flLength*lifePerc);

        if (scale < 0.01f)
            scale = 0.01f;

        Vector	start, delta;

        //NOTE: We need to do everything in screen space
        TransformParticle(ParticleMgr()->GetModelView(), pParticle->m_Pos, start);
        float sortKey = start.z;

        Vector3DMultiply(ParticleMgr()->GetModelView(), pParticle->m_vecVelocity, delta);

        float	color[4];
        float	ramp = 1.0;

        // Fade in for the first few frames
        if (pParticle->m_flLifetime <= 0.3 && m_fFlags & bitsPARTICLE_TRAIL_FADE_IN)
        {
            ramp = pParticle->m_flLifetime;
        }
        else if (m_fFlags & bitsPARTICLE_TRAIL_FADE)
        {
            ramp = (1.0f - (pParticle->m_flLifetime / pParticle->m_flDieTime));
        }

        color[0] = pParticle->m_color.r * ramp * (1.0f / 255.0f);
        color[1] = pParticle->m_color.g * ramp * (1.0f / 255.0f);
        color[2] = pParticle->m_color.b * ramp * (1.0f / 255.0f);
        color[3] = pParticle->m_color.a * ramp * (1.0f / 255.0f);

        float	flLength = (pParticle->m_vecVelocity * scale).Length();//( delta - pos ).Length();
        float	flWidth = (flLength < pParticle->m_flWidth) ? flLength : pParticle->m_flWidth;

        //See if we should fade
        Vector vecScaledDelta = (delta*scale);
        Tracer_Draw(pIterator->GetParticleDraw(), start, vecScaledDelta, flWidth, color);

        pParticle = (const TrailParticle*) pIterator->GetNext(sortKey);
    }
}
Exemple #12
0
void C_SteamJet::RenderParticles( CParticleRenderIterator *pIterator )
{
	const SteamJetParticle *pParticle = (const SteamJetParticle*)pIterator->GetFirst();
	while ( pParticle )
	{
		// Render.
		Vector tPos;
		TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos);
		float sortKey = tPos.z;

		float lifetimeT = pParticle->m_Lifetime / (pParticle->m_DieTime + 0.001);
		float fRamp = lifetimeT * (STEAMJET_NUMRAMPS-1);
		int iRamp = (int)fRamp;
		float fraction = fRamp - iRamp;
		
		Vector vRampColor = m_Ramps[iRamp] + (m_Ramps[iRamp+1] - m_Ramps[iRamp]) * fraction;

		vRampColor[0] = min( 1.0f, vRampColor[0] );
		vRampColor[1] = min( 1.0f, vRampColor[1] );
		vRampColor[2] = min( 1.0f, vRampColor[2] );

		float sinLifetime = sin(pParticle->m_Lifetime * 3.14159f / pParticle->m_DieTime);

		if ( m_nType == STEAM_HEATWAVE )
		{
			RenderParticle_ColorSizePerturbNormal(
				pIterator->GetParticleDraw(),
				tPos,
				vRampColor,
				sinLifetime * (m_clrRender->a/255.0f),
				FLerp(m_StartSize, m_EndSize, pParticle->m_Lifetime));
		}
		else
		{
			RenderParticle_ColorSizeAngle(
				pIterator->GetParticleDraw(),
				tPos,
				vRampColor,
				sinLifetime * (m_clrRender->a/255.0f),
				FLerp(pParticle->m_uchStartSize, pParticle->m_uchEndSize, pParticle->m_Lifetime),
				pParticle->m_flRoll );
		}

		pParticle = (const SteamJetParticle*)pIterator->GetNext( sortKey );
	}
}
void C_AR2Explosion::RenderParticles( CParticleRenderIterator *pIterator )
{
	const AR2ExplosionParticle *pParticle = (const AR2ExplosionParticle *)pIterator->GetFirst();
	while ( pParticle )
	{
		float sortKey = 0;
		if ( pParticle->m_Lifetime >= 0.0f )
		{
			// Draw.
			float lifetimePercent = ( pParticle->m_Lifetime - AR2_DUST_FADE_IN_TIME ) / pParticle->m_Dwell;

			// FIXME: base color should be a dirty version of the material color
			Vector color = g_AR2DustColor1 * (1.0 - lifetimePercent) + g_AR2DustColor2 * lifetimePercent;
			
			Vector tPos;
			TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos);
			sortKey = tPos.z;
			
			float	alpha;

			if ( pParticle->m_Lifetime < AR2_DUST_FADE_IN_TIME )
			{
				alpha = AR2_DUST_ALPHA * ( pParticle->m_Lifetime / AR2_DUST_FADE_IN_TIME );
			}
			else
			{
				alpha = AR2_DUST_ALPHA * ( 1.0f - lifetimePercent );
			}

			alpha *= GetAlphaDistanceFade( tPos, IsXbox() ? 100 : 50, IsXbox() ? 200 : 150 );

			RenderParticle_ColorSizeAngle(
				pIterator->GetParticleDraw(),
				tPos,
				color,
				alpha,
				pParticle->m_Dist, // size based on how far it's traveled
				pParticle->m_Roll);
		}

		pParticle = (const AR2ExplosionParticle *)pIterator->GetNext( sortKey );
	}
}
Exemple #14
0
void CDustEffect::RenderParticles( CParticleRenderIterator *pIterator )
{
	const CFuncDustParticle *pParticle = (const CFuncDustParticle*)pIterator->GetFirst();
	while ( pParticle )
	{
		// Velocity.
		float flAlpha;
		if( m_pDust->m_DustFlags & DUSTFLAGS_FROZEN )
		{
			flAlpha = 1;
		}
		else
		{
			// Alpha.
			float flAngle = (pParticle->m_flLifetime / pParticle->m_flDieTime) * M_PI * 2;
			flAlpha = sin( flAngle - (M_PI * 0.5f) ) * 0.5f + 0.5f;
		}

		Vector tPos;
		TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos );
		float sortKey = (int) tPos.z;

		if( -tPos.z <= m_pDust->m_DistMax )
		{
			flAlpha *= 1 + (tPos.z / m_pDust->m_DistMax);

			// Draw it.
			float flSize = pParticle->m_flSize;
			if( m_pDust->m_DustFlags & DUSTFLAGS_SCALEMOTES )
				flSize *= -tPos.z;

			RenderParticle_Color255Size(
				pIterator->GetParticleDraw(),
				tPos,
				Vector( m_pDust->m_Color.r, m_pDust->m_Color.g, m_pDust->m_Color.b ),
				flAlpha * m_pDust->m_Color.a,
				flSize
				);
		}

		pParticle = (const CFuncDustParticle*)pIterator->GetNext( sortKey );
	}
}
//------------------------------------------------------------------------------
// Purpose :
// Input   :
// Output  :
//------------------------------------------------------------------------------
bool CPlasmaSpray::SimulateAndRender(Particle *pParticle, ParticleDraw *pDraw, float &sortDist )
{
	SimpleParticle* pSimpleParticle = (SimpleParticle*)pParticle;

	//Should this particle die?
	pSimpleParticle->m_flLifetime += pDraw->GetTimeDelta();

	C_PlasmaBeamNode* pNode = (C_PlasmaBeamNode*)((C_BaseEntity*)m_pOwner);
	if ( pSimpleParticle->m_flLifetime >= pSimpleParticle->m_flDieTime )
	{
		return false;
	}
	// If owner is gone or spray off remove me
	else if (pNode == NULL || !pNode->m_bSprayOn)
	{
		return false;
	}

	float scale = random->RandomFloat( 0.02, 0.08 );

	// NOTE: We need to do everything in screen space
	Vector  delta;
	Vector	start;
	TransformParticle(g_ParticleMgr.GetModelView(), pSimpleParticle->m_Pos, start);

	Vector3DMultiply( CurrentWorldToViewMatrix(), pSimpleParticle->m_vecVelocity, delta );

	delta[0] *= scale;
	delta[1] *= scale;
	delta[2] *= scale;

	// See c_tracer.* for this method
	Tracer_Draw( pDraw, start, delta, random->RandomInt( 2, 8 ), 0 );

	//Simulate the movement with collision
	trace_t trace;
	float   timeDelta = pDraw->GetTimeDelta();
	m_ParticleCollision.MoveParticle( pSimpleParticle->m_Pos, pSimpleParticle->m_vecVelocity, NULL, timeDelta, &trace );

	return true;
}
void CTEParticleRenderer::RenderParticles( CParticleRenderIterator *pIterator )
{
	const StandardParticle_t *pParticle = (const StandardParticle_t*)pIterator->GetFirst();
	while ( pParticle )
	{
		// Render.
		Vector tPos;
		TransformParticle(ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos);
		float sortKey = tPos.z;

		Vector vColor(pParticle->m_Color[0]/255.9f, pParticle->m_Color[1]/255.9f, pParticle->m_Color[2]/255.9f);
		RenderParticle_ColorSize(
			pIterator->GetParticleDraw(),
			tPos,
			vColor,
			pParticle->m_Color[3]/255.9f,
			m_ParticleSize);

		pParticle = (const StandardParticle_t*)pIterator->GetNext( sortKey );
	}
}
//-----------------------------------------------------------------------------
// Purpose: Simulate and render the particle in this system
// Input  : *pInParticle - particle to consider
//			*pDraw - drawing utilities
//			&sortKey - sorting key
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CFleckParticles::SimulateAndRender( Particle *pInParticle, ParticleDraw *pDraw, float &sortKey )
{
	FleckParticle *pParticle = (FleckParticle *) pInParticle;

	const float	timeDelta = pDraw->GetTimeDelta();

	//Should this particle die?
	pParticle->m_flLifetime += timeDelta;

	if ( pParticle->m_flLifetime >= pParticle->m_flDieTime )
		return false;
	
	//Render
	Vector	tPos;

	TransformParticle( g_ParticleMgr.GetModelView(), pParticle->m_Pos, tPos );
	sortKey = (int) tPos.z;
	
	Vector	color;
	color[0] = pParticle->m_uchColor[0] / 255.0f;
	color[1] = pParticle->m_uchColor[1] / 255.0f;
	color[2] = pParticle->m_uchColor[2] / 255.0f;

	pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;

	//Render it
	RenderParticle_ColorSizeAngle(
		pDraw,
		tPos,
		color,
		1.0f - (pParticle->m_flLifetime / pParticle->m_flDieTime),
		pParticle->m_uchSize,
		pParticle->m_flRoll );

	//Simulate the movement with collision
	trace_t trace;
	m_ParticleCollision.MoveParticle( pParticle->m_Pos, pParticle->m_vecVelocity, &pParticle->m_flRollDelta, timeDelta, &trace );

	return true;
}
inline void C_EntityParticleTrail::RenderParticles( CParticleRenderIterator *pIterator )
{
    const SimpleParticle *pParticle = (const SimpleParticle*)pIterator->GetFirst();
    while ( pParticle )
    {
        float t = pParticle->m_flLifetime / pParticle->m_flDieTime;

        // Render
        Vector	tPos;
        TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos );
        float sortKey = tPos.z;

        Vector	color = Vector( pParticle->m_uchColor[0] / 255.0f, pParticle->m_uchColor[1] / 255.0f, pParticle->m_uchColor[2] / 255.0f );
        float alpha = Lerp( t, pParticle->m_uchStartAlpha / 255.0f, pParticle->m_uchEndAlpha / 255.0f );
        float flSize = Lerp( t, pParticle->m_uchStartSize, pParticle->m_uchEndSize );

        // Render it
        RenderParticle_ColorSize( pIterator->GetParticleDraw(), tPos, color, alpha, flSize );

        pParticle = (const SimpleParticle*)pIterator->GetNext( sortKey );
    }
}
bool C_FuncSmokeVolume::SimulateAndRender( Particle *pBaseParticle, ParticleDraw *pDraw, float &sortKey )
{
	if( m_CurrentDensity == 0.0f )
	{
		return true;
	}
	SmokeGrenadeParticle* pParticle = (SmokeGrenadeParticle*)pBaseParticle;

	Vector renderPos = pParticle->m_Pos;

	// Fade out globally.
	float alpha = m_CurrentDensity;

	pParticle->m_CurRotation += pParticle->m_RotationFactor * ( M_PI / 180.0f ) * m_RotationSpeed * pDraw->GetTimeDelta();

	// Apply the precalculated fade alpha from world geometry.
	alpha *= pParticle->m_FadeAlpha;
	
	// TODO: optimize this whole routine!
	Vector color = m_MinColor + (m_MaxColor - m_MinColor) * (pParticle->m_ColorInterp / 255.1f);
	color.x *= pParticle->m_Color[0] / 255.0f;
	color.y *= pParticle->m_Color[1] / 255.0f;
	color.z *= pParticle->m_Color[2] / 255.0f;
	
	Vector tRenderPos;
	TransformParticle( g_ParticleMgr.GetModelView(), renderPos, tRenderPos );
	sortKey = tRenderPos.z;

	RenderParticle_ColorSizeAngle(
		pDraw,
		tRenderPos,
		color,
		alpha * GetAlphaDistanceFade(tRenderPos, 10, 30),	// Alpha
		m_ParticleRadius,
		pParticle->m_CurRotation
		);

	return true;
}
void CSimpleEmitter::RenderParticles( CParticleRenderIterator *pIterator )
{
	const SimpleParticle *pParticle = (const SimpleParticle *)pIterator->GetFirst();
	while ( pParticle )
	{
		//Render
		Vector	tPos;

		TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, tPos );
		float sortKey = (int) tPos.z;

		//Render it
		RenderParticle_ColorSizeAngle(
			pIterator->GetParticleDraw(),
			tPos,
			UpdateColor( pParticle ),
			UpdateAlpha( pParticle ) * GetAlphaDistanceFade( tPos, m_flNearClipMin, m_flNearClipMax ),
			UpdateScale( pParticle ),
			pParticle->m_flRoll
			);

		pParticle = (const SimpleParticle *)pIterator->GetNext( sortKey );
	}
}
bool C_AR2Explosion::SimulateAndRender(Particle *pBaseParticle, ParticleDraw *pDraw, float &sortKey)
{
	AR2ExplosionParticle* pParticle = (AR2ExplosionParticle*)pBaseParticle;

	float dt = pDraw->GetTimeDelta();
	if (dt > 0.05)
		dt = 0.05; // yuck, air resistance function craps out at less then 20fps

	// Update its lifetime.
	pParticle->m_Lifetime += dt; // pDraw->GetTimeDelta();
	if(pParticle->m_Lifetime > pParticle->m_Dwell)
	{
		// faded to nothing....
		return false;
	}

	// Spin the thing
	pParticle->m_Roll += pParticle->m_RollSpeed * pDraw->GetTimeDelta();

	// delayed?
	if(pParticle->m_Lifetime < 0.0f)
	{
		// not alive yet
		return true;
	}

	// Draw.
	float lifetimePercent = ( pParticle->m_Lifetime - AR2_DUST_FADE_IN_TIME ) / pParticle->m_Dwell;

	// FIXME: base color should be a dirty version of the material color
	Vector color = g_AR2DustColor1 * (1.0 - lifetimePercent) + g_AR2DustColor2 * lifetimePercent;
	
	Vector tPos;
	TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos);
	// sortKey = tPos.z;
	
	float	alpha;

	if ( pParticle->m_Lifetime < AR2_DUST_FADE_IN_TIME )
	{
		alpha = AR2_DUST_ALPHA * ( pParticle->m_Lifetime / AR2_DUST_FADE_IN_TIME );
	}
	else
	{
		alpha = AR2_DUST_ALPHA * ( 1.0f - lifetimePercent );
	}

	alpha *= GetAlphaDistanceFade( tPos, 50, 150 );

	RenderParticle_ColorSizeAngle(
		pDraw,
		tPos,
		color,
		alpha,
		pParticle->m_Dist, // size based on how far it's traveled
		pParticle->m_Roll);

	// Move it (this comes after rendering to make it clear that moving the particle here won't change
	// its rendering for this frame since m_TransformedPos has already been set).
	pParticle->m_Pos = pParticle->m_Pos + pParticle->m_Velocity * dt;

	// keep track of distance traveled
	pParticle->m_Dist = pParticle->m_Dist + pParticle->m_Velocity.Length() * dt;

	// Dampen velocity.
	float dist = pParticle->m_Velocity.Length()	* dt;
	float r = dist * dist;
	// FIXME: this is a really screwy air-resistance function....
	pParticle->m_Velocity = pParticle->m_Velocity * (100 / (100 + r )); 

	// dampen roll
	static float dtime;
	static float decay;
	if (dtime != dt)
	{
		dtime = dt;
		decay = ExponentialDecay( 0.3, 1.0, dtime );
	}
	if (fabs(pParticle->m_RollSpeed) > 0.2)
		pParticle->m_RollSpeed = pParticle->m_RollSpeed * decay;

	return true;
}
void C_ParticleSmokeGrenade::RenderParticles( CParticleRenderIterator *pIterator )
{
	const SmokeGrenadeParticle *pParticle = (const SmokeGrenadeParticle*)pIterator->GetFirst();
	while ( pParticle )
	{
		Vector vWorldSpacePos = m_SmokeBasePos + pParticle->m_Pos;

		float sortKey;

		// Draw.
		float len = pParticle->m_Pos.Length();
		if ( len > m_ExpandRadius )
		{
			Vector vTemp;
			TransformParticle(ParticleMgr()->GetModelView(), vWorldSpacePos, vTemp);
			sortKey = vTemp.z;		
		}
		else
		{
			// This smooths out the growing sphere. Rather than having particles appear in one spot as the sphere
			// expands, they stay at the borders.
			Vector renderPos;
			if(len > m_ExpandRadius * 0.5f)
			{
				renderPos = m_SmokeBasePos + (pParticle->m_Pos * (m_ExpandRadius * 0.5f)) / len;
			}
			else
			{
				renderPos = vWorldSpacePos;
			}		

			// Figure out the alpha based on where it is in the sphere.
			float alpha = 1 - len / m_ExpandRadius;
			
			// This changes the ramp to be very solid in the core, then taper off.
			static float testCutoff=0.7;
			if(alpha > testCutoff)
			{
				alpha = 1;
			}
			else
			{
				// at testCutoff it's 1, at 0, it's 0
				alpha = alpha / testCutoff;
			}

			// Fade out globally.
			alpha *= m_FadeAlpha;

			// Apply the precalculated fade alpha from world geometry.
			alpha *= pParticle->m_FadeAlpha;

			// TODO: optimize this whole routine!
			Vector color = m_MinColor + (m_MaxColor - m_MinColor) * (pParticle->m_ColorInterp / 255.1f);
			color.x *= pParticle->m_Color[0] / 255.0f;
			color.y *= pParticle->m_Color[1] / 255.0f;
			color.z *= pParticle->m_Color[2] / 255.0f;

			// Lighting.
			ApplyDynamicLight( renderPos, color );
			
			Vector tRenderPos;
			TransformParticle(ParticleMgr()->GetModelView(), renderPos, tRenderPos);
			sortKey = tRenderPos.z;

			RenderParticle_ColorSizeAngle(
				pIterator->GetParticleDraw(),
				tRenderPos,
				color,
				alpha * GetAlphaDistanceFade(tRenderPos, 100, 200),	// Alpha
				SMOKEPARTICLE_SIZE,
				pParticle->m_CurRotation
				);
		}

		pParticle = (SmokeGrenadeParticle*)pIterator->GetNext( sortKey );
	}
}
void C_SmokeStack::SimulateParticles( CParticleSimulateIterator *pIterator )
{
	bool bSortNow = true; // Change this to false if we see sorting issues.
	bool bQuickTest = false;

	bool bDrawn = m_ParticleEffect.WasDrawnPrevFrame();

	if ( bDrawn == true && m_bInView == false )
	{
		bSortNow = true;
	}

	if ( bDrawn == false && m_bInView == true )
	{
		bQuickTest = true;
	}

	if( bQuickTest == false && m_bEmit && (!m_ParticleEffect.WasDrawnPrevFrame() && !m_ParticleEffect.GetAlwaysSimulate()) )
		return;

	SmokeStackParticle *pParticle = (SmokeStackParticle*)pIterator->GetFirst();
	while ( pParticle )
	{
		// Should this particle die?
		pParticle->m_Lifetime += pIterator->GetTimeDelta();

		float tLifetime = pParticle->m_Lifetime * m_InvLifetime;
		if( tLifetime >= 1 )
		{
			pIterator->RemoveParticle( pParticle );
		}
		else
		{
			// Transform.						   
			Vector tPos;
			if( m_bTwist )
			{
				Vector vTwist(
					pParticle->m_Pos.x - GetAbsOrigin().x,
					pParticle->m_Pos.y - GetAbsOrigin().y,
					0);

				pParticle->m_Pos.x = vTwist.x * m_TwistMat[0][0] + vTwist.y * m_TwistMat[0][1] + GetAbsOrigin().x;
				pParticle->m_Pos.y = vTwist.x * m_TwistMat[1][0] + vTwist.y * m_TwistMat[1][1] + GetAbsOrigin().y;
			}

			pParticle->m_Pos = pParticle->m_Pos + pParticle->m_Velocity * pIterator->GetTimeDelta() + pParticle->m_vAccel * pIterator->GetTimeDelta();
			pParticle->m_flAngle += pParticle->m_flRollDelta * pIterator->GetTimeDelta();

			if ( bSortNow == true )
			{
				Vector tPos;
				TransformParticle( m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos );
				pParticle->m_flSortPos = tPos.z;
			}
		}

		pParticle = (SmokeStackParticle*)pIterator->GetNext();
	}

	m_bInView = bDrawn;
}
bool C_ParticleSmokeGrenade::SimulateAndRender(Particle *pBaseParticle, ParticleDraw *pDraw, float &sortKey)
{
	SmokeGrenadeParticle* pParticle = (SmokeGrenadeParticle*)pBaseParticle;

	// Draw.
	float len = (pParticle->m_Pos - m_SmokeBasePos).Length();
	if(len > m_ExpandRadius)
	{
		Vector vTemp;
		TransformParticle(g_ParticleMgr.GetModelView(), pParticle->m_Pos, vTemp);
		sortKey = vTemp.z;		
		return true;
	}

	// This smooths out the growing sphere. Rather than having particles appear in one spot as the sphere
	// expands, they stay at the borders.
	Vector renderPos;
	if(len > m_ExpandRadius * 0.5f)
	{
		renderPos = m_SmokeBasePos + ((pParticle->m_Pos - m_SmokeBasePos) * (m_ExpandRadius * 0.5f)) / len;
	}
	else
	{
		renderPos = pParticle->m_Pos;
	}		

	// Figure out the alpha based on where it is in the sphere.
	float alpha = 1 - len / m_ExpandRadius;
	
	// This changes the ramp to be very solid in the core, then taper off.
	static float testCutoff=0.7;
	if(alpha > testCutoff)
	{
		alpha = 1;
	}
	else
	{
		// at testCutoff it's 1, at 0, it's 0
		alpha = alpha / testCutoff;
	}

	// Fade out globally.
	alpha *= m_FadeAlpha;


	pParticle->m_CurRotation += pParticle->m_RotationSpeed * pDraw->GetTimeDelta();

	// Apply the precalculated fade alpha from world geometry.
	alpha *= pParticle->m_FadeAlpha;
	
	// TODO: optimize this whole routine!
	Vector color = m_MinColor + (m_MaxColor - m_MinColor) * (pParticle->m_ColorInterp / 255.1f);
	color.x *= pParticle->m_Color[0] / 255.0f;
	color.y *= pParticle->m_Color[1] / 255.0f;
	color.z *= pParticle->m_Color[2] / 255.0f;
	
	Vector tRenderPos;
	TransformParticle(g_ParticleMgr.GetModelView(), renderPos, tRenderPos);
	sortKey = tRenderPos.z;

	RenderParticle_ColorSizeAngle(
		pDraw,
		tRenderPos,
		color,
		alpha * GetAlphaDistanceFade(tRenderPos, 10, 30),	// Alpha
		SMOKEPARTICLE_SIZE,
		pParticle->m_CurRotation
		);

	return true;
}
//-----------------------------------------------------------------------------
// Purpose: Update state + render
//-----------------------------------------------------------------------------
bool CBasePlasmaProjectile::SimulateAndRender(Particle *pInParticle, ParticleDraw *pDraw, float &sortKey)
{
	if ( IsDormantPredictable() )
		return true;

	if ( GetMoveType() == MOVETYPE_NONE )
		return true;

	// Update the particle position
	pInParticle->m_Pos = GetAbsOrigin();

	// Add our blended offset
	if ( gpGlobals->curtime < m_Shared.GetSpawnTime() + REMAP_BLEND_TIME )
	{
		float frac = ( gpGlobals->curtime - m_Shared.GetSpawnTime() ) / REMAP_BLEND_TIME;
		frac = 1.0f - clamp( frac, 0.0f, 1.0f );
		Vector scaledOffset;
		VectorScale( m_vecGunOriginOffset, frac, scaledOffset );
		pInParticle->m_Pos += scaledOffset;
	}

	float timeDelta = pDraw->GetTimeDelta();

	// Render the head particle
	if ( pInParticle == m_pHeadParticle )
	{
		SimpleParticle *pParticle = (SimpleParticle *) pInParticle;
		pParticle->m_flLifetime += timeDelta;

		// Render
		Vector tPos, vecOrigin;
		RemapPosition( m_pPreviousPositions[MAX_HISTORY-1].m_Position, m_pPreviousPositions[MAX_HISTORY-1].m_Time, vecOrigin );

		TransformParticle( ParticleMgr()->GetModelView(), vecOrigin, tPos );
		sortKey = (int) tPos.z;

		//Render it
		RenderParticle_ColorSizeAngle(
			pDraw,
			tPos,
			UpdateColor( pParticle, timeDelta ),
			UpdateAlpha( pParticle, timeDelta ) * GetAlphaDistanceFade( tPos, 16, 64 ),
			UpdateScale( pParticle, timeDelta ),
			UpdateRoll( pParticle, timeDelta ) );

		/*
		if ( m_flNextSparkEffect < gpGlobals->curtime )
		{
			// Drop sparks?
			if ( GetTeamNumber() == TEAM_HUMANS )
			{
				g_pEffects->Sparks( pInParticle->m_Pos, 1, 3 );
			}
			else
			{
				g_pEffects->EnergySplash( pInParticle->m_Pos, vec3_origin );
			}
			m_flNextSparkEffect = gpGlobals->curtime + RandomFloat( 0.5, 2 );
		}
		*/

		return true;
	}

	// Render the trail
	TrailParticle *pParticle = (TrailParticle *) pInParticle;
	pParticle->m_flLifetime += timeDelta;
	Vector vecScreenStart, vecScreenDelta;
	sortKey = pParticle->m_Pos.z;

	// NOTE: We need to do everything in screen space
	float flFragmentLength = (MAX_HISTORY > 1) ? 1.0 / (float)(MAX_HISTORY-1) : 1.0;

	for ( int i = 0; i < (MAX_HISTORY-1); i++ )
	{
		Vector vecWorldStart, vecWorldEnd, vecScreenEnd;
		float flStartV, flEndV;

		// Did we just appear?
		if ( m_pPreviousPositions[i].m_Time == 0 )
			continue;

		RemapPosition( m_pPreviousPositions[i+1].m_Position, m_pPreviousPositions[i+1].m_Time, vecWorldStart );
		RemapPosition( m_pPreviousPositions[i].m_Position, m_pPreviousPositions[i].m_Time, vecWorldEnd );

		// Texture wrapping
		flStartV = (flFragmentLength * (i+1));
		flEndV = (flFragmentLength * i);
		
		TransformParticle( ParticleMgr()->GetModelView(), vecWorldStart, vecScreenStart );
		TransformParticle( ParticleMgr()->GetModelView(), vecWorldEnd, vecScreenEnd );
		Vector vecScreenDelta = (vecScreenEnd - vecScreenStart);
		if ( vecScreenDelta == vec3_origin )
			continue;

		/*
		Vector vecForward, vecRight;
		AngleVectors( MainViewAngles(), &vecForward, &vecRight, NULL );
		Vector vecWorldDelta = ( vecWorldEnd - vecWorldStart );
		VectorNormalize( vecWorldDelta );
		float flDot = fabs(DotProduct( vecWorldDelta, vecForward ));
		if ( flDot > 0.99 )
		{
			// Remap alpha
			pParticle->m_flColor[3] = 1.0 - min( 1.0, RemapVal( flDot, 0.99, 1.0, 0, 1 ) );
		}
		*/

		// See if we should fade
		float color[4];
		Color32ToFloat4( color, pParticle->m_color );
		Tracer_Draw( pDraw, vecScreenStart, vecScreenDelta, pParticle->m_flWidth, color, flStartV, flEndV );
	}

	return true;
}