Exemple #1
0
//-----------------------------------------------------------------------------
// Spew out dust!
//-----------------------------------------------------------------------------
void FX_Dust( const Vector &vecOrigin, const Vector &vecDirection, float flSize, float flSpeed )
{
	VPROF_BUDGET( "FX_Dust", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
	
	int	numPuffs = (flSize*0.5f);

	if ( numPuffs < 1 )
		numPuffs = 1;
	if ( numPuffs > 32 )
		numPuffs = 32;

	float speed = flSpeed * 0.1f;

	if ( speed < 0 )
		speed = 1.0f;
	if (speed > 48.0f )
		speed = 48.0f;

	//FIXME: Better sampling area
	Vector offset = vecOrigin + ( vecDirection * flSize );

	//Find area ambient light color and use it to tint smoke
	Vector	worldLight = WorldGetLightForPoint( offset, true );

	// Throw puffs
	SimpleParticle particle;
	for ( int i = 0; i < numPuffs; i++ )
	{
		offset.Random( -(flSize*0.25f), flSize*0.25f );
		offset += vecOrigin + ( vecDirection * flSize );

		particle.m_Pos = offset;
		particle.m_flLifetime = 0.0f;
		particle.m_flDieTime  = random->RandomFloat( 0.4f, 1.0f );
		
		particle.m_vecVelocity = vecDirection * random->RandomFloat( speed*0.5f, speed ) * i;
		particle.m_vecVelocity[2] = 0.0f;

		int	color = random->RandomInt( 48, 64 );

		particle.m_uchColor[0] = (color+16) + ( worldLight[0] * (float) color );
		particle.m_uchColor[1] = (color+8) + ( worldLight[1] * (float) color );
		particle.m_uchColor[2] = color + ( worldLight[2] * (float) color );

		particle.m_uchStartAlpha= random->RandomInt( 64, 128 );
		particle.m_uchEndAlpha	= 0;
		particle.m_uchStartSize = random->RandomInt( 2, 8 );
		particle.m_uchEndSize	= random->RandomInt( 24, 48 );
		particle.m_flRoll		= random->RandomInt( 0, 360 );
		particle.m_flRollDelta	= random->RandomFloat( -0.5f, 0.5f );

		AddSimpleParticle( &particle, g_Mat_DustPuff[random->RandomInt(0,1)] );
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void FX_GlassImpact( const Vector &pos, const Vector &normal )
{
	VPROF_BUDGET( "FX_GlassImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
	CSmartPtr<CSimple3DEmitter> pGlassEmitter = CSimple3DEmitter::Create( "FX_GlassImpact" );
	pGlassEmitter->SetSortOrigin( pos );

	Vector vecColor;
	engine->ComputeLighting( pos, NULL, true, vecColor );

	// HACK: Blend a little toward white to match the materials...
	VectorLerp( vecColor, Vector( 1, 1, 1 ), 0.3, vecColor );

	float flShardSize	= random->RandomFloat( 2.0f, 6.0f );

	unsigned char color[3] = { 200, 200, 210 };

	// ---------------------
	// Create glass shards
	// ----------------------

	int numShards = random->RandomInt( 2, 4 );

	for ( int i = 0; i < numShards; i++ )
	{
		Particle3D *pParticle;
		
		pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Glass[random->RandomInt(0,1)], pos );

		if ( pParticle )
		{
			pParticle->m_flLifeRemaining	= random->RandomFloat(GLASS_SHARD_MIN_LIFE,GLASS_SHARD_MAX_LIFE);

			pParticle->m_vecVelocity[0]		= ( normal[0] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED );
			pParticle->m_vecVelocity[1]		= ( normal[1] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED );
			pParticle->m_vecVelocity[2]		= ( normal[2] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED );

			pParticle->m_uchSize			= flShardSize + random->RandomFloat(-0.5*flShardSize,0.5*flShardSize);
			pParticle->m_vAngles			= RandomAngle( 0, 360 );
			pParticle->m_flAngSpeed			= random->RandomFloat(-800,800);

			pParticle->m_uchFrontColor[0]	= (byte)(color[0] * vecColor.x);
			pParticle->m_uchFrontColor[1]	= (byte)(color[1] * vecColor.y);
			pParticle->m_uchFrontColor[2]	= (byte)(color[2] * vecColor.z);
			pParticle->m_uchBackColor[0]	= (byte)(color[0] * vecColor.x);
			pParticle->m_uchBackColor[1]	= (byte)(color[1] * vecColor.y);
			pParticle->m_uchBackColor[2]	= (byte)(color[2] * vecColor.z);
		}
	}

	pGlassEmitter->m_ParticleCollision.Setup( pos, &normal, GLASS_SHARD_NOISE, GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED, GLASS_SHARD_GRAVITY, GLASS_SHARD_DAMPING );

	color[0] = 64;
	color[1] = 64;
	color[2] = 92;

	// ---------------------------
	// Dust
	// ---------------------------

	Vector	dir;
	Vector	offset = pos + ( normal * 2.0f );
	float	colorRamp;

	SimpleParticle newParticle;

	for ( int i = 0; i < 4; i++ )
	{
		newParticle.m_Pos = offset;

		newParticle.m_flLifetime= 0.0f;
		newParticle.m_flDieTime	= random->RandomFloat( 0.1f, 0.25f );
		
		dir[0] = normal[0] + random->RandomFloat( -0.8f, 0.8f );
		dir[1] = normal[1] + random->RandomFloat( -0.8f, 0.8f );
		dir[2] = normal[2] + random->RandomFloat( -0.8f, 0.8f );

		newParticle.m_uchStartSize	= random->RandomInt( 1, 4 );
		newParticle.m_uchEndSize	= newParticle.m_uchStartSize * 8;

		newParticle.m_vecVelocity	= dir * random->RandomFloat( 8.0f, 16.0f )*(i+1);
		newParticle.m_vecVelocity[2] -= random->RandomFloat( 16.0f, 32.0f )*(i+1);

		newParticle.m_uchStartAlpha	= random->RandomInt( 128, 255 );
		newParticle.m_uchEndAlpha	= 0;
		
		newParticle.m_flRoll		= random->RandomFloat( 0, 360 );
		newParticle.m_flRollDelta	= random->RandomFloat( -1, 1 );

		colorRamp = random->RandomFloat( 0.5f, 1.25f );

		newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
		newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
		newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;

		AddSimpleParticle( &newParticle, g_Mat_BloodPuff[0] );
	}

	//
	// Bullet hole capper
	//
	newParticle.m_Pos = offset;

	newParticle.m_flLifetime		= 0.0f;
	newParticle.m_flDieTime		= random->RandomFloat( 1.0f, 1.5f );

	dir[0] = normal[0] + random->RandomFloat( -0.8f, 0.8f );
	dir[1] = normal[1] + random->RandomFloat( -0.8f, 0.8f );
	dir[2] = normal[2] + random->RandomFloat( -0.8f, 0.8f );

	newParticle.m_uchStartSize	= random->RandomInt( 4, 8 );
	newParticle.m_uchEndSize		= newParticle.m_uchStartSize * 4.0f;

	newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 8.0f );
	newParticle.m_vecVelocity[2] = random->RandomFloat( -2.0f, 2.0f );

	newParticle.m_uchStartAlpha	= random->RandomInt( 32, 64 );
	newParticle.m_uchEndAlpha	= 0;
	
	newParticle.m_flRoll			= random->RandomFloat( 0, 360 );
	newParticle.m_flRollDelta	= random->RandomFloat( -2, 2 );

	colorRamp = random->RandomFloat( 0.5f, 1.25f );

	newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
	newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
	newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;

	AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] );
}
//-----------------------------------------------------------------------------
// Purpose: Debris flecks caused by impacts
// Input  : origin - start
//			*trace - trace information
//			*materialName - material hit
//			materialType - type of material hit
//-----------------------------------------------------------------------------
void FX_DebrisFlecks( const Vector& origin, trace_t *tr, char materialType, int iScale, bool bNoFlecks )
{
	VPROF_BUDGET( "FX_DebrisFlecks", VPROF_BUDGETGROUP_PARTICLE_RENDERING );

	if ( !fx_drawimpactdebris.GetBool() )
		return;

#ifdef _XBOX

	//
	// XBox version
	//

	Vector	offset;
	float	spread = 0.2f;

	CSmartPtr<CDustParticle> pSimple = CDustParticle::Create( "dust" );
	pSimple->SetSortOrigin( origin );
	
	// Lock the bbox
	pSimple->GetBinding().SetBBox( origin - ( Vector( 16, 16, 16 ) * iScale ), origin + ( Vector( 16, 16, 16 ) * iScale ) );

	// Get the color of the surface we've impacted
	Vector	color;
	float	colorRamp;
	GetColorForSurface( tr, &color );

	int i;
	SimpleParticle	*pParticle;
	for ( i = 0; i < 4; i++ )
	{
		if ( i == 3 )
		{
			pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin );
		}
		else
		{
			pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin );
		}

		if ( pParticle != NULL )
		{
			pParticle->m_flLifetime = 0.0f;
			pParticle->m_flDieTime	= random->RandomFloat( 0.5f, 1.0f );

			pParticle->m_vecVelocity.Random( -spread, spread );
			pParticle->m_vecVelocity += ( tr->plane.normal * random->RandomFloat( 1.0f, 6.0f ) );

			VectorNormalize( pParticle->m_vecVelocity );

			float	fForce = random->RandomFloat( 250, 500 ) * i * 0.5f;

			// scaled
			pParticle->m_vecVelocity *= fForce * iScale;

			// Ramp the color
			colorRamp = random->RandomFloat( 0.5f, 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;

			// scaled
			pParticle->m_uchStartSize	= (iScale*0.5f) * random->RandomInt( 3, 4 ) * (i+1);

			// scaled
			pParticle->m_uchEndSize		= (iScale*0.5f) * pParticle->m_uchStartSize * 4;

			pParticle->m_uchStartAlpha	= random->RandomInt( 200, 255 );
			pParticle->m_uchEndAlpha	= 0;

			pParticle->m_flRoll			= random->RandomInt( 0, 360 );
			pParticle->m_flRollDelta	= random->RandomFloat( -1.0f, 1.0f );
		}
	}			

	// Covers the impact spot with flecks
	pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_DustPuff2, origin );

	if ( pParticle != NULL )
	{
		offset = origin;
		offset[0] += random->RandomFloat( -8.0f, 8.0f );
		offset[1] += random->RandomFloat( -8.0f, 8.0f );

		pParticle->m_flLifetime = 0.0f;
		pParticle->m_flDieTime	= random->RandomFloat( 0.5f, 1.0f );

		spread = 1.0f;

		pParticle->m_vecVelocity.Init();

		colorRamp = random->RandomFloat( 0.5f, 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	= random->RandomInt( 4, 8 );
		pParticle->m_uchEndSize		= pParticle->m_uchStartSize * 4;

		pParticle->m_uchStartAlpha	= random->RandomInt( 64, 128 );
		pParticle->m_uchEndAlpha	= 0;

		pParticle->m_flRoll			= random->RandomInt( 0, 360 );
		pParticle->m_flRollDelta	= random->RandomFloat( -0.1f, 0.1f );
	}

#else

	//
	// PC version
	//

	Vector	color;
	GetColorForSurface( tr, &color );

	if ( !bNoFlecks )
	{
		CreateFleckParticles( origin, color, tr, materialType, iScale );
	}

	//
	// Dust trail
	//
	Vector	offset = tr->endpos + ( tr->plane.normal * 2.0f );

	SimpleParticle newParticle;

	int i;
	for ( i = 0; i < 2; i++ )
	{
		newParticle.m_Pos = offset;

		newParticle.m_flLifetime	= 0.0f;
		newParticle.m_flDieTime	= 1.0f;

		Vector dir;
		dir[0] = tr->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
		dir[1] = tr->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
		dir[2] = tr->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );

		newParticle.m_uchStartSize	= random->RandomInt( 2, 4 ) * iScale;
		newParticle.m_uchEndSize	= newParticle.m_uchStartSize * 8 * iScale;

		newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 24.0f )*(i+1);
		newParticle.m_vecVelocity[2] -= random->RandomFloat( 8.0f, 32.0f )*(i+1);

		newParticle.m_uchStartAlpha	= random->RandomInt( 100, 200 );
		newParticle.m_uchEndAlpha	= 0;

		newParticle.m_flRoll			= random->RandomFloat( 0, 360 );
		newParticle.m_flRollDelta	= random->RandomFloat( -1, 1 );

		float colorRamp = random->RandomFloat( 0.5f, 1.25f );

		newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
		newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
		newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;

		AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] );
	}


	for ( i = 0; i < 4; i++ )
	{
		newParticle.m_Pos = offset;

		newParticle.m_flLifetime	= 0.0f;
		newParticle.m_flDieTime	= random->RandomFloat( 0.25f, 0.5f );

		Vector dir;
		dir[0] = tr->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
		dir[1] = tr->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
		dir[2] = tr->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );

		newParticle.m_uchStartSize	= random->RandomInt( 1, 4 );
		newParticle.m_uchEndSize	= newParticle.m_uchStartSize * 4;

		newParticle.m_vecVelocity = dir * random->RandomFloat( 8.0f, 32.0f );
		newParticle.m_vecVelocity[2] -= random->RandomFloat( 8.0f, 64.0f );

		newParticle.m_uchStartAlpha	= 255;
		newParticle.m_uchEndAlpha	= 0;

		newParticle.m_flRoll			= random->RandomFloat( 0, 360 );
		newParticle.m_flRollDelta	= random->RandomFloat( -2.0f, 2.0f );

		float colorRamp = random->RandomFloat( 0.5f, 1.25f );

		newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
		newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
		newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;

		AddSimpleParticle( &newParticle, g_Mat_BloodPuff[0] );
	}

	//
	// Bullet hole capper
	//
	newParticle.m_Pos = offset;

	newParticle.m_flLifetime		= 0.0f;
	newParticle.m_flDieTime		= random->RandomFloat( 1.0f, 1.5f );

	Vector dir;
	dir[0] = tr->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
	dir[1] = tr->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
	dir[2] = tr->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );

	newParticle.m_uchStartSize	= random->RandomInt( 4, 8 );
	newParticle.m_uchEndSize		= newParticle.m_uchStartSize * 4.0f;

	newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 24.0f );
	newParticle.m_vecVelocity[2] = random->RandomFloat( -2.0f, 2.0f );

	newParticle.m_uchStartAlpha	= random->RandomInt( 100, 200 );
	newParticle.m_uchEndAlpha	= 0;

	newParticle.m_flRoll			= random->RandomFloat( 0, 360 );
	newParticle.m_flRollDelta	= random->RandomFloat( -2, 2 );

	float colorRamp = random->RandomFloat( 0.5f, 1.25f );

	newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
	newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
	newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;

	AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] );

