sqwarmed/sdk_src/game/client/particle_iterators.h

271 lines
6.3 KiB
C
Raw Normal View History

2024-08-29 19:18:30 -04:00
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Client side CTFTeam class
//
// $NoKeywords: $
//=============================================================================//
#ifndef PARTICLE_ITERATORS_H
#define PARTICLE_ITERATORS_H
#ifdef _WIN32
#pragma once
#endif
#include "materialsystem/imesh.h"
#include "particledraw.h"
#define NUM_PARTICLES_PER_BATCH 200
#ifndef _XBOX
#define MAX_TOTAL_PARTICLES 2048 // Max particles in the world
#else
#define MAX_TOTAL_PARTICLES 1024
#endif
//
// Iterate the particles like this:
//
// Particle *pCur = pIterator->GetFirst();
// while ( pCur )
// {
// ... render the particle here and figure out the sort key and position
// pCur = pIterator->GetNext( sortKey, pCur->m_Pos );
// }
//
class CParticleRenderIterator
{
friend class CParticleMgr;
friend class CParticleEffectBinding;
public:
CParticleRenderIterator();
// The sort key is used to sort the particles incrementally as they're rendered.
// They only get sorted in the main rendered view (ie: not in reflections or monitors).
// These return const because you should only modify particles during their simulation.
const Particle* GetFirst();
const Particle* GetNext( float sortKey );
// Use this to render. This can return NULL, in which case you shouldn't render.
// This being NULL is a carryover from when particles rendered and simulated together and
// it should GO AWAY SOON!
ParticleDraw* GetParticleDraw() const;
private:
void TestFlushBatch();
private:
// Set by CParticleMgr.
CParticleEffectBinding *m_pEffectBinding;
CEffectMaterial *m_pMaterial;
ParticleDraw *m_pParticleDraw;
CMeshBuilder *m_pMeshBuilder;
IMesh *m_pMesh;
bool m_bBucketSort;
// Output after rendering.
float m_MinZ;
float m_MaxZ;
float m_zCoords[MAX_TOTAL_PARTICLES];
int m_nZCoords;
Particle *m_pCur;
bool m_bGotFirst;
float m_flPrevZ;
int m_nParticlesInCurrentBatch;
};
//
// Iterate the particles like this:
//
// Particle *pCur = pIterator->GetFirst();
// while ( pCur )
// {
// ... simulate here.. call pIterator->RemoveParticle if you want the particle to go away
// pCur = pIterator->GetNext();
// }
//
class CParticleSimulateIterator
{
friend class CParticleMgr;
friend class CParticleEffectBinding;
public:
CParticleSimulateIterator();
// Iterate through the particles, simulate them, and remove them if necessary.
Particle* GetFirst();
Particle* GetNext();
float GetTimeDelta() const;
void RemoveParticle( Particle *pParticle );
void RemoveAllParticles();
private:
CParticleEffectBinding *m_pEffectBinding;
CEffectMaterial *m_pMaterial;
float m_flTimeDelta;
bool m_bGotFirst;
Particle *m_pNextParticle;
};
// -------------------------------------------------------------------------------------------------------- //
// CParticleRenderIterator inlines
// -------------------------------------------------------------------------------------------------------- //
inline CParticleRenderIterator::CParticleRenderIterator()
{
m_pCur = NULL;
m_bGotFirst = false;
m_flPrevZ = 0;
m_nParticlesInCurrentBatch = 0;
m_MinZ = 1e24;
m_MaxZ = -1e24;
m_nZCoords = 0;
}
inline const Particle* CParticleRenderIterator::GetFirst()
{
Assert( !m_bGotFirst );
m_bGotFirst = true;
m_pCur = m_pMaterial->m_Particles.m_pNext;
if ( m_pCur == &m_pMaterial->m_Particles )
return NULL;
m_pParticleDraw->m_pSubTexture = m_pCur->m_pSubTexture;
return m_pCur;
}
inline void CParticleRenderIterator::TestFlushBatch()
{
++m_nParticlesInCurrentBatch;
if( m_nParticlesInCurrentBatch >= NUM_PARTICLES_PER_BATCH )
{
m_pMeshBuilder->End( false, true );
m_pMeshBuilder->Begin( m_pMesh, MATERIAL_QUADS, NUM_PARTICLES_PER_BATCH * 4 );
m_nParticlesInCurrentBatch = 0;
}
}
inline const Particle* CParticleRenderIterator::GetNext( float sortKey )
{
Assert( m_bGotFirst );
Assert( m_pCur );
TestFlushBatch();
Particle *pNext = m_pCur->m_pNext;
// Update the incremental sort.
if( m_bBucketSort )
{
m_MinZ = MIN( sortKey, m_MinZ );
m_MaxZ = MAX( sortKey, m_MaxZ );
m_zCoords[m_nZCoords] = sortKey;
++m_nZCoords;
}
else
{
// Swap with the previous particle (incremental sort)?
if( m_pCur != m_pMaterial->m_Particles.m_pNext && m_flPrevZ > sortKey )
{
SwapParticles( m_pCur->m_pPrev, m_pCur );
}
else
{
m_flPrevZ = sortKey;
}
}
m_pCur = pNext;
if ( m_pCur == &m_pMaterial->m_Particles )
return NULL;
m_pParticleDraw->m_pSubTexture = m_pCur->m_pSubTexture;
return m_pCur;
}
inline ParticleDraw* CParticleRenderIterator::GetParticleDraw() const
{
return m_pParticleDraw;
}
// -------------------------------------------------------------------------------------------------------- //
// CParticleSimulateIterator inlines
// -------------------------------------------------------------------------------------------------------- //
inline CParticleSimulateIterator::CParticleSimulateIterator()
{
m_pNextParticle = NULL;
#ifdef _DEBUG
m_bGotFirst = false;
#endif
}
inline Particle* CParticleSimulateIterator::GetFirst()
{
#ifdef _DEBUG
// Make sure they're either starting out fresh or that the previous guy iterated through all the particles.
if ( m_bGotFirst )
{
Assert( m_pNextParticle == &m_pMaterial->m_Particles );
}
#endif
Particle *pRet = m_pMaterial->m_Particles.m_pNext;
if ( pRet == &m_pMaterial->m_Particles )
return NULL;
#ifdef _DEBUG
m_bGotFirst = true;
#endif
m_pNextParticle = pRet->m_pNext;
return pRet;
}
inline Particle* CParticleSimulateIterator::GetNext()
{
Particle *pRet = m_pNextParticle;
if ( pRet == &m_pMaterial->m_Particles )
return NULL;
m_pNextParticle = pRet->m_pNext;
return pRet;
}
inline void CParticleSimulateIterator::RemoveParticle( Particle *pParticle )
{
m_pEffectBinding->RemoveParticle( pParticle );
}
inline void CParticleSimulateIterator::RemoveAllParticles()
{
Particle *pParticle = GetFirst();
while ( pParticle )
{
RemoveParticle( pParticle );
pParticle = GetNext();
}
}
inline float CParticleSimulateIterator::GetTimeDelta() const
{
return m_flTimeDelta;
}
#endif // PARTICLE_ITERATORS_H