Team Fortress 2 Source Code as on 22/4/2020
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

//========= 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();
}