#endif
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : &pos - 
//			&dir - 
//			type - 
//-----------------------------------------------------------------------------
void FX_GaussExplosion( const Vector &pos, const Vector &dir, int type )
{
	Vector	vDir;

	vDir[0] = dir[0] + random->RandomFloat( -1.0f, 1.0f );
	vDir[1] = dir[1] + random->RandomFloat( -1.0f, 1.0f );
	vDir[2] = dir[2] + random->RandomFloat( -1.0f, 1.0f );

	VectorNormalize( vDir );

	int i;

#if defined(_XBOX) || defined(_X360)

	//
	// XBox version
	//
	CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "FX_GaussExplosion" );
	if ( pSparkEmitter == NULL )
	{
		Assert(0);
		return;
	}

	if ( g_Material_Spark == NULL )
	{
		g_Material_Spark = pSparkEmitter->GetPMaterial( "effects/spark" );
	}

	pSparkEmitter->SetSortOrigin( pos );
	pSparkEmitter->m_ParticleCollision.SetGravity( 800.0f );
	pSparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
	pSparkEmitter->GetBinding().SetBBox( pos - Vector( 32, 32, 32 ), pos + Vector( 32, 32, 32 ) );

	int numSparks = random->RandomInt( 8, 16 );
	TrailParticle	*pParticle;
	
	// Dump out sparks
	for ( i = 0; i < numSparks; i++ )
	{
		pParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), g_Material_Spark, pos );

		if ( pParticle == NULL )
			return;

		pParticle->m_flLifetime	= 0.0f;

		vDir.Random( -0.6f, 0.6f );
		vDir += dir;
		VectorNormalize( vDir );
		
		pParticle->m_flWidth		= random->RandomFloat( 1.0f, 4.0f );
		pParticle->m_flLength		= random->RandomFloat( 0.01f, 0.1f );
		pParticle->m_flDieTime		= random->RandomFloat( 0.25f, 0.5f );
		
		pParticle->m_vecVelocity	= vDir * random->RandomFloat( 128, 512 );

		Color32Init( pParticle->m_color, 255, 255, 255, 255 );
	}

	// End cap
	SimpleParticle particle;

	particle.m_Pos = pos;
	particle.m_flLifetime = 0.0f;
	particle.m_flDieTime = 0.1f;
	particle.m_vecVelocity.Init();
	particle.m_flRoll = random->RandomInt( 0, 360 );
	particle.m_flRollDelta = 0.0f;
	particle.m_uchColor[0] = 255;
	particle.m_uchColor[1] = 255;
	particle.m_uchColor[2] = 255;
	particle.m_uchStartAlpha = 255;
	particle.m_uchEndAlpha = 255;
	particle.m_uchStartSize = random->RandomInt( 24, 32 );
	particle.m_uchEndSize = 0;

	AddSimpleParticle( &particle, ParticleMgr()->GetPMaterial( "effects/yellowflare" ) );

