mirror of
https://github.com/alliedmodders/hl2sdk.git
synced 2025-09-19 12:06:07 +08:00
Added most recent version of unmodified HL2 SDK for Episode 1 engine
This commit is contained in:
529
cl_dll/c_steamjet.cpp
Normal file
529
cl_dll/c_steamjet.cpp
Normal file
@ -0,0 +1,529 @@
|
||||
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Implements a particle system steam jet.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
#include "cbase.h"
|
||||
#include "particle_prototype.h"
|
||||
#include "particle_util.h"
|
||||
#include "baseparticleentity.h"
|
||||
#include "ClientEffectPrecacheSystem.h"
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
//NOTENOTE: Mirrored in dlls\steamjet.h
|
||||
#define STEAM_NORMAL 0
|
||||
#define STEAM_HEATWAVE 1
|
||||
|
||||
#define STEAMJET_NUMRAMPS 5
|
||||
#define SF_EMISSIVE 0x00000001
|
||||
|
||||
|
||||
CLIENTEFFECT_REGISTER_BEGIN( PrecacheSteamJet )
|
||||
CLIENTEFFECT_MATERIAL( "particle/particle_smokegrenade" )
|
||||
CLIENTEFFECT_MATERIAL( "sprites/heatwave" )
|
||||
CLIENTEFFECT_REGISTER_END()
|
||||
|
||||
//==================================================
|
||||
// C_SteamJet
|
||||
//==================================================
|
||||
|
||||
class C_SteamJet : public C_BaseParticleEntity, public IPrototypeAppEffect
|
||||
{
|
||||
public:
|
||||
DECLARE_CLIENTCLASS();
|
||||
DECLARE_CLASS( C_SteamJet, C_BaseParticleEntity );
|
||||
|
||||
C_SteamJet();
|
||||
~C_SteamJet();
|
||||
|
||||
class SteamJetParticle : public Particle
|
||||
{
|
||||
public:
|
||||
Vector m_Velocity;
|
||||
float m_flRoll;
|
||||
float m_flRollDelta;
|
||||
float m_Lifetime;
|
||||
float m_DieTime;
|
||||
unsigned char m_uchStartSize;
|
||||
unsigned char m_uchEndSize;
|
||||
};
|
||||
|
||||
int IsEmissive( void ) { return ( m_spawnflags & SF_EMISSIVE ); }
|
||||
|
||||
//C_BaseEntity
|
||||
public:
|
||||
|
||||
virtual void OnDataChanged( DataUpdateType_t updateType );
|
||||
|
||||
|
||||
//IPrototypeAppEffect
|
||||
public:
|
||||
virtual void Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs);
|
||||
virtual bool GetPropEditInfo(RecvTable **ppTable, void **ppObj);
|
||||
|
||||
|
||||
//IParticleEffect
|
||||
public:
|
||||
virtual void Update(float fTimeDelta);
|
||||
virtual void RenderParticles( CParticleRenderIterator *pIterator );
|
||||
virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
|
||||
|
||||
|
||||
//Stuff from the datatable
|
||||
public:
|
||||
|
||||
float m_SpreadSpeed;
|
||||
float m_Speed;
|
||||
float m_StartSize;
|
||||
float m_EndSize;
|
||||
float m_Rate;
|
||||
float m_JetLength; // Length of the jet. Lifetime is derived from this.
|
||||
|
||||
int m_bEmit; // Emit particles?
|
||||
int m_nType; // Type of particles to emit
|
||||
bool m_bFaceLeft; // For support of legacy env_steamjet entity, which faced left instead of forward.
|
||||
|
||||
int m_spawnflags;
|
||||
float m_flRollSpeed;
|
||||
|
||||
private:
|
||||
|
||||
void UpdateLightingRamp();
|
||||
|
||||
private:
|
||||
|
||||
// Stored the last time it updates the lighting ramp, so it can cache the values.
|
||||
Vector m_vLastRampUpdatePos;
|
||||
QAngle m_vLastRampUpdateAngles;
|
||||
|
||||
float m_Lifetime; // Calculated from m_JetLength / m_Speed;
|
||||
|
||||
// We sample the world to get these colors and ramp the particles.
|
||||
Vector m_Ramps[STEAMJET_NUMRAMPS];
|
||||
|
||||
CParticleMgr *m_pParticleMgr;
|
||||
PMaterialHandle m_MaterialHandle;
|
||||
TimedEvent m_ParticleSpawn;
|
||||
|
||||
private:
|
||||
C_SteamJet( const C_SteamJet & );
|
||||
};
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
// Tables.
|
||||
// ------------------------------------------------------------------------- //
|
||||
|
||||
// Expose to the particle app.
|
||||
EXPOSE_PROTOTYPE_EFFECT(SteamJet, C_SteamJet);
|
||||
|
||||
|
||||
// Datatable..
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_SteamJet, DT_SteamJet, CSteamJet)
|
||||
RecvPropFloat(RECVINFO(m_SpreadSpeed), 0),
|
||||
RecvPropFloat(RECVINFO(m_Speed), 0),
|
||||
RecvPropFloat(RECVINFO(m_StartSize), 0),
|
||||
RecvPropFloat(RECVINFO(m_EndSize), 0),
|
||||
RecvPropFloat(RECVINFO(m_Rate), 0),
|
||||
RecvPropFloat(RECVINFO(m_JetLength), 0),
|
||||
RecvPropInt(RECVINFO(m_bEmit), 0),
|
||||
RecvPropInt(RECVINFO(m_bFaceLeft), 0),
|
||||
RecvPropInt(RECVINFO(m_nType), 0),
|
||||
RecvPropInt( RECVINFO( m_spawnflags ) ),
|
||||
RecvPropFloat(RECVINFO(m_flRollSpeed), 0 ),
|
||||
END_RECV_TABLE()
|
||||
|
||||
// ------------------------------------------------------------------------- //
|
||||
// C_SteamJet implementation.
|
||||
// ------------------------------------------------------------------------- //
|
||||
C_SteamJet::C_SteamJet()
|
||||
{
|
||||
m_pParticleMgr = NULL;
|
||||
m_MaterialHandle = INVALID_MATERIAL_HANDLE;
|
||||
|
||||
m_SpreadSpeed = 15;
|
||||
m_Speed = 120;
|
||||
m_StartSize = 10;
|
||||
m_EndSize = 25;
|
||||
m_Rate = 26;
|
||||
m_JetLength = 80;
|
||||
m_bEmit = true;
|
||||
m_bFaceLeft = false;
|
||||
m_ParticleEffect.SetAlwaysSimulate( false ); // Don't simulate outside the PVS or frustum.
|
||||
|
||||
m_vLastRampUpdatePos.Init( 1e24, 1e24, 1e24 );
|
||||
m_vLastRampUpdateAngles.Init( 1e24, 1e24, 1e24 );
|
||||
}
|
||||
|
||||
|
||||
C_SteamJet::~C_SteamJet()
|
||||
{
|
||||
if(m_pParticleMgr)
|
||||
m_pParticleMgr->RemoveEffect( &m_ParticleEffect );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Called after a data update has occured
|
||||
// Input : bnewentity -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_SteamJet::OnDataChanged(DataUpdateType_t updateType)
|
||||
{
|
||||
C_BaseEntity::OnDataChanged(updateType);
|
||||
|
||||
if(updateType == DATA_UPDATE_CREATED)
|
||||
{
|
||||
Start(ParticleMgr(), NULL);
|
||||
}
|
||||
|
||||
// Recalulate lifetime in case length or speed changed.
|
||||
m_Lifetime = m_JetLength / m_Speed;
|
||||
m_ParticleEffect.SetParticleCullRadius( max(m_StartSize, m_EndSize) );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Starts the effect
|
||||
// Input : *pParticleMgr -
|
||||
// *pArgs -
|
||||
//-----------------------------------------------------------------------------
|
||||
void C_SteamJet::Start(CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs)
|
||||
{
|
||||
pParticleMgr->AddEffect( &m_ParticleEffect, this );
|
||||
|
||||
switch(m_nType)
|
||||
{
|
||||
case STEAM_NORMAL:
|
||||
default:
|
||||
m_MaterialHandle = m_ParticleEffect.FindOrAddMaterial("particle/particle_smokegrenade");
|
||||
break;
|
||||
|
||||
case STEAM_HEATWAVE:
|
||||
m_MaterialHandle = m_ParticleEffect.FindOrAddMaterial("sprites/heatwave");
|
||||
break;
|
||||
}
|
||||
|
||||
m_ParticleSpawn.Init(m_Rate);
|
||||
m_Lifetime = m_JetLength / m_Speed;
|
||||
m_pParticleMgr = pParticleMgr;
|
||||
|
||||
UpdateLightingRamp();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : **ppTable -
|
||||
// **ppObj -
|
||||
// Output : Returns true on success, false on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
bool C_SteamJet::GetPropEditInfo( RecvTable **ppTable, void **ppObj )
|
||||
{
|
||||
*ppTable = &REFERENCE_RECV_TABLE(DT_SteamJet);
|
||||
*ppObj = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// This might be useful someday.
|
||||
/*
|
||||
void CalcFastApproximateRenderBoundsAABB( C_BaseEntity *pEnt, float flBloatSize, Vector *pMin, Vector *pMax )
|
||||
{
|
||||
C_BaseEntity *pParent = pEnt->GetMoveParent();
|
||||
if ( pParent )
|
||||
{
|
||||
// Get the parent's abs space world bounds.
|
||||
CalcFastApproximateRenderBoundsAABB( pParent, 0, pMin, pMax );
|
||||
|
||||
// Add the maximum of our local render bounds. This is making the assumption that we can be at any
|
||||
// point and at any angle within the parent's world space bounds.
|
||||
Vector vAddMins, vAddMaxs;
|
||||
pEnt->GetRenderBounds( vAddMins, vAddMaxs );
|
||||
|
||||
flBloatSize += max( vAddMins.Length(), vAddMaxs.Length() );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Start out with our own render bounds. Since we don't have a parent, this won't incur any nasty
|
||||
pEnt->GetRenderBoundsWorldspace( *pMin, *pMax );
|
||||
}
|
||||
|
||||
// Bloat the box.
|
||||
if ( flBloatSize )
|
||||
{
|
||||
*pMin -= Vector( flBloatSize, flBloatSize, flBloatSize );
|
||||
*pMax += Vector( flBloatSize, flBloatSize, flBloatSize );
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
// Input : fTimeDelta -
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void C_SteamJet::Update(float fTimeDelta)
|
||||
{
|
||||
if(!m_pParticleMgr)
|
||||
{
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_bEmit )
|
||||
{
|
||||
// Add new particles.
|
||||
int nToEmit = 0;
|
||||
float tempDelta = fTimeDelta;
|
||||
while( m_ParticleSpawn.NextEvent(tempDelta) )
|
||||
++nToEmit;
|
||||
|
||||
if ( nToEmit > 0 )
|
||||
{
|
||||
Vector forward, right, up;
|
||||
AngleVectors(GetAbsAngles(), &forward, &right, &up);
|
||||
|
||||
// Legacy env_steamjet entities faced left instead of forward.
|
||||
if (m_bFaceLeft)
|
||||
{
|
||||
Vector temp = forward;
|
||||
forward = -right;
|
||||
right = temp;
|
||||
}
|
||||
|
||||
// EVIL: Ideally, we could tell the renderer our OBB, and let it build a big box that encloses
|
||||
// the entity with its parent so it doesn't have to setup its parent's bones here.
|
||||
Vector vEndPoint = GetAbsOrigin() + forward * m_Speed;
|
||||
Vector vMin, vMax;
|
||||
VectorMin( GetAbsOrigin(), vEndPoint, vMin );
|
||||
VectorMax( GetAbsOrigin(), vEndPoint, vMax );
|
||||
m_ParticleEffect.SetBBox( vMin, vMax );
|
||||
|
||||
if ( m_ParticleEffect.WasDrawnPrevFrame() )
|
||||
{
|
||||
while ( nToEmit-- )
|
||||
{
|
||||
// Make a new particle.
|
||||
if( SteamJetParticle *pParticle = (SteamJetParticle*) m_ParticleEffect.AddParticle( sizeof(SteamJetParticle), m_MaterialHandle ) )
|
||||
{
|
||||
pParticle->m_Pos = GetAbsOrigin();
|
||||
|
||||
pParticle->m_Velocity =
|
||||
FRand(-m_SpreadSpeed,m_SpreadSpeed) * right +
|
||||
FRand(-m_SpreadSpeed,m_SpreadSpeed) * up +
|
||||
m_Speed * forward;
|
||||
|
||||
pParticle->m_Lifetime = 0;
|
||||
pParticle->m_DieTime = m_Lifetime;
|
||||
|
||||
pParticle->m_uchStartSize = m_StartSize;
|
||||
pParticle->m_uchEndSize = m_EndSize;
|
||||
|
||||
pParticle->m_flRoll = random->RandomFloat( 0, 360 );
|
||||
pParticle->m_flRollDelta = random->RandomFloat( -m_flRollSpeed, m_flRollSpeed );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UpdateLightingRamp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Render a quad on the screen where you pass in color and size.
|
||||
// Normal is random and "flutters"
|
||||
inline void RenderParticle_ColorSizePerturbNormal(
|
||||
ParticleDraw* pDraw,
|
||||
const Vector &pos,
|
||||
const Vector &color,
|
||||
const float alpha,
|
||||
const float size
|
||||
)
|
||||
{
|
||||
// Don't render totally transparent particles.
|
||||
if( alpha < 0.001f )
|
||||
return;
|
||||
|
||||
CMeshBuilder *pBuilder = pDraw->GetMeshBuilder();
|
||||
if( !pBuilder )
|
||||
return;
|
||||
|
||||
unsigned char ubColor[4];
|
||||
ubColor[0] = (unsigned char)RoundFloatToInt( color.x * 254.9f );
|
||||
ubColor[1] = (unsigned char)RoundFloatToInt( color.y * 254.9f );
|
||||
ubColor[2] = (unsigned char)RoundFloatToInt( color.z * 254.9f );
|
||||
ubColor[3] = (unsigned char)RoundFloatToInt( alpha * 254.9f );
|
||||
|
||||
Vector vNorm;
|
||||
|
||||
vNorm.Random( -1.0f, 1.0f );
|
||||
|
||||
// Add the 4 corner vertices.
|
||||
pBuilder->Position3f( pos.x-size, pos.y-size, pos.z );
|
||||
pBuilder->Color4ubv( ubColor );
|
||||
pBuilder->Normal3fv( vNorm.Base() );
|
||||
pBuilder->TexCoord2f( 0, 0, 1.0f );
|
||||
pBuilder->AdvanceVertex();
|
||||
|
||||
pBuilder->Position3f( pos.x-size, pos.y+size, pos.z );
|
||||
pBuilder->Color4ubv( ubColor );
|
||||
pBuilder->Normal3fv( vNorm.Base() );
|
||||
pBuilder->TexCoord2f( 0, 0, 0 );
|
||||
pBuilder->AdvanceVertex();
|
||||
|
||||
pBuilder->Position3f( pos.x+size, pos.y+size, pos.z );
|
||||
pBuilder->Color4ubv( ubColor );
|
||||
pBuilder->Normal3fv( vNorm.Base() );
|
||||
pBuilder->TexCoord2f( 0, 1.0f, 0 );
|
||||
pBuilder->AdvanceVertex();
|
||||
|
||||
pBuilder->Position3f( pos.x+size, pos.y-size, pos.z );
|
||||
pBuilder->Color4ubv( ubColor );
|
||||
pBuilder->Normal3fv( vNorm.Base() );
|
||||
pBuilder->TexCoord2f( 0, 1.0f, 1.0f );
|
||||
pBuilder->AdvanceVertex();
|
||||
}
|
||||
|
||||
|
||||
void C_SteamJet::RenderParticles( CParticleRenderIterator *pIterator )
|
||||
{
|
||||
const SteamJetParticle *pParticle = (const SteamJetParticle*)pIterator->GetFirst();
|
||||
while ( pParticle )
|
||||
{
|
||||
// Render.
|
||||
Vector tPos;
|
||||
TransformParticle(m_pParticleMgr->GetModelView(), pParticle->m_Pos, tPos);
|
||||
float sortKey = tPos.z;
|
||||
|
||||
float lifetimeT = pParticle->m_Lifetime / (pParticle->m_DieTime + 0.001);
|
||||
float fRamp = lifetimeT * (STEAMJET_NUMRAMPS-1);
|
||||
int iRamp = (int)fRamp;
|
||||
float fraction = fRamp - iRamp;
|
||||
|
||||
Vector vRampColor = m_Ramps[iRamp] + (m_Ramps[iRamp+1] - m_Ramps[iRamp]) * fraction;
|
||||
|
||||
vRampColor[0] = min( 1.0f, vRampColor[0] );
|
||||
vRampColor[1] = min( 1.0f, vRampColor[1] );
|
||||
vRampColor[2] = min( 1.0f, vRampColor[2] );
|
||||
|
||||
float sinLifetime = sin(pParticle->m_Lifetime * 3.14159f / pParticle->m_DieTime);
|
||||
|
||||
if ( m_nType == STEAM_HEATWAVE )
|
||||
{
|
||||
RenderParticle_ColorSizePerturbNormal(
|
||||
pIterator->GetParticleDraw(),
|
||||
tPos,
|
||||
vRampColor,
|
||||
sinLifetime * (m_clrRender->a/255.0f),
|
||||
FLerp(m_StartSize, m_EndSize, pParticle->m_Lifetime));
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderParticle_ColorSizeAngle(
|
||||
pIterator->GetParticleDraw(),
|
||||
tPos,
|
||||
vRampColor,
|
||||
sinLifetime * (m_clrRender->a/255.0f),
|
||||
FLerp(pParticle->m_uchStartSize, pParticle->m_uchEndSize, pParticle->m_Lifetime),
|
||||
pParticle->m_flRoll );
|
||||
}
|
||||
|
||||
pParticle = (const SteamJetParticle*)pIterator->GetNext( sortKey );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void C_SteamJet::SimulateParticles( CParticleSimulateIterator *pIterator )
|
||||
{
|
||||
//Don't simulate if we're emiting particles...
|
||||
//This fixes the cases where looking away from a steam jet and then looking back would cause a break on the stream.
|
||||
if ( m_ParticleEffect.WasDrawnPrevFrame() == false && m_bEmit )
|
||||
return;
|
||||
|
||||
SteamJetParticle *pParticle = (SteamJetParticle*)pIterator->GetFirst();
|
||||
while ( pParticle )
|
||||
{
|
||||
// Should this particle die?
|
||||
pParticle->m_Lifetime += pIterator->GetTimeDelta();
|
||||
|
||||
if( pParticle->m_Lifetime > pParticle->m_DieTime )
|
||||
{
|
||||
pIterator->RemoveParticle( pParticle );
|
||||
}
|
||||
else
|
||||
{
|
||||
pParticle->m_flRoll += pParticle->m_flRollDelta * pIterator->GetTimeDelta();
|
||||
pParticle->m_Pos = pParticle->m_Pos + pParticle->m_Velocity * pIterator->GetTimeDelta();
|
||||
}
|
||||
|
||||
pParticle = (SteamJetParticle*)pIterator->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void C_SteamJet::UpdateLightingRamp()
|
||||
{
|
||||
if( VectorsAreEqual( m_vLastRampUpdatePos, GetAbsOrigin(), 0.1 ) &&
|
||||
QAnglesAreEqual( m_vLastRampUpdateAngles, GetAbsAngles(), 0.1 ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_vLastRampUpdatePos = GetAbsOrigin();
|
||||
m_vLastRampUpdateAngles = GetAbsAngles();
|
||||
|
||||
// Sample the world lighting where we think the particles will be.
|
||||
Vector forward, right, up;
|
||||
AngleVectors(GetAbsAngles(), &forward, &right, &up);
|
||||
|
||||
// Legacy env_steamjet entities faced left instead of forward.
|
||||
if (m_bFaceLeft)
|
||||
{
|
||||
Vector temp = forward;
|
||||
forward = -right;
|
||||
right = temp;
|
||||
}
|
||||
|
||||
Vector startPos = GetAbsOrigin();
|
||||
Vector endPos = GetAbsOrigin() + forward * (m_Speed * m_Lifetime);
|
||||
|
||||
for(int iRamp=0; iRamp < STEAMJET_NUMRAMPS; iRamp++)
|
||||
{
|
||||
float t = (float)iRamp / (STEAMJET_NUMRAMPS-1);
|
||||
Vector vTestPos = startPos + (endPos - startPos) * t;
|
||||
|
||||
Vector *pRamp = &m_Ramps[iRamp];
|
||||
*pRamp = WorldGetLightForPoint(vTestPos, false);
|
||||
|
||||
if ( IsEmissive() )
|
||||
{
|
||||
pRamp->x += (m_clrRender->r/255.0f);
|
||||
pRamp->y += (m_clrRender->g/255.0f);
|
||||
pRamp->z += (m_clrRender->b/255.0f);
|
||||
|
||||
pRamp->x = clamp( pRamp->x, 0.0f, 1.0f );
|
||||
pRamp->y = clamp( pRamp->y, 0.0f, 1.0f );
|
||||
pRamp->z = clamp( pRamp->z, 0.0f, 1.0f );
|
||||
}
|
||||
else
|
||||
{
|
||||
pRamp->x *= (m_clrRender->r/255.0f);
|
||||
pRamp->y *= (m_clrRender->g/255.0f);
|
||||
pRamp->z *= (m_clrRender->b/255.0f);
|
||||
}
|
||||
|
||||
// Renormalize?
|
||||
float maxVal = max(pRamp->x, max(pRamp->y, pRamp->z));
|
||||
if(maxVal > 1)
|
||||
{
|
||||
*pRamp = *pRamp / maxVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user