//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "particle_prototype.h" #include "particle_util.h" #include "baseparticleentity.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" // ------------------------------------------------------------------------- // // Definitions // ------------------------------------------------------------------------- // #define NUM_MOVIEEXPLOSION_EMITTERS 50 #define EXPLOSION_EMITTER_LIFETIME 3 #define EMITTED_PARTICLE_LIFETIME 1 // ------------------------------------------------------------------------- // // Classes // ------------------------------------------------------------------------- // class MovieExplosionEmitter { public: Vector m_Pos; Vector m_Velocity; float m_Lifetime; TimedEvent m_ParticleSpawn; }; class C_MovieExplosion : public C_BaseParticleEntity, public IPrototypeAppEffect { public: DECLARE_CLASS( C_MovieExplosion, C_BaseParticleEntity ); DECLARE_CLIENTCLASS(); C_MovieExplosion(); ~C_MovieExplosion(); // C_BaseEntity. public: virtual void OnDataChanged(DataUpdateType_t updateType); // IPrototypeAppEffect. public: virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs); // IParticleEffect. public: virtual void Update(float fTimeDelta); virtual void RenderParticles( CParticleRenderIterator *pIterator ); virtual void SimulateParticles( CParticleSimulateIterator *pIterator ); public: MovieExplosionEmitter m_Emitters[NUM_MOVIEEXPLOSION_EMITTERS]; float m_EmitterLifetime; CParticleMgr *m_pParticleMgr; PMaterialHandle m_iFireballMaterial; // Setup for temporary usage in SimulateAndRender. float m_EmitterAlpha; private: C_MovieExplosion( const C_MovieExplosion & ); }; // Expose to the particle app. EXPOSE_PROTOTYPE_EFFECT(MovieExplosion, C_MovieExplosion); IMPLEMENT_CLIENTCLASS_DT(C_MovieExplosion, DT_MovieExplosion, MovieExplosion) END_RECV_TABLE() // ------------------------------------------------------------------------- // // C_MovieExplosion // ------------------------------------------------------------------------- // C_MovieExplosion::C_MovieExplosion() { m_pParticleMgr = NULL; } C_MovieExplosion::~C_MovieExplosion() { if(m_pParticleMgr) m_pParticleMgr->RemoveEffect( &m_ParticleEffect ); } void C_MovieExplosion::OnDataChanged(DataUpdateType_t updateType) { C_BaseEntity::OnDataChanged(updateType); if(updateType == DATA_UPDATE_CREATED) { Start( ParticleMgr(), NULL ); } } void C_MovieExplosion::Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs) { if(!pParticleMgr->AddEffect(&m_ParticleEffect, this)) return; // Setup our emitters. for(int iEmitter=0; iEmitter < NUM_MOVIEEXPLOSION_EMITTERS; iEmitter++) { MovieExplosionEmitter *pEmitter = &m_Emitters[iEmitter]; pEmitter->m_Velocity = RandomVector(-1, 1) * 200; pEmitter->m_Pos = GetAbsOrigin(); pEmitter->m_Lifetime = 0; pEmitter->m_ParticleSpawn.Init(15); } m_EmitterLifetime = 0; // Get our materials. m_iFireballMaterial = m_ParticleEffect.FindOrAddMaterial("particle/particle_sphere"); m_pParticleMgr = pParticleMgr; } void C_MovieExplosion::Update(float fTimeDelta) { if(!m_pParticleMgr) return; m_EmitterLifetime += fTimeDelta; if(m_EmitterLifetime > EXPLOSION_EMITTER_LIFETIME) return; m_EmitterAlpha = (float)sin(m_EmitterLifetime * 3.14159f / EXPLOSION_EMITTER_LIFETIME); // Simulate the emitters and have them spit out particles. for(int iEmitter=0; iEmitter < NUM_MOVIEEXPLOSION_EMITTERS; iEmitter++) { MovieExplosionEmitter *pEmitter = &m_Emitters[iEmitter]; pEmitter->m_Pos = pEmitter->m_Pos + pEmitter->m_Velocity * fTimeDelta; pEmitter->m_Velocity = pEmitter->m_Velocity * 0.9; float tempDelta = fTimeDelta; while(pEmitter->m_ParticleSpawn.NextEvent(tempDelta)) { StandardParticle_t *pParticle = (StandardParticle_t*)m_ParticleEffect.AddParticle( sizeof(StandardParticle_t), m_iFireballMaterial); if(pParticle) { pParticle->m_Pos = pEmitter->m_Pos; pParticle->m_Velocity = pEmitter->m_Velocity * 0.2f + RandomVector(-20, 20); } } } } void C_MovieExplosion::RenderParticles( CParticleRenderIterator *pIterator ) { const StandardParticle_t *pParticle = (const StandardParticle_t*)pIterator->GetFirst(); while ( pParticle ) { // Draw. Vector tPos; TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos); float sortKey = tPos.z; float lifetimePercent = pParticle->m_Lifetime / EMITTED_PARTICLE_LIFETIME; Vector color; color.x = sin(lifetimePercent * 3.14159); color.y = color.x * 0.5f; color.z = 0; RenderParticle_ColorSize( pIterator->GetParticleDraw(), tPos, color, m_EmitterAlpha * sin(3.14159 * lifetimePercent), 10); pParticle = (const StandardParticle_t*)pIterator->GetNext( sortKey ); } } void C_MovieExplosion::SimulateParticles( CParticleSimulateIterator *pIterator ) { StandardParticle_t *pParticle = (StandardParticle_t*)pIterator->GetFirst(); while ( pParticle ) { // Update its lifetime. pParticle->m_Lifetime += pIterator->GetTimeDelta(); if(pParticle->m_Lifetime > 1) { pIterator->RemoveParticle( pParticle ); } else { // Move it (this comes after rendering to make it clear that moving the particle here won't change // its rendering for this frame since m_TransformedPos has already been set). pParticle->m_Pos = pParticle->m_Pos + pParticle->m_Velocity * pIterator->GetTimeDelta(); } pParticle = (StandardParticle_t*)pIterator->GetNext(); } }