#else
	
	//
	// PC version
	//
	CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "FX_ElectricSpark" );

	if ( !pSparkEmitter )
	{
		Assert(0);
		return;
	}

	PMaterialHandle	hMaterial	= pSparkEmitter->GetPMaterial( "effects/spark" );

	pSparkEmitter->SetSortOrigin( pos );

	pSparkEmitter->m_ParticleCollision.SetGravity( 800.0f );
	pSparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN|bitsPARTICLE_TRAIL_COLLIDE );

	//Setup our collision information
	pSparkEmitter->m_ParticleCollision.Setup( pos, &vDir, 0.8f, 128, 512, 800, 0.3f );

	int numSparks = random->RandomInt( 16, 32 );
	TrailParticle	*pParticle;

	// Dump out sparks
	for ( i = 0; i < numSparks; i++ )
	{
		pParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, pos );

		if ( pParticle == NULL )
			return;

		pParticle->m_flLifetime	= 0.0f;

		vDir.Random( -0.6f, 0.6f );
		vDir += dir;
		VectorNormalize( vDir );

		pParticle->m_flWidth		= random->RandomFloat( 1.0f, 4.0f );
		pParticle->m_flLength		= random->RandomFloat( 0.01f, 0.1f );
		pParticle->m_flDieTime		= random->RandomFloat( 0.25f, 1.0f );

		pParticle->m_vecVelocity	= vDir * random->RandomFloat( 128, 512 );

		Color32Init( pParticle->m_color, 255, 255, 255, 255 );
	}


	FX_ElectricSpark( pos, 1, 1, &vDir );
