aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/c_func_smokevolume.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/c_func_smokevolume.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/c_func_smokevolume.cpp')
-rw-r--r--mp/src/game/client/c_func_smokevolume.cpp1276
1 files changed, 638 insertions, 638 deletions
diff --git a/mp/src/game/client/c_func_smokevolume.cpp b/mp/src/game/client/c_func_smokevolume.cpp
index 85fa81cd..d976c57b 100644
--- a/mp/src/game/client/c_func_smokevolume.cpp
+++ b/mp/src/game/client/c_func_smokevolume.cpp
@@ -1,638 +1,638 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-#include "cbase.h"
-#include "c_smoke_trail.h"
-#include "smoke_fog_overlay.h"
-#include "engine/IEngineTrace.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-#define SF_EMISSIVE 0x00000001
-
-// ------------------------------------------------------------------------- //
-// Definitions
-// ------------------------------------------------------------------------- //
-
-static Vector s_FadePlaneDirections[] =
-{
- Vector( 1,0,0),
- Vector(-1,0,0),
- Vector(0, 1,0),
- Vector(0,-1,0),
- Vector(0,0, 1),
- Vector(0,0,-1)
-};
-#define NUM_FADE_PLANES (sizeof(s_FadePlaneDirections)/sizeof(s_FadePlaneDirections[0]))
-
-// ------------------------------------------------------------------------- //
-// Classes
-// ------------------------------------------------------------------------- //
-class C_FuncSmokeVolume : public C_BaseParticleEntity, public IPrototypeAppEffect
-{
-public:
- DECLARE_CLASS( C_FuncSmokeVolume, C_BaseParticleEntity );
- DECLARE_CLIENTCLASS();
-
- C_FuncSmokeVolume();
- ~C_FuncSmokeVolume();
-
- int IsEmissive( void ) { return ( m_spawnflags & SF_EMISSIVE ); }
-
-private:
- class SmokeGrenadeParticle : public Particle
- {
- public:
- float m_RotationFactor;
- float m_CurRotation;
- float m_FadeAlpha; // Set as it moves around.
- unsigned char m_ColorInterp; // Amount between min and max colors.
- unsigned char m_Color[4];
- };
-
-// C_BaseEntity.
-public:
- virtual void OnDataChanged( DataUpdateType_t updateType );
-
-// IPrototypeAppEffect.
-public:
- virtual void Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs );
-
-// IParticleEffect.
-public:
- virtual void Update(float fTimeDelta);
- virtual void RenderParticles( CParticleRenderIterator *pIterator );
- virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
- virtual void NotifyRemove();
-
-private:
- // The SmokeEmitter represents a grid in 3D space.
- class SmokeParticleInfo
- {
- public:
- SmokeGrenadeParticle *m_pParticle;
- int m_TradeIndex; // -1 if not exchanging yet.
- float m_TradeClock; // How long since they started trading.
- float m_TradeDuration; // How long the trade will take to finish.
- float m_FadeAlpha; // Calculated from nearby world geometry.
- unsigned char m_Color[4];
- };
-
- inline int GetSmokeParticleIndex(int x, int y, int z)
- {
- Assert( IsValidXYZCoords( x, y, z ) );
- return z*m_xCount*m_yCount+y*m_xCount+x;
- }
-
- inline SmokeParticleInfo *GetSmokeParticleInfo(int x, int y, int z)
- {
- Assert( IsValidXYZCoords( x, y, z ) );
- return &m_pSmokeParticleInfos[GetSmokeParticleIndex(x,y,z)];
- }
-
- inline void GetParticleInfoXYZ(int index, int &x, int &y, int &z)
- {
- Assert( index >= 0 && index < m_xCount * m_yCount * m_zCount );
- z = index / (m_xCount*m_yCount);
- int zIndex = z*m_xCount*m_yCount;
- y = (index - zIndex) / m_xCount;
- int yIndex = y*m_xCount;
- x = index - zIndex - yIndex;
- Assert( IsValidXYZCoords( x, y, z ) );
- }
-
- inline bool IsValidXYZCoords(int x, int y, int z)
- {
- return x >= 0 && y >= 0 && z >= 0 && x < m_xCount && y < m_yCount && z < m_zCount;
- }
-
- inline Vector GetSmokeParticlePos(int x, int y, int z )
- {
- return WorldAlignMins() +
- Vector( x * m_SpacingRadius * 2 + m_SpacingRadius,
- y * m_SpacingRadius * 2 + m_SpacingRadius,
- z * m_SpacingRadius * 2 + m_SpacingRadius );
- }
-
- inline Vector GetSmokeParticlePosIndex(int index)
- {
- int x, y, z;
- GetParticleInfoXYZ(index, x, y, z);
- return GetSmokeParticlePos(x, y, z);
- }
-
- // Start filling the smoke volume
- void FillVolume();
-
-private:
-// State variables from server.
- color32 m_Color1;
- color32 m_Color2;
- char m_MaterialName[255];
- float m_ParticleDrawWidth;
- float m_ParticleSpacingDistance;
- float m_DensityRampSpeed;
- float m_RotationSpeed;
- float m_MovementSpeed;
- float m_Density;
- int m_spawnflags;
-
-private:
- C_FuncSmokeVolume( const C_FuncSmokeVolume & );
-
- float m_CurrentDensity;
- float m_ParticleRadius;
- bool m_bStarted;
-
- PMaterialHandle m_MaterialHandle;
-
- SmokeParticleInfo *m_pSmokeParticleInfos;
- int m_xCount, m_yCount, m_zCount;
- float m_SpacingRadius;
-
- Vector m_MinColor;
- Vector m_MaxColor;
-
- Vector m_vLastOrigin;
- QAngle m_vLastAngles;
- bool m_bFirstUpdate;
-};
-
-IMPLEMENT_CLIENTCLASS_DT( C_FuncSmokeVolume, DT_FuncSmokeVolume, CFuncSmokeVolume )
- RecvPropInt( RECVINFO( m_Color1 ), 0, RecvProxy_IntToColor32 ),
- RecvPropInt( RECVINFO( m_Color2 ), 0, RecvProxy_IntToColor32 ),
- RecvPropString( RECVINFO( m_MaterialName ) ),
- RecvPropFloat( RECVINFO( m_ParticleDrawWidth ) ),
- RecvPropFloat( RECVINFO( m_ParticleSpacingDistance ) ),
- RecvPropFloat( RECVINFO( m_DensityRampSpeed ) ),
- RecvPropFloat( RECVINFO( m_RotationSpeed ) ),
- RecvPropFloat( RECVINFO( m_MovementSpeed ) ),
- RecvPropFloat( RECVINFO( m_Density ) ),
- RecvPropInt( RECVINFO( m_spawnflags ) ),
- RecvPropDataTable( RECVINFO_DT( m_Collision ), 0, &REFERENCE_RECV_TABLE(DT_CollisionProperty) ),
-END_RECV_TABLE()
-
-// Helpers.
-// ------------------------------------------------------------------------- //
-
-static inline void InterpColor(unsigned char dest[4], unsigned char src1[4], unsigned char src2[4], float percent)
-{
- dest[0] = (unsigned char)(src1[0] + (src2[0] - src1[0]) * percent);
- dest[1] = (unsigned char)(src1[1] + (src2[1] - src1[1]) * percent);
- dest[2] = (unsigned char)(src1[2] + (src2[2] - src1[2]) * percent);
-}
-
-
-static inline int GetWorldPointContents(const Vector &vPos)
-{
-#if defined(PARTICLEPROTOTYPE_APP)
- return 0;
-#else
- return enginetrace->GetPointContents( vPos );
-#endif
-}
-
-static inline void WorldTraceLine( const Vector &start, const Vector &end, int contentsMask, trace_t *trace )
-{
-#if defined(PARTICLEPROTOTYPE_APP)
- trace->fraction = 1;
-#else
- UTIL_TraceLine(start, end, contentsMask, NULL, COLLISION_GROUP_NONE, trace);
-#endif
-}
-
-static inline Vector EngineGetLightForPoint(const Vector &vPos)
-{
-#if defined(PARTICLEPROTOTYPE_APP)
- return Vector(1,1,1);
-#else
- return engine->GetLightForPoint(vPos, true);
-#endif
-}
-
-static inline Vector& EngineGetVecRenderOrigin()
-{
-#if defined(PARTICLEPROTOTYPE_APP)
- static Vector dummy(0,0,0);
- return dummy;
-#else
- extern Vector g_vecRenderOrigin;
- return g_vecRenderOrigin;
-#endif
-}
-
-static inline float& EngineGetSmokeFogOverlayAlpha()
-{
-#if defined(PARTICLEPROTOTYPE_APP)
- static float dummy;
- return dummy;
-#else
- return g_SmokeFogOverlayAlpha;
-#endif
-}
-
-static inline C_BaseEntity* ParticleGetEntity( int index )
-{
-#if defined(PARTICLEPROTOTYPE_APP)
- return NULL;
-#else
- return cl_entitylist->GetEnt( index );
-#endif
-}
-
-// ------------------------------------------------------------------------- //
-// C_FuncSmokeVolume
-// ------------------------------------------------------------------------- //
-C_FuncSmokeVolume::C_FuncSmokeVolume()
-{
- m_bFirstUpdate = true;
- m_vLastOrigin.Init();
- m_vLastAngles.Init();
-
- m_pSmokeParticleInfos = NULL;
- m_SpacingRadius = 0.0f;
- m_ParticleRadius = 0.0f;
- m_MinColor.Init( 1.0, 1.0, 1.0 );
- m_MaxColor.Init( 1.0, 1.0, 1.0 );
-}
-
-C_FuncSmokeVolume::~C_FuncSmokeVolume()
-{
- delete [] m_pSmokeParticleInfos;
-}
-
-static ConVar mat_reduceparticles( "mat_reduceparticles", "0" );
-
-void C_FuncSmokeVolume::OnDataChanged( DataUpdateType_t updateType )
-{
- m_MinColor[0] = ( 1.0f / 255.0f ) * m_Color1.r;
- m_MinColor[1] = ( 1.0f / 255.0f ) * m_Color1.g;
- m_MinColor[2] = ( 1.0f / 255.0f ) * m_Color1.b;
-
- m_MaxColor[0] = ( 1.0f / 255.0f ) * m_Color2.r;
- m_MaxColor[1] = ( 1.0f / 255.0f ) * m_Color2.g;
- m_MaxColor[2] = ( 1.0f / 255.0f ) * m_Color2.b;
-
- if ( mat_reduceparticles.GetBool() )
- {
- m_Density *= 0.5f;
- m_ParticleSpacingDistance *= 1.5f;
- }
-
- m_ParticleRadius = m_ParticleDrawWidth * 0.5f;
- m_SpacingRadius = m_ParticleSpacingDistance * 0.5f;
-
- m_ParticleEffect.SetParticleCullRadius( m_ParticleRadius );
-
-// Warning( "m_Density: %f\n", m_Density );
-// Warning( "m_MovementSpeed: %f\n", m_MovementSpeed );
-
- if( updateType == DATA_UPDATE_CREATED )
- {
- Vector size = WorldAlignMaxs() - WorldAlignMins();
- m_xCount = 0.5f + ( size.x / ( m_SpacingRadius * 2.0f ) );
- m_yCount = 0.5f + ( size.y / ( m_SpacingRadius * 2.0f ) );
- m_zCount = 0.5f + ( size.z / ( m_SpacingRadius * 2.0f ) );
- m_CurrentDensity = m_Density;
-
- delete [] m_pSmokeParticleInfos;
- m_pSmokeParticleInfos = new SmokeParticleInfo[m_xCount * m_yCount * m_zCount];
- Start( ParticleMgr(), NULL );
- }
- BaseClass::OnDataChanged( updateType );
-}
-
-void C_FuncSmokeVolume::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs )
-{
- if( !pParticleMgr->AddEffect( &m_ParticleEffect, this ) )
- return;
-
- m_MaterialHandle = m_ParticleEffect.FindOrAddMaterial( m_MaterialName );
- FillVolume();
-
- m_bStarted = true;
-}
-
-
-void C_FuncSmokeVolume::Update( float fTimeDelta )
-{
- // Update our world space bbox if we've moved at all.
- // We do this manually because sometimes people make HUGE bboxes, and if they're constantly changing because their
- // particles wander outside the current bounds sometimes, it'll be linking them into all the leaves repeatedly.
- const Vector &curOrigin = GetAbsOrigin();
- const QAngle &curAngles = GetAbsAngles();
- if ( !VectorsAreEqual( curOrigin, m_vLastOrigin, 0.1 ) ||
- fabs( curAngles.x - m_vLastAngles.x ) > 0.1 ||
- fabs( curAngles.y - m_vLastAngles.y ) > 0.1 ||
- fabs( curAngles.z - m_vLastAngles.z ) > 0.1 ||
- m_bFirstUpdate )
- {
- m_bFirstUpdate = false;
- m_vLastAngles = curAngles;
- m_vLastOrigin = curOrigin;
-
- Vector vWorldMins, vWorldMaxs;
- CollisionProp()->WorldSpaceAABB( &vWorldMins, &vWorldMaxs );
- vWorldMins -= Vector( m_ParticleRadius, m_ParticleRadius, m_ParticleRadius );
- vWorldMaxs += Vector( m_ParticleRadius, m_ParticleRadius, m_ParticleRadius );
-
- m_ParticleEffect.SetBBox( vWorldMins, vWorldMaxs );
- }
-
- // lerp m_CurrentDensity towards m_Density at a rate of m_DensityRampSpeed
- if( m_CurrentDensity < m_Density )
- {
- m_CurrentDensity += m_DensityRampSpeed * fTimeDelta;
- if( m_CurrentDensity > m_Density )
- {
- m_CurrentDensity = m_Density;
- }
- }
- else if( m_CurrentDensity > m_Density )
- {
- m_CurrentDensity -= m_DensityRampSpeed * fTimeDelta;
- if( m_CurrentDensity < m_Density )
- {
- m_CurrentDensity = m_Density;
- }
- }
-
- if( m_CurrentDensity == 0.0f )
- {
- return;
- }
-
- // This is used to randomize the direction it chooses to move a particle in.
-
- int offsetLookup[3] = {-1,0,1};
-
- float tradeDurationMax = m_ParticleSpacingDistance / ( m_MovementSpeed + 0.1f );
- float tradeDurationMin = tradeDurationMax * 0.5f;
-
- if ( IS_NAN( tradeDurationMax ) || IS_NAN( tradeDurationMin ) )
- return;
-
-// Warning( "tradeDuration: [%f,%f]\n", tradeDurationMin, tradeDurationMax );
-
- // Update all the moving traders and establish new ones.
- int nTotal = m_xCount * m_yCount * m_zCount;
- for( int i=0; i < nTotal; i++ )
- {
- SmokeParticleInfo *pInfo = &m_pSmokeParticleInfos[i];
-
- if(!pInfo->m_pParticle)
- continue;
-
- if(pInfo->m_TradeIndex == -1)
- {
- pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha;
- pInfo->m_pParticle->m_Color[0] = pInfo->m_Color[0];
- pInfo->m_pParticle->m_Color[1] = pInfo->m_Color[1];
- pInfo->m_pParticle->m_Color[2] = pInfo->m_Color[2];
-
- // Is there an adjacent one that's not trading?
- int x, y, z;
- GetParticleInfoXYZ(i, x, y, z);
-
- int xCountOffset = rand();
- int yCountOffset = rand();
- int zCountOffset = rand();
-
- bool bFound = false;
- for(int xCount=0; xCount < 3 && !bFound; xCount++)
- {
- for(int yCount=0; yCount < 3 && !bFound; yCount++)
- {
- for(int zCount=0; zCount < 3; zCount++)
- {
- int testX = x + offsetLookup[(xCount+xCountOffset) % 3];
- int testY = y + offsetLookup[(yCount+yCountOffset) % 3];
- int testZ = z + offsetLookup[(zCount+zCountOffset) % 3];
-
- if(testX == x && testY == y && testZ == z)
- continue;
-
- if(IsValidXYZCoords(testX, testY, testZ))
- {
- SmokeParticleInfo *pOther = GetSmokeParticleInfo(testX, testY, testZ);
- if(pOther->m_pParticle && pOther->m_TradeIndex == -1)
- {
- // Ok, this one is looking to trade also.
- pInfo->m_TradeIndex = GetSmokeParticleIndex(testX, testY, testZ);
- pOther->m_TradeIndex = i;
- pInfo->m_TradeClock = pOther->m_TradeClock = 0;
- pOther->m_TradeDuration = pInfo->m_TradeDuration = FRand( tradeDurationMin, tradeDurationMax );
-
- bFound = true;
- break;
- }
- }
- }
- }
- }
- }
- else
- {
- SmokeParticleInfo *pOther = &m_pSmokeParticleInfos[pInfo->m_TradeIndex];
- assert(pOther->m_TradeIndex == i);
-
- // This makes sure the trade only gets updated once per frame.
- if(pInfo < pOther)
- {
- // Increment the trade clock..
- pInfo->m_TradeClock = (pOther->m_TradeClock += fTimeDelta);
- int x, y, z;
- GetParticleInfoXYZ(i, x, y, z);
- Vector myPos = GetSmokeParticlePos(x, y, z);
-
- int otherX, otherY, otherZ;
- GetParticleInfoXYZ(pInfo->m_TradeIndex, otherX, otherY, otherZ);
- Vector otherPos = GetSmokeParticlePos(otherX, otherY, otherZ);
-
- // Is the trade finished?
- if(pInfo->m_TradeClock >= pInfo->m_TradeDuration)
- {
- pInfo->m_TradeIndex = pOther->m_TradeIndex = -1;
-
- pInfo->m_pParticle->m_Pos = otherPos;
- pOther->m_pParticle->m_Pos = myPos;
-
- SmokeGrenadeParticle *temp = pInfo->m_pParticle;
- pInfo->m_pParticle = pOther->m_pParticle;
- pOther->m_pParticle = temp;
- }
- else
- {
- // Ok, move them closer.
- float percent = (float)cos(pInfo->m_TradeClock * 2 * 1.57079632f / pInfo->m_TradeDuration);
- percent = percent * 0.5 + 0.5;
-
- pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * (1 - percent);
- pOther->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * percent;
-
- InterpColor(pInfo->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, 1-percent);
- InterpColor(pOther->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, percent);
-
- pInfo->m_pParticle->m_Pos = myPos + (otherPos - myPos) * (1 - percent);
- pOther->m_pParticle->m_Pos = myPos + (otherPos - myPos) * percent;
- }
- }
- }
- }
-}
-
-
-void C_FuncSmokeVolume::RenderParticles( CParticleRenderIterator *pIterator )
-{
- if ( m_CurrentDensity == 0 )
- return;
-
- const SmokeGrenadeParticle *pParticle = (const SmokeGrenadeParticle*)pIterator->GetFirst();
- while ( pParticle )
- {
- Vector renderPos = pParticle->m_Pos;
-
- // Fade out globally.
- float alpha = m_CurrentDensity;
-
- // Apply the precalculated fade alpha from world geometry.
- alpha *= pParticle->m_FadeAlpha;
-
- // TODO: optimize this whole routine!
- Vector color = m_MinColor + (m_MaxColor - m_MinColor) * (pParticle->m_ColorInterp / 255.1f);
- if ( IsEmissive() )
- {
- color.x += pParticle->m_Color[0] / 255.0f;
- color.y += pParticle->m_Color[1] / 255.0f;
- color.z += pParticle->m_Color[2] / 255.0f;
-
- color.x = clamp( color.x, 0.0f, 1.0f );
- color.y = clamp( color.y, 0.0f, 1.0f );
- color.z = clamp( color.z, 0.0f, 1.0f );
- }
- else
- {
- color.x *= pParticle->m_Color[0] / 255.0f;
- color.y *= pParticle->m_Color[1] / 255.0f;
- color.z *= pParticle->m_Color[2] / 255.0f;
- }
-
- Vector tRenderPos;
- TransformParticle( ParticleMgr()->GetModelView(), renderPos, tRenderPos );
- float sortKey = 1;//tRenderPos.z;
-
- // If we're reducing particle cost, only render sufficiently opaque particles
- if ( ( alpha > 0.05f ) || !mat_reduceparticles.GetBool() )
- {
- RenderParticle_ColorSizeAngle(
- pIterator->GetParticleDraw(),
- tRenderPos,
- color,
- alpha * GetAlphaDistanceFade(tRenderPos, 10, 30), // Alpha
- m_ParticleRadius,
- pParticle->m_CurRotation
- );
- }
-
- pParticle = (const SmokeGrenadeParticle*)pIterator->GetNext( sortKey );
- }
-}
-
-
-void C_FuncSmokeVolume::SimulateParticles( CParticleSimulateIterator *pIterator )
-{
- if ( m_CurrentDensity == 0 )
- return;
-
- SmokeGrenadeParticle *pParticle = (SmokeGrenadeParticle*)pIterator->GetFirst();
- while ( pParticle )
- {
- pParticle->m_CurRotation += pParticle->m_RotationFactor * ( M_PI / 180.0f ) * m_RotationSpeed * pIterator->GetTimeDelta();
- pParticle = (SmokeGrenadeParticle*)pIterator->GetNext();
- }
-}
-
-
-void C_FuncSmokeVolume::NotifyRemove()
-{
- m_xCount = m_yCount = m_zCount = 0;
-}
-
-
-void C_FuncSmokeVolume::FillVolume()
-{
- Vector vPos;
- for(int x=0; x < m_xCount; x++)
- {
- for(int y=0; y < m_yCount; y++)
- {
- for(int z=0; z < m_zCount; z++)
- {
- vPos = GetSmokeParticlePos( x, y, z );
- if(SmokeParticleInfo *pInfo = GetSmokeParticleInfo(x,y,z))
- {
- int contents = GetWorldPointContents(vPos);
- if(contents & CONTENTS_SOLID)
- {
- pInfo->m_pParticle = NULL;
- }
- else
- {
- SmokeGrenadeParticle *pParticle =
- (SmokeGrenadeParticle*)m_ParticleEffect.AddParticle(sizeof(SmokeGrenadeParticle), m_MaterialHandle);
-
- if(pParticle)
- {
- pParticle->m_Pos = vPos;
- pParticle->m_ColorInterp = (unsigned char)((rand() * 255) / VALVE_RAND_MAX);
- pParticle->m_RotationFactor = FRand( -1.0f, 1.0f ); // Rotation factor.
- pParticle->m_CurRotation = FRand( -m_RotationSpeed, m_RotationSpeed );
- }
-
-#ifdef _DEBUG
- int testX, testY, testZ;
- int index = GetSmokeParticleIndex(x,y,z);
- GetParticleInfoXYZ(index, testX, testY, testZ);
- assert(testX == x && testY == y && testZ == z);
-#endif
-
- Vector vColor = EngineGetLightForPoint(vPos);
- pInfo->m_Color[0] = LinearToTexture( vColor.x );
- pInfo->m_Color[1] = LinearToTexture( vColor.y );
- pInfo->m_Color[2] = LinearToTexture( vColor.z );
-
- // Cast some rays and if it's too close to anything, fade its alpha down.
- pInfo->m_FadeAlpha = 1;
-
- for(int i=0; i < NUM_FADE_PLANES; i++)
- {
- trace_t trace;
- WorldTraceLine(vPos, vPos + s_FadePlaneDirections[i] * 100, MASK_SOLID_BRUSHONLY, &trace);
- if(trace.fraction < 1.0f)
- {
- float dist = DotProduct(trace.plane.normal, vPos) - trace.plane.dist;
- if(dist < 0)
- {
- pInfo->m_FadeAlpha = 0;
- }
- else if(dist < m_ParticleRadius)
- {
- float alphaScale = dist / m_ParticleRadius;
- alphaScale *= alphaScale * alphaScale;
- pInfo->m_FadeAlpha *= alphaScale;
- }
- }
- }
-
- pInfo->m_pParticle = pParticle;
- pInfo->m_TradeIndex = -1;
- }
- }
- }
- }
- }
-}
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "c_smoke_trail.h"
+#include "smoke_fog_overlay.h"
+#include "engine/IEngineTrace.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define SF_EMISSIVE 0x00000001
+
+// ------------------------------------------------------------------------- //
+// Definitions
+// ------------------------------------------------------------------------- //
+
+static Vector s_FadePlaneDirections[] =
+{
+ Vector( 1,0,0),
+ Vector(-1,0,0),
+ Vector(0, 1,0),
+ Vector(0,-1,0),
+ Vector(0,0, 1),
+ Vector(0,0,-1)
+};
+#define NUM_FADE_PLANES (sizeof(s_FadePlaneDirections)/sizeof(s_FadePlaneDirections[0]))
+
+// ------------------------------------------------------------------------- //
+// Classes
+// ------------------------------------------------------------------------- //
+class C_FuncSmokeVolume : public C_BaseParticleEntity, public IPrototypeAppEffect
+{
+public:
+ DECLARE_CLASS( C_FuncSmokeVolume, C_BaseParticleEntity );
+ DECLARE_CLIENTCLASS();
+
+ C_FuncSmokeVolume();
+ ~C_FuncSmokeVolume();
+
+ int IsEmissive( void ) { return ( m_spawnflags & SF_EMISSIVE ); }
+
+private:
+ class SmokeGrenadeParticle : public Particle
+ {
+ public:
+ float m_RotationFactor;
+ float m_CurRotation;
+ float m_FadeAlpha; // Set as it moves around.
+ unsigned char m_ColorInterp; // Amount between min and max colors.
+ unsigned char m_Color[4];
+ };
+
+// C_BaseEntity.
+public:
+ virtual void OnDataChanged( DataUpdateType_t updateType );
+
+// IPrototypeAppEffect.
+public:
+ virtual void Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs );
+
+// IParticleEffect.
+public:
+ virtual void Update(float fTimeDelta);
+ virtual void RenderParticles( CParticleRenderIterator *pIterator );
+ virtual void SimulateParticles( CParticleSimulateIterator *pIterator );
+ virtual void NotifyRemove();
+
+private:
+ // The SmokeEmitter represents a grid in 3D space.
+ class SmokeParticleInfo
+ {
+ public:
+ SmokeGrenadeParticle *m_pParticle;
+ int m_TradeIndex; // -1 if not exchanging yet.
+ float m_TradeClock; // How long since they started trading.
+ float m_TradeDuration; // How long the trade will take to finish.
+ float m_FadeAlpha; // Calculated from nearby world geometry.
+ unsigned char m_Color[4];
+ };
+
+ inline int GetSmokeParticleIndex(int x, int y, int z)
+ {
+ Assert( IsValidXYZCoords( x, y, z ) );
+ return z*m_xCount*m_yCount+y*m_xCount+x;
+ }
+
+ inline SmokeParticleInfo *GetSmokeParticleInfo(int x, int y, int z)
+ {
+ Assert( IsValidXYZCoords( x, y, z ) );
+ return &m_pSmokeParticleInfos[GetSmokeParticleIndex(x,y,z)];
+ }
+
+ inline void GetParticleInfoXYZ(int index, int &x, int &y, int &z)
+ {
+ Assert( index >= 0 && index < m_xCount * m_yCount * m_zCount );
+ z = index / (m_xCount*m_yCount);
+ int zIndex = z*m_xCount*m_yCount;
+ y = (index - zIndex) / m_xCount;
+ int yIndex = y*m_xCount;
+ x = index - zIndex - yIndex;
+ Assert( IsValidXYZCoords( x, y, z ) );
+ }
+
+ inline bool IsValidXYZCoords(int x, int y, int z)
+ {
+ return x >= 0 && y >= 0 && z >= 0 && x < m_xCount && y < m_yCount && z < m_zCount;
+ }
+
+ inline Vector GetSmokeParticlePos(int x, int y, int z )
+ {
+ return WorldAlignMins() +
+ Vector( x * m_SpacingRadius * 2 + m_SpacingRadius,
+ y * m_SpacingRadius * 2 + m_SpacingRadius,
+ z * m_SpacingRadius * 2 + m_SpacingRadius );
+ }
+
+ inline Vector GetSmokeParticlePosIndex(int index)
+ {
+ int x, y, z;
+ GetParticleInfoXYZ(index, x, y, z);
+ return GetSmokeParticlePos(x, y, z);
+ }
+
+ // Start filling the smoke volume
+ void FillVolume();
+
+private:
+// State variables from server.
+ color32 m_Color1;
+ color32 m_Color2;
+ char m_MaterialName[255];
+ float m_ParticleDrawWidth;
+ float m_ParticleSpacingDistance;
+ float m_DensityRampSpeed;
+ float m_RotationSpeed;
+ float m_MovementSpeed;
+ float m_Density;
+ int m_spawnflags;
+
+private:
+ C_FuncSmokeVolume( const C_FuncSmokeVolume & );
+
+ float m_CurrentDensity;
+ float m_ParticleRadius;
+ bool m_bStarted;
+
+ PMaterialHandle m_MaterialHandle;
+
+ SmokeParticleInfo *m_pSmokeParticleInfos;
+ int m_xCount, m_yCount, m_zCount;
+ float m_SpacingRadius;
+
+ Vector m_MinColor;
+ Vector m_MaxColor;
+
+ Vector m_vLastOrigin;
+ QAngle m_vLastAngles;
+ bool m_bFirstUpdate;
+};
+
+IMPLEMENT_CLIENTCLASS_DT( C_FuncSmokeVolume, DT_FuncSmokeVolume, CFuncSmokeVolume )
+ RecvPropInt( RECVINFO( m_Color1 ), 0, RecvProxy_IntToColor32 ),
+ RecvPropInt( RECVINFO( m_Color2 ), 0, RecvProxy_IntToColor32 ),
+ RecvPropString( RECVINFO( m_MaterialName ) ),
+ RecvPropFloat( RECVINFO( m_ParticleDrawWidth ) ),
+ RecvPropFloat( RECVINFO( m_ParticleSpacingDistance ) ),
+ RecvPropFloat( RECVINFO( m_DensityRampSpeed ) ),
+ RecvPropFloat( RECVINFO( m_RotationSpeed ) ),
+ RecvPropFloat( RECVINFO( m_MovementSpeed ) ),
+ RecvPropFloat( RECVINFO( m_Density ) ),
+ RecvPropInt( RECVINFO( m_spawnflags ) ),
+ RecvPropDataTable( RECVINFO_DT( m_Collision ), 0, &REFERENCE_RECV_TABLE(DT_CollisionProperty) ),
+END_RECV_TABLE()
+
+// Helpers.
+// ------------------------------------------------------------------------- //
+
+static inline void InterpColor(unsigned char dest[4], unsigned char src1[4], unsigned char src2[4], float percent)
+{
+ dest[0] = (unsigned char)(src1[0] + (src2[0] - src1[0]) * percent);
+ dest[1] = (unsigned char)(src1[1] + (src2[1] - src1[1]) * percent);
+ dest[2] = (unsigned char)(src1[2] + (src2[2] - src1[2]) * percent);
+}
+
+
+static inline int GetWorldPointContents(const Vector &vPos)
+{
+#if defined(PARTICLEPROTOTYPE_APP)
+ return 0;
+#else
+ return enginetrace->GetPointContents( vPos );
+#endif
+}
+
+static inline void WorldTraceLine( const Vector &start, const Vector &end, int contentsMask, trace_t *trace )
+{
+#if defined(PARTICLEPROTOTYPE_APP)
+ trace->fraction = 1;
+#else
+ UTIL_TraceLine(start, end, contentsMask, NULL, COLLISION_GROUP_NONE, trace);
+#endif
+}
+
+static inline Vector EngineGetLightForPoint(const Vector &vPos)
+{
+#if defined(PARTICLEPROTOTYPE_APP)
+ return Vector(1,1,1);
+#else
+ return engine->GetLightForPoint(vPos, true);
+#endif
+}
+
+static inline Vector& EngineGetVecRenderOrigin()
+{
+#if defined(PARTICLEPROTOTYPE_APP)
+ static Vector dummy(0,0,0);
+ return dummy;
+#else
+ extern Vector g_vecRenderOrigin;
+ return g_vecRenderOrigin;
+#endif
+}
+
+static inline float& EngineGetSmokeFogOverlayAlpha()
+{
+#if defined(PARTICLEPROTOTYPE_APP)
+ static float dummy;
+ return dummy;
+#else
+ return g_SmokeFogOverlayAlpha;
+#endif
+}
+
+static inline C_BaseEntity* ParticleGetEntity( int index )
+{
+#if defined(PARTICLEPROTOTYPE_APP)
+ return NULL;
+#else
+ return cl_entitylist->GetEnt( index );
+#endif
+}
+
+// ------------------------------------------------------------------------- //
+// C_FuncSmokeVolume
+// ------------------------------------------------------------------------- //
+C_FuncSmokeVolume::C_FuncSmokeVolume()
+{
+ m_bFirstUpdate = true;
+ m_vLastOrigin.Init();
+ m_vLastAngles.Init();
+
+ m_pSmokeParticleInfos = NULL;
+ m_SpacingRadius = 0.0f;
+ m_ParticleRadius = 0.0f;
+ m_MinColor.Init( 1.0, 1.0, 1.0 );
+ m_MaxColor.Init( 1.0, 1.0, 1.0 );
+}
+
+C_FuncSmokeVolume::~C_FuncSmokeVolume()
+{
+ delete [] m_pSmokeParticleInfos;
+}
+
+static ConVar mat_reduceparticles( "mat_reduceparticles", "0" );
+
+void C_FuncSmokeVolume::OnDataChanged( DataUpdateType_t updateType )
+{
+ m_MinColor[0] = ( 1.0f / 255.0f ) * m_Color1.r;
+ m_MinColor[1] = ( 1.0f / 255.0f ) * m_Color1.g;
+ m_MinColor[2] = ( 1.0f / 255.0f ) * m_Color1.b;
+
+ m_MaxColor[0] = ( 1.0f / 255.0f ) * m_Color2.r;
+ m_MaxColor[1] = ( 1.0f / 255.0f ) * m_Color2.g;
+ m_MaxColor[2] = ( 1.0f / 255.0f ) * m_Color2.b;
+
+ if ( mat_reduceparticles.GetBool() )
+ {
+ m_Density *= 0.5f;
+ m_ParticleSpacingDistance *= 1.5f;
+ }
+
+ m_ParticleRadius = m_ParticleDrawWidth * 0.5f;
+ m_SpacingRadius = m_ParticleSpacingDistance * 0.5f;
+
+ m_ParticleEffect.SetParticleCullRadius( m_ParticleRadius );
+
+// Warning( "m_Density: %f\n", m_Density );
+// Warning( "m_MovementSpeed: %f\n", m_MovementSpeed );
+
+ if( updateType == DATA_UPDATE_CREATED )
+ {
+ Vector size = WorldAlignMaxs() - WorldAlignMins();
+ m_xCount = 0.5f + ( size.x / ( m_SpacingRadius * 2.0f ) );
+ m_yCount = 0.5f + ( size.y / ( m_SpacingRadius * 2.0f ) );
+ m_zCount = 0.5f + ( size.z / ( m_SpacingRadius * 2.0f ) );
+ m_CurrentDensity = m_Density;
+
+ delete [] m_pSmokeParticleInfos;
+ m_pSmokeParticleInfos = new SmokeParticleInfo[m_xCount * m_yCount * m_zCount];
+ Start( ParticleMgr(), NULL );
+ }
+ BaseClass::OnDataChanged( updateType );
+}
+
+void C_FuncSmokeVolume::Start( CParticleMgr *pParticleMgr, IPrototypeArgAccess *pArgs )
+{
+ if( !pParticleMgr->AddEffect( &m_ParticleEffect, this ) )
+ return;
+
+ m_MaterialHandle = m_ParticleEffect.FindOrAddMaterial( m_MaterialName );
+ FillVolume();
+
+ m_bStarted = true;
+}
+
+
+void C_FuncSmokeVolume::Update( float fTimeDelta )
+{
+ // Update our world space bbox if we've moved at all.
+ // We do this manually because sometimes people make HUGE bboxes, and if they're constantly changing because their
+ // particles wander outside the current bounds sometimes, it'll be linking them into all the leaves repeatedly.
+ const Vector &curOrigin = GetAbsOrigin();
+ const QAngle &curAngles = GetAbsAngles();
+ if ( !VectorsAreEqual( curOrigin, m_vLastOrigin, 0.1 ) ||
+ fabs( curAngles.x - m_vLastAngles.x ) > 0.1 ||
+ fabs( curAngles.y - m_vLastAngles.y ) > 0.1 ||
+ fabs( curAngles.z - m_vLastAngles.z ) > 0.1 ||
+ m_bFirstUpdate )
+ {
+ m_bFirstUpdate = false;
+ m_vLastAngles = curAngles;
+ m_vLastOrigin = curOrigin;
+
+ Vector vWorldMins, vWorldMaxs;
+ CollisionProp()->WorldSpaceAABB( &vWorldMins, &vWorldMaxs );
+ vWorldMins -= Vector( m_ParticleRadius, m_ParticleRadius, m_ParticleRadius );
+ vWorldMaxs += Vector( m_ParticleRadius, m_ParticleRadius, m_ParticleRadius );
+
+ m_ParticleEffect.SetBBox( vWorldMins, vWorldMaxs );
+ }
+
+ // lerp m_CurrentDensity towards m_Density at a rate of m_DensityRampSpeed
+ if( m_CurrentDensity < m_Density )
+ {
+ m_CurrentDensity += m_DensityRampSpeed * fTimeDelta;
+ if( m_CurrentDensity > m_Density )
+ {
+ m_CurrentDensity = m_Density;
+ }
+ }
+ else if( m_CurrentDensity > m_Density )
+ {
+ m_CurrentDensity -= m_DensityRampSpeed * fTimeDelta;
+ if( m_CurrentDensity < m_Density )
+ {
+ m_CurrentDensity = m_Density;
+ }
+ }
+
+ if( m_CurrentDensity == 0.0f )
+ {
+ return;
+ }
+
+ // This is used to randomize the direction it chooses to move a particle in.
+
+ int offsetLookup[3] = {-1,0,1};
+
+ float tradeDurationMax = m_ParticleSpacingDistance / ( m_MovementSpeed + 0.1f );
+ float tradeDurationMin = tradeDurationMax * 0.5f;
+
+ if ( IS_NAN( tradeDurationMax ) || IS_NAN( tradeDurationMin ) )
+ return;
+
+// Warning( "tradeDuration: [%f,%f]\n", tradeDurationMin, tradeDurationMax );
+
+ // Update all the moving traders and establish new ones.
+ int nTotal = m_xCount * m_yCount * m_zCount;
+ for( int i=0; i < nTotal; i++ )
+ {
+ SmokeParticleInfo *pInfo = &m_pSmokeParticleInfos[i];
+
+ if(!pInfo->m_pParticle)
+ continue;
+
+ if(pInfo->m_TradeIndex == -1)
+ {
+ pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha;
+ pInfo->m_pParticle->m_Color[0] = pInfo->m_Color[0];
+ pInfo->m_pParticle->m_Color[1] = pInfo->m_Color[1];
+ pInfo->m_pParticle->m_Color[2] = pInfo->m_Color[2];
+
+ // Is there an adjacent one that's not trading?
+ int x, y, z;
+ GetParticleInfoXYZ(i, x, y, z);
+
+ int xCountOffset = rand();
+ int yCountOffset = rand();
+ int zCountOffset = rand();
+
+ bool bFound = false;
+ for(int xCount=0; xCount < 3 && !bFound; xCount++)
+ {
+ for(int yCount=0; yCount < 3 && !bFound; yCount++)
+ {
+ for(int zCount=0; zCount < 3; zCount++)
+ {
+ int testX = x + offsetLookup[(xCount+xCountOffset) % 3];
+ int testY = y + offsetLookup[(yCount+yCountOffset) % 3];
+ int testZ = z + offsetLookup[(zCount+zCountOffset) % 3];
+
+ if(testX == x && testY == y && testZ == z)
+ continue;
+
+ if(IsValidXYZCoords(testX, testY, testZ))
+ {
+ SmokeParticleInfo *pOther = GetSmokeParticleInfo(testX, testY, testZ);
+ if(pOther->m_pParticle && pOther->m_TradeIndex == -1)
+ {
+ // Ok, this one is looking to trade also.
+ pInfo->m_TradeIndex = GetSmokeParticleIndex(testX, testY, testZ);
+ pOther->m_TradeIndex = i;
+ pInfo->m_TradeClock = pOther->m_TradeClock = 0;
+ pOther->m_TradeDuration = pInfo->m_TradeDuration = FRand( tradeDurationMin, tradeDurationMax );
+
+ bFound = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ SmokeParticleInfo *pOther = &m_pSmokeParticleInfos[pInfo->m_TradeIndex];
+ assert(pOther->m_TradeIndex == i);
+
+ // This makes sure the trade only gets updated once per frame.
+ if(pInfo < pOther)
+ {
+ // Increment the trade clock..
+ pInfo->m_TradeClock = (pOther->m_TradeClock += fTimeDelta);
+ int x, y, z;
+ GetParticleInfoXYZ(i, x, y, z);
+ Vector myPos = GetSmokeParticlePos(x, y, z);
+
+ int otherX, otherY, otherZ;
+ GetParticleInfoXYZ(pInfo->m_TradeIndex, otherX, otherY, otherZ);
+ Vector otherPos = GetSmokeParticlePos(otherX, otherY, otherZ);
+
+ // Is the trade finished?
+ if(pInfo->m_TradeClock >= pInfo->m_TradeDuration)
+ {
+ pInfo->m_TradeIndex = pOther->m_TradeIndex = -1;
+
+ pInfo->m_pParticle->m_Pos = otherPos;
+ pOther->m_pParticle->m_Pos = myPos;
+
+ SmokeGrenadeParticle *temp = pInfo->m_pParticle;
+ pInfo->m_pParticle = pOther->m_pParticle;
+ pOther->m_pParticle = temp;
+ }
+ else
+ {
+ // Ok, move them closer.
+ float percent = (float)cos(pInfo->m_TradeClock * 2 * 1.57079632f / pInfo->m_TradeDuration);
+ percent = percent * 0.5 + 0.5;
+
+ pInfo->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * (1 - percent);
+ pOther->m_pParticle->m_FadeAlpha = pInfo->m_FadeAlpha + (pOther->m_FadeAlpha - pInfo->m_FadeAlpha) * percent;
+
+ InterpColor(pInfo->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, 1-percent);
+ InterpColor(pOther->m_pParticle->m_Color, pInfo->m_Color, pOther->m_Color, percent);
+
+ pInfo->m_pParticle->m_Pos = myPos + (otherPos - myPos) * (1 - percent);
+ pOther->m_pParticle->m_Pos = myPos + (otherPos - myPos) * percent;
+ }
+ }
+ }
+ }
+}
+
+
+void C_FuncSmokeVolume::RenderParticles( CParticleRenderIterator *pIterator )
+{
+ if ( m_CurrentDensity == 0 )
+ return;
+
+ const SmokeGrenadeParticle *pParticle = (const SmokeGrenadeParticle*)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ Vector renderPos = pParticle->m_Pos;
+
+ // Fade out globally.
+ float alpha = m_CurrentDensity;
+
+ // Apply the precalculated fade alpha from world geometry.
+ alpha *= pParticle->m_FadeAlpha;
+
+ // TODO: optimize this whole routine!
+ Vector color = m_MinColor + (m_MaxColor - m_MinColor) * (pParticle->m_ColorInterp / 255.1f);
+ if ( IsEmissive() )
+ {
+ color.x += pParticle->m_Color[0] / 255.0f;
+ color.y += pParticle->m_Color[1] / 255.0f;
+ color.z += pParticle->m_Color[2] / 255.0f;
+
+ color.x = clamp( color.x, 0.0f, 1.0f );
+ color.y = clamp( color.y, 0.0f, 1.0f );
+ color.z = clamp( color.z, 0.0f, 1.0f );
+ }
+ else
+ {
+ color.x *= pParticle->m_Color[0] / 255.0f;
+ color.y *= pParticle->m_Color[1] / 255.0f;
+ color.z *= pParticle->m_Color[2] / 255.0f;
+ }
+
+ Vector tRenderPos;
+ TransformParticle( ParticleMgr()->GetModelView(), renderPos, tRenderPos );
+ float sortKey = 1;//tRenderPos.z;
+
+ // If we're reducing particle cost, only render sufficiently opaque particles
+ if ( ( alpha > 0.05f ) || !mat_reduceparticles.GetBool() )
+ {
+ RenderParticle_ColorSizeAngle(
+ pIterator->GetParticleDraw(),
+ tRenderPos,
+ color,
+ alpha * GetAlphaDistanceFade(tRenderPos, 10, 30), // Alpha
+ m_ParticleRadius,
+ pParticle->m_CurRotation
+ );
+ }
+
+ pParticle = (const SmokeGrenadeParticle*)pIterator->GetNext( sortKey );
+ }
+}
+
+
+void C_FuncSmokeVolume::SimulateParticles( CParticleSimulateIterator *pIterator )
+{
+ if ( m_CurrentDensity == 0 )
+ return;
+
+ SmokeGrenadeParticle *pParticle = (SmokeGrenadeParticle*)pIterator->GetFirst();
+ while ( pParticle )
+ {
+ pParticle->m_CurRotation += pParticle->m_RotationFactor * ( M_PI / 180.0f ) * m_RotationSpeed * pIterator->GetTimeDelta();
+ pParticle = (SmokeGrenadeParticle*)pIterator->GetNext();
+ }
+}
+
+
+void C_FuncSmokeVolume::NotifyRemove()
+{
+ m_xCount = m_yCount = m_zCount = 0;
+}
+
+
+void C_FuncSmokeVolume::FillVolume()
+{
+ Vector vPos;
+ for(int x=0; x < m_xCount; x++)
+ {
+ for(int y=0; y < m_yCount; y++)
+ {
+ for(int z=0; z < m_zCount; z++)
+ {
+ vPos = GetSmokeParticlePos( x, y, z );
+ if(SmokeParticleInfo *pInfo = GetSmokeParticleInfo(x,y,z))
+ {
+ int contents = GetWorldPointContents(vPos);
+ if(contents & CONTENTS_SOLID)
+ {
+ pInfo->m_pParticle = NULL;
+ }
+ else
+ {
+ SmokeGrenadeParticle *pParticle =
+ (SmokeGrenadeParticle*)m_ParticleEffect.AddParticle(sizeof(SmokeGrenadeParticle), m_MaterialHandle);
+
+ if(pParticle)
+ {
+ pParticle->m_Pos = vPos;
+ pParticle->m_ColorInterp = (unsigned char)((rand() * 255) / VALVE_RAND_MAX);
+ pParticle->m_RotationFactor = FRand( -1.0f, 1.0f ); // Rotation factor.
+ pParticle->m_CurRotation = FRand( -m_RotationSpeed, m_RotationSpeed );
+ }
+
+#ifdef _DEBUG
+ int testX, testY, testZ;
+ int index = GetSmokeParticleIndex(x,y,z);
+ GetParticleInfoXYZ(index, testX, testY, testZ);
+ assert(testX == x && testY == y && testZ == z);
+#endif
+
+ Vector vColor = EngineGetLightForPoint(vPos);
+ pInfo->m_Color[0] = LinearToTexture( vColor.x );
+ pInfo->m_Color[1] = LinearToTexture( vColor.y );
+ pInfo->m_Color[2] = LinearToTexture( vColor.z );
+
+ // Cast some rays and if it's too close to anything, fade its alpha down.
+ pInfo->m_FadeAlpha = 1;
+
+ for(int i=0; i < NUM_FADE_PLANES; i++)
+ {
+ trace_t trace;
+ WorldTraceLine(vPos, vPos + s_FadePlaneDirections[i] * 100, MASK_SOLID_BRUSHONLY, &trace);
+ if(trace.fraction < 1.0f)
+ {
+ float dist = DotProduct(trace.plane.normal, vPos) - trace.plane.dist;
+ if(dist < 0)
+ {
+ pInfo->m_FadeAlpha = 0;
+ }
+ else if(dist < m_ParticleRadius)
+ {
+ float alphaScale = dist / m_ParticleRadius;
+ alphaScale *= alphaScale * alphaScale;
+ pInfo->m_FadeAlpha *= alphaScale;
+ }
+ }
+ }
+
+ pInfo->m_pParticle = pParticle;
+ pInfo->m_TradeIndex = -1;
+ }
+ }
+ }
+ }
+ }
+}