You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
273 lines
6.2 KiB
273 lines
6.2 KiB
//========= Copyright © 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
|
|
#define MAX_TOTAL_PARTICLES 2048 // Max particles in the world
|
|
|
|
//
|
|
// 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;
|
|
IMaterialSystem *m_pMaterialSystem; // Needed when we have to break particles into multiple batches
|
|
|
|
// 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 );
|
|
|
|
if(m_pMaterialSystem)
|
|
{
|
|
CMatRenderContextPtr pRenderContext( m_pMaterialSystem );
|
|
m_pMesh = pRenderContext->GetDynamicMesh( 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
|
|
|