#endif
}
Exemple #5
0
//-----------------------------------------------------------------------------
// Purpose: Debris flecks caused by impacts
// Input  : origin - start
//			*trace - trace information
//			*materialName - material hit
//			materialType - type of material hit
//-----------------------------------------------------------------------------
void FX_DebrisFlecks(const Vector& origin, trace_t *tr, char materialType, int iScale, bool bNoFlecks)
{
    VPROF_BUDGET("FX_DebrisFlecks", VPROF_BUDGETGROUP_PARTICLE_RENDERING);

    if (!fx_drawimpactdebris.GetBool())
        return;
    //
    // PC version
    //

    Vector	color;
    GetColorForSurface(tr, &color);

    if (!bNoFlecks)
    {
        CreateFleckParticles(origin, color, tr, materialType, iScale);
    }

    //
    // Dust trail
    //
    Vector	offset = tr->endpos + (tr->plane.normal * 2.0f);

    SimpleParticle newParticle;

    int i;
    for (i = 0; i < 2; i++)
    {
        newParticle.m_Pos = offset;

        newParticle.m_flLifetime = 0.0f;
        newParticle.m_flDieTime = 1.0f;

        Vector dir;
        dir[0] = tr->plane.normal[0] + random->RandomFloat(-0.8f, 0.8f);
        dir[1] = tr->plane.normal[1] + random->RandomFloat(-0.8f, 0.8f);
        dir[2] = tr->plane.normal[2] + random->RandomFloat(-0.8f, 0.8f);

        newParticle.m_uchStartSize = random->RandomInt(2, 4) * iScale;
        newParticle.m_uchEndSize = newParticle.m_uchStartSize * 8 * iScale;

        newParticle.m_vecVelocity = dir * random->RandomFloat(2.0f, 24.0f)*(i + 1);
        newParticle.m_vecVelocity[2] -= random->RandomFloat(8.0f, 32.0f)*(i + 1);

        newParticle.m_uchStartAlpha = random->RandomInt(100, 200);
        newParticle.m_uchEndAlpha = 0;

        newParticle.m_flRoll = random->RandomFloat(0, 360);
        newParticle.m_flRollDelta = random->RandomFloat(-1, 1);

        float colorRamp = random->RandomFloat(0.5f, 1.25f);

        newParticle.m_uchColor[0] = MIN(1.0f, color[0] * colorRamp)*255.0f;
        newParticle.m_uchColor[1] = MIN(1.0f, color[1] * colorRamp)*255.0f;
        newParticle.m_uchColor[2] = MIN(1.0f, color[2] * colorRamp)*255.0f;

        AddSimpleParticle(&newParticle, g_Mat_DustPuff[0]);
    }


    for (i = 0; i < 4; i++)
    {
        newParticle.m_Pos = offset;

        newParticle.m_flLifetime = 0.0f;
        newParticle.m_flDieTime = random->RandomFloat(0.25f, 0.5f);

        Vector dir;
        dir[0] = tr->plane.normal[0] + random->RandomFloat(-0.8f, 0.8f);
        dir[1] = tr->plane.normal[1] + random->RandomFloat(-0.8f, 0.8f);
        dir[2] = tr->plane.normal[2] + random->RandomFloat(-0.8f, 0.8f);

        newParticle.m_uchStartSize = random->RandomInt(1, 4);
        newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4;

        newParticle.m_vecVelocity = dir * random->RandomFloat(8.0f, 32.0f);
        newParticle.m_vecVelocity[2] -= random->RandomFloat(8.0f, 64.0f);

        newParticle.m_uchStartAlpha = 255;
        newParticle.m_uchEndAlpha = 0;

        newParticle.m_flRoll = random->RandomFloat(0, 360);
        newParticle.m_flRollDelta = random->RandomFloat(-2.0f, 2.0f);

        float colorRamp = random->RandomFloat(0.5f, 1.25f);

        newParticle.m_uchColor[0] = MIN(1.0f, color[0] * colorRamp)*255.0f;
        newParticle.m_uchColor[1] = MIN(1.0f, color[1] * colorRamp)*255.0f;
        newParticle.m_uchColor[2] = MIN(1.0f, color[2] * colorRamp)*255.0f;

        AddSimpleParticle(&newParticle, g_Mat_BloodPuff[0]);
    }

    //
    // Bullet hole capper
    //
    newParticle.m_Pos = offset;

    newParticle.m_flLifetime = 0.0f;
    newParticle.m_flDieTime = random->RandomFloat(1.0f, 1.5f);

    Vector dir;
    dir[0] = tr->plane.normal[0] + random->RandomFloat(-0.8f, 0.8f);
    dir[1] = tr->plane.normal[1] + random->RandomFloat(-0.8f, 0.8f);
    dir[2] = tr->plane.normal[2] + random->RandomFloat(-0.8f, 0.8f);

    newParticle.m_uchStartSize = random->RandomInt(4, 8);
    newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4.0f;

    newParticle.m_vecVelocity = dir * random->RandomFloat(2.0f, 24.0f);
    newParticle.m_vecVelocity[2] = random->RandomFloat(-2.0f, 2.0f);

    newParticle.m_uchStartAlpha = random->RandomInt(100, 200);
    newParticle.m_uchEndAlpha = 0;

    newParticle.m_flRoll = random->RandomFloat(0, 360);
    newParticle.m_flRollDelta = random->RandomFloat(-2, 2);

    float colorRamp = random->RandomFloat(0.5f, 1.25f);

    newParticle.m_uchColor[0] = MIN(1.0f, color[0] * colorRamp)*255.0f;
    newParticle.m_uchColor[1] = MIN(1.0f, color[1] * colorRamp)*255.0f;
    newParticle.m_uchColor[2] = MIN(1.0f, color[2] * colorRamp)*255.0f;

    AddSimpleParticle(&newParticle, g_Mat_DustPuff[0]);
}
void C_TEAntlionDust::PostDataUpdate( DataUpdateType_t updateType )
{
	// This style of creating dust emitters is now deprecated; we use the simple particle singleton exclusively.
	/*
	CSmartPtr<CAntlionDustEmitter> pDustEmitter = CAntlionDustEmitter::Create( "TEAntlionDust" );
	Assert( pDustEmitter );
	if ( pDustEmitter == NULL )
		return;

	pDustEmitter->SetSortOrigin( m_vecOrigin );
	pDustEmitter->SetNearClip( 32, 64 );
	pDustEmitter->GetBinding().SetBBox( m_vecOrigin - Vector( 32, 32, 32 ), m_vecOrigin + Vector( 32, 32, 32 ) );
	*/

	Vector	offset;
	Vector	vecColor;
	GetDustColor( vecColor );

	int iParticleCount = 16;

	if ( m_bBlockedSpawner == true )
	{
		iParticleCount = 8;
	}

	//Spawn the dust
	SimpleParticle particle;
	for ( int i = 0; i < iParticleCount; i++ )
	{
		//Offset this dust puff's origin
		offset[0] = random->RandomFloat( -DUST_RADIUS, DUST_RADIUS );
		offset[1] = random->RandomFloat( -DUST_RADIUS, DUST_RADIUS );
		offset[2] = random->RandomFloat(  -16, 8 );
		
		offset += m_vecOrigin;

		particle.m_Pos = offset;
		particle.m_flDieTime	= random->RandomFloat( 0.75f, 1.25f );
		particle.m_flLifetime	= 0.0f;
		
		Vector	dir	= particle.m_Pos - m_vecOrigin;
		particle.m_vecVelocity = dir * random->RandomFloat( 0.5f, 1.0f );
		dir.z = fabs(dir.z);

		float	colorRamp = random->RandomFloat( 0.5f, 1.0f );
		Vector	color = vecColor*colorRamp;

		color[0] = clamp( color[0], 0.0f, 1.0f );
		color[1] = clamp( color[1], 0.0f, 1.0f );
		color[2] = clamp( color[2], 0.0f, 1.0f );

		color *= 255;

		particle.m_uchColor[0]	= color[0];
		particle.m_uchColor[1]	= color[1];
		particle.m_uchColor[2]	= color[2];

		particle.m_uchStartAlpha= random->RandomFloat( 64, 128 );
		particle.m_uchEndAlpha	= 0;

		particle.m_uchStartSize	= random->RandomInt( 16, 32 );
		particle.m_uchEndSize	= particle.m_uchStartSize * 3;
		particle.m_flRoll		= random->RandomInt( 0, 360 );
		particle.m_flRollDelta	= random->RandomFloat( -0.2f, 0.2f );

		// Though it appears there are two particle handle entries in g_Mat_DustPuff, in fact
		// only the one present at index 0 actually draws. Trying to spawn a particle with
		// the other material will give you no particle at all. Therefore while instead of this:
		// AddSimpleParticle( &particle, g_Mat_DustPuff[random->RandomInt(0,1)  );
		// we have to do this:
		AddSimpleParticle( &particle, g_Mat_DustPuff[0] );
	}
}
void CGasolineEmitter::UpdateFire( float frametime )
{
	float flLifetime = gpGlobals->curtime - m_pBlob->m_flCreateTime;

	float litPercent = 1;
	if ( m_pBlob->IsLit() )
	{
		litPercent = 1 - (flLifetime / m_pBlob->m_flMaxLifetime);
		if ( litPercent <= 0 )
			return;
	}
	else
	{
		return;
	}

	// Don't show a burn effect for a blob that hasn't hit anything yet.
	// If you do, it tends to make the flamethrower effect look weird.
	if ( !m_pBlob->IsStopped() )
		return;

	// Make a coordinate system in which to spawn the particles. It 
	Vector vUp, vRight;
	vUp.Init();
	vRight.Init();
	if ( m_pBlob->IsStopped() )
	{
		QAngle angles;
		VectorAngles( m_pBlob->GetSurfaceNormal(), angles );
		AngleVectors( angles, NULL, &vRight, &vUp );
	}
	
	PMaterialHandle hMaterial = m_hFireMaterial;
	float flParticleLifetime = 1;
	float flRadius = 7;
	unsigned char uchColor[4] = { 255, 128, 0, 128 };
	float flMaxZVel = 29;


	float curDelta = frametime;
	while ( m_Timer.NextEvent( curDelta ) )
	{
		// Based on how close we are to expiring, show less particles.
		if ( RandomFloat( 0, 1 ) > litPercent )
			continue;

		Vector vPos = m_pBlob->GetAbsOrigin();
		if ( m_pBlob->IsStopped() )
		{
			float flAngle = RandomFloat( 0, M_PI * 2 );
			float flDist = RandomFloat( 0, GASOLINE_BLOB_RADIUS );
			vPos += vRight * (cos( flAngle ) * flDist);
			vPos += vUp * ( sin( flAngle ) * flDist );
		}
		else
		{
			vPos += RandomVector( -GASOLINE_BLOB_RADIUS, GASOLINE_BLOB_RADIUS );
		}
		
		SimpleParticle *pParticle = AddSimpleParticle( hMaterial, vPos, flParticleLifetime, flRadius );
		if ( pParticle )
		{
			pParticle->m_uchColor[0] = uchColor[0];
			pParticle->m_uchColor[1] = uchColor[1];
			pParticle->m_uchColor[2] = uchColor[2];

			pParticle->m_uchEndAlpha = 0;
			pParticle->m_uchStartAlpha = uchColor[3];

			pParticle->m_vecVelocity.x = RandomFloat( -2, 2 );
			pParticle->m_vecVelocity.y = RandomFloat( -2, 2 );
			pParticle->m_vecVelocity.z = RandomFloat( 3, flMaxZVel );
		}
	}
}
void FX_ElectricSpark( const Vector &pos, int nMagnitude, int nTrailLength, const Vector *vecDir )
{
	VPROF_BUDGET( "FX_ElectricSpark", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
	CSmartPtr<CTrailParticles> pSparkEmitter	= CTrailParticles::Create( "FX_ElectricSpark 1" );

	if ( !pSparkEmitter )
	{
		Assert(0);
		return;
	}

	if ( g_Material_Spark == NULL )
	{
		g_Material_Spark = pSparkEmitter->GetPMaterial( "effects/spark" );
	}

	//Setup our collision information
	pSparkEmitter->Setup( (Vector &) pos, 
							NULL, 
							SPARK_ELECTRIC_SPREAD, 
							SPARK_ELECTRIC_MINSPEED, 
							SPARK_ELECTRIC_MAXSPEED, 
							SPARK_ELECTRIC_GRAVITY, 
							SPARK_ELECTRIC_DAMPEN, 
							bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );

	pSparkEmitter->SetSortOrigin( pos );

	//
	// Big sparks.
	//
	Vector	dir;
	int		numSparks = nMagnitude * nMagnitude * random->RandomFloat( 2, 4 );

	int i;
	TrailParticle	*pParticle;
	for ( i = 0; i < numSparks; i++ )
	{
		pParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), g_Material_Spark, pos );

		if ( pParticle == NULL )
			return;

		pParticle->m_flLifetime	= 0.0f;
		pParticle->m_flDieTime	= nMagnitude * random->RandomFloat( 1.0f, 2.0f );

		dir.Random( -1.0f, 1.0f );
		dir[2] = random->RandomFloat( 0.5f, 1.0f );
	
		if ( vecDir )
		{
			dir += 2 * (*vecDir);
			VectorNormalize( dir );
		}
			
		pParticle->m_flWidth		= random->RandomFloat( 2.0f, 5.0f );
		pParticle->m_flLength		= nTrailLength * random->RandomFloat( 0.02, 0.05f );
		
		pParticle->m_vecVelocity	= dir * random->RandomFloat( SPARK_ELECTRIC_MINSPEED, SPARK_ELECTRIC_MAXSPEED );

		Color32Init( pParticle->m_color, 255, 255, 255, 255 );
	}

