You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
304 lines
8.9 KiB
304 lines
8.9 KiB
//========= Copyright 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 ) { return 0; } |
|
virtual int GetFxBlend( void ) { 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 ); |
|
} |
|
|
|
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(); |
|
}
|
|
|