source-sdk-2013-mapbase/sp/src/game/client/c_impact_effects.cpp
Alexander 'z33ky' Hirsch e9c45e5235 Implement GetColorForSurface() failure workaround
This function is used to color impact particles.
On Linux I've noticed that this function sometimes is not successful on
retrieving the surface color, leaving an odd color to render the
particles with. The engine function TraceLineMaterialAndLighting() even
has a boolean return value indicating success.
GetModelMaterialColorAndLighting() does not though, but I still observe
failures (the color parameter is not modified). The color is initialized
with an invalid value. If it detects that retrieving the color failed
(engine function said so or the invalid value was left in place), this
now hamfistedly assumes a lightish grey color, but at least still
correctly (presumably) incorporates lighting information.
When this situation is detected, a warning is also printed to the
console. Because why not.
2024-09-05 23:35:46 +02:00

1441 lines
45 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "fx.h"
#include "fx_sparks.h"
#include "clienteffectprecachesystem.h"
#include "particle_simple3d.h"
#include "decals.h"
#include "engine/IEngineSound.h"
#include "c_te_particlesystem.h"
#include "engine/ivmodelinfo.h"
#include "particles_ez.h"
#include "c_impact_effects.h"
#include "engine/IStaticPropMgr.h"
#include "tier0/vprof.h"
#include "c_te_effect_dispatch.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//Precahce the effects
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectImpacts )
CLIENTEFFECT_MATERIAL( "effects/fleck_cement1" )
CLIENTEFFECT_MATERIAL( "effects/fleck_cement2" )
CLIENTEFFECT_MATERIAL( "effects/fleck_antlion1" )
CLIENTEFFECT_MATERIAL( "effects/fleck_antlion2" )
CLIENTEFFECT_MATERIAL( "effects/fleck_wood1" )
CLIENTEFFECT_MATERIAL( "effects/fleck_wood2" )
CLIENTEFFECT_MATERIAL( "effects/blood" )
CLIENTEFFECT_MATERIAL( "effects/blood2" )
CLIENTEFFECT_MATERIAL( "sprites/bloodspray" )
CLIENTEFFECT_MATERIAL( "particle/particle_noisesphere" )
CLIENTEFFECT_REGISTER_END()
// Cached handles to commonly used materials
PMaterialHandle g_Mat_Fleck_Wood[2] = { NULL, NULL };
PMaterialHandle g_Mat_Fleck_Cement[2] = { NULL, NULL };
PMaterialHandle g_Mat_Fleck_Antlion[2] = { NULL, NULL };
PMaterialHandle g_Mat_Fleck_Glass[2] = { NULL, NULL };
PMaterialHandle g_Mat_Fleck_Tile[2] = { NULL, NULL };
PMaterialHandle g_Mat_DustPuff[2] = { NULL, NULL };
PMaterialHandle g_Mat_BloodPuff[2] = { NULL, NULL };
PMaterialHandle g_Mat_SMG_Muzzleflash[4] = { NULL, NULL, NULL, NULL };
PMaterialHandle g_Mat_Combine_Muzzleflash[3] = { NULL, NULL, NULL };
static ConVar fx_drawimpactdebris( "fx_drawimpactdebris", "1", FCVAR_DEVELOPMENTONLY, "Draw impact debris effects." );
static ConVar fx_drawimpactdust( "fx_drawimpactdust", "1", FCVAR_DEVELOPMENTONLY, "Draw impact dust effects." );
void FX_CacheMaterialHandles( void )
{
g_Mat_Fleck_Wood[0] = ParticleMgr()->GetPMaterial( "effects/fleck_wood1" );
g_Mat_Fleck_Wood[1] = ParticleMgr()->GetPMaterial( "effects/fleck_wood2" );
g_Mat_Fleck_Cement[0] = ParticleMgr()->GetPMaterial( "effects/fleck_cement1");
g_Mat_Fleck_Cement[1] = ParticleMgr()->GetPMaterial( "effects/fleck_cement2" );
g_Mat_Fleck_Antlion[0] = ParticleMgr()->GetPMaterial( "effects/fleck_antlion1" );
g_Mat_Fleck_Antlion[1] = ParticleMgr()->GetPMaterial( "effects/fleck_antlion2" );
g_Mat_Fleck_Glass[0] = ParticleMgr()->GetPMaterial( "effects/fleck_glass1" );
g_Mat_Fleck_Glass[1] = ParticleMgr()->GetPMaterial( "effects/fleck_glass2" );
g_Mat_Fleck_Tile[0] = ParticleMgr()->GetPMaterial( "effects/fleck_tile1" );
g_Mat_Fleck_Tile[1] = ParticleMgr()->GetPMaterial( "effects/fleck_tile2" );
g_Mat_DustPuff[0] = ParticleMgr()->GetPMaterial( "particle/particle_smokegrenade" );
g_Mat_DustPuff[1] = ParticleMgr()->GetPMaterial( "particle/particle_noisesphere" );
g_Mat_BloodPuff[0] = ParticleMgr()->GetPMaterial( "effects/blood" );
g_Mat_BloodPuff[1] = ParticleMgr()->GetPMaterial( "effects/blood2" );
#ifndef TF_CLIENT_DLL
g_Mat_SMG_Muzzleflash[0] = ParticleMgr()->GetPMaterial( "effects/muzzleflash1" );
g_Mat_SMG_Muzzleflash[1] = ParticleMgr()->GetPMaterial( "effects/muzzleflash2" );
g_Mat_SMG_Muzzleflash[2] = ParticleMgr()->GetPMaterial( "effects/muzzleflash3" );
g_Mat_SMG_Muzzleflash[3] = ParticleMgr()->GetPMaterial( "effects/muzzleflash4" );
#ifndef CSTRIKE_DLL
g_Mat_Combine_Muzzleflash[0] = ParticleMgr()->GetPMaterial( "effects/combinemuzzle1" );
g_Mat_Combine_Muzzleflash[1] = ParticleMgr()->GetPMaterial( "effects/combinemuzzle2" );
g_Mat_Combine_Muzzleflash[2] = ParticleMgr()->GetPMaterial( "effects/strider_muzzle" );
#endif
#endif
}
extern PMaterialHandle g_Material_Spark;
//-----------------------------------------------------------------------------
// Purpose: Returns the color given trace information
// Input : *trace - trace to get results for
// *color - return color, gamma corrected (0.0f to 1.0f)
//-----------------------------------------------------------------------------
void GetColorForSurface( trace_t *trace, Vector *color )
{
Vector baseColor = vec3_invalid, diffuseColor;
const char *kind;
if ( trace->DidHitWorld() )
{
if ( trace->hitbox == 0 )
{
kind = "World";
Vector end = trace->startpos + ( trace->endpos - trace->startpos ) * 1.1f;
// If we hit the world, then ask the world for the fleck color
if ( !engine->TraceLineMaterialAndLighting( trace->startpos, end, diffuseColor, baseColor ) ) {
baseColor = vec3_invalid; // Make sure this wasn't modified
}
}
else
{
kind = "Static Prop";
// In this case we hit a static prop.
staticpropmgr->GetStaticPropMaterialColorAndLighting( trace, trace->hitbox - 1, diffuseColor, baseColor );
}
}
else
{
// In this case, we hit an entity. Find out the model associated with it
C_BaseEntity *pEnt = trace->m_pEnt;
if ( !pEnt )
{
kind = "Null-Entity";
} else {
kind = "Entity";
ICollideable *pCollide = pEnt->GetCollideable();
int modelIndex = pCollide->GetCollisionModelIndex();
model_t* pModel = const_cast<model_t*>(modelinfo->GetModel( modelIndex ));
// Ask the model info about what we need to know
modelinfo->GetModelMaterialColorAndLighting( pModel, pCollide->GetCollisionOrigin(),
pCollide->GetCollisionAngles(), trace, diffuseColor, baseColor );
}
}
if ( baseColor == vec3_invalid )
{
Warning( "Couldn't find surface color of %s\n", kind );
baseColor = Vector( .5f, .5f, .5f );
diffuseColor = engine->GetLightForPoint( trace->endpos, true );
}
//Get final light value
color->x = pow( diffuseColor[0], 1.0f/2.2f ) * baseColor[0];
color->y = pow( diffuseColor[1], 1.0f/2.2f ) * baseColor[1];
color->z = pow( diffuseColor[2], 1.0f/2.2f ) * baseColor[2];
}
//-----------------------------------------------------------------------------
// This does the actual debris flecks
//-----------------------------------------------------------------------------
#define FLECK_MIN_SPEED 64.0f
#define FLECK_MAX_SPEED 128.0f
#define FLECK_GRAVITY 800.0f
#define FLECK_DAMPEN 0.3f
#define FLECK_ANGULAR_SPRAY 0.6f
#ifndef _XBOX
//
// PC ONLY!
//
static void CreateFleckParticles( const Vector& origin, const Vector &color, trace_t *trace, char materialType, int iScale )
{
Vector spawnOffset = trace->endpos + ( trace->plane.normal * 1.0f );
CSmartPtr<CFleckParticles> fleckEmitter = CFleckParticles::Create( "FX_DebrisFlecks", spawnOffset, Vector(5,5,5) );
if ( !fleckEmitter )
return;
// 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;
switch ( materialType )
{
case CHAR_TEX_WOOD:
hMaterial = g_Mat_Fleck_Wood;
break;
case CHAR_TEX_CONCRETE:
case CHAR_TEX_TILE:
default:
hMaterial = g_Mat_Fleck_Cement;
break;
}
Vector dir, end;
float colorRamp;
float fScale = g_pParticleSystemMgr->ParticleThrottleScaling() * (float)iScale;
int numFlecks = (int)( 0.5f + fScale * (float)( random->RandomInt( 4, 16 ) ) );
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;
}
}
#endif // _XBOX
//-----------------------------------------------------------------------------
// 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
}
#define GLASS_SHARD_MIN_LIFE 2.5f
#define GLASS_SHARD_MAX_LIFE 5.0f
#define GLASS_SHARD_NOISE 0.8
#define GLASS_SHARD_GRAVITY 800
#define GLASS_SHARD_DAMPING 0.3
#define GLASS_SHARD_MIN_SPEED 1
#define GLASS_SHARD_MAX_SPEED 300
//-----------------------------------------------------------------------------
// 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] );
}
void GlassImpactCallback( const CEffectData &data )
{
FX_GlassImpact( data.m_vOrigin, data.m_vNormal );
}
DECLARE_CLIENT_EFFECT( "GlassImpact", GlassImpactCallback );
//-----------------------------------------------------------------------------
// Purpose:
// Input : &pos -
// *tr -
//-----------------------------------------------------------------------------
void FX_AntlionImpact( const Vector &pos, trace_t *trace )
{
#if defined( _X360 )
return;
#endif // _X360
VPROF_BUDGET( "FX_AntlionImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
CSmartPtr<CSimple3DEmitter> fleckEmitter = CSimple3DEmitter::Create( "FX_DebrisFlecks" );
if ( fleckEmitter == NULL )
return;
Vector shotDir = ( trace->startpos - trace->endpos );
VectorNormalize( shotDir );
Vector spawnOffset = trace->endpos + ( shotDir * 2.0f );
Vector vWorldMins, vWorldMaxs;
if ( trace->m_pEnt )
{
float scale = trace->m_pEnt->CollisionProp()->BoundingRadius();
vWorldMins[0] = spawnOffset[0] - scale;
vWorldMins[1] = spawnOffset[1] - scale;
vWorldMins[2] = spawnOffset[2] - scale;
vWorldMaxs[0] = spawnOffset[0] + scale;
vWorldMaxs[1] = spawnOffset[1] + scale;
vWorldMaxs[2] = spawnOffset[2] + scale;
}
else
{
return;
}
fleckEmitter->SetSortOrigin( spawnOffset );
fleckEmitter->GetBinding().SetBBox( spawnOffset-Vector(32,32,32), spawnOffset+Vector(32,32,32), true );
// Handle increased scale
float flMaxSpeed = 256.0f;
float flAngularSpray = 1.0f;
// Setup our collision information
fleckEmitter->m_ParticleCollision.Setup( spawnOffset, &shotDir, flAngularSpray, 8.0f, flMaxSpeed, FLECK_GRAVITY, FLECK_DAMPEN );
Vector dir, end;
Vector color = Vector( 1, 0.9, 0.75 );
float colorRamp;
int numFlecks = random->RandomInt( 8, 16 );
Particle3D *pFleckParticle;
// Dump out flecks
int i;
for ( i = 0; i < numFlecks; i++ )
{
pFleckParticle = (Particle3D *) fleckEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Antlion[random->RandomInt(0,1)], spawnOffset );
if ( pFleckParticle == NULL )
break;
pFleckParticle->m_flLifeRemaining = 3.0f;
dir[0] = shotDir[0] + random->RandomFloat( -flAngularSpray, flAngularSpray );
dir[1] = shotDir[1] + random->RandomFloat( -flAngularSpray, flAngularSpray );
dir[2] = shotDir[2] + random->RandomFloat( -flAngularSpray, flAngularSpray );
pFleckParticle->m_uchSize = random->RandomInt( 1, 6 );
pFleckParticle->m_vecVelocity = dir * random->RandomFloat( FLECK_MIN_SPEED, flMaxSpeed);
pFleckParticle->m_vAngles.Random( 0, 360 );
pFleckParticle->m_flAngSpeed = random->RandomFloat(-800,800);
pFleckParticle->m_uchFrontColor[0] = 255;
pFleckParticle->m_uchFrontColor[1] = 255;
pFleckParticle->m_uchFrontColor[2] = 255;
pFleckParticle->m_uchBackColor[0] = 128;
pFleckParticle->m_uchBackColor[1] = 128;
pFleckParticle->m_uchBackColor[2] = 128;
}
//
// Dust trail
//
SimpleParticle *pParticle;
CSmartPtr<CSimpleEmitter> dustEmitter = CSimpleEmitter::Create( "FX_DebrisFlecks" );
if ( !dustEmitter )
return;
Vector offset = trace->endpos + ( shotDir * 4.0f );
dustEmitter->SetSortOrigin( offset );
dustEmitter->GetBinding().SetBBox( spawnOffset-Vector(32,32,32), spawnOffset+Vector(32,32,32), true );
for ( i = 0; i < 4; i++ )
{
pParticle = (SimpleParticle *) dustEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[0], offset );
if ( pParticle == NULL )
break;
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = 1.0f;
dir[0] = shotDir[0] + random->RandomFloat( -0.8f, 0.8f );
dir[1] = shotDir[1] + random->RandomFloat( -0.8f, 0.8f );
dir[2] = shotDir[2] + random->RandomFloat( -0.8f, 0.8f );
pParticle->m_uchStartSize = random->RandomInt( 8, 16 );
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4.0f;
pParticle->m_vecVelocity = dir * random->RandomFloat( 4.0f, 64.0f );
pParticle->m_uchStartAlpha = random->RandomInt( 32, 64);
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomFloat( 0, 2.0f*M_PI );
pParticle->m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
colorRamp = random->RandomFloat( 0.5f, 1.0f );
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;
}
CLocalPlayerFilter filter;
C_BaseEntity::EmitSound( filter, 0, "FX_AntlionImpact.ShellImpact", &trace->endpos );
}
//-----------------------------------------------------------------------------
// Purpose: Spurt out bug blood
// Input : &pos -
// &dir -
//-----------------------------------------------------------------------------
#if defined( _XBOX )
#define NUM_BUG_BLOOD 16
#define NUM_BUG_BLOOD2 8
#define NUM_BUG_SPLATS 8
#else
#define NUM_BUG_BLOOD 32
#define NUM_BUG_BLOOD2 16
#define NUM_BUG_SPLATS 16
#endif
void FX_BugBlood( Vector &pos, Vector &dir, Vector &vWorldMins, Vector &vWorldMaxs )
{
VPROF_BUDGET( "FX_BugBlood", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_BugBlood" );
if ( !pSimple )
return;
pSimple->SetSortOrigin( pos );
pSimple->GetBinding().SetBBox( vWorldMins, vWorldMaxs, true );
pSimple->GetBinding().SetBBox( pos-Vector(32,32,32), pos+Vector(32,32,32), true );
Vector vDir;
vDir[0] = dir[0] + random->RandomFloat( -2.0f, 2.0f );
vDir[1] = dir[1] + random->RandomFloat( -2.0f, 2.0f );
vDir[2] = dir[2] + random->RandomFloat( -2.0f, 2.0f );
VectorNormalize( vDir );
int i;
for ( i = 0; i < NUM_BUG_BLOOD; i++ )
{
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], pos );
if ( sParticle == NULL )
return;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = 0.25f;
float speed = random->RandomFloat( 32.0f, 150.0f );
sParticle->m_vecVelocity = vDir * -speed;
sParticle->m_vecVelocity[2] -= 32.0f;
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 200;
sParticle->m_uchColor[2] = 32;
sParticle->m_uchStartAlpha = 255;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 1, 2 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize*random->RandomInt( 1, 4 );
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
}
for ( i = 0; i < NUM_BUG_BLOOD2; i++ )
{
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], pos );
if ( sParticle == NULL )
{
return;
}
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
float speed = random->RandomFloat( 8.0f, 255.0f );
sParticle->m_vecVelocity = vDir * -speed;
sParticle->m_vecVelocity[2] -= 16.0f;
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 200;
sParticle->m_uchColor[2] = 32;
sParticle->m_uchStartAlpha = random->RandomInt( 16, 32 );
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 1, 3 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize*random->RandomInt( 1, 4 );
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
}
Vector offset;
for ( i = 0; i < NUM_BUG_SPLATS; i++ )
{
offset.Random( -2, 2 );
offset += pos;
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], offset );
if ( sParticle == NULL )
{
return;
}
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
float speed = 75.0f * ((i/(float)NUM_BUG_SPLATS)+1);
sParticle->m_vecVelocity.Random( -16.0f, 16.0f );
sParticle->m_vecVelocity += vDir * -speed;
sParticle->m_vecVelocity[2] -= ( 64.0f * ((i/(float)NUM_BUG_SPLATS)+1) );
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 200;
sParticle->m_uchColor[2] = 32;
sParticle->m_uchStartAlpha = 255;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 1, 2 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize*4;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
}
}
//-----------------------------------------------------------------------------
// Purpose: Blood puff
//-----------------------------------------------------------------------------
void FX_Blood( Vector &pos, Vector &dir, float r, float g, float b, float a )
{
VPROF_BUDGET( "FX_Blood", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
// Cloud
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_Blood" );
if ( !pSimple )
return;
pSimple->SetSortOrigin( pos );
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;
for ( i = 0; i < 2; i++ )
{
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], pos );
if ( sParticle == NULL )
{
return;
}
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
float speed = random->RandomFloat( 2.0f, 8.0f );
sParticle->m_vecVelocity = vDir * (speed*i);
sParticle->m_vecVelocity[2] += random->RandomFloat( -32.0f, -16.0f );
sParticle->m_uchColor[0] = r;
sParticle->m_uchColor[1] = g;
sParticle->m_uchColor[2] = b;
sParticle->m_uchStartAlpha = a;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = 2;
sParticle->m_uchEndSize = sParticle->m_uchStartSize*4;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
}
for ( i = 0; i < 2; i++ )
{
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], pos );
if ( sParticle == NULL )
{
return;
}
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = 0.5f;
float speed = random->RandomFloat( 4.0f, 16.0f );
sParticle->m_vecVelocity = vDir * (speed*i);
sParticle->m_uchColor[0] = r;
sParticle->m_uchColor[1] = g;
sParticle->m_uchColor[2] = b;
sParticle->m_uchStartAlpha = 128;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = 2;
sParticle->m_uchEndSize = sParticle->m_uchStartSize*4;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
}
}
//-----------------------------------------------------------------------------
// Purpose: Dust impact
// Input : &origin - position
// &tr - trace information
//-----------------------------------------------------------------------------
void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale )
{
if ( !fx_drawimpactdust.GetBool() )
return;
#ifdef _XBOX
//
// XBox version
//
VPROF_BUDGET( "FX_DustImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
Vector offset;
float spread = 0.2f;
CSmartPtr<CDustParticle> pSimple = CDustParticle::Create( "dust" );
pSimple->SetSortOrigin( origin );
pSimple->GetBinding().SetBBox( origin - ( Vector( 32, 32, 32 ) * iScale ), origin + ( Vector( 32, 32, 32 ) * iScale ) );
Vector color;
float colorRamp;
GetColorForSurface( tr, &color );
int i;
SimpleParticle *pParticle;
for ( i = 0; i < 4; i++ )
{
// Last puff is gritty (hides end)
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_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;
// scaled
pParticle->m_vecVelocity *= fForce * iScale;
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;
// scaled
pParticle->m_uchStartSize = iScale * random->RandomInt( 3, 4 ) * (i+1);
// scaled
pParticle->m_uchEndSize = iScale * pParticle->m_uchStartSize * 4;
pParticle->m_uchStartAlpha = random->RandomInt( 32, 255 );
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
if ( i == 3 )
{
pParticle->m_flRollDelta = random->RandomFloat( -0.1f, 0.1f );
pParticle->m_flDieTime = 0.5f;
}
else
{
pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
}
}
}
//Impact hit
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_DustPuff, 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 );
pParticle->m_vecVelocity.Init();
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 = random->RandomInt( 4, 8 );
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
pParticle->m_uchStartAlpha = random->RandomInt( 32, 64 );
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
}
#else
FX_DustImpact( origin, tr, (float)iScale );
#endif // _XBOX
}
void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale )
{
//
// PC version
//
VPROF_BUDGET( "FX_DustImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
Vector offset;
float spread = 0.2f;
CSmartPtr<CDustParticle> pSimple = CDustParticle::Create( "dust" );
pSimple->SetSortOrigin( origin );
// Three types of particle, ideally we want 4 of each.
float fNumParticles = 4.0f * g_pParticleSystemMgr->ParticleThrottleScaling();
int nParticles1 = (int)( 0.50f + fNumParticles );
int nParticles2 = (int)( 0.83f + fNumParticles ); // <-- most visible particle type.
int nParticles3 = (int)( 0.17f + fNumParticles );
SimpleParticle *pParticle;
Vector color;
float colorRamp;
GetColorForSurface( tr, &color );
// To get a decent spread even when scaling down the number of particles...
const static int nParticleIdArray[4] = {3,1,2,0};
int i;
for ( i = 0; i < nParticles1; i++ )
{
int nId = nParticleIdArray[i];
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 ) * nId;
// scaled
pParticle->m_vecVelocity *= fForce * flScale;
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;
// scaled
pParticle->m_uchStartSize = ( unsigned char )( flScale * random->RandomInt( 3, 4 ) * (nId+1) );
// scaled
pParticle->m_uchEndSize = ( unsigned char )( flScale * pParticle->m_uchStartSize * 4 );
pParticle->m_uchStartAlpha = random->RandomInt( 32, 255 );
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
}
}
//Dust specs
for ( i = 0; i < nParticles2; i++ )
{
int nId = nParticleIdArray[i];
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin );
if ( pParticle != NULL )
{
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.75f );
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 ) * nId;
pParticle->m_vecVelocity *= fForce;
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 = random->RandomInt( 2, 4 ) * (nId+1);
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
pParticle->m_uchStartAlpha = 255;
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
}
}
//Impact hit
for ( i = 0; i < nParticles3; i++ )
{
//int nId = nParticleIdArray[i];
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], 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.Random( -spread, spread );
pParticle->m_vecVelocity += tr->plane.normal;
VectorNormalize( pParticle->m_vecVelocity );
float fForce = random->RandomFloat( 0, 50 );
pParticle->m_vecVelocity *= fForce;
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 = random->RandomInt( 1, 4 );
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
pParticle->m_uchStartAlpha = random->RandomInt( 32, 64 );
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
}
}
}
#ifdef _XBOX
extern PMaterialHandle g_Material_Spark;
#endif // _XBOX
//-----------------------------------------------------------------------------
// 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
}
class C_TEGaussExplosion : public C_TEParticleSystem
{
public:
DECLARE_CLASS( C_TEGaussExplosion, C_TEParticleSystem );
DECLARE_CLIENTCLASS();
C_TEGaussExplosion();
virtual ~C_TEGaussExplosion();
public:
virtual void PostDataUpdate( DataUpdateType_t updateType );
virtual bool ShouldDraw() { return true; }
public:
int m_nType;
Vector m_vecDirection;
};
IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEGaussExplosion, DT_TEGaussExplosion, CTEGaussExplosion )
RecvPropInt(RECVINFO(m_nType)),
RecvPropVector(RECVINFO(m_vecDirection)),
END_RECV_TABLE()
//==================================================
// C_TEGaussExplosion
//==================================================
C_TEGaussExplosion::C_TEGaussExplosion()
{
}
C_TEGaussExplosion::~C_TEGaussExplosion()
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : bNewEntity - whether or not to start a new entity
//-----------------------------------------------------------------------------
void C_TEGaussExplosion::PostDataUpdate( DataUpdateType_t updateType )
{
FX_GaussExplosion( m_vecOrigin, m_vecDirection, m_nType );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : filter -
// delay -
// &pos -
// &dir -
// type -
//-----------------------------------------------------------------------------
void TE_GaussExplosion( IRecipientFilter& filter, float delay, const Vector &pos, const Vector &dir, int type )
{
FX_GaussExplosion( pos, dir, type );
}