#ifdef _XBOX

	//
	// Cap
	//

	SimpleParticle sParticle;

	sParticle.m_Pos = pos;
	sParticle.m_flLifetime		= 0.0f;
	sParticle.m_flDieTime		= 0.2f;

	sParticle.m_vecVelocity.Init();

	sParticle.m_uchColor[0]	= 255;
	sParticle.m_uchColor[1]	= 255;
	sParticle.m_uchColor[2]	= 255;
	sParticle.m_uchStartAlpha	= 255;
	sParticle.m_uchEndAlpha	= 255;
	sParticle.m_uchStartSize	= nMagnitude * random->RandomInt( 4, 8 );
	sParticle.m_uchEndSize		= 0;
	sParticle.m_flRoll			= random->RandomInt( 0, 360 );
	sParticle.m_flRollDelta	= 0.0f;

	AddSimpleParticle( &sParticle, ParticleMgr()->GetPMaterial( "effects/yellowflare" ) );

#else

	//
	// Little sparks
	//
	
	CSmartPtr<CTrailParticles> pSparkEmitter2	= CTrailParticles::Create( "FX_ElectricSpark 2" );

	if ( !pSparkEmitter2 )
	{
		Assert(0);
		return;
	}

	pSparkEmitter2->SetSortOrigin( pos );
	
	pSparkEmitter2->m_ParticleCollision.SetGravity( 400.0f );
	pSparkEmitter2->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );

	numSparks = nMagnitude * random->RandomInt( 16, 32 );

	// Dump out sparks
	for ( i = 0; i < numSparks; i++ )
	{
		pParticle = (TrailParticle *) pSparkEmitter2->AddParticle( sizeof(TrailParticle), g_Material_Spark, pos );

		if ( pParticle == NULL )
			return;

		pParticle->m_flLifetime	= 0.0f;

		dir.Random( -1.0f, 1.0f );
		if ( vecDir )
		{
			dir += *vecDir;
			VectorNormalize( dir );
		}
		
		pParticle->m_flWidth		= random->RandomFloat( 2.0f, 4.0f );
		pParticle->m_flLength		= nTrailLength * random->RandomFloat( 0.02f, 0.03f );
		pParticle->m_flDieTime		= nMagnitude * random->RandomFloat( 0.1f, 0.2f );
		
		pParticle->m_vecVelocity	= dir * random->RandomFloat( 128, 256 );

		Color32Init( pParticle->m_color, 255, 255, 255, 255 );
	}

	//
	// Caps
	//
	CSmartPtr<CSimpleGlowEmitter> pSimple = CSimpleGlowEmitter::Create( "FX_ElectricSpark 3", pos, gpGlobals->curtime + 0.2 );

	// NOTE: None of these will render unless the effect is visible!
	//
	// Inner glow
	//
	SimpleParticle *sParticle;

	sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/yellowflare_noz" ), pos );
		
	if ( sParticle == NULL )
		return;

	sParticle->m_flLifetime		= 0.0f;
	sParticle->m_flDieTime		= 0.2f;
	
	sParticle->m_vecVelocity.Init();

	sParticle->m_uchColor[0]	= 255;
	sParticle->m_uchColor[1]	= 255;
	sParticle->m_uchColor[2]	= 255;
	sParticle->m_uchStartAlpha	= 255;
	sParticle->m_uchEndAlpha	= 255;
	sParticle->m_uchStartSize	= nMagnitude * random->RandomInt( 4, 8 );
	sParticle->m_uchEndSize		= 0;
	sParticle->m_flRoll			= random->RandomInt( 0, 360 );
	sParticle->m_flRollDelta	= 0.0f;
	
	sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/yellowflare_noz" ), pos );
		
	if ( sParticle == NULL )
		return;

	sParticle->m_flLifetime		= 0.0f;
	sParticle->m_flDieTime		= 0.2f;
	
	sParticle->m_vecVelocity.Init();

	float	fColor = random->RandomInt( 32, 64 );
	sParticle->m_uchColor[0]	= fColor;
	sParticle->m_uchColor[1]	= fColor;
	sParticle->m_uchColor[2]	= fColor;
	sParticle->m_uchStartAlpha	= fColor;
	sParticle->m_uchEndAlpha	= 0;
	sParticle->m_uchStartSize	= nMagnitude * random->RandomInt( 32, 64 );
	sParticle->m_uchEndSize		= 0;
	sParticle->m_flRoll			= random->RandomInt( 0, 360 );
	sParticle->m_flRollDelta	= random->RandomFloat( -1.0f, 1.0f );

	//
	// Smoke
	//
	Vector	sOffs;

	sOffs[0] = pos[0] + random->RandomFloat( -4.0f, 4.0f );
	sOffs[1] = pos[1] + random->RandomFloat( -4.0f, 4.0f );
	sOffs[2] = pos[2];

	sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[1], sOffs );
		
	if ( sParticle == NULL )
		return;

	sParticle->m_flLifetime		= 0.0f;
	sParticle->m_flDieTime		= 1.0f;
	
	sParticle->m_vecVelocity.Init();
	
	sParticle->m_vecVelocity[2] = 16.0f;
	
	sParticle->m_vecVelocity[0] = random->RandomFloat( -16.0f, 16.0f );
	sParticle->m_vecVelocity[1] = random->RandomFloat( -16.0f, 16.0f );

	sParticle->m_uchColor[0]	= 255;
	sParticle->m_uchColor[1]	= 255;
	sParticle->m_uchColor[2]	= 200;
	sParticle->m_uchStartAlpha	= random->RandomInt( 16, 32 );
	sParticle->m_uchEndAlpha	= 0;
	sParticle->m_uchStartSize	= random->RandomInt( 4, 8 );
	sParticle->m_uchEndSize		= sParticle->m_uchStartSize*4.0f;
	sParticle->m_flRoll			= random->RandomInt( 0, 360 );
	sParticle->m_flRollDelta	= random->RandomFloat( -2.0f, 2.0f );

	//
	// Dlight
	//

	/*
	dlight_t *dl= effects->CL_AllocDlight ( 0 );

	dl->origin	= pos;
	dl->color.r = dl->color.g = dl->color.b = 250;
	dl->radius	= random->RandomFloat(16,32);
	dl->die		= gpGlobals->curtime + 0.001;
	*/

