diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/particles_new.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/particles_new.cpp')
| -rw-r--r-- | mp/src/game/client/particles_new.cpp | 1208 |
1 files changed, 604 insertions, 604 deletions
diff --git a/mp/src/game/client/particles_new.cpp b/mp/src/game/client/particles_new.cpp index 0c762ac7..d3dc6599 100644 --- a/mp/src/game/client/particles_new.cpp +++ b/mp/src/game/client/particles_new.cpp @@ -1,604 +1,604 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//===========================================================================//
-#include "cbase.h"
-#include "particlemgr.h"
-#include "particles_new.h"
-#include "iclientmode.h"
-#include "engine/ivdebugoverlay.h"
-#include "particle_property.h"
-#include "toolframework/itoolframework.h"
-#include "toolframework_client.h"
-#include "tier1/KeyValues.h"
-#include "model_types.h"
-#include "vprof.h"
-#include "input.h"
-
-extern ConVar cl_particleeffect_aabb_buffer;
-
-//extern ConVar cl_particle_show_bbox;
-//extern ConVar cl_particle_show_bbox_cost;
-extern bool g_cl_particle_show_bbox;
-extern int g_cl_particle_show_bbox_cost;
-
-
-//-----------------------------------------------------------------------------
-// Constructor, destructor
-//-----------------------------------------------------------------------------
-CNewParticleEffect::CNewParticleEffect( CBaseEntity *pOwner, CParticleSystemDefinition *pEffect )
-{
- m_hOwner = pOwner;
- Init( pEffect );
- Construct();
-}
-
-CNewParticleEffect::CNewParticleEffect( CBaseEntity *pOwner, const char* pEffectName )
-{
- m_hOwner = pOwner;
- Init( pEffectName );
- Construct();
-}
-
-void CNewParticleEffect::Construct()
-{
- m_vSortOrigin.Init();
-
- m_bDontRemove = false;
- m_bRemove = false;
- m_bDrawn = false;
- m_bNeedsBBoxUpdate = false;
- m_bIsFirstFrame = true;
- m_bAutoUpdateBBox = false;
- m_bAllocated = true;
- m_bSimulate = true;
- m_bShouldPerformCullCheck = false;
-
- m_nToolParticleEffectId = TOOLPARTICLESYSTEMID_INVALID;
- m_RefCount = 0;
- ParticleMgr()->AddEffect( this );
- m_LastMax = Vector( -1.0e6, -1.0e6, -1.0e6 );
- m_LastMin = Vector( 1.0e6, 1.0e6, 1.0e6 );
- m_MinBounds = Vector( 1.0e6, 1.0e6, 1.0e6 );
- m_MaxBounds = Vector( -1.0e6, -1.0e6, -1.0e6 );
- m_pDebugName = NULL;
-
- if ( IsValid() && clienttools->IsInRecordingMode() )
- {
- int nId = AllocateToolParticleEffectId();
-
- static ParticleSystemCreatedState_t state;
- state.m_nParticleSystemId = nId;
- state.m_flTime = gpGlobals->curtime;
- state.m_pName = GetName();
- state.m_nOwner = m_hOwner.Get() ? m_hOwner->entindex() : -1;
-
- KeyValues *msg = new KeyValues( "ParticleSystem_Create" );
- msg->SetPtr( "state", &state );
- ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
- }
-}
-
-CNewParticleEffect::~CNewParticleEffect(void)
-{
- if ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID && clienttools->IsInRecordingMode() )
- {
- static ParticleSystemDestroyedState_t state;
- state.m_nParticleSystemId = gpGlobals->curtime;
- state.m_flTime = gpGlobals->curtime;
-
- KeyValues *msg = new KeyValues( "ParticleSystem_Destroy" );
- msg->SetPtr( "state", &state );
-
- ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
- m_nToolParticleEffectId = TOOLPARTICLESYSTEMID_INVALID;
- }
-
- m_bAllocated = false;
- if ( m_hOwner )
- {
- // NOTE: This can provoke another NotifyRemove call which is why flags is set to 0
- m_hOwner->ParticleProp()->OnParticleSystemDeleted( this );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Refcounting
-//-----------------------------------------------------------------------------
-void CNewParticleEffect::AddRef()
-{
- ++m_RefCount;
-}
-
-void CNewParticleEffect::Release()
-{
- Assert( m_RefCount > 0 );
- --m_RefCount;
-
- // If all the particles are already gone, delete ourselves now.
- // If there are still particles, wait for the last NotifyDestroyParticle.
- if ( m_RefCount == 0 )
- {
- if ( m_bAllocated )
- {
- if ( IsFinished() )
- {
- SetRemoveFlag();
- }
- }
- }
-}
-
-void CNewParticleEffect::NotifyRemove()
-{
- if ( m_bAllocated )
- {
- delete this;
- }
-}
-
-int CNewParticleEffect::IsReleased()
-{
- return m_RefCount == 0;
-}
-
-
-//-----------------------------------------------------------------------------
-// Refraction and soft particle support
-//-----------------------------------------------------------------------------
-bool CNewParticleEffect::UsesPowerOfTwoFrameBufferTexture( void )
-{
- // NOTE: Need to do this because CParticleCollection's version is non-virtual
- return CParticleCollection::UsesPowerOfTwoFrameBufferTexture( true );
-}
-
-bool CNewParticleEffect::UsesFullFrameBufferTexture( void )
-{
- // NOTE: Need to do this because CParticleCollection's version is non-virtual
- return CParticleCollection::UsesFullFrameBufferTexture( true );
-}
-
-bool CNewParticleEffect::IsTwoPass( void )
-{
- // NOTE: Need to do this because CParticleCollection's version is non-virtual
- return CParticleCollection::IsTwoPass();
-}
-
-
-//-----------------------------------------------------------------------------
-// Overrides for recording
-//-----------------------------------------------------------------------------
-void CNewParticleEffect::StopEmission( bool bInfiniteOnly, bool bRemoveAllParticles, bool bWakeOnStop )
-{
- if ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID && clienttools->IsInRecordingMode() )
- {
- KeyValues *msg = new KeyValues( "ParticleSystem_StopEmission" );
-
- static ParticleSystemStopEmissionState_t state;
- state.m_nParticleSystemId = GetToolParticleEffectId();
- state.m_flTime = gpGlobals->curtime;
- state.m_bInfiniteOnly = bInfiniteOnly;
-
- msg->SetPtr( "state", &state );
- ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
- }
-
- CParticleCollection::StopEmission( bInfiniteOnly, bRemoveAllParticles, bWakeOnStop );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CNewParticleEffect::SetDormant( bool bDormant )
-{
- CParticleCollection::SetDormant( bDormant );
-}
-
-void CNewParticleEffect::SetControlPointEntity( int nWhichPoint, CBaseEntity *pEntity )
-{
- if ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID && clienttools->IsInRecordingMode() )
- {
- static ParticleSystemSetControlPointObjectState_t state;
- state.m_nParticleSystemId = GetToolParticleEffectId();
- state.m_flTime = gpGlobals->curtime;
- state.m_nControlPoint = nWhichPoint;
- state.m_nObject = pEntity ? pEntity->entindex() : -1;
-
- KeyValues *msg = new KeyValues( "ParticleSystem_SetControlPointObject" );
- msg->SetPtr( "state", &state );
- ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
- }
-
- if ( pEntity )
- {
- CParticleCollection::SetControlPointObject( nWhichPoint, &m_hControlPointOwners[ nWhichPoint ] );
- m_hControlPointOwners[ nWhichPoint ] = pEntity;
- }
- else
- CParticleCollection::SetControlPointObject( nWhichPoint, NULL );
-}
-
-
-void CNewParticleEffect::SetControlPoint( int nWhichPoint, const Vector &v )
-{
- if ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID && clienttools->IsInRecordingMode() )
- {
- static ParticleSystemSetControlPointPositionState_t state;
- state.m_nParticleSystemId = GetToolParticleEffectId();
- state.m_flTime = gpGlobals->curtime;
- state.m_nControlPoint = nWhichPoint;
- state.m_vecPosition = v;
-
- KeyValues *msg = new KeyValues( "ParticleSystem_SetControlPointPosition" );
- msg->SetPtr( "state", &state );
- ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
- }
-
- CParticleCollection::SetControlPoint( nWhichPoint, v );
-}
-
-
-void CNewParticleEffect::RecordControlPointOrientation( int nWhichPoint )
-{
- if ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID && clienttools->IsInRecordingMode() )
- {
- // FIXME: Make a more direct way of getting
- QAngle angles;
- VectorAngles( m_ControlPoints[nWhichPoint].m_ForwardVector, m_ControlPoints[nWhichPoint].m_UpVector, angles );
-
- static ParticleSystemSetControlPointOrientationState_t state;
- state.m_nParticleSystemId = GetToolParticleEffectId();
- state.m_flTime = gpGlobals->curtime;
- state.m_nControlPoint = nWhichPoint;
- AngleQuaternion( angles, state.m_qOrientation );
-
- KeyValues *msg = new KeyValues( "ParticleSystem_SetControlPointOrientation" );
- msg->SetPtr( "state", &state );
- ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
- }
-}
-
-void CNewParticleEffect::SetControlPointOrientation( int nWhichPoint,
- const Vector &forward, const Vector &right, const Vector &up )
-{
- CParticleCollection::SetControlPointOrientation( nWhichPoint, forward, right, up );
- RecordControlPointOrientation( nWhichPoint );
-}
-
-void CNewParticleEffect::SetControlPointOrientation( int nWhichPoint, const Quaternion &q )
-{
- CParticleCollection::SetControlPointOrientation( nWhichPoint, q );
- RecordControlPointOrientation( nWhichPoint );
-}
-
-void CNewParticleEffect::SetControlPointForwardVector( int nWhichPoint, const Vector &v )
-{
- CParticleCollection::SetControlPointForwardVector( nWhichPoint, v );
- RecordControlPointOrientation( nWhichPoint );
-}
-
-void CNewParticleEffect::SetControlPointUpVector( int nWhichPoint, const Vector &v )
-{
- CParticleCollection::SetControlPointUpVector( nWhichPoint, v );
- RecordControlPointOrientation( nWhichPoint );
-}
-
-void CNewParticleEffect::SetControlPointRightVector( int nWhichPoint, const Vector &v )
-{
- CParticleCollection::SetControlPointRightVector( nWhichPoint, v );
- RecordControlPointOrientation( nWhichPoint );
-}
-
-
-//-----------------------------------------------------------------------------
-// Called when the particle effect is about to update
-//-----------------------------------------------------------------------------
-void CNewParticleEffect::Update( float flTimeDelta )
-{
- if ( m_hOwner )
- {
- m_hOwner->ParticleProp()->OnParticleSystemUpdated( this, flTimeDelta );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Bounding box
-//-----------------------------------------------------------------------------
-CNewParticleEffect* CNewParticleEffect::ReplaceWith( const char *pParticleSystemName )
-{
- StopEmission( false, true, true );
- if ( !pParticleSystemName || !pParticleSystemName[0] )
- return NULL;
-
- CSmartPtr< CNewParticleEffect > pNewEffect = CNewParticleEffect::Create( GetOwner(), pParticleSystemName, pParticleSystemName );
- if ( !pNewEffect->IsValid() )
- return pNewEffect.GetObject();
-
- // Copy over the control point data
- for ( int i = 0; i < MAX_PARTICLE_CONTROL_POINTS; ++i )
- {
- if ( !ReadsControlPoint( i ) )
- continue;
-
- Vector vecForward, vecRight, vecUp;
- pNewEffect->SetControlPoint( i, GetControlPointAtCurrentTime( i ) );
- GetControlPointOrientationAtCurrentTime( i, &vecForward, &vecRight, &vecUp );
- pNewEffect->SetControlPointOrientation( i, vecForward, vecRight, vecUp );
- pNewEffect->SetControlPointParent( i, GetControlPointParent( i ) );
- }
-
- if ( !m_hOwner )
- return pNewEffect.GetObject();
-
- m_hOwner->ParticleProp()->ReplaceParticleEffect( this, pNewEffect.GetObject() );
- return pNewEffect.GetObject();
-}
-
-
-//-----------------------------------------------------------------------------
-// Bounding box
-//-----------------------------------------------------------------------------
-void CNewParticleEffect::SetParticleCullRadius( float radius )
-{
-}
-
-bool CNewParticleEffect::RecalculateBoundingBox()
-{
- BloatBoundsUsingControlPoint();
- if ( m_MaxBounds.x < m_MinBounds.x )
- {
- m_MaxBounds = m_MinBounds = GetSortOrigin();
- return false;
- }
-
- return true;
-}
-
-
-void CNewParticleEffect::GetRenderBounds( Vector& mins, Vector& maxs )
-{
- VectorSubtract( m_MinBounds, GetRenderOrigin(), mins );
- VectorSubtract( m_MaxBounds, GetRenderOrigin(), maxs );
-}
-
-void CNewParticleEffect::DetectChanges()
-{
- // if we have no render handle, return
- if ( m_hRenderHandle == INVALID_CLIENT_RENDER_HANDLE )
- return;
-
- float flBuffer = cl_particleeffect_aabb_buffer.GetFloat();
- float flExtraBuffer = flBuffer * 1.3f;
-
- // if nothing changed, return
- if ( m_MinBounds.x < m_LastMin.x ||
- m_MinBounds.y < m_LastMin.y ||
- m_MinBounds.z < m_LastMin.z ||
-
- m_MinBounds.x > (m_LastMin.x + flExtraBuffer) ||
- m_MinBounds.y > (m_LastMin.y + flExtraBuffer) ||
- m_MinBounds.z > (m_LastMin.z + flExtraBuffer) ||
-
- m_MaxBounds.x > m_LastMax.x ||
- m_MaxBounds.y > m_LastMax.y ||
- m_MaxBounds.z > m_LastMax.z ||
-
- m_MaxBounds.x < (m_LastMax.x - flExtraBuffer) ||
- m_MaxBounds.y < (m_LastMax.y - flExtraBuffer) ||
- m_MaxBounds.z < (m_LastMax.z - flExtraBuffer)
- )
- {
- // call leafsystem to updated this guy
- ClientLeafSystem()->RenderableChanged( m_hRenderHandle );
-
- // remember last parameters
- // Add some padding in here so we don't reinsert it into the leaf system if it just changes a tiny amount.
- m_LastMin = m_MinBounds - Vector( flBuffer, flBuffer, flBuffer );
- m_LastMax = m_MaxBounds + Vector( flBuffer, flBuffer, flBuffer );
- }
-}
-
-extern ConVar r_DrawParticles;
-
-
-void CNewParticleEffect::DebugDrawBbox ( bool bCulled )
-{
- int nParticlesShowBboxCost = g_cl_particle_show_bbox_cost;
- bool bShowCheapSystems = false;
- if ( nParticlesShowBboxCost < 0 )
- {
- nParticlesShowBboxCost = -nParticlesShowBboxCost;
- bShowCheapSystems = true;
- }
-
- Vector center = GetRenderOrigin();
- Vector mins = m_MinBounds - center;
- Vector maxs = m_MaxBounds - center;
-
- int r, g, b;
- bool bDraw = true;
- if ( bCulled )
- {
- r = 64;
- g = 64;
- b = 64;
- }
- else if ( nParticlesShowBboxCost > 0 )
- {
- float fAmount = (float)m_nActiveParticles / (float)nParticlesShowBboxCost;
- if ( fAmount < 0.5f )
- {
- if ( bShowCheapSystems )
- {
- r = 0;
- g = 255;
- b = 0;
- }
- else
- {
- // Prevent the screen getting spammed with low-count particles which aren't that expensive.
- bDraw = false;
- r = 0;
- g = 0;
- b = 0;
- }
- }
- else if ( fAmount < 1.0f )
- {
- // green 0.5-1.0 blue
- int nBlend = (int)( 512.0f * ( fAmount - 0.5f ) );
- nBlend = MIN ( 255, MAX ( 0, nBlend ) );
- r = 0;
- g = 255 - nBlend;
- b = nBlend;
- }
- else if ( fAmount < 2.0f )
- {
- // blue 1.0-2.0 red
- int nBlend = (int)( 256.0f * ( fAmount - 1.0f ) );
- nBlend = MIN ( 255, MAX ( 0, nBlend ) );
- r = nBlend;
- g = 0;
- b = 255 - nBlend;
- }
- else
- {
- r = 255;
- g = 0;
- b = 0;
- }
- }
- else
- {
- if ( GetAutoUpdateBBox() )
- {
- // red is bad, the bbox update is costly
- r = 255;
- g = 0;
- b = 0;
- }
- else
- {
- // green, this effect presents less cpu load
- r = 0;
- g = 255;
- b = 0;
- }
- }
-
- if ( bDraw )
- {
- debugoverlay->AddBoxOverlay( center, mins, maxs, QAngle( 0, 0, 0 ), r, g, b, 16, 0 );
- debugoverlay->AddTextOverlayRGB( center, 0, 0, r, g, b, 64, "%s:(%d)", GetEffectName(), m_nActiveParticles );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Rendering
-//-----------------------------------------------------------------------------
-int CNewParticleEffect::DrawModel( int flags )
-{
- VPROF_BUDGET( "CNewParticleEffect::DrawModel", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
- if ( r_DrawParticles.GetBool() == false )
- return 0;
-
- if ( !g_pClientMode->ShouldDrawParticles() || !ParticleMgr()->ShouldRenderParticleSystems() )
- return 0;
-
- if ( ( flags & ( STUDIO_SHADOWDEPTHTEXTURE | STUDIO_SSAODEPTHTEXTURE ) ) != 0 )
- {
- return 0;
- }
-
- // do distance cull check here. We do it here instead of in particles so we can easily only do
- // it for root objects, not bothering to cull children individually
- CMatRenderContextPtr pRenderContext( materials );
- Vector vecCamera;
- pRenderContext->GetWorldSpaceCameraPosition( &vecCamera );
- if ( CalcSqrDistanceToAABB( m_MinBounds, m_MaxBounds, vecCamera ) > ( m_pDef->m_flMaxDrawDistance * m_pDef->m_flMaxDrawDistance ) )
- {
- if ( !IsRetail() && ( g_cl_particle_show_bbox || ( g_cl_particle_show_bbox_cost != 0 ) ) )
- {
- DebugDrawBbox ( true );
- }
-
- // Still need to make sure we set this or they won't follow their attachemnt points.
- m_flNextSleepTime = Max ( m_flNextSleepTime, ( g_pParticleSystemMgr->GetLastSimulationTime() + m_pDef->m_flNoDrawTimeToGoToSleep ));
-
- return 0;
- }
-
- if ( flags & STUDIO_TRANSPARENCY )
- {
- int viewentity = render->GetViewEntity();
- C_BaseEntity *pCameraObject = cl_entitylist->GetEnt( viewentity );
- // apply logic that lets you skip rendering a system if the camera is attached to its entity
- if ( pCameraObject &&
- ( m_pDef->m_nSkipRenderControlPoint != -1 ) &&
- ( m_pDef->m_nSkipRenderControlPoint <= m_nHighestCP ) )
- {
- C_BaseEntity *pEntity = (EHANDLE)GetControlPointEntity( m_pDef->m_nSkipRenderControlPoint );
- if ( pEntity )
- {
- // If we're in thirdperson, we still see it
- if ( !input->CAM_IsThirdPerson() )
- {
- if ( pEntity == pCameraObject )
- return 0;
- C_BaseEntity *pRootMove = pEntity->GetRootMoveParent();
- if ( pRootMove == pCameraObject )
- return 0;
-
- // If we're spectating in-eyes of the camera object, we don't see it
- C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
- if ( pPlayer == pCameraObject )
- {
- C_BaseEntity *pObTarget = pPlayer->GetObserverTarget();
- if ( pPlayer->GetObserverMode() == OBS_MODE_IN_EYE && (pObTarget == pEntity || pRootMove == pObTarget ) )
- return 0;
- }
- }
- }
- }
-
- pRenderContext->MatrixMode( MATERIAL_MODEL );
- pRenderContext->PushMatrix();
- pRenderContext->LoadIdentity();
- Render( pRenderContext, IsTwoPass(), pCameraObject );
- pRenderContext->MatrixMode( MATERIAL_MODEL );
- pRenderContext->PopMatrix();
- }
- else
- {
- g_pParticleSystemMgr->AddToRenderCache( this );
- }
-
- if ( !IsRetail() )
- {
- CParticleMgr *pMgr = ParticleMgr();
- if ( pMgr->m_bStatsRunning )
- {
- pMgr->StatsNewParticleEffectDrawn ( this );
- }
-
- if ( g_cl_particle_show_bbox || ( g_cl_particle_show_bbox_cost != 0 ) )
- {
- DebugDrawBbox ( false );
- }
- }
-
- return 1;
-}
-
-static void DumpParticleStats_f( void )
-{
- g_pParticleSystemMgr->DumpProfileInformation();
-}
-
-static ConCommand cl_dump_particle_stats( "cl_dump_particle_stats", DumpParticleStats_f, "dump particle profiling info to particle_profile.csv") ;
-
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//===========================================================================// +#include "cbase.h" +#include "particlemgr.h" +#include "particles_new.h" +#include "iclientmode.h" +#include "engine/ivdebugoverlay.h" +#include "particle_property.h" +#include "toolframework/itoolframework.h" +#include "toolframework_client.h" +#include "tier1/KeyValues.h" +#include "model_types.h" +#include "vprof.h" +#include "input.h" + +extern ConVar cl_particleeffect_aabb_buffer; + +//extern ConVar cl_particle_show_bbox; +//extern ConVar cl_particle_show_bbox_cost; +extern bool g_cl_particle_show_bbox; +extern int g_cl_particle_show_bbox_cost; + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CNewParticleEffect::CNewParticleEffect( CBaseEntity *pOwner, CParticleSystemDefinition *pEffect ) +{ + m_hOwner = pOwner; + Init( pEffect ); + Construct(); +} + +CNewParticleEffect::CNewParticleEffect( CBaseEntity *pOwner, const char* pEffectName ) +{ + m_hOwner = pOwner; + Init( pEffectName ); + Construct(); +} + +void CNewParticleEffect::Construct() +{ + m_vSortOrigin.Init(); + + m_bDontRemove = false; + m_bRemove = false; + m_bDrawn = false; + m_bNeedsBBoxUpdate = false; + m_bIsFirstFrame = true; + m_bAutoUpdateBBox = false; + m_bAllocated = true; + m_bSimulate = true; + m_bShouldPerformCullCheck = false; + + m_nToolParticleEffectId = TOOLPARTICLESYSTEMID_INVALID; + m_RefCount = 0; + ParticleMgr()->AddEffect( this ); + m_LastMax = Vector( -1.0e6, -1.0e6, -1.0e6 ); + m_LastMin = Vector( 1.0e6, 1.0e6, 1.0e6 ); + m_MinBounds = Vector( 1.0e6, 1.0e6, 1.0e6 ); + m_MaxBounds = Vector( -1.0e6, -1.0e6, -1.0e6 ); + m_pDebugName = NULL; + + if ( IsValid() && clienttools->IsInRecordingMode() ) + { + int nId = AllocateToolParticleEffectId(); + + static ParticleSystemCreatedState_t state; + state.m_nParticleSystemId = nId; + state.m_flTime = gpGlobals->curtime; + state.m_pName = GetName(); + state.m_nOwner = m_hOwner.Get() ? m_hOwner->entindex() : -1; + + KeyValues *msg = new KeyValues( "ParticleSystem_Create" ); + msg->SetPtr( "state", &state ); + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + } +} + +CNewParticleEffect::~CNewParticleEffect(void) +{ + if ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID && clienttools->IsInRecordingMode() ) + { + static ParticleSystemDestroyedState_t state; + state.m_nParticleSystemId = gpGlobals->curtime; + state.m_flTime = gpGlobals->curtime; + + KeyValues *msg = new KeyValues( "ParticleSystem_Destroy" ); + msg->SetPtr( "state", &state ); + + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + m_nToolParticleEffectId = TOOLPARTICLESYSTEMID_INVALID; + } + + m_bAllocated = false; + if ( m_hOwner ) + { + // NOTE: This can provoke another NotifyRemove call which is why flags is set to 0 + m_hOwner->ParticleProp()->OnParticleSystemDeleted( this ); + } +} + + +//----------------------------------------------------------------------------- +// Refcounting +//----------------------------------------------------------------------------- +void CNewParticleEffect::AddRef() +{ + ++m_RefCount; +} + +void CNewParticleEffect::Release() +{ + Assert( m_RefCount > 0 ); + --m_RefCount; + + // If all the particles are already gone, delete ourselves now. + // If there are still particles, wait for the last NotifyDestroyParticle. + if ( m_RefCount == 0 ) + { + if ( m_bAllocated ) + { + if ( IsFinished() ) + { + SetRemoveFlag(); + } + } + } +} + +void CNewParticleEffect::NotifyRemove() +{ + if ( m_bAllocated ) + { + delete this; + } +} + +int CNewParticleEffect::IsReleased() +{ + return m_RefCount == 0; +} + + +//----------------------------------------------------------------------------- +// Refraction and soft particle support +//----------------------------------------------------------------------------- +bool CNewParticleEffect::UsesPowerOfTwoFrameBufferTexture( void ) +{ + // NOTE: Need to do this because CParticleCollection's version is non-virtual + return CParticleCollection::UsesPowerOfTwoFrameBufferTexture( true ); +} + +bool CNewParticleEffect::UsesFullFrameBufferTexture( void ) +{ + // NOTE: Need to do this because CParticleCollection's version is non-virtual + return CParticleCollection::UsesFullFrameBufferTexture( true ); +} + +bool CNewParticleEffect::IsTwoPass( void ) +{ + // NOTE: Need to do this because CParticleCollection's version is non-virtual + return CParticleCollection::IsTwoPass(); +} + + +//----------------------------------------------------------------------------- +// Overrides for recording +//----------------------------------------------------------------------------- +void CNewParticleEffect::StopEmission( bool bInfiniteOnly, bool bRemoveAllParticles, bool bWakeOnStop ) +{ + if ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID && clienttools->IsInRecordingMode() ) + { + KeyValues *msg = new KeyValues( "ParticleSystem_StopEmission" ); + + static ParticleSystemStopEmissionState_t state; + state.m_nParticleSystemId = GetToolParticleEffectId(); + state.m_flTime = gpGlobals->curtime; + state.m_bInfiniteOnly = bInfiniteOnly; + + msg->SetPtr( "state", &state ); + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + } + + CParticleCollection::StopEmission( bInfiniteOnly, bRemoveAllParticles, bWakeOnStop ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CNewParticleEffect::SetDormant( bool bDormant ) +{ + CParticleCollection::SetDormant( bDormant ); +} + +void CNewParticleEffect::SetControlPointEntity( int nWhichPoint, CBaseEntity *pEntity ) +{ + if ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID && clienttools->IsInRecordingMode() ) + { + static ParticleSystemSetControlPointObjectState_t state; + state.m_nParticleSystemId = GetToolParticleEffectId(); + state.m_flTime = gpGlobals->curtime; + state.m_nControlPoint = nWhichPoint; + state.m_nObject = pEntity ? pEntity->entindex() : -1; + + KeyValues *msg = new KeyValues( "ParticleSystem_SetControlPointObject" ); + msg->SetPtr( "state", &state ); + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + } + + if ( pEntity ) + { + CParticleCollection::SetControlPointObject( nWhichPoint, &m_hControlPointOwners[ nWhichPoint ] ); + m_hControlPointOwners[ nWhichPoint ] = pEntity; + } + else + CParticleCollection::SetControlPointObject( nWhichPoint, NULL ); +} + + +void CNewParticleEffect::SetControlPoint( int nWhichPoint, const Vector &v ) +{ + if ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID && clienttools->IsInRecordingMode() ) + { + static ParticleSystemSetControlPointPositionState_t state; + state.m_nParticleSystemId = GetToolParticleEffectId(); + state.m_flTime = gpGlobals->curtime; + state.m_nControlPoint = nWhichPoint; + state.m_vecPosition = v; + + KeyValues *msg = new KeyValues( "ParticleSystem_SetControlPointPosition" ); + msg->SetPtr( "state", &state ); + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + } + + CParticleCollection::SetControlPoint( nWhichPoint, v ); +} + + +void CNewParticleEffect::RecordControlPointOrientation( int nWhichPoint ) +{ + if ( m_nToolParticleEffectId != TOOLPARTICLESYSTEMID_INVALID && clienttools->IsInRecordingMode() ) + { + // FIXME: Make a more direct way of getting + QAngle angles; + VectorAngles( m_ControlPoints[nWhichPoint].m_ForwardVector, m_ControlPoints[nWhichPoint].m_UpVector, angles ); + + static ParticleSystemSetControlPointOrientationState_t state; + state.m_nParticleSystemId = GetToolParticleEffectId(); + state.m_flTime = gpGlobals->curtime; + state.m_nControlPoint = nWhichPoint; + AngleQuaternion( angles, state.m_qOrientation ); + + KeyValues *msg = new KeyValues( "ParticleSystem_SetControlPointOrientation" ); + msg->SetPtr( "state", &state ); + ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg ); + } +} + +void CNewParticleEffect::SetControlPointOrientation( int nWhichPoint, + const Vector &forward, const Vector &right, const Vector &up ) +{ + CParticleCollection::SetControlPointOrientation( nWhichPoint, forward, right, up ); + RecordControlPointOrientation( nWhichPoint ); +} + +void CNewParticleEffect::SetControlPointOrientation( int nWhichPoint, const Quaternion &q ) +{ + CParticleCollection::SetControlPointOrientation( nWhichPoint, q ); + RecordControlPointOrientation( nWhichPoint ); +} + +void CNewParticleEffect::SetControlPointForwardVector( int nWhichPoint, const Vector &v ) +{ + CParticleCollection::SetControlPointForwardVector( nWhichPoint, v ); + RecordControlPointOrientation( nWhichPoint ); +} + +void CNewParticleEffect::SetControlPointUpVector( int nWhichPoint, const Vector &v ) +{ + CParticleCollection::SetControlPointUpVector( nWhichPoint, v ); + RecordControlPointOrientation( nWhichPoint ); +} + +void CNewParticleEffect::SetControlPointRightVector( int nWhichPoint, const Vector &v ) +{ + CParticleCollection::SetControlPointRightVector( nWhichPoint, v ); + RecordControlPointOrientation( nWhichPoint ); +} + + +//----------------------------------------------------------------------------- +// Called when the particle effect is about to update +//----------------------------------------------------------------------------- +void CNewParticleEffect::Update( float flTimeDelta ) +{ + if ( m_hOwner ) + { + m_hOwner->ParticleProp()->OnParticleSystemUpdated( this, flTimeDelta ); + } +} + + +//----------------------------------------------------------------------------- +// Bounding box +//----------------------------------------------------------------------------- +CNewParticleEffect* CNewParticleEffect::ReplaceWith( const char *pParticleSystemName ) +{ + StopEmission( false, true, true ); + if ( !pParticleSystemName || !pParticleSystemName[0] ) + return NULL; + + CSmartPtr< CNewParticleEffect > pNewEffect = CNewParticleEffect::Create( GetOwner(), pParticleSystemName, pParticleSystemName ); + if ( !pNewEffect->IsValid() ) + return pNewEffect.GetObject(); + + // Copy over the control point data + for ( int i = 0; i < MAX_PARTICLE_CONTROL_POINTS; ++i ) + { + if ( !ReadsControlPoint( i ) ) + continue; + + Vector vecForward, vecRight, vecUp; + pNewEffect->SetControlPoint( i, GetControlPointAtCurrentTime( i ) ); + GetControlPointOrientationAtCurrentTime( i, &vecForward, &vecRight, &vecUp ); + pNewEffect->SetControlPointOrientation( i, vecForward, vecRight, vecUp ); + pNewEffect->SetControlPointParent( i, GetControlPointParent( i ) ); + } + + if ( !m_hOwner ) + return pNewEffect.GetObject(); + + m_hOwner->ParticleProp()->ReplaceParticleEffect( this, pNewEffect.GetObject() ); + return pNewEffect.GetObject(); +} + + +//----------------------------------------------------------------------------- +// Bounding box +//----------------------------------------------------------------------------- +void CNewParticleEffect::SetParticleCullRadius( float radius ) +{ +} + +bool CNewParticleEffect::RecalculateBoundingBox() +{ + BloatBoundsUsingControlPoint(); + if ( m_MaxBounds.x < m_MinBounds.x ) + { + m_MaxBounds = m_MinBounds = GetSortOrigin(); + return false; + } + + return true; +} + + +void CNewParticleEffect::GetRenderBounds( Vector& mins, Vector& maxs ) +{ + VectorSubtract( m_MinBounds, GetRenderOrigin(), mins ); + VectorSubtract( m_MaxBounds, GetRenderOrigin(), maxs ); +} + +void CNewParticleEffect::DetectChanges() +{ + // if we have no render handle, return + if ( m_hRenderHandle == INVALID_CLIENT_RENDER_HANDLE ) + return; + + float flBuffer = cl_particleeffect_aabb_buffer.GetFloat(); + float flExtraBuffer = flBuffer * 1.3f; + + // if nothing changed, return + if ( m_MinBounds.x < m_LastMin.x || + m_MinBounds.y < m_LastMin.y || + m_MinBounds.z < m_LastMin.z || + + m_MinBounds.x > (m_LastMin.x + flExtraBuffer) || + m_MinBounds.y > (m_LastMin.y + flExtraBuffer) || + m_MinBounds.z > (m_LastMin.z + flExtraBuffer) || + + m_MaxBounds.x > m_LastMax.x || + m_MaxBounds.y > m_LastMax.y || + m_MaxBounds.z > m_LastMax.z || + + m_MaxBounds.x < (m_LastMax.x - flExtraBuffer) || + m_MaxBounds.y < (m_LastMax.y - flExtraBuffer) || + m_MaxBounds.z < (m_LastMax.z - flExtraBuffer) + ) + { + // call leafsystem to updated this guy + ClientLeafSystem()->RenderableChanged( m_hRenderHandle ); + + // remember last parameters + // Add some padding in here so we don't reinsert it into the leaf system if it just changes a tiny amount. + m_LastMin = m_MinBounds - Vector( flBuffer, flBuffer, flBuffer ); + m_LastMax = m_MaxBounds + Vector( flBuffer, flBuffer, flBuffer ); + } +} + +extern ConVar r_DrawParticles; + + +void CNewParticleEffect::DebugDrawBbox ( bool bCulled ) +{ + int nParticlesShowBboxCost = g_cl_particle_show_bbox_cost; + bool bShowCheapSystems = false; + if ( nParticlesShowBboxCost < 0 ) + { + nParticlesShowBboxCost = -nParticlesShowBboxCost; + bShowCheapSystems = true; + } + + Vector center = GetRenderOrigin(); + Vector mins = m_MinBounds - center; + Vector maxs = m_MaxBounds - center; + + int r, g, b; + bool bDraw = true; + if ( bCulled ) + { + r = 64; + g = 64; + b = 64; + } + else if ( nParticlesShowBboxCost > 0 ) + { + float fAmount = (float)m_nActiveParticles / (float)nParticlesShowBboxCost; + if ( fAmount < 0.5f ) + { + if ( bShowCheapSystems ) + { + r = 0; + g = 255; + b = 0; + } + else + { + // Prevent the screen getting spammed with low-count particles which aren't that expensive. + bDraw = false; + r = 0; + g = 0; + b = 0; + } + } + else if ( fAmount < 1.0f ) + { + // green 0.5-1.0 blue + int nBlend = (int)( 512.0f * ( fAmount - 0.5f ) ); + nBlend = MIN ( 255, MAX ( 0, nBlend ) ); + r = 0; + g = 255 - nBlend; + b = nBlend; + } + else if ( fAmount < 2.0f ) + { + // blue 1.0-2.0 red + int nBlend = (int)( 256.0f * ( fAmount - 1.0f ) ); + nBlend = MIN ( 255, MAX ( 0, nBlend ) ); + r = nBlend; + g = 0; + b = 255 - nBlend; + } + else + { + r = 255; + g = 0; + b = 0; + } + } + else + { + if ( GetAutoUpdateBBox() ) + { + // red is bad, the bbox update is costly + r = 255; + g = 0; + b = 0; + } + else + { + // green, this effect presents less cpu load + r = 0; + g = 255; + b = 0; + } + } + + if ( bDraw ) + { + debugoverlay->AddBoxOverlay( center, mins, maxs, QAngle( 0, 0, 0 ), r, g, b, 16, 0 ); + debugoverlay->AddTextOverlayRGB( center, 0, 0, r, g, b, 64, "%s:(%d)", GetEffectName(), m_nActiveParticles ); + } +} + + +//----------------------------------------------------------------------------- +// Rendering +//----------------------------------------------------------------------------- +int CNewParticleEffect::DrawModel( int flags ) +{ + VPROF_BUDGET( "CNewParticleEffect::DrawModel", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); + if ( r_DrawParticles.GetBool() == false ) + return 0; + + if ( !g_pClientMode->ShouldDrawParticles() || !ParticleMgr()->ShouldRenderParticleSystems() ) + return 0; + + if ( ( flags & ( STUDIO_SHADOWDEPTHTEXTURE | STUDIO_SSAODEPTHTEXTURE ) ) != 0 ) + { + return 0; + } + + // do distance cull check here. We do it here instead of in particles so we can easily only do + // it for root objects, not bothering to cull children individually + CMatRenderContextPtr pRenderContext( materials ); + Vector vecCamera; + pRenderContext->GetWorldSpaceCameraPosition( &vecCamera ); + if ( CalcSqrDistanceToAABB( m_MinBounds, m_MaxBounds, vecCamera ) > ( m_pDef->m_flMaxDrawDistance * m_pDef->m_flMaxDrawDistance ) ) + { + if ( !IsRetail() && ( g_cl_particle_show_bbox || ( g_cl_particle_show_bbox_cost != 0 ) ) ) + { + DebugDrawBbox ( true ); + } + + // Still need to make sure we set this or they won't follow their attachemnt points. + m_flNextSleepTime = Max ( m_flNextSleepTime, ( g_pParticleSystemMgr->GetLastSimulationTime() + m_pDef->m_flNoDrawTimeToGoToSleep )); + + return 0; + } + + if ( flags & STUDIO_TRANSPARENCY ) + { + int viewentity = render->GetViewEntity(); + C_BaseEntity *pCameraObject = cl_entitylist->GetEnt( viewentity ); + // apply logic that lets you skip rendering a system if the camera is attached to its entity + if ( pCameraObject && + ( m_pDef->m_nSkipRenderControlPoint != -1 ) && + ( m_pDef->m_nSkipRenderControlPoint <= m_nHighestCP ) ) + { + C_BaseEntity *pEntity = (EHANDLE)GetControlPointEntity( m_pDef->m_nSkipRenderControlPoint ); + if ( pEntity ) + { + // If we're in thirdperson, we still see it + if ( !input->CAM_IsThirdPerson() ) + { + if ( pEntity == pCameraObject ) + return 0; + C_BaseEntity *pRootMove = pEntity->GetRootMoveParent(); + if ( pRootMove == pCameraObject ) + return 0; + + // If we're spectating in-eyes of the camera object, we don't see it + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer == pCameraObject ) + { + C_BaseEntity *pObTarget = pPlayer->GetObserverTarget(); + if ( pPlayer->GetObserverMode() == OBS_MODE_IN_EYE && (pObTarget == pEntity || pRootMove == pObTarget ) ) + return 0; + } + } + } + } + + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + pRenderContext->LoadIdentity(); + Render( pRenderContext, IsTwoPass(), pCameraObject ); + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PopMatrix(); + } + else + { + g_pParticleSystemMgr->AddToRenderCache( this ); + } + + if ( !IsRetail() ) + { + CParticleMgr *pMgr = ParticleMgr(); + if ( pMgr->m_bStatsRunning ) + { + pMgr->StatsNewParticleEffectDrawn ( this ); + } + + if ( g_cl_particle_show_bbox || ( g_cl_particle_show_bbox_cost != 0 ) ) + { + DebugDrawBbox ( false ); + } + } + + return 1; +} + +static void DumpParticleStats_f( void ) +{ + g_pParticleSystemMgr->DumpProfileInformation(); +} + +static ConCommand cl_dump_particle_stats( "cl_dump_particle_stats", DumpParticleStats_f, "dump particle profiling info to particle_profile.csv") ; + |