diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/c_smokestack.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/client/c_smokestack.cpp')
| -rw-r--r-- | game/client/c_smokestack.cpp | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/game/client/c_smokestack.cpp b/game/client/c_smokestack.cpp new file mode 100644 index 0000000..c2c0a9f --- /dev/null +++ b/game/client/c_smokestack.cpp @@ -0,0 +1,503 @@ +//========= 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. + 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; +} + + |