From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/game/client/c_particle_fire.cpp | 339 +++++++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 mp/src/game/client/c_particle_fire.cpp (limited to 'mp/src/game/client/c_particle_fire.cpp') diff --git a/mp/src/game/client/c_particle_fire.cpp b/mp/src/game/client/c_particle_fire.cpp new file mode 100644 index 00000000..84922da4 --- /dev/null +++ b/mp/src/game/client/c_particle_fire.cpp @@ -0,0 +1,339 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" +#include "particle_prototype.h" +#include "particle_util.h" +#include "baseparticleentity.h" +#include "engine/IEngineTrace.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// ------------------------------------------------------------------------- // +// Defines. +// ------------------------------------------------------------------------- // + +#define MAX_FIRE_EMITTERS 128 +#define FIRE_PARTICLE_LIFETIME 2 + +Vector g_FireSpreadDirection(0,0,1); + + +class FireRamp +{ +public: + FireRamp(const Vector &s, const Vector &e) + { + m_Start=s; + m_End=e; + } + + Vector m_Start; + Vector m_End; +}; + +FireRamp g_FireRamps[] = +{ + FireRamp(Vector(1,0,0), Vector(1,1,0)), + FireRamp(Vector(0.5,0.5,0), Vector(0,0,0)) +}; +#define NUM_FIRE_RAMPS (sizeof(g_FireRamps) / sizeof(g_FireRamps[0])) + + +#define NUM_FIREGRID_OFFSETS 8 +Vector g_Offsets[NUM_FIREGRID_OFFSETS] = +{ + Vector(-1,-1,-1), + Vector( 1,-1,-1), + Vector(-1, 1,-1), + Vector( 1, 1,-1), + + Vector(-1,-1, 1), + Vector( 1,-1, 1), + Vector(-1, 1, 1), + Vector( 1, 1, 1), +}; + +// If you follow g_Offset[index], you can follow g_Offsets[GetOppositeOffset(index)] to get back. +inline int GetOppositeOffset(int offset) +{ + return NUM_FIREGRID_OFFSETS - offset - 1; +} + + +// ------------------------------------------------------------------------- // +// Classes. +// ------------------------------------------------------------------------- // + +class C_ParticleFire : public C_BaseParticleEntity, public IPrototypeAppEffect +{ +public: + DECLARE_CLASS( C_ParticleFire, C_BaseParticleEntity ); + DECLARE_CLIENTCLASS(); + + C_ParticleFire(); + ~C_ParticleFire(); + + class FireEmitter + { + public: + Vector m_Pos; + TimedEvent m_SpawnEvent; + float m_Lifetime; // How long it's been emitting. + unsigned char m_DirectionsTested; // 1 bit for each of g_Offsets. + }; + + class FireParticle : public Particle + { + public: + Vector m_StartPos; // The particle moves from m_StartPos to (m_StartPos+m_Direction) over its lifetime. + Vector m_Direction; + + float m_Lifetime; + float m_SpinAngle; + unsigned char m_iRamp; // Which fire ramp are we using? + }; + + +// 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: + CParticleMgr *m_pParticleMgr; + PMaterialHandle m_MaterialHandle; + + // Controls where the initial fire goes. + Vector m_vOrigin; + Vector m_vDirection; + + TimedEvent m_EmitterSpawn; + FireEmitter m_Emitters[MAX_FIRE_EMITTERS]; + int m_nEmitters; + +private: + C_ParticleFire( const C_ParticleFire & ); +}; + + +// ------------------------------------------------------------------------- // +// Tables. +// ------------------------------------------------------------------------- // + +// Expose to the particle app. +EXPOSE_PROTOTYPE_EFFECT(ParticleFire, C_ParticleFire); + + +// Datatable.. +IMPLEMENT_CLIENTCLASS_DT_NOBASE(C_ParticleFire, DT_ParticleFire, CParticleFire) + RecvPropVector(RECVINFO(m_vOrigin)), + RecvPropVector(RECVINFO(m_vDirection)), +END_RECV_TABLE() + + + +// ------------------------------------------------------------------------- // +// C_FireSmoke implementation. +// ------------------------------------------------------------------------- // +C_ParticleFire::C_ParticleFire() +{ + m_pParticleMgr = NULL; + m_MaterialHandle = INVALID_MATERIAL_HANDLE; +} + + +C_ParticleFire::~C_ParticleFire() +{ + if(m_pParticleMgr) + m_pParticleMgr->RemoveEffect( &m_ParticleEffect ); +} + + +void C_ParticleFire::OnDataChanged(DataUpdateType_t updateType) +{ + C_BaseEntity::OnDataChanged(updateType); + + if(updateType == DATA_UPDATE_CREATED) + { + Start(ParticleMgr(), NULL); + } +} + + +void C_ParticleFire::Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs) +{ + m_pParticleMgr = pParticleMgr; + m_pParticleMgr->AddEffect( &m_ParticleEffect, this ); + m_MaterialHandle = m_ParticleEffect.FindOrAddMaterial("particle/particle_fire"); + + // Start + m_nEmitters = 0; + m_EmitterSpawn.Init(15); +} + +static float fireSpreadDist = 15; +static float size = 20; + +void C_ParticleFire::Update(float fTimeDelta) +{ + if(!m_pParticleMgr) + { + assert(false); + return; + } + + + // Add new emitters. + if(m_nEmitters < MAX_FIRE_EMITTERS) + { + float tempDelta = fTimeDelta; + while(m_EmitterSpawn.NextEvent(tempDelta)) + { + FireEmitter *pEmitter = NULL; + + if(m_nEmitters == 0) + { + // Make the first emitter. + trace_t trace; + UTIL_TraceLine(m_vOrigin, m_vOrigin+m_vDirection*1000, MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trace); + if(trace.fraction < 1) + { + pEmitter = &m_Emitters[m_nEmitters]; + pEmitter->m_Pos = trace.endpos + trace.plane.normal * (size - 1); + pEmitter->m_DirectionsTested = 0; + } + } + else + { + static int nTries = 50; + for(int iTry=0; iTry < nTries; iTry++) + { + FireEmitter *pSourceEmitter = &m_Emitters[rand() % m_nEmitters]; + + int iOffset = rand() % NUM_FIREGRID_OFFSETS; + if(pSourceEmitter->m_DirectionsTested & (1 << iOffset)) + continue; + + // Test the corners of the new cube. If some points are solid and some are not, then + // we can put fire here. + Vector basePos = pSourceEmitter->m_Pos + g_Offsets[iOffset] * fireSpreadDist; + int nSolidCorners = 0; + for(int iCorner=0; iCorner < NUM_FIREGRID_OFFSETS; iCorner++) + { + Vector vCorner = basePos + g_Offsets[iCorner]*fireSpreadDist; + if ( enginetrace->GetPointContents(vCorner) & CONTENTS_SOLID ) + ++nSolidCorners; + } + + // Don't test this square again. + pSourceEmitter->m_DirectionsTested |= 1 << iOffset; + + if(nSolidCorners != 0 && nSolidCorners != NUM_FIREGRID_OFFSETS) + { + pEmitter = &m_Emitters[m_nEmitters]; + pEmitter->m_Pos = basePos; + pEmitter->m_DirectionsTested = 1 << GetOppositeOffset(iOffset); + } + } + } + + if(pEmitter) + { + pEmitter->m_Lifetime = 0; + pEmitter->m_SpawnEvent.Init(1); + ++m_nEmitters; + } + } + } + + // Spawn particles out of the emitters. + for(int i=0; i < m_nEmitters; i++) + { + FireEmitter *pEmitter = &m_Emitters[i]; + + float tempDelta = fTimeDelta; + while(pEmitter->m_SpawnEvent.NextEvent(tempDelta)) + { + FireParticle *pParticle = (FireParticle*)m_ParticleEffect.AddParticle(sizeof(FireParticle), m_MaterialHandle); + if(pParticle) + { + static float particleSpeed = 15; + pParticle->m_StartPos = pEmitter->m_Pos; + pParticle->m_Direction = g_FireSpreadDirection * particleSpeed + RandomVector(0, particleSpeed*0.5); + pParticle->m_iRamp = rand() % NUM_FIRE_RAMPS; + pParticle->m_Lifetime = 0; + } + } + } +} + + +void C_ParticleFire::RenderParticles( CParticleRenderIterator *pIterator ) +{ + const FireParticle *pParticle = (const FireParticle*)pIterator->GetFirst(); + while ( pParticle ) + { + float smooth01 = 1 - (cos(pParticle->m_Lifetime * 3.14159 / FIRE_PARTICLE_LIFETIME) * 0.5 + 0.5); + float smooth00 = 1 - (cos(pParticle->m_Lifetime * 3.14159 * 2 / FIRE_PARTICLE_LIFETIME) * 0.5 + 0.5); + + FireRamp *pRamp = &g_FireRamps[pParticle->m_iRamp]; + Vector curColor = pRamp->m_Start + (pRamp->m_End - pRamp->m_Start) * smooth01; + + // Render. + Vector tPos; + TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos); + float sortKey = (int)tPos.z; + + RenderParticle_ColorSize( + pIterator->GetParticleDraw(), + tPos, + curColor, + smooth00, + size); + + pParticle = (const FireParticle*)pIterator->GetNext( sortKey ); + } +} + + +void C_ParticleFire::SimulateParticles( CParticleSimulateIterator *pIterator ) +{ + FireParticle *pParticle = (FireParticle*)pIterator->GetFirst(); + while ( pParticle ) + { + // Should this particle die? + pParticle->m_Lifetime += pIterator->GetTimeDelta(); + if(pParticle->m_Lifetime > FIRE_PARTICLE_LIFETIME) + { + pIterator->RemoveParticle( pParticle ); + } + else + { + float smooth01 = 1 - (cos(pParticle->m_Lifetime * 3.14159 / FIRE_PARTICLE_LIFETIME) * 0.5 + 0.5); + pParticle->m_Pos = pParticle->m_StartPos + pParticle->m_Direction * smooth01; + } + + pParticle = (FireParticle*)pIterator->GetNext(); + } +} + + -- cgit v1.2.3