From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- sp/src/game/client/particles_new.cpp | 1208 +++++++++++++++++----------------- 1 file changed, 604 insertions(+), 604 deletions(-) (limited to 'sp/src/game/client/particles_new.cpp') diff --git a/sp/src/game/client/particles_new.cpp b/sp/src/game/client/particles_new.cpp index 0c762ac7..d3dc6599 100644 --- a/sp/src/game/client/particles_new.cpp +++ b/sp/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") ; + -- cgit v1.2.3