305 lines
9.3 KiB
C++
305 lines
9.3 KiB
C++
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//===========================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "c_baseanimating.h"
|
|
#include "particlemgr.h"
|
|
#include "materialsystem/imaterialvar.h"
|
|
#include "cl_animevent.h"
|
|
#include "particle_util.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// An entity which emits other entities at points
|
|
//-----------------------------------------------------------------------------
|
|
class C_EnvParticleScript : public C_BaseAnimating, public IParticleEffect
|
|
{
|
|
public:
|
|
DECLARE_CLASS( C_EnvParticleScript, C_BaseAnimating );
|
|
DECLARE_CLIENTCLASS();
|
|
|
|
C_EnvParticleScript();
|
|
|
|
// IParticleEffect overrides.
|
|
public:
|
|
virtual bool ShouldSimulate() const { return m_bSimulate; }
|
|
virtual void SetShouldSimulate( bool bSim ) { m_bSimulate = bSim; }
|
|
|
|
virtual void RenderParticles( CParticleRenderIterator *pIterator );
|
|
virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
|
|
|
|
virtual const Vector &GetSortOrigin();
|
|
|
|
// C_BaseAnimating overrides
|
|
public:
|
|
// NOTE: Ths enclosed particle effect binding will do all the drawing
|
|
// But we have to return true, unlike other particle systems, for the animation events to work
|
|
virtual bool ShouldDraw() { return true; }
|
|
virtual int DrawModel( int flags, const RenderableInstance_t &instance ) { return 0; }
|
|
|
|
virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options );
|
|
virtual void OnPreDataChanged( DataUpdateType_t updateType );
|
|
virtual void OnDataChanged( DataUpdateType_t updateType );
|
|
|
|
private:
|
|
|
|
// Creates, destroys particles attached to an attachment
|
|
void CreateParticle( const char *pAttachmentName, const char *pSpriteName );
|
|
void DestroyAllParticles( const char *pAttachmentName );
|
|
void DestroyAllParticles( );
|
|
|
|
private:
|
|
struct ParticleScriptParticle_t : public Particle
|
|
{
|
|
int m_nAttachment;
|
|
float m_flSize;
|
|
};
|
|
|
|
CParticleEffectBinding m_ParticleEffect;
|
|
float m_flMaxParticleSize;
|
|
int m_nOldSequence;
|
|
float m_flSequenceScale;
|
|
bool m_bSimulate;
|
|
};
|
|
|
|
REGISTER_EFFECT( C_EnvParticleScript );
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Datatable
|
|
//-----------------------------------------------------------------------------
|
|
IMPLEMENT_CLIENTCLASS_DT( C_EnvParticleScript, DT_EnvParticleScript, CEnvParticleScript )
|
|
RecvPropFloat( RECVINFO(m_flSequenceScale) ),
|
|
END_RECV_TABLE()
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Constructor
|
|
//-----------------------------------------------------------------------------
|
|
C_EnvParticleScript::C_EnvParticleScript()
|
|
{
|
|
m_flMaxParticleSize = 0.0f;
|
|
m_bSimulate = true;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Check for changed sequence numbers
|
|
//-----------------------------------------------------------------------------
|
|
void C_EnvParticleScript::OnPreDataChanged( DataUpdateType_t updateType )
|
|
{
|
|
BaseClass::OnPreDataChanged( updateType );
|
|
|
|
m_nOldSequence = GetSequence();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Starts up the particle system
|
|
//-----------------------------------------------------------------------------
|
|
void C_EnvParticleScript::OnDataChanged( DataUpdateType_t updateType )
|
|
{
|
|
BaseClass::OnDataChanged( updateType );
|
|
|
|
if( updateType == DATA_UPDATE_CREATED )
|
|
{
|
|
ParticleMgr()->AddEffect( &m_ParticleEffect, this );
|
|
g_pClientLeafSystem->EnableRendering( RenderHandle(), false );
|
|
}
|
|
|
|
if ( m_nOldSequence != GetSequence() )
|
|
{
|
|
DestroyAllParticles();
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Creates, destroys particles attached to an attachment
|
|
//-----------------------------------------------------------------------------
|
|
void C_EnvParticleScript::CreateParticle( const char *pAttachmentName, const char *pSpriteName )
|
|
{
|
|
// Find the attachment
|
|
int nAttachment = LookupAttachment( pAttachmentName );
|
|
if ( nAttachment <= 0 )
|
|
return;
|
|
|
|
// Get the sprite materials
|
|
PMaterialHandle hMat = m_ParticleEffect.FindOrAddMaterial( pSpriteName );
|
|
ParticleScriptParticle_t *pParticle =
|
|
(ParticleScriptParticle_t*)m_ParticleEffect.AddParticle(sizeof(ParticleScriptParticle_t), hMat);
|
|
|
|
if ( pParticle == NULL )
|
|
return;
|
|
|
|
// Get the sprite size from the material's materialvars
|
|
bool bFound = false;
|
|
IMaterialVar *pMaterialVar = NULL;
|
|
IMaterial *pMaterial = ParticleMgr()->PMaterialToIMaterial( hMat );
|
|
if ( pMaterial )
|
|
{
|
|
pMaterialVar = pMaterial->FindVar( "$spritesize", &bFound, false );
|
|
}
|
|
|
|
if ( bFound )
|
|
{
|
|
pParticle->m_flSize = pMaterialVar->GetFloatValue();
|
|
}
|
|
else
|
|
{
|
|
pParticle->m_flSize = 100.0f;
|
|
}
|
|
|
|
// Make sure the particle cull size reflects our particles
|
|
if ( pParticle->m_flSize > m_flMaxParticleSize )
|
|
{
|
|
m_flMaxParticleSize = pParticle->m_flSize;
|
|
m_ParticleEffect.SetParticleCullRadius( m_flMaxParticleSize );
|
|
}
|
|
|
|
// Place the particle on the attachment specified
|
|
pParticle->m_nAttachment = nAttachment;
|
|
QAngle vecAngles;
|
|
GetAttachment( nAttachment, pParticle->m_Pos, vecAngles );
|
|
|
|
if ( m_flSequenceScale != 1.0f )
|
|
{
|
|
pParticle->m_Pos -= GetAbsOrigin();
|
|
pParticle->m_Pos *= m_flSequenceScale;
|
|
pParticle->m_Pos += GetAbsOrigin();
|
|
}
|
|
}
|
|
|
|
void C_EnvParticleScript::DestroyAllParticles( const char *pAttachmentName )
|
|
{
|
|
int nAttachment = LookupAttachment( pAttachmentName );
|
|
if ( nAttachment <= 0 )
|
|
return;
|
|
|
|
int nCount = m_ParticleEffect.GetNumActiveParticles();
|
|
Particle** ppParticles = (Particle**)stackalloc( nCount * sizeof(Particle*) );
|
|
int nActualCount = m_ParticleEffect.GetActiveParticleList( nCount, ppParticles );
|
|
Assert( nActualCount == nCount );
|
|
|
|
for ( int i = 0; i < nActualCount; ++i )
|
|
{
|
|
ParticleScriptParticle_t *pParticle = (ParticleScriptParticle_t*)ppParticles[i];
|
|
if ( pParticle->m_nAttachment == nAttachment )
|
|
{
|
|
// Mark for deletion
|
|
pParticle->m_nAttachment = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void C_EnvParticleScript::DestroyAllParticles( )
|
|
{
|
|
int nCount = m_ParticleEffect.GetNumActiveParticles();
|
|
Particle** ppParticles = (Particle**)stackalloc( nCount * sizeof(Particle*) );
|
|
int nActualCount = m_ParticleEffect.GetActiveParticleList( nCount, ppParticles );
|
|
Assert( nActualCount == nCount );
|
|
|
|
for ( int i = 0; i < nActualCount; ++i )
|
|
{
|
|
ParticleScriptParticle_t *pParticle = (ParticleScriptParticle_t*)ppParticles[i];
|
|
|
|
// Mark for deletion
|
|
pParticle->m_nAttachment = -1;
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// The animation events will create particles on the attachment points
|
|
//-----------------------------------------------------------------------------
|
|
void C_EnvParticleScript::FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options )
|
|
{
|
|
// Handle events to create + destroy particles
|
|
switch( event )
|
|
{
|
|
case CL_EVENT_SPRITEGROUP_CREATE:
|
|
{
|
|
char pAttachmentName[256];
|
|
char pSpriteName[256];
|
|
int nArgs = sscanf( options, "%255s %255s", pAttachmentName, pSpriteName );
|
|
if ( nArgs == 2 )
|
|
{
|
|
CreateParticle( pAttachmentName, pSpriteName );
|
|
}
|
|
}
|
|
return;
|
|
|
|
case CL_EVENT_SPRITEGROUP_DESTROY:
|
|
{
|
|
char pAttachmentName[256];
|
|
int nArgs = sscanf( options, "%255s", pAttachmentName );
|
|
if ( nArgs == 1 )
|
|
{
|
|
DestroyAllParticles( pAttachmentName );
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Fall back
|
|
BaseClass::FireEvent( origin, angles, event, options );
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Simulate the particles
|
|
//-----------------------------------------------------------------------------
|
|
void C_EnvParticleScript::RenderParticles( CParticleRenderIterator *pIterator )
|
|
{
|
|
const ParticleScriptParticle_t* pParticle = (const ParticleScriptParticle_t*)pIterator->GetFirst();
|
|
while ( pParticle )
|
|
{
|
|
Vector vecRenderPos;
|
|
TransformParticle( ParticleMgr()->GetModelView(), pParticle->m_Pos, vecRenderPos );
|
|
float sortKey = vecRenderPos.z;
|
|
|
|
Vector color( 1, 1, 1 );
|
|
RenderParticle_ColorSize( pIterator->GetParticleDraw(), vecRenderPos, color, 1.0f, pParticle->m_flSize );
|
|
|
|
pParticle = (const ParticleScriptParticle_t*)pIterator->GetNext( sortKey );
|
|
}
|
|
}
|
|
|
|
void C_EnvParticleScript::SimulateParticles( CParticleSimulateIterator *pIterator )
|
|
{
|
|
ParticleScriptParticle_t* pParticle = (ParticleScriptParticle_t*)pIterator->GetFirst();
|
|
while ( pParticle )
|
|
{
|
|
// Here's how we retire particles
|
|
if ( pParticle->m_nAttachment == -1 )
|
|
{
|
|
pIterator->RemoveParticle( pParticle );
|
|
}
|
|
else
|
|
{
|
|
// Move the particle to the attachment point
|
|
QAngle vecAngles;
|
|
GetAttachment( pParticle->m_nAttachment, pParticle->m_Pos, vecAngles );
|
|
|
|
if ( m_flSequenceScale != 1.0f )
|
|
{
|
|
pParticle->m_Pos -= GetAbsOrigin();
|
|
pParticle->m_Pos *= m_flSequenceScale;
|
|
pParticle->m_Pos += GetAbsOrigin();
|
|
}
|
|
}
|
|
|
|
pParticle = (ParticleScriptParticle_t*)pIterator->GetNext();
|
|
}
|
|
}
|
|
|
|
const Vector &C_EnvParticleScript::GetSortOrigin()
|
|
{
|
|
return GetAbsOrigin();
|
|
}
|