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.
328 lines
11 KiB
328 lines
11 KiB
//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// |
|
// |
|
// Purpose: |
|
// |
|
// $Workfile: $ |
|
// $NoKeywords: $ |
|
//===========================================================================// |
|
#include "cbase.h" |
|
#include "c_basetempentity.h" |
|
#include "particle_simple3D.h" |
|
#include "tier1/keyvalues.h" |
|
#include "toolframework_client.h" |
|
#include "fx.h" |
|
#include "tier0/vprof.h" |
|
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
#define PI 3.14159265359 |
|
#define GLASS_SHARD_MIN_LIFE 2 |
|
#define GLASS_SHARD_MAX_LIFE 5 |
|
#define GLASS_SHARD_NOISE 0.3 |
|
#define GLASS_SHARD_GRAVITY 500 |
|
#define GLASS_SHARD_DAMPING 0.3 |
|
|
|
#include "precache_register.h" |
|
|
|
PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectGlassShatter ) |
|
PRECACHE( MATERIAL, "effects/fleck_glass1" ) |
|
PRECACHE( MATERIAL, "effects/fleck_glass2" ) |
|
PRECACHE( MATERIAL, "effects/fleck_tile1" ) |
|
PRECACHE( MATERIAL, "effects/fleck_tile2" ) |
|
PRECACHE_REGISTER_END() |
|
|
|
ConVar fx_glass_velocity_cap("fx_glass_velocity_cap", "0", 0, "Maximum downwards speed of shattered glass particles"); |
|
|
|
//################################################### |
|
// > C_TEShatterSurface |
|
//################################################### |
|
class C_TEShatterSurface : public C_BaseTempEntity |
|
{ |
|
public: |
|
DECLARE_CLASS( C_TEShatterSurface, C_BaseTempEntity ); |
|
DECLARE_CLIENTCLASS(); |
|
|
|
C_TEShatterSurface( void ); |
|
~C_TEShatterSurface( void ); |
|
|
|
virtual void PostDataUpdate( DataUpdateType_t updateType ); |
|
|
|
private: |
|
// Recording |
|
void RecordShatterSurface( ); |
|
|
|
public: |
|
Vector m_vecOrigin; |
|
QAngle m_vecAngles; |
|
Vector m_vecForce; |
|
Vector m_vecForcePos; |
|
float m_flWidth; |
|
float m_flHeight; |
|
float m_flShardSize; |
|
PMaterialHandle m_pMaterialHandle; |
|
int m_nSurfaceType; |
|
byte m_uchFrontColor[3]; |
|
byte m_uchBackColor[3]; |
|
}; |
|
|
|
|
|
//------------------------------------------------------------------------------ |
|
// Networking |
|
//------------------------------------------------------------------------------ |
|
IMPLEMENT_CLIENTCLASS_EVENT_DT(C_TEShatterSurface, DT_TEShatterSurface, CTEShatterSurface) |
|
RecvPropVector( RECVINFO(m_vecOrigin)), |
|
RecvPropVector( RECVINFO(m_vecAngles)), |
|
RecvPropVector( RECVINFO(m_vecForce)), |
|
RecvPropVector( RECVINFO(m_vecForcePos)), |
|
RecvPropFloat( RECVINFO(m_flWidth)), |
|
RecvPropFloat( RECVINFO(m_flHeight)), |
|
RecvPropFloat( RECVINFO(m_flShardSize)), |
|
RecvPropInt( RECVINFO(m_nSurfaceType)), |
|
RecvPropInt( RECVINFO(m_uchFrontColor[0])), |
|
RecvPropInt( RECVINFO(m_uchFrontColor[1])), |
|
RecvPropInt( RECVINFO(m_uchFrontColor[2])), |
|
RecvPropInt( RECVINFO(m_uchBackColor[0])), |
|
RecvPropInt( RECVINFO(m_uchBackColor[1])), |
|
RecvPropInt( RECVINFO(m_uchBackColor[2])), |
|
END_RECV_TABLE() |
|
|
|
|
|
//------------------------------------------------------------------------------ |
|
// Constructor, destructor |
|
//------------------------------------------------------------------------------ |
|
C_TEShatterSurface::C_TEShatterSurface( void ) |
|
{ |
|
m_vecOrigin.Init(); |
|
m_vecAngles.Init(); |
|
m_vecForce.Init(); |
|
m_vecForcePos.Init(); |
|
m_flWidth = 16.0; |
|
m_flHeight = 16.0; |
|
m_flShardSize = 3; |
|
m_nSurfaceType = SHATTERSURFACE_GLASS; |
|
m_uchFrontColor[0] = 255; |
|
m_uchFrontColor[1] = 255; |
|
m_uchFrontColor[2] = 255; |
|
m_uchBackColor[0] = 255; |
|
m_uchBackColor[1] = 255; |
|
m_uchBackColor[2] = 255; |
|
} |
|
|
|
C_TEShatterSurface::~C_TEShatterSurface() |
|
{ |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Recording |
|
//----------------------------------------------------------------------------- |
|
void C_TEShatterSurface::RecordShatterSurface( ) |
|
{ |
|
if ( !ToolsEnabled() ) |
|
return; |
|
|
|
if ( clienttools->IsInRecordingMode() ) |
|
{ |
|
Color front( m_uchFrontColor[0], m_uchFrontColor[1], m_uchFrontColor[2], 255 ); |
|
Color back( m_uchBackColor[0], m_uchBackColor[1], m_uchBackColor[2], 255 ); |
|
|
|
KeyValues *msg = new KeyValues( "TempEntity" ); |
|
|
|
msg->SetInt( "te", TE_SHATTER_SURFACE ); |
|
msg->SetString( "name", "TE_ShatterSurface" ); |
|
msg->SetFloat( "time", gpGlobals->curtime ); |
|
msg->SetFloat( "originx", m_vecOrigin.x ); |
|
msg->SetFloat( "originy", m_vecOrigin.y ); |
|
msg->SetFloat( "originz", m_vecOrigin.z ); |
|
msg->SetFloat( "anglesx", m_vecAngles.x ); |
|
msg->SetFloat( "anglesy", m_vecAngles.y ); |
|
msg->SetFloat( "anglesz", m_vecAngles.z ); |
|
msg->SetFloat( "forcex", m_vecForce.x ); |
|
msg->SetFloat( "forcey", m_vecForce.y ); |
|
msg->SetFloat( "forcez", m_vecForce.z ); |
|
msg->SetFloat( "forceposx", m_vecForcePos.x ); |
|
msg->SetFloat( "forceposy", m_vecForcePos.y ); |
|
msg->SetFloat( "forceposz", m_vecForcePos.z ); |
|
msg->SetColor( "frontcolor", front ); |
|
msg->SetColor( "backcolor", back ); |
|
msg->SetFloat( "width", m_flWidth ); |
|
msg->SetFloat( "height", m_flHeight ); |
|
msg->SetFloat( "size", m_flShardSize ); |
|
msg->SetInt( "surfacetype", m_nSurfaceType ); |
|
|
|
ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); |
|
msg->deleteThis(); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_TEShatterSurface::PostDataUpdate( DataUpdateType_t updateType ) |
|
{ |
|
VPROF( "C_TEShatterSurface::PostDataUpdate" ); |
|
|
|
RecordShatterSurface(); |
|
|
|
CSmartPtr<CSimple3DEmitter> pGlassEmitter = CSimple3DEmitter::Create( "C_TEShatterSurface 1" ); |
|
pGlassEmitter->SetSortOrigin( m_vecOrigin ); |
|
|
|
Vector vecColor; |
|
engine->ComputeLighting( m_vecOrigin, NULL, true, vecColor ); |
|
|
|
// HACK: Blend a little toward white to match the materials... |
|
VectorLerp( vecColor, Vector( 1, 1, 1 ), 0.3, vecColor ); |
|
|
|
PMaterialHandle *hMaterial; |
|
if (m_nSurfaceType == SHATTERSURFACE_GLASS) |
|
{ |
|
hMaterial = g_Mat_Fleck_Glass; |
|
} |
|
else |
|
{ |
|
hMaterial = g_Mat_Fleck_Tile; |
|
} |
|
|
|
// --------------------------------------------------- |
|
// Figure out number of particles required to fill space |
|
// --------------------------------------------------- |
|
int nNumWide = m_flWidth / m_flShardSize; |
|
int nNumHigh = m_flHeight / m_flShardSize; |
|
|
|
Vector vWidthStep,vHeightStep; |
|
AngleVectors(m_vecAngles,NULL,&vWidthStep,&vHeightStep); |
|
vWidthStep *= m_flShardSize; |
|
vHeightStep *= m_flShardSize; |
|
|
|
// --------------------- |
|
// Create glass shards |
|
// ---------------------- |
|
Vector vCurPos = m_vecOrigin; |
|
vCurPos.x += 0.5*m_flShardSize; |
|
vCurPos.z += 0.5*m_flShardSize; |
|
|
|
float flMinSpeed = 9999999999.0f; |
|
float flMaxSpeed = 0; |
|
|
|
Particle3D *pParticle = NULL; |
|
|
|
for (int width=0;width<nNumWide;width++) |
|
{ |
|
for (int height=0;height<nNumHigh;height++) |
|
{ |
|
pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), hMaterial[random->RandomInt(0,1)], vCurPos ); |
|
|
|
Vector vForceVel = Vector(0,0,0); |
|
if (random->RandomInt(0, 3) != 0) |
|
{ |
|
float flForceDistSqr = (vCurPos - m_vecForcePos).LengthSqr(); |
|
vForceVel = m_vecForce; |
|
if (flForceDistSqr > 0 ) |
|
{ |
|
vForceVel *= ( 40.0f / flForceDistSqr ); |
|
} |
|
} |
|
|
|
// cap the Z velocity of the shards |
|
if (fx_glass_velocity_cap.GetFloat() > 0 && vForceVel.z < -fx_glass_velocity_cap.GetFloat()) |
|
{ |
|
vForceVel.z = random->RandomFloat(-fx_glass_velocity_cap.GetFloat(), -(fx_glass_velocity_cap.GetFloat() * 0.66f)); |
|
} |
|
|
|
if (pParticle) |
|
{ |
|
pParticle->m_flLifeRemaining = random->RandomFloat(GLASS_SHARD_MIN_LIFE,GLASS_SHARD_MAX_LIFE); |
|
pParticle->m_vecVelocity = vForceVel; |
|
pParticle->m_vecVelocity += RandomVector(-25,25); |
|
pParticle->m_uchSize = m_flShardSize + random->RandomFloat(-0.5*m_flShardSize,0.5*m_flShardSize); |
|
pParticle->m_vAngles = m_vecAngles; |
|
pParticle->m_flAngSpeed = random->RandomFloat(-400,400); |
|
|
|
pParticle->m_uchFrontColor[0] = (byte)(m_uchFrontColor[0] * vecColor.x ); |
|
pParticle->m_uchFrontColor[1] = (byte)(m_uchFrontColor[1] * vecColor.y ); |
|
pParticle->m_uchFrontColor[2] = (byte)(m_uchFrontColor[2] * vecColor.z ); |
|
pParticle->m_uchBackColor[0] = (byte)(m_uchBackColor[0] * vecColor.x ); |
|
pParticle->m_uchBackColor[1] = (byte)(m_uchBackColor[1] * vecColor.y ); |
|
pParticle->m_uchBackColor[2] = (byte)(m_uchBackColor[2] * vecColor.z ); |
|
} |
|
|
|
// Keep track of min and max speed for collision detection |
|
float flForceSpeed = vForceVel.Length(); |
|
if (flForceSpeed > flMaxSpeed) |
|
{ |
|
flMaxSpeed = flForceSpeed; |
|
} |
|
if (flForceSpeed < flMinSpeed) |
|
{ |
|
flMinSpeed = flForceSpeed; |
|
} |
|
|
|
vCurPos += vHeightStep; |
|
} |
|
vCurPos -= nNumHigh*vHeightStep; |
|
vCurPos += vWidthStep; |
|
} |
|
|
|
// -------------------------------------------------- |
|
// Set collision parameters |
|
// -------------------------------------------------- |
|
Vector vMoveDir = m_vecForce; |
|
VectorNormalize(vMoveDir); |
|
|
|
pGlassEmitter->m_ParticleCollision.Setup( m_vecOrigin, &vMoveDir, GLASS_SHARD_NOISE, |
|
flMinSpeed, flMaxSpeed, GLASS_SHARD_GRAVITY, GLASS_SHARD_DAMPING ); |
|
} |
|
|
|
void TE_ShatterSurface( IRecipientFilter& filter, float delay, |
|
const Vector* pos, const QAngle* angle, const Vector* vForce, const Vector* vForcePos, |
|
float width, float height, float shardsize, ShatterSurface_t surfacetype, |
|
int front_r, int front_g, int front_b, int back_r, int back_g, int back_b) |
|
{ |
|
// Major hack to simulate receiving network message |
|
__g_C_TEShatterSurface.m_vecOrigin = *pos; |
|
__g_C_TEShatterSurface.m_vecAngles = *angle; |
|
__g_C_TEShatterSurface.m_vecForce = *vForce; |
|
__g_C_TEShatterSurface.m_vecForcePos = *vForcePos; |
|
__g_C_TEShatterSurface.m_flWidth = width; |
|
__g_C_TEShatterSurface.m_flHeight = height; |
|
__g_C_TEShatterSurface.m_flShardSize = shardsize; |
|
__g_C_TEShatterSurface.m_nSurfaceType = surfacetype; |
|
__g_C_TEShatterSurface.m_uchFrontColor[0] = front_r; |
|
__g_C_TEShatterSurface.m_uchFrontColor[1] = front_g; |
|
__g_C_TEShatterSurface.m_uchFrontColor[2] = front_b; |
|
__g_C_TEShatterSurface.m_uchBackColor[0] = back_r; |
|
__g_C_TEShatterSurface.m_uchBackColor[1] = back_g; |
|
__g_C_TEShatterSurface.m_uchBackColor[2] = back_b; |
|
|
|
__g_C_TEShatterSurface.PostDataUpdate( DATA_UPDATE_CREATED ); |
|
} |
|
|
|
void TE_ShatterSurface( IRecipientFilter& filter, float delay, KeyValues *pKeyValues ) |
|
{ |
|
Vector vecOrigin, vecForce, vecForcePos; |
|
QAngle angles; |
|
vecOrigin.x = pKeyValues->GetFloat( "originx" ); |
|
vecOrigin.y = pKeyValues->GetFloat( "originy" ); |
|
vecOrigin.z = pKeyValues->GetFloat( "originz" ); |
|
angles.x = pKeyValues->GetFloat( "anglesx" ); |
|
angles.y = pKeyValues->GetFloat( "anglesy" ); |
|
angles.z = pKeyValues->GetFloat( "anglesz" ); |
|
vecForce.x = pKeyValues->GetFloat( "forcex" ); |
|
vecForce.y = pKeyValues->GetFloat( "forcey" ); |
|
vecForce.z = pKeyValues->GetFloat( "forcez" ); |
|
vecForcePos.x = pKeyValues->GetFloat( "forceposx" ); |
|
vecForcePos.y = pKeyValues->GetFloat( "forceposy" ); |
|
vecForcePos.z = pKeyValues->GetFloat( "forceposz" ); |
|
Color front = pKeyValues->GetColor( "frontcolor" ); |
|
Color back = pKeyValues->GetColor( "backcolor" ); |
|
float flWidth = pKeyValues->GetFloat( "width" ); |
|
float flHeight = pKeyValues->GetFloat( "height" ); |
|
float flSize = pKeyValues->GetFloat( "size" ); |
|
ShatterSurface_t nSurfaceType = (ShatterSurface_t)pKeyValues->GetInt( "surfacetype" ); |
|
TE_ShatterSurface( filter, 0.0f, &vecOrigin, &angles, &vecForce, &vecForcePos, |
|
flWidth, flHeight, flSize, nSurfaceType, front.r(), front.g(), front.b(), |
|
back.r(), back.g(), back.b() ); |
|
}
|
|
|