diff options
| author | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
|---|---|---|
| committer | Joe Ludwig <[email protected]> | 2013-06-26 15:22:04 -0700 |
| commit | 39ed87570bdb2f86969d4be821c94b722dc71179 (patch) | |
| tree | abc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/client/particles_new.cpp | |
| download | source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip | |
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/client/particles_new.cpp')
| -rw-r--r-- | mp/src/game/client/particles_new.cpp | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/mp/src/game/client/particles_new.cpp b/mp/src/game/client/particles_new.cpp new file mode 100644 index 00000000..0c762ac7 --- /dev/null +++ b/mp/src/game/client/particles_new.cpp @@ -0,0 +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") ;
+
|