aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/c_func_dust.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/client/c_func_dust.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/client/c_func_dust.cpp')
-rw-r--r--mp/src/game/client/c_func_dust.cpp365
1 files changed, 365 insertions, 0 deletions
diff --git a/mp/src/game/client/c_func_dust.cpp b/mp/src/game/client/c_func_dust.cpp
new file mode 100644
index 00000000..73d51345
--- /dev/null
+++ b/mp/src/game/client/c_func_dust.cpp
@@ -0,0 +1,365 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "fx.h"
+#include "c_func_dust.h"
+#include "func_dust_shared.h"
+#include "c_te_particlesystem.h"
+#include "env_wind_shared.h"
+#include "engine/IEngineTrace.h"
+#include "tier0/vprof.h"
+#include "clienteffectprecachesystem.h"
+#include "particles_ez.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+IMPLEMENT_CLIENTCLASS_DT_NOBASE( C_Func_Dust, DT_Func_Dust, CFunc_Dust )
+ RecvPropInt( RECVINFO(m_Color) ),
+ RecvPropInt( RECVINFO(m_SpawnRate) ),
+ RecvPropFloat( RECVINFO(m_flSizeMin) ),
+ RecvPropFloat( RECVINFO(m_flSizeMax) ),
+ RecvPropInt( RECVINFO(m_LifetimeMin) ),
+ RecvPropInt( RECVINFO(m_LifetimeMax) ),
+ RecvPropInt( RECVINFO(m_DustFlags) ),
+ RecvPropInt( RECVINFO(m_SpeedMax) ),
+ RecvPropInt( RECVINFO(m_DistMax) ),
+ RecvPropInt( RECVINFO( m_nModelIndex ) ),
+ RecvPropFloat( RECVINFO( m_FallSpeed ) ),
+ RecvPropDataTable( RECVINFO_DT( m_Collision ), 0, &REFERENCE_RECV_TABLE(DT_CollisionProperty) ),
+END_RECV_TABLE()
+
+
+
+// ------------------------------------------------------------------------------------ //
+// CDustEffect implementation.
+// ------------------------------------------------------------------------------------ //
+#define DUST_ACCEL 50
+
+
+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 );
+ }
+}
+
+void CDustEffect::SimulateParticles( CParticleSimulateIterator *pIterator )
+{
+ Vector vecWind;
+ GetWindspeedAtTime( gpGlobals->curtime, vecWind );
+
+
+ CFuncDustParticle *pParticle = (CFuncDustParticle*)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ // Velocity.
+ if( !(m_pDust->m_DustFlags & DUSTFLAGS_FROZEN) )
+ {
+ // Kill the particle?
+ pParticle->m_flLifetime += pIterator->GetTimeDelta();
+ if( pParticle->m_flLifetime >= pParticle->m_flDieTime )
+ {
+ pIterator->RemoveParticle( pParticle );
+ }
+ else
+ {
+ for ( int i = 0 ; i < 2 ; i++ )
+ {
+ if ( pParticle->m_vVelocity[i] < vecWind[i] )
+ {
+ pParticle->m_vVelocity[i] += ( gpGlobals->frametime * DUST_ACCEL );
+
+ // clamp
+ if ( pParticle->m_vVelocity[i] > vecWind[i] )
+ pParticle->m_vVelocity[i] = vecWind[i];
+ }
+ else if (pParticle->m_vVelocity[i] > vecWind[i] )
+ {
+ pParticle->m_vVelocity[i] -= ( gpGlobals->frametime * DUST_ACCEL );
+
+ // clamp.
+ if ( pParticle->m_vVelocity[i] < vecWind[i] )
+ pParticle->m_vVelocity[i] = vecWind[i];
+ }
+ }
+
+ // Apply velocity.
+ pParticle->m_Pos.MulAdd( pParticle->m_Pos, pParticle->m_vVelocity, pIterator->GetTimeDelta() );
+ }
+ }
+
+ pParticle = (CFuncDustParticle*)pIterator->GetNext();
+ }
+}
+
+
+// ------------------------------------------------------------------------------------ //
+// C_Func_Dust implementation.
+// ------------------------------------------------------------------------------------ //
+
+C_Func_Dust::C_Func_Dust() : m_Effect( "C_Func_Dust" )
+{
+ m_Effect.m_pDust = this;
+ m_Effect.SetDynamicallyAllocated( false ); // So it doesn't try to delete itself.
+}
+
+
+C_Func_Dust::~C_Func_Dust()
+{
+}
+
+void C_Func_Dust::OnDataChanged( DataUpdateType_t updateType )
+{
+ BaseClass::OnDataChanged( updateType );
+
+ if( updateType == DATA_UPDATE_CREATED )
+ {
+ m_hMaterial = m_Effect.GetPMaterial( "particle/sparkles" );
+
+ m_Effect.SetSortOrigin( WorldSpaceCenter( ) );
+
+ // Let us think each frame.
+ SetNextClientThink( CLIENT_THINK_ALWAYS );
+
+ // If we're setup to be frozen, just make a bunch of particles initially.
+ if( m_DustFlags & DUSTFLAGS_FROZEN )
+ {
+ for( int i=0; i < m_SpawnRate; i++ )
+ {
+ AttemptSpawnNewParticle();
+ }
+ }
+ }
+
+ m_Spawner.Init( m_SpawnRate ); // N particles per second
+}
+
+
+void C_Func_Dust::ClientThink()
+{
+ // If frozen, don't make new particles.
+ if( m_DustFlags & DUSTFLAGS_FROZEN )
+ return;
+
+ // Spawn particles?
+ if( m_DustFlags & DUSTFLAGS_ON )
+ {
+ float flDelta = MIN( gpGlobals->frametime, 0.1f );
+ while( m_Spawner.NextEvent( flDelta ) )
+ {
+ AttemptSpawnNewParticle();
+ }
+ }
+
+ // Tell the particle manager our bbox.
+ Vector vWorldMins, vWorldMaxs;
+ CollisionProp()->WorldSpaceAABB( &vWorldMins, &vWorldMaxs );
+ vWorldMins -= Vector( m_flSizeMax, m_flSizeMax, m_flSizeMax );
+ vWorldMaxs += Vector( m_flSizeMax, m_flSizeMax, m_flSizeMax );
+ m_Effect.GetBinding().SetBBox( vWorldMins, vWorldMaxs );
+}
+
+
+bool C_Func_Dust::ShouldDraw()
+{
+ return false;
+}
+
+
+void C_Func_Dust::AttemptSpawnNewParticle()
+{
+ // Find a random spot inside our bmodel.
+ static int nTests=10;
+
+ for( int iTest=0; iTest < nTests; iTest++ )
+ {
+ Vector vPercent = RandomVector( 0, 1 );
+ Vector vTest = WorldAlignMins() + (WorldAlignMaxs() - WorldAlignMins()) * vPercent;
+
+ int contents = enginetrace->GetPointContents_Collideable( GetCollideable(), vTest );
+ if( contents & CONTENTS_SOLID )
+ {
+ CFuncDustParticle *pParticle = (CFuncDustParticle*)m_Effect.AddParticle( 10, m_hMaterial, vTest );
+ if( pParticle )
+ {
+ pParticle->m_vVelocity = RandomVector( -m_SpeedMax, m_SpeedMax );
+ pParticle->m_vVelocity.z -= m_FallSpeed;
+
+ pParticle->m_flLifetime = 0;
+ pParticle->m_flDieTime = RemapVal( rand(), 0, VALVE_RAND_MAX, m_LifetimeMin, m_LifetimeMax );
+
+ if( m_DustFlags & DUSTFLAGS_SCALEMOTES )
+ pParticle->m_flSize = RemapVal( rand(), 0, VALVE_RAND_MAX, m_flSizeMin/10000.0f, m_flSizeMax/10000.0f );
+ else
+ pParticle->m_flSize = RemapVal( rand(), 0, VALVE_RAND_MAX, m_flSizeMin, m_flSizeMax );
+
+ pParticle->m_Color = m_Color;
+ }
+
+ break;
+ }
+ }
+}
+
+//
+// Dust
+//
+
+//-----------------------------------------------------------------------------
+// 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)] );
+ }
+}
+
+
+class C_TEDust: public C_TEParticleSystem
+{
+public:
+ DECLARE_CLASS( C_TEDust, C_TEParticleSystem );
+ DECLARE_CLIENTCLASS();
+
+ C_TEDust();
+ virtual ~C_TEDust();
+
+public:
+ virtual void PostDataUpdate( DataUpdateType_t updateType );
+ virtual bool ShouldDraw() { return true; }
+
+public:
+
+ float m_flSize;
+ float m_flSpeed;
+ Vector m_vecDirection;
+
+protected:
+ void GetDustColor( Vector &color );
+};
+
+IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEDust, DT_TEDust, CTEDust )
+ RecvPropFloat(RECVINFO(m_flSize)),
+ RecvPropFloat(RECVINFO(m_flSpeed)),
+ RecvPropVector(RECVINFO(m_vecDirection)),
+END_RECV_TABLE()
+
+//==================================================
+// C_TEDust
+//==================================================
+
+C_TEDust::C_TEDust()
+{
+}
+
+C_TEDust::~C_TEDust()
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : bNewEntity - whether or not to start a new entity
+//-----------------------------------------------------------------------------
+void C_TEDust::PostDataUpdate( DataUpdateType_t updateType )
+{
+ FX_Dust( m_vecOrigin, m_vecDirection, m_flSize, m_flSpeed );
+}
+
+
+void TE_Dust( IRecipientFilter& filter, float delay,
+ const Vector &pos, const Vector &dir, float size, float speed )
+{
+ FX_Dust( pos, dir, size, speed );
+}