aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/c_smokestack.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/c_smokestack.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/c_smokestack.cpp')
-rw-r--r--mp/src/game/client/c_smokestack.cpp1008
1 files changed, 504 insertions, 504 deletions
diff --git a/mp/src/game/client/c_smokestack.cpp b/mp/src/game/client/c_smokestack.cpp
index 2065da52..2c66dcf5 100644
--- a/mp/src/game/client/c_smokestack.cpp
+++ b/mp/src/game/client/c_smokestack.cpp
@@ -1,504 +1,504 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: Implements a particle system steam jet.
-//
-// $NoKeywords: $
-//=============================================================================//
-#include "cbase.h"
-#include "particle_prototype.h"
-#include "baseparticleentity.h"
-#include "particles_simple.h"
-#include "filesystem.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#ifdef HL2_EPISODIC
- #define SMOKESTACK_MAX_MATERIALS 8
-#else
- #define SMOKESTACK_MAX_MATERIALS 1
-#endif
-
-//==================================================
-// C_SmokeStack
-//==================================================
-
-class C_SmokeStack : public C_BaseParticleEntity, public IPrototypeAppEffect
-{
-public:
- DECLARE_CLIENTCLASS();
- DECLARE_CLASS( C_SmokeStack, C_BaseParticleEntity );
-
- C_SmokeStack();
- ~C_SmokeStack();
-
- class SmokeStackParticle : public Particle
- {
- public:
- Vector m_Velocity;
- Vector m_vAccel;
- float m_Lifetime;
- float m_flAngle;
- float m_flRollDelta;
- float m_flSortPos;
- };
-
-//C_BaseEntity
-public:
- virtual void OnDataChanged( DataUpdateType_t updateType );
- virtual void ClientThink();
-
-//IPrototypeAppEffect
-public:
- virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs);
- virtual bool GetPropEditInfo(RecvTable **ppTable, void **ppObj);
-
-
-//IParticleEffect
-public:
- virtual void Update(float fTimeDelta);
- virtual void RenderParticles( CParticleRenderIterator *pIterator );
- virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
- virtual void StartRender( VMatrix &effectMatrix );
-
-
-private:
-
- void QueueLightParametersInRenderer();
-
-
-//Stuff from the datatable
-public:
-
- CParticleSphereRenderer m_Renderer;
-
- float m_SpreadSpeed;
- float m_Speed;
- float m_StartSize;
- float m_EndSize;
- float m_Rate;
- float m_JetLength; // Length of the jet. Lifetime is derived from this.
-
- int m_bEmit; // Emit particles?
- float m_flBaseSpread;
-
- class CLightInfo
- {
- public:
- Vector m_vPos;
- Vector m_vColor;
- float m_flIntensity;
- };
-
- // Note: there are two ways the directional light can be specified. The default is to use
- // DirLightColor and a default dirlight source (from above or below).
- // In this case, m_DirLight.m_vPos and m_DirLight.m_flIntensity are ignored.
- //
- // The other is to attach a directional env_particlelight to us.
- // In this case, m_DirLightSource is ignored and all the m_DirLight parameters are used.
- CParticleLightInfo m_AmbientLight;
- CParticleLightInfo m_DirLight;
-
- Vector m_vBaseColor;
-
- Vector m_vWind;
- float m_flTwist;
- int m_iMaterialModel;
-
-private:
- C_SmokeStack( const C_SmokeStack & );
-
- float m_TwistMat[2][2];
- int m_bTwist;
-
- float m_flAlphaScale;
- float m_InvLifetime; // Calculated from m_JetLength / m_Speed;
-
- CParticleMgr *m_pParticleMgr;
- PMaterialHandle m_MaterialHandle[SMOKESTACK_MAX_MATERIALS];
- TimedEvent m_ParticleSpawn;
- int m_iMaxFrames;
- bool m_bInView;
- float m_flRollSpeed;
-};
-
-
-// ------------------------------------------------------------------------- //
-// Tables.
-// ------------------------------------------------------------------------- //
-
-// Expose to the particle app.
-EXPOSE_PROTOTYPE_EFFECT(SmokeStack, C_SmokeStack);
-
-
-IMPLEMENT_CLIENTCLASS_DT(C_SmokeStack, DT_SmokeStack, CSmokeStack)
- RecvPropFloat(RECVINFO(m_SpreadSpeed), 0),
- RecvPropFloat(RECVINFO(m_Speed), 0),
- RecvPropFloat(RECVINFO(m_StartSize), 0),
- RecvPropFloat(RECVINFO(m_EndSize), 0),
- RecvPropFloat(RECVINFO(m_Rate), 0),
- RecvPropFloat(RECVINFO(m_JetLength), 0),
- RecvPropInt(RECVINFO(m_bEmit), 0),
- RecvPropFloat(RECVINFO(m_flBaseSpread)),
- RecvPropFloat(RECVINFO(m_flTwist)),
- RecvPropFloat(RECVINFO(m_flRollSpeed )),
- RecvPropIntWithMinusOneFlag( RECVINFO( m_iMaterialModel ) ),
-
- RecvPropVector( RECVINFO(m_AmbientLight.m_vPos) ),
- RecvPropVector( RECVINFO(m_AmbientLight.m_vColor) ),
- RecvPropFloat( RECVINFO(m_AmbientLight.m_flIntensity) ),
-
- RecvPropVector( RECVINFO(m_DirLight.m_vPos) ),
- RecvPropVector( RECVINFO(m_DirLight.m_vColor) ),
- RecvPropFloat( RECVINFO(m_DirLight.m_flIntensity) ),
-
- RecvPropVector(RECVINFO(m_vWind))
-END_RECV_TABLE()
-
-
-
-// ------------------------------------------------------------------------- //
-// C_SmokeStack implementation.
-// ------------------------------------------------------------------------- //
-C_SmokeStack::C_SmokeStack()
-{
- m_pParticleMgr = NULL;
- m_MaterialHandle[0] = INVALID_MATERIAL_HANDLE;
- m_iMaterialModel = -1;
-
- m_SpreadSpeed = 15;
- m_Speed = 30;
- m_StartSize = 10;
- m_EndSize = 15;
- m_Rate = 80;
- m_JetLength = 180;
- m_bEmit = true;
-
- m_flBaseSpread = 20;
- m_bInView = false;
-
- // Lighting is (base color) + (ambient / dist^2) + bump(directional / dist^2)
- // By default, we use bottom-up lighting for the directional.
- SetRenderColor( 0, 0, 0, 255 );
-
- m_AmbientLight.m_vPos.Init(0,0,-100);
- m_AmbientLight.m_vColor.Init( 40, 40, 40 );
- m_AmbientLight.m_flIntensity = 8000;
-
- m_DirLight.m_vColor.Init( 255, 128, 0 );
-
- m_vWind.Init();
-
- m_flTwist = 0;
-}
-
-
-C_SmokeStack::~C_SmokeStack()
-{
- if(m_pParticleMgr)
- m_pParticleMgr->RemoveEffect( &m_ParticleEffect );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Called after a data update has occured
-// Input : bnewentity -
-//-----------------------------------------------------------------------------
-void C_SmokeStack::OnDataChanged(DataUpdateType_t updateType)
-{
- C_BaseEntity::OnDataChanged(updateType);
-
- if(updateType == DATA_UPDATE_CREATED)
- {
- Start(ParticleMgr(), NULL);
- }
-
- // Recalulate lifetime in case length or speed changed.
- m_InvLifetime = m_Speed / m_JetLength;
-}
-
-
-static ConVar mat_reduceparticles( "mat_reduceparticles", "0" );
-
-//-----------------------------------------------------------------------------
-// Purpose: Starts the effect
-// Input : *pParticleMgr -
-// *pArgs -
-//-----------------------------------------------------------------------------
-void C_SmokeStack::Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs)
-{
- pParticleMgr->AddEffect( &m_ParticleEffect, this );
-
- // Figure out the material name.
- char str[512] = "unset_material";
- const model_t *pModel = modelinfo->GetModel( m_iMaterialModel );
- if ( pModel )
- {
- Q_strncpy( str, modelinfo->GetModelName( pModel ), sizeof( str ) );
-
- // Get rid of the extension because the material system doesn't want it.
- char *pExt = Q_stristr( str, ".vmt" );
- if ( pExt )
- pExt[0] = 0;
- }
-
- m_MaterialHandle[0] = m_ParticleEffect.FindOrAddMaterial( str );
-
-#ifdef HL2_EPISODIC
- int iCount = 1;
- char szNames[512];
-
- int iLength = Q_strlen( str );
- str[iLength-1] = '\0';
-
- Q_snprintf( szNames, sizeof( szNames ), "%s%d.vmt", str, iCount );
-
- while ( filesystem->FileExists( VarArgs( "materials/%s", szNames ) ) && iCount < SMOKESTACK_MAX_MATERIALS )
- {
- char *pExt = Q_stristr( szNames, ".vmt" );
- if ( pExt )
- pExt[0] = 0;
-
- m_MaterialHandle[iCount] = m_ParticleEffect.FindOrAddMaterial( szNames );
- iCount++;
- }
-
- m_iMaxFrames = iCount-1;
-
- m_ParticleSpawn.Init( mat_reduceparticles.GetBool() ? m_Rate / 4 : m_Rate ); // Obey mat_reduceparticles in episodic
-#else
- m_ParticleSpawn.Init( m_Rate );
-#endif
-
- m_InvLifetime = m_Speed / m_JetLength;
-
- m_pParticleMgr = pParticleMgr;
-
- // Figure out how we need to draw.
- IMaterial *pMaterial = pParticleMgr->PMaterialToIMaterial( m_MaterialHandle[0] );
- if( pMaterial )
- {
- m_Renderer.Init( pParticleMgr, pMaterial );
- }
-
- QueueLightParametersInRenderer();
-
- // For the first N seconds, always simulate so it can build up the smokestack.
- // Afterwards, we set it to freeze when it's not being rendered.
- m_ParticleEffect.SetAlwaysSimulate( true );
- SetNextClientThink( gpGlobals->curtime + 5 );
-}
-
-
-void C_SmokeStack::ClientThink()
-{
- m_ParticleEffect.SetAlwaysSimulate( false );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : **ppTable -
-// **ppObj -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool C_SmokeStack::GetPropEditInfo( RecvTable **ppTable, void **ppObj )
-{
- *ppTable = &REFERENCE_RECV_TABLE(DT_SmokeStack);
- *ppObj = this;
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : fTimeDelta -
-//-----------------------------------------------------------------------------
-void C_SmokeStack::Update(float fTimeDelta)
-{
- if( !m_pParticleMgr )
- {
- assert(false);
- return;
- }
-
- // Don't spawn particles unless we're visible.
- if( m_bEmit && (m_ParticleEffect.WasDrawnPrevFrame() || m_ParticleEffect.GetAlwaysSimulate()) )
- {
- // Add new particles.
- Vector forward, right, up;
- AngleVectors(GetAbsAngles(), &forward, &right, &up);
-
- float tempDelta = fTimeDelta;
- while(m_ParticleSpawn.NextEvent(tempDelta))
- {
- int iRandomFrame = random->RandomInt( 0, m_iMaxFrames );
-
-#ifndef HL2_EPISODIC
- iRandomFrame = 0;
-#endif
-
- // Make a new particle.
- if(SmokeStackParticle *pParticle = (SmokeStackParticle*)m_ParticleEffect.AddParticle(sizeof(SmokeStackParticle), m_MaterialHandle[iRandomFrame]))
- {
- float angle = FRand( 0, 2.0f*M_PI_F );
-
- pParticle->m_Pos = GetAbsOrigin() +
- right * (cos( angle ) * m_flBaseSpread) +
- forward * (sin( angle ) * m_flBaseSpread);
-
- pParticle->m_Velocity =
- FRand(-m_SpreadSpeed,m_SpreadSpeed) * right +
- FRand(-m_SpreadSpeed,m_SpreadSpeed) * forward +
- m_Speed * up;
-
- pParticle->m_vAccel = m_vWind;
- pParticle->m_Lifetime = 0;
- pParticle->m_flAngle = 0.0f;
-
-#ifdef HL2_EPISODIC
- pParticle->m_flAngle = RandomFloat( 0, 360 );
-#endif
- pParticle->m_flRollDelta = random->RandomFloat( -m_flRollSpeed, m_flRollSpeed );
- pParticle->m_flSortPos = pParticle->m_Pos.z;
- }
- }
- }
-
- // Setup the twist matrix.
- float flTwist = (m_flTwist * (M_PI_F * 2.f) / 360.0f) * Helper_GetFrameTime();
- if( ( m_bTwist = !!flTwist ) )
- {
- m_TwistMat[0][0] = cos(flTwist);
- m_TwistMat[0][1] = sin(flTwist);
- m_TwistMat[1][0] = -sin(flTwist);
- m_TwistMat[1][1] = cos(flTwist);
- }
-
- QueueLightParametersInRenderer();
-}
-
-
-void C_SmokeStack::StartRender( VMatrix &effectMatrix )
-{
- m_Renderer.StartRender( effectMatrix );
-}
-
-
-void C_SmokeStack::QueueLightParametersInRenderer()
-{
- m_Renderer.SetBaseColor( Vector( m_clrRender->r / 255.0f, m_clrRender->g / 255.0f, m_clrRender->b / 255.0f ) );
- m_Renderer.SetAmbientLight( m_AmbientLight );
- m_Renderer.SetDirectionalLight( m_DirLight );
- m_flAlphaScale = (float)m_clrRender->a;
-}
-
-
-void C_SmokeStack::RenderParticles( CParticleRenderIterator *pIterator )
-{
- const SmokeStackParticle *pParticle = (const SmokeStackParticle*)pIterator->GetFirst();
- while ( pParticle )
- {
- // Transform.
- Vector tPos;
- TransformParticle( m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos );
-
- // Figure out its alpha. Squaring it after it gets halfway through its lifetime
- // makes it get translucent and fade out for a longer time.
- //float alpha = cosf( -M_PI_F + tLifetime * M_PI_F * 2.f ) * 0.5f + 0.5f;
- float tLifetime = pParticle->m_Lifetime * m_InvLifetime;
- float alpha = TableCos( -M_PI_F + tLifetime * M_PI_F * 2.f ) * 0.5f + 0.5f;
- if( tLifetime > 0.5f )
- alpha *= alpha;
-
- m_Renderer.RenderParticle(
- pIterator->GetParticleDraw(),
- pParticle->m_Pos,
- tPos,
- alpha * m_flAlphaScale,
- FLerp(m_StartSize, m_EndSize, tLifetime),
- DEG2RAD( pParticle->m_flAngle )
- );
-
- pParticle = (const SmokeStackParticle*)pIterator->GetNext( pParticle->m_flSortPos );
- }
-}
-
-
-void C_SmokeStack::SimulateParticles( CParticleSimulateIterator *pIterator )
-{
- bool bSortNow = true; // Change this to false if we see sorting issues.
- bool bQuickTest = false;
-
- bool bDrawn = m_ParticleEffect.WasDrawnPrevFrame();
-
- if ( bDrawn == true && m_bInView == false )
- {
- bSortNow = true;
- }
-
- if ( bDrawn == false && m_bInView == true )
- {
- bQuickTest = true;
- }
-
-#ifndef HL2_EPISODIC
- bQuickTest = false;
- bSortNow = true;
-#endif
-
- if( bQuickTest == false && m_bEmit && (!m_ParticleEffect.WasDrawnPrevFrame() && !m_ParticleEffect.GetAlwaysSimulate()) )
- return;
-
- SmokeStackParticle *pParticle = (SmokeStackParticle*)pIterator->GetFirst();
- while ( pParticle )
- {
- // Should this particle die?
- pParticle->m_Lifetime += pIterator->GetTimeDelta();
-
- float tLifetime = pParticle->m_Lifetime * m_InvLifetime;
- if( tLifetime >= 1 )
- {
- pIterator->RemoveParticle( pParticle );
- }
- else
- {
- // Transform.
- Vector tPos;
- if( m_bTwist )
- {
- Vector vTwist(
- pParticle->m_Pos.x - GetAbsOrigin().x,
- pParticle->m_Pos.y - GetAbsOrigin().y,
- 0);
-
- pParticle->m_Pos.x = vTwist.x * m_TwistMat[0][0] + vTwist.y * m_TwistMat[0][1] + GetAbsOrigin().x;
- pParticle->m_Pos.y = vTwist.x * m_TwistMat[1][0] + vTwist.y * m_TwistMat[1][1] + GetAbsOrigin().y;
- }
-
-#ifndef HL2_EPISODIC
- pParticle->m_Pos = pParticle->m_Pos +
- pParticle->m_Velocity * pIterator->GetTimeDelta() +
- pParticle->m_vAccel * (0.5f * pIterator->GetTimeDelta() * pIterator->GetTimeDelta());
-
- pParticle->m_Velocity += pParticle->m_vAccel * pIterator->GetTimeDelta();
-#else
- pParticle->m_Pos = pParticle->m_Pos + pParticle->m_Velocity * pIterator->GetTimeDelta() + pParticle->m_vAccel * pIterator->GetTimeDelta();
-#endif
-
- pParticle->m_flAngle += pParticle->m_flRollDelta * pIterator->GetTimeDelta();
-
- if ( bSortNow == true )
- {
- Vector tPos;
- TransformParticle( m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos );
- pParticle->m_flSortPos = tPos.z;
- }
- }
-
- pParticle = (SmokeStackParticle*)pIterator->GetNext();
- }
-
- m_bInView = bDrawn;
-}
-
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implements a particle system steam jet.
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "particle_prototype.h"
+#include "baseparticleentity.h"
+#include "particles_simple.h"
+#include "filesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#ifdef HL2_EPISODIC
+ #define SMOKESTACK_MAX_MATERIALS 8
+#else
+ #define SMOKESTACK_MAX_MATERIALS 1
+#endif
+
+//==================================================
+// C_SmokeStack
+//==================================================
+
+class C_SmokeStack : public C_BaseParticleEntity, public IPrototypeAppEffect
+{
+public:
+ DECLARE_CLIENTCLASS();
+ DECLARE_CLASS( C_SmokeStack, C_BaseParticleEntity );
+
+ C_SmokeStack();
+ ~C_SmokeStack();
+
+ class SmokeStackParticle : public Particle
+ {
+ public:
+ Vector m_Velocity;
+ Vector m_vAccel;
+ float m_Lifetime;
+ float m_flAngle;
+ float m_flRollDelta;
+ float m_flSortPos;
+ };
+
+//C_BaseEntity
+public:
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+ virtual void ClientThink();
+
+//IPrototypeAppEffect
+public:
+ virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs);
+ virtual bool GetPropEditInfo(RecvTable **ppTable, void **ppObj);
+
+
+//IParticleEffect
+public:
+ virtual void Update(float fTimeDelta);
+ virtual void RenderParticles( CParticleRenderIterator *pIterator );
+ virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
+ virtual void StartRender( VMatrix &effectMatrix );
+
+
+private:
+
+ void QueueLightParametersInRenderer();
+
+
+//Stuff from the datatable
+public:
+
+ CParticleSphereRenderer m_Renderer;
+
+ float m_SpreadSpeed;
+ float m_Speed;
+ float m_StartSize;
+ float m_EndSize;
+ float m_Rate;
+ float m_JetLength; // Length of the jet. Lifetime is derived from this.
+
+ int m_bEmit; // Emit particles?
+ float m_flBaseSpread;
+
+ class CLightInfo
+ {
+ public:
+ Vector m_vPos;
+ Vector m_vColor;
+ float m_flIntensity;
+ };
+
+ // Note: there are two ways the directional light can be specified. The default is to use
+ // DirLightColor and a default dirlight source (from above or below).
+ // In this case, m_DirLight.m_vPos and m_DirLight.m_flIntensity are ignored.
+ //
+ // The other is to attach a directional env_particlelight to us.
+ // In this case, m_DirLightSource is ignored and all the m_DirLight parameters are used.
+ CParticleLightInfo m_AmbientLight;
+ CParticleLightInfo m_DirLight;
+
+ Vector m_vBaseColor;
+
+ Vector m_vWind;
+ float m_flTwist;
+ int m_iMaterialModel;
+
+private:
+ C_SmokeStack( const C_SmokeStack & );
+
+ float m_TwistMat[2][2];
+ int m_bTwist;
+
+ float m_flAlphaScale;
+ float m_InvLifetime; // Calculated from m_JetLength / m_Speed;
+
+ CParticleMgr *m_pParticleMgr;
+ PMaterialHandle m_MaterialHandle[SMOKESTACK_MAX_MATERIALS];
+ TimedEvent m_ParticleSpawn;
+ int m_iMaxFrames;
+ bool m_bInView;
+ float m_flRollSpeed;
+};
+
+
+// ------------------------------------------------------------------------- //
+// Tables.
+// ------------------------------------------------------------------------- //
+
+// Expose to the particle app.
+EXPOSE_PROTOTYPE_EFFECT(SmokeStack, C_SmokeStack);
+
+
+IMPLEMENT_CLIENTCLASS_DT(C_SmokeStack, DT_SmokeStack, CSmokeStack)
+ RecvPropFloat(RECVINFO(m_SpreadSpeed), 0),
+ RecvPropFloat(RECVINFO(m_Speed), 0),
+ RecvPropFloat(RECVINFO(m_StartSize), 0),
+ RecvPropFloat(RECVINFO(m_EndSize), 0),
+ RecvPropFloat(RECVINFO(m_Rate), 0),
+ RecvPropFloat(RECVINFO(m_JetLength), 0),
+ RecvPropInt(RECVINFO(m_bEmit), 0),
+ RecvPropFloat(RECVINFO(m_flBaseSpread)),
+ RecvPropFloat(RECVINFO(m_flTwist)),
+ RecvPropFloat(RECVINFO(m_flRollSpeed )),
+ RecvPropIntWithMinusOneFlag( RECVINFO( m_iMaterialModel ) ),
+
+ RecvPropVector( RECVINFO(m_AmbientLight.m_vPos) ),
+ RecvPropVector( RECVINFO(m_AmbientLight.m_vColor) ),
+ RecvPropFloat( RECVINFO(m_AmbientLight.m_flIntensity) ),
+
+ RecvPropVector( RECVINFO(m_DirLight.m_vPos) ),
+ RecvPropVector( RECVINFO(m_DirLight.m_vColor) ),
+ RecvPropFloat( RECVINFO(m_DirLight.m_flIntensity) ),
+
+ RecvPropVector(RECVINFO(m_vWind))
+END_RECV_TABLE()
+
+
+
+// ------------------------------------------------------------------------- //
+// C_SmokeStack implementation.
+// ------------------------------------------------------------------------- //
+C_SmokeStack::C_SmokeStack()
+{
+ m_pParticleMgr = NULL;
+ m_MaterialHandle[0] = INVALID_MATERIAL_HANDLE;
+ m_iMaterialModel = -1;
+
+ m_SpreadSpeed = 15;
+ m_Speed = 30;
+ m_StartSize = 10;
+ m_EndSize = 15;
+ m_Rate = 80;
+ m_JetLength = 180;
+ m_bEmit = true;
+
+ m_flBaseSpread = 20;
+ m_bInView = false;
+
+ // Lighting is (base color) + (ambient / dist^2) + bump(directional / dist^2)
+ // By default, we use bottom-up lighting for the directional.
+ SetRenderColor( 0, 0, 0, 255 );
+
+ m_AmbientLight.m_vPos.Init(0,0,-100);
+ m_AmbientLight.m_vColor.Init( 40, 40, 40 );
+ m_AmbientLight.m_flIntensity = 8000;
+
+ m_DirLight.m_vColor.Init( 255, 128, 0 );
+
+ m_vWind.Init();
+
+ m_flTwist = 0;
+}
+
+
+C_SmokeStack::~C_SmokeStack()
+{
+ if(m_pParticleMgr)
+ m_pParticleMgr->RemoveEffect( &m_ParticleEffect );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called after a data update has occured
+// Input : bnewentity -
+//-----------------------------------------------------------------------------
+void C_SmokeStack::OnDataChanged(DataUpdateType_t updateType)
+{
+ C_BaseEntity::OnDataChanged(updateType);
+
+ if(updateType == DATA_UPDATE_CREATED)
+ {
+ Start(ParticleMgr(), NULL);
+ }
+
+ // Recalulate lifetime in case length or speed changed.
+ m_InvLifetime = m_Speed / m_JetLength;
+}
+
+
+static ConVar mat_reduceparticles( "mat_reduceparticles", "0" );
+
+//-----------------------------------------------------------------------------
+// Purpose: Starts the effect
+// Input : *pParticleMgr -
+// *pArgs -
+//-----------------------------------------------------------------------------
+void C_SmokeStack::Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs)
+{
+ pParticleMgr->AddEffect( &m_ParticleEffect, this );
+
+ // Figure out the material name.
+ char str[512] = "unset_material";
+ const model_t *pModel = modelinfo->GetModel( m_iMaterialModel );
+ if ( pModel )
+ {
+ Q_strncpy( str, modelinfo->GetModelName( pModel ), sizeof( str ) );
+
+ // Get rid of the extension because the material system doesn't want it.
+ char *pExt = Q_stristr( str, ".vmt" );
+ if ( pExt )
+ pExt[0] = 0;
+ }
+
+ m_MaterialHandle[0] = m_ParticleEffect.FindOrAddMaterial( str );
+
+#ifdef HL2_EPISODIC
+ int iCount = 1;
+ char szNames[512];
+
+ int iLength = Q_strlen( str );
+ str[iLength-1] = '\0';
+
+ Q_snprintf( szNames, sizeof( szNames ), "%s%d.vmt", str, iCount );
+
+ while ( filesystem->FileExists( VarArgs( "materials/%s", szNames ) ) && iCount < SMOKESTACK_MAX_MATERIALS )
+ {
+ char *pExt = Q_stristr( szNames, ".vmt" );
+ if ( pExt )
+ pExt[0] = 0;
+
+ m_MaterialHandle[iCount] = m_ParticleEffect.FindOrAddMaterial( szNames );
+ iCount++;
+ }
+
+ m_iMaxFrames = iCount-1;
+
+ m_ParticleSpawn.Init( mat_reduceparticles.GetBool() ? m_Rate / 4 : m_Rate ); // Obey mat_reduceparticles in episodic
+#else
+ m_ParticleSpawn.Init( m_Rate );
+#endif
+
+ m_InvLifetime = m_Speed / m_JetLength;
+
+ m_pParticleMgr = pParticleMgr;
+
+ // Figure out how we need to draw.
+ IMaterial *pMaterial = pParticleMgr->PMaterialToIMaterial( m_MaterialHandle[0] );
+ if( pMaterial )
+ {
+ m_Renderer.Init( pParticleMgr, pMaterial );
+ }
+
+ QueueLightParametersInRenderer();
+
+ // For the first N seconds, always simulate so it can build up the smokestack.
+ // Afterwards, we set it to freeze when it's not being rendered.
+ m_ParticleEffect.SetAlwaysSimulate( true );
+ SetNextClientThink( gpGlobals->curtime + 5 );
+}
+
+
+void C_SmokeStack::ClientThink()
+{
+ m_ParticleEffect.SetAlwaysSimulate( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : **ppTable -
+// **ppObj -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool C_SmokeStack::GetPropEditInfo( RecvTable **ppTable, void **ppObj )
+{
+ *ppTable = &REFERENCE_RECV_TABLE(DT_SmokeStack);
+ *ppObj = this;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : fTimeDelta -
+//-----------------------------------------------------------------------------
+void C_SmokeStack::Update(float fTimeDelta)
+{
+ if( !m_pParticleMgr )
+ {
+ assert(false);
+ return;
+ }
+
+ // Don't spawn particles unless we're visible.
+ if( m_bEmit && (m_ParticleEffect.WasDrawnPrevFrame() || m_ParticleEffect.GetAlwaysSimulate()) )
+ {
+ // Add new particles.
+ Vector forward, right, up;
+ AngleVectors(GetAbsAngles(), &forward, &right, &up);
+
+ float tempDelta = fTimeDelta;
+ while(m_ParticleSpawn.NextEvent(tempDelta))
+ {
+ int iRandomFrame = random->RandomInt( 0, m_iMaxFrames );
+
+#ifndef HL2_EPISODIC
+ iRandomFrame = 0;
+#endif
+
+ // Make a new particle.
+ if(SmokeStackParticle *pParticle = (SmokeStackParticle*)m_ParticleEffect.AddParticle(sizeof(SmokeStackParticle), m_MaterialHandle[iRandomFrame]))
+ {
+ float angle = FRand( 0, 2.0f*M_PI_F );
+
+ pParticle->m_Pos = GetAbsOrigin() +
+ right * (cos( angle ) * m_flBaseSpread) +
+ forward * (sin( angle ) * m_flBaseSpread);
+
+ pParticle->m_Velocity =
+ FRand(-m_SpreadSpeed,m_SpreadSpeed) * right +
+ FRand(-m_SpreadSpeed,m_SpreadSpeed) * forward +
+ m_Speed * up;
+
+ pParticle->m_vAccel = m_vWind;
+ pParticle->m_Lifetime = 0;
+ pParticle->m_flAngle = 0.0f;
+
+#ifdef HL2_EPISODIC
+ pParticle->m_flAngle = RandomFloat( 0, 360 );
+#endif
+ pParticle->m_flRollDelta = random->RandomFloat( -m_flRollSpeed, m_flRollSpeed );
+ pParticle->m_flSortPos = pParticle->m_Pos.z;
+ }
+ }
+ }
+
+ // Setup the twist matrix.
+ float flTwist = (m_flTwist * (M_PI_F * 2.f) / 360.0f) * Helper_GetFrameTime();
+ if( ( m_bTwist = !!flTwist ) )
+ {
+ m_TwistMat[0][0] = cos(flTwist);
+ m_TwistMat[0][1] = sin(flTwist);
+ m_TwistMat[1][0] = -sin(flTwist);
+ m_TwistMat[1][1] = cos(flTwist);
+ }
+
+ QueueLightParametersInRenderer();
+}
+
+
+void C_SmokeStack::StartRender( VMatrix &effectMatrix )
+{
+ m_Renderer.StartRender( effectMatrix );
+}
+
+
+void C_SmokeStack::QueueLightParametersInRenderer()
+{
+ m_Renderer.SetBaseColor( Vector( m_clrRender->r / 255.0f, m_clrRender->g / 255.0f, m_clrRender->b / 255.0f ) );
+ m_Renderer.SetAmbientLight( m_AmbientLight );
+ m_Renderer.SetDirectionalLight( m_DirLight );
+ m_flAlphaScale = (float)m_clrRender->a;
+}
+
+
+void C_SmokeStack::RenderParticles( CParticleRenderIterator *pIterator )
+{
+ const SmokeStackParticle *pParticle = (const SmokeStackParticle*)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ // Transform.
+ Vector tPos;
+ TransformParticle( m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos );
+
+ // Figure out its alpha. Squaring it after it gets halfway through its lifetime
+ // makes it get translucent and fade out for a longer time.
+ //float alpha = cosf( -M_PI_F + tLifetime * M_PI_F * 2.f ) * 0.5f + 0.5f;
+ float tLifetime = pParticle->m_Lifetime * m_InvLifetime;
+ float alpha = TableCos( -M_PI_F + tLifetime * M_PI_F * 2.f ) * 0.5f + 0.5f;
+ if( tLifetime > 0.5f )
+ alpha *= alpha;
+
+ m_Renderer.RenderParticle(
+ pIterator->GetParticleDraw(),
+ pParticle->m_Pos,
+ tPos,
+ alpha * m_flAlphaScale,
+ FLerp(m_StartSize, m_EndSize, tLifetime),
+ DEG2RAD( pParticle->m_flAngle )
+ );
+
+ pParticle = (const SmokeStackParticle*)pIterator->GetNext( pParticle->m_flSortPos );
+ }
+}
+
+
+void C_SmokeStack::SimulateParticles( CParticleSimulateIterator *pIterator )
+{
+ bool bSortNow = true; // Change this to false if we see sorting issues.
+ bool bQuickTest = false;
+
+ bool bDrawn = m_ParticleEffect.WasDrawnPrevFrame();
+
+ if ( bDrawn == true && m_bInView == false )
+ {
+ bSortNow = true;
+ }
+
+ if ( bDrawn == false && m_bInView == true )
+ {
+ bQuickTest = true;
+ }
+
+#ifndef HL2_EPISODIC
+ bQuickTest = false;
+ bSortNow = true;
+#endif
+
+ if( bQuickTest == false && m_bEmit && (!m_ParticleEffect.WasDrawnPrevFrame() && !m_ParticleEffect.GetAlwaysSimulate()) )
+ return;
+
+ SmokeStackParticle *pParticle = (SmokeStackParticle*)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ // Should this particle die?
+ pParticle->m_Lifetime += pIterator->GetTimeDelta();
+
+ float tLifetime = pParticle->m_Lifetime * m_InvLifetime;
+ if( tLifetime >= 1 )
+ {
+ pIterator->RemoveParticle( pParticle );
+ }
+ else
+ {
+ // Transform.
+ Vector tPos;
+ if( m_bTwist )
+ {
+ Vector vTwist(
+ pParticle->m_Pos.x - GetAbsOrigin().x,
+ pParticle->m_Pos.y - GetAbsOrigin().y,
+ 0);
+
+ pParticle->m_Pos.x = vTwist.x * m_TwistMat[0][0] + vTwist.y * m_TwistMat[0][1] + GetAbsOrigin().x;
+ pParticle->m_Pos.y = vTwist.x * m_TwistMat[1][0] + vTwist.y * m_TwistMat[1][1] + GetAbsOrigin().y;
+ }
+
+#ifndef HL2_EPISODIC
+ pParticle->m_Pos = pParticle->m_Pos +
+ pParticle->m_Velocity * pIterator->GetTimeDelta() +
+ pParticle->m_vAccel * (0.5f * pIterator->GetTimeDelta() * pIterator->GetTimeDelta());
+
+ pParticle->m_Velocity += pParticle->m_vAccel * pIterator->GetTimeDelta();
+#else
+ pParticle->m_Pos = pParticle->m_Pos + pParticle->m_Velocity * pIterator->GetTimeDelta() + pParticle->m_vAccel * pIterator->GetTimeDelta();
+#endif
+
+ pParticle->m_flAngle += pParticle->m_flRollDelta * pIterator->GetTimeDelta();
+
+ if ( bSortNow == true )
+ {
+ Vector tPos;
+ TransformParticle( m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos );
+ pParticle->m_flSortPos = tPos.z;
+ }
+ }
+
+ pParticle = (SmokeStackParticle*)pIterator->GetNext();
+ }
+
+ m_bInView = bDrawn;
+}
+
+