#endif	// !_XBOX
}
void FX_DebrisFlecks( Vector& origin, trace_t *trace, char materialType, int iScale )
{
	VPROF_BUDGET( "FX_DebrisFlecks", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
	Vector	spawnOffset	= trace->endpos + ( trace->plane.normal * 1.0f );

	CSmartPtr<CFleckParticles> fleckEmitter = CFleckParticles::Create( "FX_DebrisFlecks" );

	if ( !fleckEmitter )
		return;

	fleckEmitter->SetSortOrigin( spawnOffset );

	// Handle increased scale
	float flMaxSpeed = FLECK_MAX_SPEED * iScale;
	float flAngularSpray = max( 0.2, FLECK_ANGULAR_SPRAY - ( (float)iScale * 0.2f) ); // More power makes the spray more controlled

	//Setup our collision information
	fleckEmitter->m_ParticleCollision.Setup( spawnOffset, &trace->plane.normal, flAngularSpray, FLECK_MIN_SPEED, flMaxSpeed, FLECK_GRAVITY, FLECK_DAMPEN );

	PMaterialHandle	hMaterial[2];
	
	switch ( materialType )
	{
	case CHAR_TEX_CONCRETE:
	default:
		hMaterial[0] = fleckEmitter->GetPMaterial( "effects/fleck_cement1" );
		hMaterial[1] = fleckEmitter->GetPMaterial( "effects/fleck_cement2" );
		break;
	}

	Vector	dir, end;
	
	Vector	color;
	float	colorRamp;

	GetColorForSurface( trace, &color );

	int	numFlecks = random->RandomInt( 4, 16 ) * iScale;

	FleckParticle	*pFleckParticle;

	//Dump out flecks
	int i;
	for ( i = 0; i < numFlecks; i++ )
	{
		pFleckParticle = (FleckParticle *) fleckEmitter->AddParticle( sizeof(FleckParticle), hMaterial[random->RandomInt(0,1)], spawnOffset );

		if ( pFleckParticle == NULL )
			break;

		pFleckParticle->m_flLifetime	= 0.0f;
		pFleckParticle->m_flDieTime		= 3.0f;

		dir[0] = trace->plane.normal[0] + random->RandomFloat( -flAngularSpray, flAngularSpray );
		dir[1] = trace->plane.normal[1] + random->RandomFloat( -flAngularSpray, flAngularSpray );
		dir[2] = trace->plane.normal[2] + random->RandomFloat( -flAngularSpray, flAngularSpray );

		pFleckParticle->m_uchSize		= random->RandomInt( 1, 2 );

		pFleckParticle->m_vecVelocity	= dir * ( random->RandomFloat( FLECK_MIN_SPEED, flMaxSpeed) * ( 3 - pFleckParticle->m_uchSize ) );
		
		pFleckParticle->m_flRoll		= random->RandomFloat( 0, 360 );
		pFleckParticle->m_flRollDelta	= random->RandomFloat( 0, 360 );

		colorRamp = random->RandomFloat( 0.75f, 1.25f );

		pFleckParticle->m_uchColor[0] = min( 1.0f, color[0]*colorRamp )*255.0f;
		pFleckParticle->m_uchColor[1] = min( 1.0f, color[1]*colorRamp )*255.0f;
		pFleckParticle->m_uchColor[2] = min( 1.0f, color[2]*colorRamp )*255.0f;
	}

	//
	// Dust trail
	//
	Vector	offset = trace->endpos + ( trace->plane.normal * 2.0f );

	SimpleParticle newParticle;
	hMaterial[0] = g_ParticleMgr.GetPMaterial( "particle/particle_smokegrenade" );

	for ( i = 0; i < 2; i++ )
	{
		newParticle.m_Pos = offset;

		newParticle.m_flLifetime	= 0.0f;
		newParticle.m_flDieTime	= 1.0f;
		
		dir[0] = trace->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
		dir[1] = trace->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
		dir[2] = trace->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );

		newParticle.m_uchStartSize	= random->RandomInt( 2, 4 ) * iScale;
		newParticle.m_uchEndSize	= newParticle.m_uchStartSize * 8 * iScale;

		newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 24.0f )*(i+1);
		newParticle.m_vecVelocity[2] -= random->RandomFloat( 8.0f, 32.0f )*(i+1);

		newParticle.m_uchStartAlpha	= random->RandomInt( 100, 200 );
		newParticle.m_uchEndAlpha	= 0;
		
		newParticle.m_flRoll			= random->RandomFloat( 0, 360 );
		newParticle.m_flRollDelta	= random->RandomFloat( -1, 1 );

		colorRamp = random->RandomFloat( 0.5f, 1.25f );

		newParticle.m_uchColor[0] = min( 1.0f, color[0]*colorRamp )*255.0f;
		newParticle.m_uchColor[1] = min( 1.0f, color[1]*colorRamp )*255.0f;
		newParticle.m_uchColor[2] = min( 1.0f, color[2]*colorRamp )*255.0f;

		AddSimpleParticle( &newParticle, hMaterial[0] );
	}

	for ( i = 0; i < 4; i++ )
	{
		newParticle.m_Pos = offset;

		newParticle.m_flLifetime	= 0.0f;
		newParticle.m_flDieTime	= random->RandomFloat( 0.25f, 0.5f );
		
		dir[0] = trace->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
		dir[1] = trace->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
		dir[2] = trace->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );

		newParticle.m_uchStartSize	= random->RandomInt( 1, 4 );
		newParticle.m_uchEndSize	= newParticle.m_uchStartSize * 4;

		newParticle.m_vecVelocity = dir * random->RandomFloat( 8.0f, 32.0f );
		newParticle.m_vecVelocity[2] -= random->RandomFloat( 8.0f, 64.0f );

		newParticle.m_uchStartAlpha	= 255;
		newParticle.m_uchEndAlpha	= 0;
		
		newParticle.m_flRoll			= random->RandomFloat( 0, 360 );
		newParticle.m_flRollDelta	= random->RandomFloat( -2.0f, 2.0f );

		colorRamp = random->RandomFloat( 0.5f, 1.25f );

		newParticle.m_uchColor[0] = min( 1.0f, color[0]*colorRamp )*255.0f;
		newParticle.m_uchColor[1] = min( 1.0f, color[1]*colorRamp )*255.0f;
		newParticle.m_uchColor[2] = min( 1.0f, color[2]*colorRamp )*255.0f;

		AddSimpleParticle( &newParticle, g_ParticleMgr.GetPMaterial("effects/blood") );
	}

	//
	// Bullet hole capper
	//
	newParticle.m_Pos = offset;

	newParticle.m_flLifetime		= 0.0f;
	newParticle.m_flDieTime		= random->RandomFloat( 1.0f, 1.5f );

	dir[0] = trace->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
	dir[1] = trace->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
	dir[2] = trace->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );

	newParticle.m_uchStartSize	= random->RandomInt( 4, 8 );
	newParticle.m_uchEndSize		= newParticle.m_uchStartSize * 4.0f;

	newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 24.0f );
	newParticle.m_vecVelocity[2] = random->RandomFloat( -2.0f, 2.0f );

	newParticle.m_uchStartAlpha	= random->RandomInt( 100, 200 );
	newParticle.m_uchEndAlpha	= 0;
	
	newParticle.m_flRoll			= random->RandomFloat( 0, 360 );
	newParticle.m_flRollDelta	= random->RandomFloat( -2, 2 );

	colorRamp = random->RandomFloat( 0.5f, 1.25f );

	newParticle.m_uchColor[0] = min( 1.0f, color[0]*colorRamp )*255.0f;
	newParticle.m_uchColor[1] = min( 1.0f, color[1]*colorRamp )*255.0f;
	newParticle.m_uchColor[2] = min( 1.0f, color[2]*colorRamp )*255.0f;

	AddSimpleParticle( &newParticle, hMaterial[0] );
}