//========= 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 #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