mirror of
https://github.com/nillerusr/source-engine.git
synced 2025-01-13 00:28:18 +00:00
296 lines
7.3 KiB
C++
296 lines
7.3 KiB
C++
#include "cbase.h"
|
|
#include "c_te_effect_dispatch.h"
|
|
#include "c_asw_mesh_emitter_entity.h"
|
|
#include "c_asw_generic_emitter.h"
|
|
#include "model_types.h"
|
|
#include "engine/IVDebugOverlay.h"
|
|
#include "tier0/vprof.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
// this is a particle emitter where each particle is a mesh instead of a sprite
|
|
|
|
LINK_ENTITY_TO_CLASS( client_asw_mesh_emitter, C_ASW_Mesh_Emitter );
|
|
|
|
C_ASW_Mesh_Emitter::C_ASW_Mesh_Emitter()
|
|
{
|
|
DisableCachedRenderBounds( true );
|
|
|
|
m_fScale = 1.0f;
|
|
m_fDieTime = false;
|
|
|
|
m_hClientAttach = NULL;
|
|
m_szAttach[0] = 0;
|
|
|
|
m_bFrozen = false;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Called when data changes on the server
|
|
//-----------------------------------------------------------------------------
|
|
void C_ASW_Mesh_Emitter::OnDataChanged( DataUpdateType_t updateType )
|
|
{
|
|
// NOTE: We MUST call the base classes' implementation of this function
|
|
BaseClass::OnDataChanged( updateType );
|
|
|
|
// Setup our entity's particle system on creation
|
|
if ( updateType == DATA_UPDATE_CREATED )
|
|
{
|
|
CreateEmitter(vec3_origin);
|
|
}
|
|
//if (m_hEmitter.IsValid() && !strcmp(m_szTemplateName, m_hEmitter->GetTemplateName()))
|
|
//m_hEmitter->UseTemplate(m_szTemplateName);
|
|
|
|
m_hEmitter->SetActive(m_bEmit);
|
|
m_hEmitter->Update();
|
|
}
|
|
|
|
void C_ASW_Mesh_Emitter::CreateEmitter(const Vector &force)
|
|
{
|
|
// Creat the emitter
|
|
m_hEmitter = CASWGenericEmitter::Create( "asw_emitter" );
|
|
m_hEmitter->SetSortOrigin(GetAbsOrigin());
|
|
|
|
// Obtain a reference handle to our particle's desired material
|
|
if ( m_hEmitter.IsValid() )
|
|
{
|
|
m_hEmitter->UseTemplate(m_szTemplateName);
|
|
m_hEmitter->velocityMin += force;
|
|
m_hEmitter->velocityMax += force;
|
|
m_hEmitter->SetMeshEmitter(this);
|
|
m_hEmitter->SetEmitterScale(m_fScale);
|
|
//m_hMaterial = m_hEmitter->GetPMaterial( "effects/yellowflare" );
|
|
//sprintf(m_szMaterialName, "effects/yellowflare");
|
|
m_hEmitter->m_bHullTraces = true;
|
|
m_hEmitter->m_fReduceRollRateOnCollision = 0.7f;
|
|
m_hEmitter->SetActive(m_bEmit);
|
|
m_hEmitter->Update();
|
|
}
|
|
|
|
// Call our ClientThink() function once every client frame
|
|
SetNextClientThink( CLIENT_THINK_ALWAYS );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Client-side think function for the entity
|
|
//-----------------------------------------------------------------------------
|
|
void C_ASW_Mesh_Emitter::ClientThink( void )
|
|
{
|
|
// We must have a valid emitter
|
|
if ( m_hEmitter == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// if we're clientside attached to something, update our position/angle
|
|
if (m_hClientAttach.Get())
|
|
{
|
|
Vector pos;
|
|
QAngle ang;
|
|
m_hClientAttach->GetAttachment( m_hClientAttach->LookupAttachment( m_szAttach ), pos, ang );
|
|
SetAbsOrigin(pos);
|
|
SetAbsAngles(ang);
|
|
}
|
|
|
|
m_hEmitter->Think(gpGlobals->frametime, GetAbsOrigin(), GetAbsAngles());
|
|
if (m_fScale != m_fDesiredScale)
|
|
{
|
|
if (m_fScale < m_fDesiredScale)
|
|
{
|
|
m_fScale = MIN(m_fScale + m_fScaleRate * gpGlobals->frametime, m_fDesiredScale);
|
|
}
|
|
else
|
|
{
|
|
m_fScale = MAX(m_fScale - m_fScaleRate * gpGlobals->frametime, m_fDesiredScale);
|
|
}
|
|
}
|
|
m_hEmitter->SetEmitterScale(m_fScale);
|
|
if (gpGlobals->curtime > m_fDieTime && m_fDieTime != 0)
|
|
{
|
|
Die();
|
|
}
|
|
}
|
|
|
|
|
|
void C_ASW_Mesh_Emitter::UseTemplate(const char* pTemplateName, bool bLoadFromCache)
|
|
{
|
|
if (m_hEmitter == NULL)
|
|
return;
|
|
|
|
strcpy(m_szTemplateName, pTemplateName);
|
|
m_hEmitter->UseTemplate(pTemplateName,true,bLoadFromCache);
|
|
m_hEmitter->SetMeshEmitter(this);
|
|
}
|
|
|
|
void C_ASW_Mesh_Emitter::SaveAsTemplate(const char* pTemplateName)
|
|
{
|
|
if (m_hEmitter == NULL)
|
|
return;
|
|
|
|
strcpy(m_szTemplateName, pTemplateName);
|
|
m_hEmitter->SaveTemplateAs(pTemplateName);
|
|
}
|
|
|
|
void C_ASW_Mesh_Emitter::SetDieTime(float fDieTime)
|
|
{
|
|
m_fDieTime = fDieTime;
|
|
}
|
|
|
|
void C_ASW_Mesh_Emitter::Die()
|
|
{
|
|
// make sure our emitter knows to die
|
|
if (!(m_hEmitter == NULL))
|
|
{
|
|
m_hEmitter->SetDieTime(m_fDieTime);
|
|
}
|
|
Release();
|
|
}
|
|
|
|
void C_ASW_Mesh_Emitter::ClientAttach(C_BaseAnimating *pParent, const char *szAttach)
|
|
{
|
|
strcpy(m_szAttach, szAttach);
|
|
m_hClientAttach = pParent;
|
|
}
|
|
|
|
bool C_ASW_Mesh_Emitter::PrepareToDraw()
|
|
{
|
|
if ( !GetModel() )
|
|
return false;
|
|
|
|
if (!m_hEmitter)
|
|
return false;
|
|
|
|
// This should never happen, but if the server class hierarchy has bmodel entities derived from CBaseAnimating or does a
|
|
// SetModel with the wrong type of model, this could occur.
|
|
if ( modelinfo->GetModelType( GetModel() ) != mod_studio )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Make sure hdr is valid for drawing
|
|
if ( !GetModelPtr() )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
// don't use fast path
|
|
IClientModelRenderable* C_ASW_Mesh_Emitter::GetClientModelRenderable()
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
int C_ASW_Mesh_Emitter::InternalDrawModel( int flags, const RenderableInstance_t &instance )
|
|
{
|
|
VPROF( "C_ASW_Mesh_Emitter::InternalDrawModel" );
|
|
|
|
if ( !GetModel() )
|
|
return 0;
|
|
|
|
if (!m_hEmitter)
|
|
return 0;
|
|
|
|
// This should never happen, but if the server class hierarchy has bmodel entities derived from CBaseAnimating or does a
|
|
// SetModel with the wrong type of model, this could occur.
|
|
if ( modelinfo->GetModelType( GetModel() ) != mod_studio )
|
|
{
|
|
return BaseClass::DrawModel( flags, instance );
|
|
}
|
|
|
|
// Make sure hdr is valid for drawing
|
|
if ( !GetModelPtr() )
|
|
return 0;
|
|
|
|
if ( IsEffectActive( EF_ITEM_BLINK ) )
|
|
{
|
|
flags |= STUDIO_ITEM_BLINK;
|
|
}
|
|
|
|
ModelRenderInfo_t sInfo;
|
|
sInfo.flags = flags;
|
|
sInfo.pRenderable = this;
|
|
sInfo.instance = GetModelInstance();
|
|
sInfo.entity_index = index;
|
|
sInfo.pModel = GetModel();
|
|
sInfo.origin = GetRenderOrigin();
|
|
sInfo.angles = GetRenderAngles();
|
|
sInfo.skin = m_nSkin;
|
|
sInfo.body = m_nBody;
|
|
sInfo.hitboxset = m_nHitboxSet;
|
|
|
|
Vector vecPreDrawPos = GetAbsOrigin();
|
|
QAngle angPreDrawAngles = GetAbsAngles();
|
|
|
|
int drawn = 0;
|
|
for (int i=0; i<m_hEmitter->GetBinding().m_Materials.Count(); i++)
|
|
{
|
|
CEffectMaterial *pMaterial = m_hEmitter->GetBinding().m_Materials[i];
|
|
if (pMaterial)
|
|
{
|
|
Particle *pCur = pMaterial->m_Particles.m_pNext;
|
|
while (pCur != &pMaterial->m_Particles && pCur != NULL)
|
|
{
|
|
InvalidateBoneCaches();
|
|
SetAbsOrigin( pCur->m_Pos );
|
|
ASWParticle *pParticle = static_cast<ASWParticle*>(pCur);
|
|
if (pParticle)
|
|
{
|
|
float roll = RAD2DEG(pParticle->m_flRoll);
|
|
//Msg("Setting angle to roll %f\n", pParticle->m_flRoll);
|
|
SetAbsAngles( QAngle(roll, roll, roll) );
|
|
}
|
|
else
|
|
{
|
|
Msg("Couldn't get aswparticle\n");
|
|
}
|
|
sInfo.origin = pCur->m_Pos;
|
|
sInfo.angles = GetAbsAngles();
|
|
drawn += modelrender->DrawModelEx( sInfo );
|
|
pCur = pCur->m_pNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetAbsOrigin(vecPreDrawPos);
|
|
SetAbsAngles(angPreDrawAngles);
|
|
|
|
|
|
if (drawn > 0)
|
|
{
|
|
drawn = 1;
|
|
}
|
|
|
|
return drawn;
|
|
}
|
|
|
|
int C_ASW_Mesh_Emitter::DrawParticle(Vector &vecPos)
|
|
{
|
|
VPROF( "C_ASW_Mesh_Emitter::DrawParticle" );
|
|
|
|
ModelRenderInfo_t sInfo;
|
|
sInfo.flags = STUDIO_RENDER;
|
|
sInfo.pRenderable = this;
|
|
sInfo.instance = GetModelInstance();
|
|
sInfo.entity_index = index;
|
|
sInfo.pModel = GetModel();
|
|
sInfo.origin = vecPos;
|
|
sInfo.angles = QAngle(0,0,0);
|
|
sInfo.skin = m_nSkin;
|
|
sInfo.body = m_nBody;
|
|
sInfo.hitboxset = m_nHitboxSet;
|
|
|
|
int drawn = modelrender->DrawModelEx( sInfo ); // asw 1.0f, 0.2f
|
|
|
|
return drawn;
|
|
}
|
|
|
|
void C_ASW_Mesh_Emitter::GetRenderBounds( Vector& theMins, Vector& theMaxs )
|
|
{
|
|
if (m_hEmitter.IsValid())
|
|
{
|
|
m_hEmitter->GetBinding().GetRenderBounds(theMins, theMaxs);
|
|
return;
|
|
}
|
|
BaseClass::GetRenderBounds(theMins, theMaxs);
|
|
} |