summaryrefslogtreecommitdiff
path: root/game/client/tf/vgui/tf_particlepanel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf/vgui/tf_particlepanel.cpp')
-rw-r--r--game/client/tf/vgui/tf_particlepanel.cpp556
1 files changed, 556 insertions, 0 deletions
diff --git a/game/client/tf/vgui/tf_particlepanel.cpp b/game/client/tf/vgui/tf_particlepanel.cpp
new file mode 100644
index 0000000..8513dd1
--- /dev/null
+++ b/game/client/tf/vgui/tf_particlepanel.cpp
@@ -0,0 +1,556 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A panel that display particle systems
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include <KeyValues.h>
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+#include <vgui_controls/EditablePanel.h>
+#include "vgui/IVGui.h"
+
+#include "tf_particlepanel.h"
+#include "matsys_controls/matsyscontrols.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "tier2/renderutils.h"
+#include "renderparm.h"
+
+using namespace vgui;
+
+
+CTFParticlePanel::ParticleEffect_t::ParticleEffect_t()
+ : m_bLoop( true )
+ , m_pParticleSystem( NULL )
+ , m_flLastTime( FLT_MAX )
+ , m_ParticleSystemName( NULL )
+ , m_bStartActivated( true )
+ , m_flScale( 1.f )
+ , m_flEndTime( FLT_MAX )
+ , m_nXPos( 0 )
+ , m_nYPos( 0 )
+ , m_Angles( 0.f, 0.f, 0.f )
+ , m_pParent( NULL )
+ , m_bForceStopped( false )
+ , m_bAutoDelete( false )
+ , m_bStarted( false )
+{}
+
+
+DECLARE_BUILD_FACTORY( CTFParticlePanel );
+//-----------------------------------------------------------------------------
+// Constructor, destructor
+//-----------------------------------------------------------------------------
+CTFParticlePanel::CTFParticlePanel( vgui::Panel *pParent, const char *pName )
+ : BaseClass( pParent, pName )
+{
+ m_Camera.m_flZNear = 3.0f;
+ m_Camera.m_flZFar = 16384.0f * 1.73205080757f;
+ m_Camera.m_flFOV = 30.0f;
+ m_Camera.m_origin = Vector(0,0,0);
+ m_Camera.m_angles = QAngle(0,0,0);
+
+ m_pLightmapTexture.Init( "//platform/materials/debug/defaultlightmap", "editor" );
+ m_DefaultEnvCubemap.Init( "editor/cubemap", "editor", true );
+}
+
+CTFParticlePanel::~CTFParticlePanel()
+{
+ m_pLightmapTexture.Shutdown();
+ m_DefaultEnvCubemap.Shutdown();
+ m_vecParticleEffects.PurgeAndDeleteElements();
+}
+
+
+void CTFParticlePanel::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ KeyValues *pKVParticleEffects = inResourceData->FindKey( "ParticleEffects" );
+ if ( pKVParticleEffects )
+ {
+ FOR_EACH_SUBKEY( pKVParticleEffects, pKVEffect )
+ {
+ m_vecParticleEffects[ m_vecParticleEffects.AddToTail() ] = new ParticleEffect_t();
+ ParticleEffect_t* pEffect = m_vecParticleEffects.Tail();
+
+ // get the position
+ int alignScreenWide = GetWide(), alignScreenTall = GetTall(); // screen dimensions used for pinning in splitscreen
+
+ int x, y;
+ GetPos(x, y);
+ const char *xstr = pKVEffect->GetString( "particle_xpos", NULL );
+ const char *ystr = pKVEffect->GetString( "particle_ypos", NULL );
+
+ if (xstr)
+ {
+ bool bRightAlign = false;
+ bool bCenterAlign = false;
+ // look for alignment flags
+ if (xstr[0] == 'r' || xstr[0] == 'R')
+ {
+ bRightAlign = true;
+ xstr++;
+ }
+ else if (xstr[0] == 'c' || xstr[0] == 'C')
+ {
+ bCenterAlign = true;
+ xstr++;
+ }
+
+ // get the value
+ x = atoi(xstr);
+ // scale the x up to our screen co-ords
+ if ( IsProportional() )
+ {
+ x = scheme()->GetProportionalScaledValueEx(GetScheme(), x);
+ }
+ // now correct the alignment
+ if ( bRightAlign )
+ {
+ x = alignScreenWide - x;
+ }
+ else if ( bCenterAlign )
+ {
+ x = (alignScreenWide / 2) + x;
+ }
+ }
+
+ if (ystr)
+ {
+ bool bBottomAlign = false;
+ bool bCenterAlign = false;
+ // look for alignment flags
+ if (ystr[0] == 'r' || ystr[0] == 'R')
+ {
+ bBottomAlign = true;
+ ystr++;
+ }
+ else if (ystr[0] == 'c' || ystr[0] == 'C')
+ {
+ bCenterAlign = true;
+ ystr++;
+ }
+ y = atoi(ystr);
+ if (IsProportional())
+ {
+ // scale the y up to our screen co-ords
+ y = scheme()->GetProportionalScaledValueEx(GetScheme(), y);
+ }
+ // now correct the alignment
+ if ( bBottomAlign )
+ {
+ y = alignScreenTall - y;
+ }
+ else if ( bCenterAlign )
+ {
+ y = (alignScreenTall / 2) + y;
+ }
+ }
+
+ pEffect->m_nXPos = x;
+ pEffect->m_nYPos = y;
+
+ pEffect->m_flScale = pKVEffect->GetFloat( "particle_scale", 1.f );
+ // Scale the scale factor the same way we do the XY position coordinates
+ if( IsProportional() )
+ {
+ int wide, tall;
+ surface()->GetScreenSize( wide, tall );
+
+ int proH, proW;
+ surface()->GetProportionalBase( proW, proH );
+ double scale = (double)tall / (double)proH;
+ pEffect->m_flScale *= scale;
+ }
+
+ pEffect->m_pParent = this;
+ pEffect->m_bLoop = pKVEffect->GetBool( "loop", true );
+ pEffect->m_bStartActivated = pKVEffect->GetBool( "start_activated", true );
+ pEffect->SetParticleSystem( pKVEffect->GetString( "particleName" ) );
+
+ // Read angles for the particle system
+ {
+ float x1,y1,z1;
+ const char* pszAngles = pKVEffect->GetString( "angles" );
+ if( *pszAngles )
+ {
+ if( pEffect->m_pParticleSystem && sscanf( pszAngles, "%f %f %f", &x1, &y1, &z1 ) == 3 )
+ {
+ pEffect->m_Angles = QAngle( x1, y1, z1 );
+ Quaternion q;
+ AngleQuaternion( pEffect->m_Angles , q );
+ pEffect->m_pParticleSystem->SetControlPointOrientation( 0, q );
+ }
+ }
+ }
+
+ pEffect->SetControlPointValue( 0, Vector(0,0,0) );
+ // Read all control point values
+ const char* pszControlPoint = NULL;
+ int nControlPointNumber = 0;
+ do
+ {
+ pszControlPoint = pKVEffect->GetString( VarArgs("control_point%d", nControlPointNumber), "" );
+ if ( *pszControlPoint )
+ {
+ float x2,y2,z2;
+ if (sscanf(pszControlPoint, "%f %f %f", &x2, &y2, &z2 ) == 3)
+ {
+ pEffect->SetControlPointValue( nControlPointNumber, Vector( x2, y2, z2 ) );
+ }
+ }
+
+ ++nControlPointNumber;
+ }
+ while( *pszControlPoint );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Scheme
+//-----------------------------------------------------------------------------
+void CTFParticlePanel::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetMouseInputEnabled( false );
+ SetKeyBoardInputEnabled( false );
+}
+
+void CTFParticlePanel::OnCommand( const char *command )
+{
+ if ( !Q_strnicmp( command, "start", ARRAYSIZE("start") - 1 ) )
+ {
+ // Check if they specified a particular one to turn on
+ const char* pszNum = command + ARRAYSIZE( "start" ) - 1;
+ int nIndex = m_vecParticleEffects.InvalidIndex();
+
+ if( pszNum && pszNum[0] )
+ {
+ nIndex = atoi(pszNum);
+ Assert( nIndex >= 0 && nIndex < m_vecParticleEffects.Count() );
+ }
+
+ FOR_EACH_VEC( m_vecParticleEffects, i )
+ {
+ if ( nIndex != m_vecParticleEffects.InvalidIndex() && i != nIndex )
+ continue;
+
+ ParticleEffect_t* pEffect = m_vecParticleEffects[ i ];
+
+ if( !pEffect->m_pParticleSystem )
+ {
+ pEffect->SetParticleSystem( pEffect->m_ParticleSystemName );
+ }
+
+ if( !pEffect->m_pParticleSystem )
+ continue;
+
+ pEffect->StartupParticleCollection();
+ pEffect->m_pParticleSystem->StartEmission();
+ pEffect->m_bForceStopped = false;
+ }
+ }
+ else if ( !Q_strnicmp( command, "stop", ARRAYSIZE("stop") - 1 ) )
+ {
+ // Check if they specified a specific one to turn off
+ const char* pszNum = command + ARRAYSIZE( "start" ) - 1;
+ if( pszNum && pszNum[0] )
+ {
+ int iIndex = atoi(pszNum);
+ Assert( iIndex >= 0 && iIndex < m_vecParticleEffects.Count() );
+
+ ParticleEffect_t* pEffect = m_vecParticleEffects[iIndex];
+ if( pEffect->m_pParticleSystem )
+ {
+ pEffect->m_pParticleSystem->StopEmission();
+ pEffect->m_bForceStopped = true;
+ }
+ }
+ else
+ {
+ // Turn them ALL off
+ FOR_EACH_VEC( m_vecParticleEffects, i )
+ {
+ ParticleEffect_t* pEffect = m_vecParticleEffects[ i ];
+ if( pEffect->m_pParticleSystem )
+ {
+ pEffect->m_pParticleSystem->StopEmission();
+ pEffect->m_bForceStopped = true;
+ }
+ }
+ }
+ }
+}
+
+void CTFParticlePanel::FireParticleEffect( const char *pszName, int xPos, int yPos, float flScale, bool bLoop, float flEndTime )
+{
+ m_vecParticleEffects[ m_vecParticleEffects.AddToTail() ] = new ParticleEffect_t();
+ ParticleEffect_t* pEffect = m_vecParticleEffects.Tail();
+
+ int iParentAbsX, iParentAbsY;
+ vgui::ipanel()->GetAbsPos( GetParent()->GetVPanel(), iParentAbsX, iParentAbsY );
+
+ pEffect->m_pParent = this;
+ pEffect->m_nXPos = xPos - iParentAbsX;
+ pEffect->m_nYPos = yPos - iParentAbsY;
+ pEffect->m_flScale = flScale;
+ pEffect->m_bLoop = bLoop;
+ pEffect->m_bAutoDelete = true; // This will get automatically deleted once it stops
+ pEffect->m_bStartActivated = true;
+ pEffect->m_flEndTime = gpGlobals->curtime + flEndTime;
+
+ if( IsProportional() )
+ {
+ int wide, tall;
+ surface()->GetScreenSize( wide, tall );
+
+ int proH, proW;
+ surface()->GetProportionalBase( proW, proH );
+ double scale = (double)tall / (double)proH;
+ pEffect->m_flScale *= scale;
+ }
+
+ for ( int i = 0; i < MAX_PARTICLE_CONTROL_POINTS; ++i )
+ {
+ pEffect->SetControlPointValue( i, Vector( 0, 0, 10.0f * i ) );
+ }
+ pEffect->SetParticleSystem( pszName );
+}
+
+
+static bool IsValidHierarchy( CParticleCollection *pCollection )
+{
+ if ( !pCollection->IsValid() )
+ return false;
+
+ for( CParticleCollection *pChild = pCollection->m_Children.m_pHead; pChild; pChild = pChild->m_pNext )
+ {
+ if ( !IsValidHierarchy( pChild ) )
+ return false;
+ }
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Simulate the particle system
+//-----------------------------------------------------------------------------
+void CTFParticlePanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ float flTime = engine->Time();
+
+ bool bAnyActive = false;
+ // Update all particles
+ FOR_EACH_VEC_BACK( m_vecParticleEffects, i )
+ {
+ bAnyActive |= m_vecParticleEffects[i]->Update( flTime );
+ // If this effect is done and should auto-delete, then now is when we delete
+ if( m_vecParticleEffects[i]->m_pParticleSystem == NULL && m_vecParticleEffects[i]->m_bAutoDelete )
+ {
+ delete m_vecParticleEffects[i];
+ m_vecParticleEffects.FastRemove( i );
+ }
+ }
+
+ if ( !bAnyActive )
+ {
+ vgui::ivgui()->RemoveTickSignal( GetVPanel() );
+ }
+}
+
+
+void CTFParticlePanel::Paint()
+{
+ // This needs calling to reset various counters.
+ g_pParticleSystemMgr->SetLastSimulationTime( gpGlobals->curtime );
+
+ // No particles? Do nothing.
+ if( m_vecParticleEffects.Count() == 0 )
+ return;
+
+ int screenW, screenH;
+ vgui::surface()->GetScreenSize( screenW, screenH );
+
+ vgui::MatSystemSurface()->Begin3DPaint( 0, 0, screenW, screenH, false );
+
+ VMatrix view, projection;
+ ComputeViewMatrix( &view, m_Camera );
+ ComputeProjectionMatrix( &projection, m_Camera, screenW, screenH );
+
+ CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
+
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CCW );
+ pRenderContext->SetIntRenderingParameter( INT_RENDERPARM_WRITE_DEPTH_TO_DESTALPHA, false );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->LoadIdentity( );
+
+ pRenderContext->MatrixMode( MATERIAL_VIEW );
+ pRenderContext->LoadMatrix( view );
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->LoadMatrix( projection );
+
+ int iXOffset, iYOffset;
+ vgui::ipanel()->GetAbsPos( GetVPanel(), iXOffset, iYOffset );
+ if ( iXOffset > 0 )
+ iXOffset = 0;
+ if ( iYOffset > 0 )
+ iYOffset = 0;
+
+ float flXScale = 1.f;
+ if ( GetWide() > screenW )
+ flXScale = (float)screenW / GetWide();
+ float flYScale = 1.f;
+ if ( GetTall() > screenH )
+ flYScale = (float)screenH / GetTall();
+
+ FOR_EACH_VEC( m_vecParticleEffects, i )
+ {
+ m_vecParticleEffects[i]->Paint( pRenderContext, iXOffset, iYOffset, flXScale, flYScale, screenW, screenH );
+ }
+
+ pRenderContext->CullMode( MATERIAL_CULLMODE_CW );
+
+ vgui::MatSystemSurface()->End3DPaint();
+}
+
+bool CTFParticlePanel::ParticleEffect_t::Update( float flTime )
+{
+ if ( !m_pParticleSystem || !m_bStarted )
+ return false;
+
+ if ( m_flLastTime == FLT_MAX )
+ {
+ m_flLastTime = flTime;
+ }
+
+ float flDt = flTime - m_flLastTime;
+ m_flLastTime = flTime;
+
+ Quaternion q;
+ AngleQuaternion( m_Angles, q );
+
+ for ( int i = 0; i < MAX_PARTICLE_CONTROL_POINTS; ++i )
+ {
+ if ( !m_pParticleSystem->ReadsControlPoint( i ) )
+ continue;
+
+ m_pParticleSystem->SetControlPoint( i, m_pControlPointValue[i] );
+ m_pParticleSystem->SetControlPointOrientation( i, q );
+ m_pParticleSystem->SetControlPointParent( i, i );
+ }
+
+ // Restart the particle system if it's finished
+ bool bIsInvalid = !IsValidHierarchy( m_pParticleSystem );
+
+ if ( !bIsInvalid )
+ {
+ m_pParticleSystem->Simulate( flDt, false );
+ }
+
+ // Past our end time?
+ bool bEnd = gpGlobals->curtime >= m_flEndTime;
+
+ if ( m_pParticleSystem->IsFinished() || bIsInvalid || bEnd )
+ {
+ delete m_pParticleSystem;
+ m_pParticleSystem = NULL;
+
+ // Loop if we're supposed to
+ if ( m_bLoop && m_ParticleSystemName.Length() && !m_bForceStopped )
+ {
+ m_pParticleSystem = g_pParticleSystemMgr->CreateParticleCollection( m_ParticleSystemName );
+ }
+
+ if ( bIsInvalid && m_pParent )
+ {
+ m_pParent->PostActionSignal( new KeyValues( "ParticleSystemReconstructed" ) );
+ }
+ m_flLastTime = FLT_MAX;
+ }
+
+ return m_pParticleSystem != NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Startup, shutdown particle collection
+//-----------------------------------------------------------------------------
+void CTFParticlePanel::ParticleEffect_t::StartupParticleCollection()
+{
+ if ( m_pParticleSystem && m_pParent )
+ {
+ vgui::ivgui()->AddTickSignal( m_pParent->GetVPanel(), 0 );
+ }
+ m_flLastTime = FLT_MAX;
+ m_bStarted = true;
+}
+
+void CTFParticlePanel::ParticleEffect_t::ShutdownParticleCollection()
+{
+ if ( m_pParticleSystem && m_pParent )
+ {
+ delete m_pParticleSystem;
+ m_pParticleSystem = NULL;
+ }
+ m_bStarted = false;
+}
+
+//-----------------------------------------------------------------------------
+// Set the particle system to draw
+//-----------------------------------------------------------------------------
+void CTFParticlePanel::ParticleEffect_t::SetParticleSystem( const char* pszParticleSystemName )
+{
+ ShutdownParticleCollection();
+
+ if( !g_pParticleSystemMgr->IsParticleSystemDefined( pszParticleSystemName ) )
+ {
+ AssertMsg1( false, "%s is not a valid particle system name", pszParticleSystemName );
+ return;
+ }
+ m_pParticleSystem = g_pParticleSystemMgr->CreateParticleCollection( pszParticleSystemName );
+ m_ParticleSystemName = pszParticleSystemName;
+
+ m_pParent->PostActionSignal( new KeyValues( "ParticleSystemReconstructed" ) );
+
+ if( m_bStartActivated )
+ {
+ StartupParticleCollection();
+ }
+}
+
+
+void CTFParticlePanel::ParticleEffect_t::Paint( CMatRenderContextPtr& pRenderContext, int iXOffset, int iYOffset, float flXScale, float flYScale, int screenW, int screenH )
+{
+ if ( !m_pParticleSystem || !m_bStarted )
+ return;
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity();
+
+ pRenderContext->Ortho( 0, 0, screenW, screenH, -9999, 9999 );
+
+ pRenderContext->Translate( flXScale * ( m_nXPos + iXOffset ), screenH - flYScale * ( m_nYPos + iYOffset ), 0.f );
+ pRenderContext->Scale( m_flScale, m_flScale, m_flScale );
+
+ // Render Particles
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PushMatrix();
+ pRenderContext->LoadIdentity( );
+
+ m_pParticleSystem->Render( pRenderContext );
+
+ pRenderContext->MatrixMode( MATERIAL_MODEL );
+ pRenderContext->PopMatrix();
+
+ pRenderContext->MatrixMode( MATERIAL_PROJECTION );
+ pRenderContext->PopMatrix();
+} \ No newline at end of file