Counter Strike : Global Offensive Source Code
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.

949 lines
33 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //===========================================================================//
  8. //
  9. // This module implements the particle manager for the client DLL.
  10. // In a nutshell, to create your own effect, implement the ParticleEffect
  11. // interface and call CParticleMgr::AddEffect to add your effect. Then you can
  12. // add particles and simulate and render them.
  13. /*
  14. Particle manager documentation
  15. -----------------------------------------------------------------------------
  16. All particle effects are managed by a class called CParticleMgr. It tracks
  17. the list of particles, manages their materials, sorts the particles, and
  18. has callbacks to render them.
  19. Conceptually, CParticleMgr is NOT part of VEngine's entity system. It does
  20. not care about entities, only particle effects. Usually, the two are implemented
  21. together, but you should be aware the CParticleMgr talks to you through its
  22. own interfaces and does not talk to entities. Thus, it is possible to have
  23. particle effects that are not entities.
  24. To make a particle effect, you need two things:
  25. 1. An implementation of the IParticleEffect interface. This is how CParticleMgr
  26. talks to you for things like rendering and updating your effect.
  27. 2. A (member) variable of type CParticleEffectBinding. This allows CParticleMgr to
  28. store its internal data associated with your effect.
  29. Once you have those two things, you call CParticleMgr::AddEffect and pass them
  30. both in. You will then get updates through IParticleEffect::Update, and you will
  31. be asked to render your particles with IParticleEffect::SimulateAndRender.
  32. When you want to remove the effect, call CParticleEffectBinding::SetRemoveFlag(), which
  33. tells CParticleMgr to remove the effect next chance it gets.
  34. Example class:
  35. class CMyEffect : public IParticleEffect
  36. {
  37. public:
  38. // Call this to start the effect by adding it to the particle manager.
  39. void Start()
  40. {
  41. ParticleMgr()->AddEffect( &m_ParticleEffect, this );
  42. }
  43. // implementation of IParticleEffect functions go here...
  44. public:
  45. CParticleEffectBinding m_ParticleEffect;
  46. };
  47. How the particle effects are integrated with the entity system
  48. -----------------------------------------------------------------------------
  49. There are two helper classes that you can use to create particles for your
  50. entities. Each one is useful under different conditions.
  51. 1. CSimpleEmitter is a class that does some of the dirty work of using particles.
  52. If you want, you can just instantiate one of these with CSimpleEmitter::Create
  53. and call its AddParticle functions to add particles. When you are done and
  54. want to 'free' it, call its Release function rather than deleting it, and it
  55. will wait until all of its particles have gone away before removing itself
  56. (so you don't have to write code to wait for all of the particles to go away).
  57. In most cases, it is the easiest and most clear to use CSimpleEmitter or
  58. derive a class from it, then use that class from inside an entity that wants
  59. to make particles.
  60. CSimpleEmitter and derived classes handle adding themselves to the particle
  61. manager, tracking how many particles in the effect are active, and
  62. rendering the particles.
  63. CSimpleEmitter has code to simulate and render particles in a generic fashion,
  64. but if you derive a class from it, you can override some of its behavior
  65. with virtuals like UpdateAlpha, UpdateScale, UpdateColor, etc..
  66. Example code:
  67. CSimpleEmitter *pEmitter = CSimpleEmitter::Create();
  68. CEffectMaterialHandle hMaterial = pEmitter->GetCEffectMaterial( "mymaterial" );
  69. for( int i=0; i < 100; i++ )
  70. pEmitter->AddParticle( hMaterial, RandomVector(0,10), 4 );
  71. pEmitter->Release();
  72. 2. Some older effects derive from C_BaseParticleEffect and implement an entity
  73. and a particle system at the same time. This gets nasty and is not encouraged anymore.
  74. */
  75. #ifndef PARTICLEMGR_H
  76. #define PARTICLEMGR_H
  77. #ifdef _WIN32
  78. #pragma once
  79. #endif
  80. #include "materialsystem/imaterial.h"
  81. #include "materialsystem/imaterialsystem.h"
  82. #include "mathlib/vector.h"
  83. #include "mathlib/vmatrix.h"
  84. #include "mathlib/mathlib.h"
  85. #include "iclientrenderable.h"
  86. #include "clientleafsystem.h"
  87. #include "tier0/fasttimer.h"
  88. #include "utllinkedlist.h"
  89. #include "utldict.h"
  90. #ifdef WIN32
  91. #include <typeinfo.h>
  92. #else
  93. #include <typeinfo>
  94. #endif
  95. #include "tier1/utlintrusivelist.h"
  96. #include "tier1/utlobjectreference.h"
  97. #include "tier1/utlstring.h"
  98. //-----------------------------------------------------------------------------
  99. // forward declarations
  100. //-----------------------------------------------------------------------------
  101. class IParticleEffect;
  102. class IClientParticleListener;
  103. struct Particle;
  104. class ParticleDraw;
  105. class CMeshBuilder;
  106. class CUtlMemoryPool;
  107. class CEffectMaterial;
  108. class CParticleSimulateIterator;
  109. class CParticleRenderIterator;
  110. class IThreadPool;
  111. class CParticleSystemDefinition;
  112. class CParticleMgr;
  113. class CNewParticleEffect;
  114. class CParticleCollection;
  115. #define INVALID_MATERIAL_HANDLE NULL
  116. // Various stats, disabled
  117. // extern int g_nParticlesDrawn;
  118. // extern CCycleCount g_ParticleTimer;
  119. class CParticleSubTexture;
  120. class CParticleSubTextureGroup;
  121. //-----------------------------------------------------------------------------
  122. // The basic particle description; all particles need to inherit from this.
  123. //-----------------------------------------------------------------------------
  124. struct Particle
  125. {
  126. Particle *m_pPrev, *m_pNext;
  127. // Which sub texture this particle uses (so we can get at the tcoord mins and maxs).
  128. CParticleSubTexture *m_pSubTexture;
  129. // If m_Pos isn't used to store the world position, then implement IParticleEffect::GetParticlePosition()
  130. Vector m_Pos; // Position of the particle in world space
  131. };
  132. //-----------------------------------------------------------------------------
  133. // This is the CParticleMgr's reference to a material in the material system.
  134. // Particles are sorted by material.
  135. //-----------------------------------------------------------------------------
  136. // This indexes CParticleMgr::m_SubTextures.
  137. typedef CParticleSubTexture* PMaterialHandle;
  138. // Each effect stores a list of particles associated with each material. The list is
  139. // hashed on the IMaterial pointer.
  140. class CEffectMaterial
  141. {
  142. public:
  143. CEffectMaterial();
  144. public:
  145. // This provides the material that gets bound for this material in this effect.
  146. // There can be multiple subtextures all within the same CEffectMaterial.
  147. CParticleSubTextureGroup *m_pGroup;
  148. Particle m_Particles;
  149. CEffectMaterial *m_pHashedNext;
  150. };
  151. class CParticleSubTextureGroup
  152. {
  153. public:
  154. CParticleSubTextureGroup();
  155. ~CParticleSubTextureGroup();
  156. // Even though each of the subtextures has its own material, they should all basically be
  157. // the same exact material and just use different texture coordinates, so this is the
  158. // material of the first subtexture that is bound.
  159. //
  160. // This is gotten from GetMaterialPage().
  161. IMaterial *m_pPageMaterial;
  162. };
  163. // Precalculated data for each material used for particles.
  164. // This allows us to put multiple subtextures into one VTF and sort them against each other.
  165. class CParticleSubTexture
  166. {
  167. public:
  168. CParticleSubTexture();
  169. float m_tCoordMins[2]; // bbox in texel space that this particle material uses.
  170. float m_tCoordMaxs[2]; // Specified in the SubTextureMins/SubTextureMaxs parameter in the materials.
  171. // Which group does this subtexture belong to?
  172. CParticleSubTextureGroup *m_pGroup;
  173. CParticleSubTextureGroup m_DefaultGroup; // This is used as the group if a particle's material
  174. // isn't using a group.
  175. #ifdef _DEBUG
  176. char *m_szDebugName;
  177. #endif
  178. IMaterial *m_pMaterial;
  179. };
  180. //-----------------------------------------------------------------------------
  181. // interface IParticleEffect:
  182. //
  183. // This is the interface that particles effects must implement. The effect is
  184. // responsible for starting itself and calling CParticleMgr::AddEffect, then it
  185. // will get the callbacks it needs to simulate and render the particles.
  186. //-----------------------------------------------------------------------------
  187. abstract_class IParticleEffect
  188. {
  189. // Overridables.
  190. public:
  191. virtual ~IParticleEffect() {}
  192. // Called at the beginning of a frame to precalculate data for rendering
  193. // the particles. If you manage your own list of particles and want to
  194. // simulate them all at once, you can do that here and just render them in
  195. // the SimulateAndRender call.
  196. virtual void Update( float fTimeDelta ) {}
  197. // Called once for the entire effect before the batch of SimulateAndRender() calls.
  198. // For particle systems using FLAGS_CAMERASPACE (the default), effectMatrix transforms the particles from
  199. // world space into camera space. You can change this matrix if you want your particles relative to something
  200. // else like an attachment's space.
  201. virtual void StartRender( VMatrix &effectMatrix ) {}
  202. // Simulate the particles.
  203. virtual bool ShouldSimulate() const = 0;
  204. virtual void SetShouldSimulate( bool bSim ) = 0;
  205. virtual void SimulateParticles( CParticleSimulateIterator *pIterator ) = 0;
  206. // Render the particles.
  207. virtual void RenderParticles( CParticleRenderIterator *pIterator ) = 0;
  208. // Implementing this is optional. It is called when an effect is removed. It is useful if
  209. // you hold onto pointers to the particles you created (so when this is called, you should
  210. // clean up your data so you don't reference the particles again).
  211. // NOTE: after calling this, the particle manager won't touch the IParticleEffect
  212. // or its associated CParticleEffectBinding anymore.
  213. virtual void NotifyRemove() {}
  214. // This method notifies the effect a particle is about to be deallocated.
  215. // Implementations should *not* actually deallocate it.
  216. // NOTE: The particle effect's GetNumActiveParticles is updated BEFORE this is called
  217. // so if GetNumActiveParticles returns 0, then you know this is the last particle
  218. // in the system being removed.
  219. virtual void NotifyDestroyParticle( Particle* pParticle ) {}
  220. // Fill in the origin used to sort this entity.
  221. // This is a world space position.
  222. virtual const Vector &GetSortOrigin() = 0;
  223. // Fill in the origin used to sort this entity.
  224. // TODO: REMOVE THIS. ALL PARTICLE SYSTEMS SHOULD EITHER SET m_Pos IN CONJUNCTION WITH THE
  225. // PARTICLE_LOCALSPACE FLAG, OR DO SETBBOX THEMSELVES.
  226. virtual const Vector *GetParticlePosition( Particle *pParticle ) { return &pParticle->m_Pos; }
  227. virtual const char *GetEffectName() { return "???"; }
  228. };
  229. #define REGISTER_EFFECT( effect ) \
  230. IParticleEffect* effect##_Factory() \
  231. { \
  232. return new effect; \
  233. } \
  234. struct effect##_RegistrationHelper \
  235. { \
  236. effect##_RegistrationHelper() \
  237. { \
  238. ParticleMgr()->RegisterEffect( typeid( effect ).name(), effect##_Factory ); \
  239. } \
  240. }; \
  241. static effect##_RegistrationHelper g_##effect##_RegistrationHelper
  242. #define REGISTER_EFFECT_USING_CREATE( effect ) \
  243. IParticleEffect* effect##_Factory() \
  244. { \
  245. return effect::Create( #effect ).GetObject(); \
  246. } \
  247. struct effect##_RegistrationHelper \
  248. { \
  249. effect##_RegistrationHelper() \
  250. { \
  251. ParticleMgr()->RegisterEffect( typeid( effect ).name(), effect##_Factory ); \
  252. } \
  253. }; \
  254. static effect##_RegistrationHelper g_##effect##_RegistrationHelper
  255. // In order to create a particle effect, you must have one of these around and
  256. // implement IParticleEffect. Pass them both into CParticleMgr::AddEffect and you
  257. // are good to go.
  258. class CParticleEffectBinding : public CDefaultClientRenderable
  259. {
  260. friend class CParticleMgr;
  261. friend class CParticleSimulateIterator;
  262. friend class CNewParticleEffect;
  263. public:
  264. CParticleEffectBinding();
  265. ~CParticleEffectBinding();
  266. // Helper functions to setup, add particles, etc..
  267. public:
  268. // Simulate all the particles.
  269. void SimulateParticles( float flTimeDelta );
  270. // Use this to specify materials when adding particles.
  271. // Returns the index of the material it found or added.
  272. // Returns INVALID_MATERIAL_HANDLE if it couldn't find or add a material.
  273. PMaterialHandle FindOrAddMaterial( const char *pMaterialName );
  274. // Allocate particles. The Particle manager will automagically
  275. // deallocate them when the IParticleEffect SimulateAndRender() method
  276. // returns false. The first argument is the size of the particle
  277. // structure in bytes
  278. Particle* AddParticle( int sizeInBytes, PMaterialHandle pMaterial );
  279. // This is an optional call you can make if you want to manually manage the effect's
  280. // bounding box. Normally, the bounding box is managed automatically, but in certain
  281. // cases it is more efficient to set it manually.
  282. //
  283. // Note: this is a WORLD SPACE bounding box, even if you've used SetLocalSpaceTransform.
  284. //
  285. // After you make this call, the particle manager will no longer update the bounding
  286. // box automatically if bDisableAutoUpdate is true.
  287. void SetBBox( const Vector &bbMin, const Vector &bbMax, bool bDisableAutoUpdate = true );
  288. // gets a copy of the current bbox mins/maxs in worldspace
  289. void GetWorldspaceBounds( Vector *pMins, Vector *pMaxs );
  290. // This tells the particle manager that your particles are transformed by the specified matrix.
  291. // That way, it can transform the bbox defined by Particle::m_Pos into world space correctly.
  292. //
  293. // It also sets up the matrix returned by CParticleMgr::GetModelView() to include this matrix, so you
  294. // can do TransformParticle with it like any other particle system.
  295. const matrix3x4_t& GetLocalSpaceTransform() const;
  296. void SetLocalSpaceTransform( const matrix3x4_t &transform );
  297. // This expands the bbox to contain the specified point. Returns true if bbox changed
  298. bool EnlargeBBoxToContain( const Vector &pt );
  299. // The EZ particle singletons use this - they don't want to be added to all the leaves and drawn through the
  300. // leaf system - they are specifically told to draw each frame at a certain point.
  301. void SetDrawThruLeafSystem( int bDraw );
  302. // Some view model particle effects want to be drawn right before the view model (after everything else is
  303. // drawn).
  304. void SetDrawBeforeViewModel( int bDraw );
  305. // Call this to have the effect removed whenever it safe to do so.
  306. // This is a lot safer than calling CParticleMgr::RemoveEffect.
  307. int GetRemoveFlag() { return GetFlag( FLAGS_REMOVE ); }
  308. void SetRemoveFlag() { SetFlag( FLAGS_REMOVE, 1 ); }
  309. // Set this flag to tell the particle manager to simulate your particles even
  310. // if the particle system isn't visible. Tempents and fast effects can always use
  311. // this if they want since they want to simulate their particles until they go away.
  312. // This flag is ON by default.
  313. int GetAlwaysSimulate() { return GetFlag( FLAGS_ALWAYSSIMULATE ); }
  314. void SetAlwaysSimulate( int bAlwaysSimulate ) { SetFlag( FLAGS_ALWAYSSIMULATE, bAlwaysSimulate ); }
  315. void SetIsNewParticleSystem( void ) { SetFlag( FLAGS_NEW_PARTICLE_SYSTEM, 1 ); }
  316. // Set if the effect was drawn the previous frame.
  317. // This can be used by particle effect classes
  318. // to decide whether or not they want to spawn
  319. // new particles - if they weren't drawn, then
  320. // they can 'freeze' the particle system to avoid
  321. // overhead.
  322. int WasDrawnPrevFrame() { return GetFlag( FLAGS_DRAWN_PREVFRAME ); }
  323. void SetWasDrawnPrevFrame( int bWasDrawnPrevFrame ) { SetFlag( FLAGS_DRAWN_PREVFRAME, bWasDrawnPrevFrame ); }
  324. // When the effect is in camera space mode, then the transforms are setup such that
  325. // the particle vertices are specified in camera space (in CParticleDraw) rather than world space.
  326. //
  327. // This makes it faster to specify the particles - you only have to transform the center
  328. // by CParticleMgr::GetModelView then add to X and Y to build the quad.
  329. //
  330. // Effects that want to specify verts (in CParticleDraw) in world space should set this to false and
  331. // ignore CParticleMgr::GetModelView.
  332. //
  333. // Camera space mode is ON by default.
  334. int IsEffectCameraSpace() { return GetFlag( FLAGS_CAMERASPACE ); }
  335. void SetEffectCameraSpace( int bCameraSpace ) { SetFlag( FLAGS_CAMERASPACE, bCameraSpace ); }
  336. // This tells it whether or not to apply the local transform to the matrix returned by CParticleMgr::GetModelView().
  337. // Usually, you'll want this, so you can just say TransformParticle( pMgr->GetModelView(), vPos ), but you may want
  338. // to manually apply your local transform before saying TransformParticle.
  339. //
  340. // This is ON by default.
  341. int GetAutoApplyLocalTransform() const { return GetFlag( FLAGS_AUTOAPPLYLOCALTRANSFORM ); }
  342. void SetAutoApplyLocalTransform( int b ) { SetFlag( FLAGS_AUTOAPPLYLOCALTRANSFORM, b ); }
  343. // If this is true, then the bbox is calculated from particle positions. This works
  344. // fine if you always simulate (SetAlwaysSimulateFlag) so the system can become visible
  345. // if it moves into the PVS. If you don't use this, then you should call SetBBox at
  346. // least once to tell the particle manager where your entity is.
  347. int GetAutoUpdateBBox() { return GetFlag( FLAGS_AUTOUPDATEBBOX ); }
  348. void SetAutoUpdateBBox( int bAutoUpdate ) { SetFlag( FLAGS_AUTOUPDATEBBOX, bAutoUpdate ); }
  349. // Get the current number of particles in the effect.
  350. int GetNumActiveParticles();
  351. // The is the max size of the particles for use in bounding computation
  352. void SetParticleCullRadius( float flMaxParticleRadius );
  353. // Build a list of all active particles, returns actual count filled in
  354. int GetActiveParticleList( int nCount, Particle **ppParticleList );
  355. // detect origin/bbox changes and update leaf system if necessary
  356. void DetectChanges();
  357. private:
  358. // Change flags..
  359. void SetFlag( int flag, int bOn ) { if( bOn ) m_Flags |= flag; else m_Flags &= ~flag; }
  360. int GetFlag( int flag ) const { return m_Flags & flag; }
  361. void Init( CParticleMgr *pMgr, IParticleEffect *pSim );
  362. void Term();
  363. // Get rid of the specified particle.
  364. void RemoveParticle( Particle *pParticle );
  365. void StartDrawMaterialParticles(
  366. CEffectMaterial *pMaterial,
  367. float flTimeDelta,
  368. IMesh* &pMesh,
  369. CMeshBuilder &builder,
  370. ParticleDraw &particleDraw,
  371. bool bWireframe );
  372. int DrawMaterialParticles(
  373. bool bBucketSort,
  374. CEffectMaterial *pMaterial,
  375. float flTimeDelta,
  376. bool bWireframe
  377. );
  378. void GrowBBoxFromParticlePositions( CEffectMaterial *pMaterial, bool &bboxSet, Vector &bbMin, Vector &bbMax );
  379. void RenderStart( VMatrix &mTempModel, VMatrix &mTempView );
  380. void RenderEnd( VMatrix &mModel, VMatrix &mView );
  381. void BBoxCalcStart( Vector &bbMin, Vector &bbMax );
  382. void BBoxCalcEnd( bool bboxSet, Vector &bbMin, Vector &bbMax );
  383. void DoBucketSort(
  384. CEffectMaterial *pMaterial,
  385. float *zCoords,
  386. int nZCoords,
  387. float minZ,
  388. float maxZ );
  389. int GetRemovalInProgressFlag() { return GetFlag( FLAGS_REMOVALINPROGRESS ); }
  390. void SetRemovalInProgressFlag() { SetFlag( FLAGS_REMOVALINPROGRESS, 1 ); }
  391. // BBox is recalculated before it's put into the tree for the first time.
  392. int GetNeedsBBoxUpdate() { return GetFlag( FLAGS_NEEDS_BBOX_UPDATE ); }
  393. void SetNeedsBBoxUpdate( int bFirstUpdate ) { SetFlag( FLAGS_NEEDS_BBOX_UPDATE, bFirstUpdate ); }
  394. // Set on creation and cleared after the first PostRender (whether or not the system was rendered).
  395. int GetFirstFrameFlag() { return GetFlag( FLAGS_FIRST_FRAME ); }
  396. void SetFirstFrameFlag( int bFirstUpdate ) { SetFlag( FLAGS_FIRST_FRAME, bFirstUpdate ); }
  397. int WasDrawn() { return GetFlag( FLAGS_DRAWN ); }
  398. void SetDrawn( int bDrawn ) { SetFlag( FLAGS_DRAWN, bDrawn ); }
  399. // Update m_Min/m_Max. Returns false and sets the bbox to the sort origin if there are no particles.
  400. bool RecalculateBoundingBox();
  401. CEffectMaterial* GetEffectMaterial( CParticleSubTexture *pSubTexture );
  402. // IClientRenderable overrides.
  403. public:
  404. virtual const Vector& GetRenderOrigin( void );
  405. virtual const QAngle& GetRenderAngles( void );
  406. virtual const matrix3x4_t & RenderableToWorldTransform();
  407. virtual void GetRenderBounds( Vector& mins, Vector& maxs );
  408. virtual bool ShouldDraw( void );
  409. virtual int DrawModel( int flags, const RenderableInstance_t &instance );
  410. private:
  411. enum
  412. {
  413. FLAGS_REMOVE = (1<<0), // Set in SetRemoveFlag
  414. FLAGS_REMOVALINPROGRESS = (1<<1), // Set while the effect is being removed to prevent
  415. // infinite recursion.
  416. FLAGS_NEEDS_BBOX_UPDATE = (1<<2), // This is set until the effect's bbox has been updated once.
  417. FLAGS_AUTOUPDATEBBOX = (1<<3), // Update bbox automatically? Cleared in SetBBox.
  418. FLAGS_ALWAYSSIMULATE = (1<<4), // See SetAlwaysSimulate.
  419. FLAGS_DRAWN = (1<<5), // Set if the effect is drawn through the leaf system.
  420. FLAGS_DRAWN_PREVFRAME = (1<<6), // Set if the effect was drawn the previous frame.
  421. // This can be used by particle effect classes
  422. // to decide whether or not they want to spawn
  423. // new particles - if they weren't drawn, then
  424. // they can 'freeze' the particle system to avoid
  425. // overhead.
  426. FLAGS_CAMERASPACE = (1<<7), // See SetEffectCameraSpace.
  427. FLAGS_DRAW_THRU_LEAF_SYSTEM=(1<<8), // This is the default - do the effect's visibility through the leaf system.
  428. FLAGS_DRAW_BEFORE_VIEW_MODEL=(1<<9),// Draw before the view model? If this is set, it assumes FLAGS_DRAW_THRU_LEAF_SYSTEM goes off.
  429. FLAGS_AUTOAPPLYLOCALTRANSFORM=(1<<10), // Automatically apply the local transform to CParticleMgr::GetModelView()'s matrix.
  430. FLAGS_FIRST_FRAME = (1<<11), // Cleared after the first frame that this system exists (so it can simulate after rendering once).
  431. FLAGS_NEW_PARTICLE_SYSTEM= (1<<12) // uses new particle system
  432. };
  433. VMatrix m_LocalSpaceTransform;
  434. bool m_bLocalSpaceTransformIdentity; // If this is true, then m_LocalSpaceTransform is assumed to be identity.
  435. // Bounding box. Stored in WORLD space.
  436. Vector m_Min;
  437. Vector m_Max;
  438. // paramter copies to detect changes
  439. Vector m_LastMin;
  440. Vector m_LastMax;
  441. // The particle cull size
  442. float m_flParticleCullRadius;
  443. // Number of active particles.
  444. unsigned short m_nActiveParticles;
  445. // See CParticleMgr::m_FrameCode.
  446. unsigned short m_FrameCode;
  447. // For CParticleMgr's list index.
  448. unsigned short m_ListIndex;
  449. IParticleEffect *m_pSim;
  450. CParticleMgr *m_pParticleMgr;
  451. // Combination of the CParticleEffectBinding::FLAGS_ flags.
  452. int m_Flags;
  453. // Materials this effect is using.
  454. enum { EFFECT_MATERIAL_HASH_SIZE = 8 };
  455. CEffectMaterial *m_EffectMaterialHash[EFFECT_MATERIAL_HASH_SIZE];
  456. #ifdef INFESTED_PARTICLES
  457. // We'll remove this when we move Infested to using the new particle system
  458. public:
  459. #endif
  460. // For faster iteration.
  461. CUtlLinkedList<CEffectMaterial*, unsigned short> m_Materials;
  462. // auto updates the bbox after N frames
  463. unsigned short m_UpdateBBoxCounter;
  464. };
  465. class CParticleLightInfo
  466. {
  467. public:
  468. Vector m_vPos;
  469. Vector m_vColor; // 0-1
  470. float m_flIntensity;
  471. };
  472. typedef IParticleEffect* (*CreateParticleEffectFN)();
  473. enum
  474. {
  475. TOOLPARTICLESYSTEMID_INVALID = -1,
  476. };
  477. class CParticleCollection;
  478. class CNonDrawingParticleSystem
  479. {
  480. public:
  481. CNonDrawingParticleSystem *m_pNext;
  482. CNonDrawingParticleSystem *m_pPrev;
  483. CParticleCollection *m_pSystem;
  484. FORCEINLINE CParticleCollection *operator()( void ) const
  485. {
  486. return m_pSystem;
  487. }
  488. FORCEINLINE CParticleCollection *Get( void ) const
  489. {
  490. return m_pSystem;
  491. }
  492. ~CNonDrawingParticleSystem( void );
  493. };
  494. class CClientTools;
  495. class CParticleMgr
  496. {
  497. friend class CParticleEffectBinding;
  498. friend class CParticleCollection;
  499. friend class CNonDrawingParticleSystem;
  500. friend class CClientTools;
  501. public:
  502. CParticleMgr();
  503. virtual ~CParticleMgr();
  504. // Call at init time to preallocate the bucket of particles.
  505. bool Init(unsigned long nPreallocatedParticles, IMaterialSystem *pMaterial);
  506. // Shutdown - free everything.
  507. void Term(bool bCanReferenceOtherStaticObjects = true);
  508. void LevelInit();
  509. void RegisterEffect( const char *pEffectType, CreateParticleEffectFN func );
  510. IParticleEffect *CreateEffect( const char *pEffectType );
  511. // Add and remove effects from the active list.
  512. // Note: once you call AddEffect, CParticleEffectBinding will automatically call
  513. // RemoveEffect in its destructor.
  514. // Note: it's much safer to call CParticleEffectBinding::SetRemoveFlag instead of
  515. // CParticleMgr::RemoveEffect.
  516. bool AddEffect( CParticleEffectBinding *pEffect, IParticleEffect *pSim );
  517. void RemoveEffect( CParticleEffectBinding *pEffect );
  518. void AddEffect( CNewParticleEffect *pEffect );
  519. void RemoveEffect( CNewParticleEffect *pEffect );
  520. // Called at level shutdown to free all the lingering particle effects (usually
  521. // CParticleEffect-derived effects that can linger with noone holding onto them).
  522. void RemoveAllEffects();
  523. // This should be called at the start of the frame.
  524. void IncrementFrameCode();
  525. // This updates all the particle effects and inserts them into the leaves.
  526. void Simulate( float fTimeDelta );
  527. // This just marks effects that were drawn so during their next simulation they can know
  528. // if they were drawn in the previous frame.
  529. void PostRender();
  530. // Draw the effects marked with SetDrawBeforeViewModel.
  531. void DrawBeforeViewModelEffects();
  532. // Returns the modelview matrix
  533. VMatrix& GetModelView();
  534. Particle *AllocParticle( int size );
  535. void FreeParticle( Particle * );
  536. PMaterialHandle GetPMaterial( const char *pMaterialName );
  537. IMaterial* PMaterialToIMaterial( PMaterialHandle hMaterial );
  538. //HACKHACK: quick fix that compensates for the fact that this system was designed to never release materials EVER.
  539. void RepairPMaterial( PMaterialHandle hMaterial );
  540. // Particles drawn with the ParticleSphere material will use this info.
  541. // This should be set in IParticleEffect.
  542. void GetDirectionalLightInfo( CParticleLightInfo &info ) const;
  543. void SetDirectionalLightInfo( const CParticleLightInfo &info );
  544. void SpewInfo( bool bDetail );
  545. // add a class that gets notified of entity events
  546. void AddEffectListener( IClientParticleListener *pListener );
  547. void RemoveEffectListener( IClientParticleListener *pListener );
  548. // Tool effect ids
  549. int AllocateToolParticleEffectId();
  550. // Remove all new effects
  551. void RemoveAllNewEffects();
  552. CNewParticleEffect *FirstNewEffect();
  553. CNewParticleEffect *NextNewEffect( CNewParticleEffect *pEffect );
  554. // Should particle effects be rendered?
  555. void RenderParticleSystems( bool bEnable );
  556. bool ShouldRenderParticleSystems() const;
  557. void RemoveOldParticleEffects( float flTime ); // Removes all particles created more than flTime in the past immediately
  558. void SetRemoveAllParticleEffects( void ); // Flags all the particle effects for removal.
  559. int GetNumParticles() const { return m_nCurrentParticlesAllocated; }
  560. CNonDrawingParticleSystem *CreateNonDrawingEffect( const char *pEffectName );
  561. private:
  562. struct RetireInfo_t
  563. {
  564. CParticleCollection *m_pCollection;
  565. float m_flScreenArea;
  566. bool m_bFirstFrame;
  567. };
  568. // Call Update() on all the effects.
  569. void UpdateAllEffects( float flTimeDelta );
  570. void UpdateNewEffects( float flTimeDelta ); // update new particle effects
  571. void SpewActiveParticleSystems( );
  572. CParticleSubTextureGroup* FindOrAddSubTextureGroup( IMaterial *pPageMaterial );
  573. int ComputeParticleDefScreenArea( int nInfoCount, RetireInfo_t *pInfo, float *pTotalArea, CParticleSystemDefinition* pDef,
  574. const CViewSetup& view, const VMatrix &worldToPixels, float flFocalDist );
  575. bool RetireParticleCollections( CParticleSystemDefinition* pDef, int nCount, RetireInfo_t *pInfo, float flScreenArea, float flMaxTotalArea );
  576. void BuildParticleSimList( CUtlVector< CNewParticleEffect* > &list );
  577. bool EarlyRetireParticleSystems( int nCount, CNewParticleEffect **ppEffects );
  578. static int RetireSort( const void *p1, const void *p2 );
  579. private:
  580. int m_nCurrentParticlesAllocated;
  581. // Directional lighting info.
  582. CParticleLightInfo m_DirectionalLight;
  583. // Frame code, used to prevent CParticleEffects from simulating multiple times per frame.
  584. // Their DrawModel can be called multiple times per frame because of water reflections,
  585. // but we only want to simulate the particles once.
  586. unsigned short m_FrameCode;
  587. bool m_bUpdatingEffects;
  588. bool m_bRenderParticleEffects;
  589. // All the active effects.
  590. CUtlLinkedList<CParticleEffectBinding*, unsigned short> m_Effects;
  591. // all the active effects using the new particle interface
  592. CUtlIntrusiveDList< CNewParticleEffect > m_NewEffects;
  593. CUtlIntrusiveDList< CNonDrawingParticleSystem > m_NonDrawingParticleSystems;
  594. CUtlVector< IClientParticleListener *> m_effectListeners;
  595. IMaterialSystem *m_pMaterialSystem;
  596. // Store the concatenated modelview matrix
  597. VMatrix m_mModelView;
  598. CUtlVector<CParticleSubTextureGroup*> m_SubTextureGroups; // lookup by group name
  599. CUtlDict<CParticleSubTexture*,unsigned short> m_SubTextures; // lookup by material name
  600. CParticleSubTexture m_DefaultInvalidSubTexture; // Used when they specify an invalid material name.
  601. CUtlMap< const char*, CreateParticleEffectFN > m_effectFactories;
  602. int m_nToolParticleEffectId;
  603. IThreadPool *m_pThreadPool[2];
  604. };
  605. inline int CParticleMgr::AllocateToolParticleEffectId()
  606. {
  607. return m_nToolParticleEffectId++;
  608. }
  609. // Implement this class and register with CParticleMgr to receive particle effect add/remove notification
  610. class IClientParticleListener
  611. {
  612. public:
  613. virtual void OnParticleEffectAdded( IParticleEffect *pEffect ) = 0;
  614. virtual void OnParticleEffectRemoved( IParticleEffect *pEffect ) = 0;
  615. };
  616. // Helper functions to abstract out the particle testbed app.
  617. float Helper_GetTime();
  618. float Helper_GetFrameTime();
  619. float Helper_RandomFloat( float minVal, float maxVal );
  620. int Helper_RandomInt( int minVal, int maxVal );
  621. // ------------------------------------------------------------------------ //
  622. // CParticleMgr inlines
  623. // ------------------------------------------------------------------------ //
  624. inline VMatrix& CParticleMgr::GetModelView()
  625. {
  626. return m_mModelView;
  627. }
  628. // ------------------------------------------------------------------------ //
  629. // CParticleEffectBinding inlines.
  630. // ------------------------------------------------------------------------ //
  631. inline const matrix3x4_t& CParticleEffectBinding::GetLocalSpaceTransform() const
  632. {
  633. return m_LocalSpaceTransform.As3x4();
  634. }
  635. // ------------------------------------------------------------------------ //
  636. // GLOBALS
  637. // ------------------------------------------------------------------------ //
  638. CParticleMgr *ParticleMgr();
  639. //-----------------------------------------------------------------------------
  640. // StandardParticle_t; this is just one type of particle
  641. // effects may implement their own particle data structures
  642. //-----------------------------------------------------------------------------
  643. struct StandardParticle_t : public Particle
  644. {
  645. // Color and alpha values are 0 - 1
  646. void SetColor(float r, float g, float b);
  647. void SetAlpha(float a);
  648. Vector m_Velocity;
  649. // How this is used is up to the effect's discretion. Some use it for how long it has been alive
  650. // and others use it to count down until the particle disappears.
  651. float m_Lifetime;
  652. unsigned char m_EffectData; // Data specific to the IParticleEffect. This can be used to distinguish between
  653. // different types of particles the effect is simulating.
  654. unsigned short m_EffectDataWord;
  655. unsigned char m_Color[4]; // RGBA - not all effects need to use this.
  656. };
  657. // ------------------------------------------------------------------------ //
  658. // Transform a particle.
  659. // ------------------------------------------------------------------------ //
  660. inline void TransformParticle(const VMatrix &vMat, const Vector &vIn, Vector &vOut)
  661. {
  662. //vOut = vMat.VMul4x3(vIn);
  663. vOut.x = vMat.m[0][0]*vIn.x + vMat.m[0][1]*vIn.y + vMat.m[0][2]*vIn.z + vMat.m[0][3];
  664. vOut.y = vMat.m[1][0]*vIn.x + vMat.m[1][1]*vIn.y + vMat.m[1][2]*vIn.z + vMat.m[1][3];
  665. vOut.z = vMat.m[2][0]*vIn.x + vMat.m[2][1]*vIn.y + vMat.m[2][2]*vIn.z + vMat.m[2][3];
  666. }
  667. // ------------------------------------------------------------------------ //
  668. // CEffectMaterial inlines
  669. // ------------------------------------------------------------------------ //
  670. inline void StandardParticle_t::SetColor(float r, float g, float b)
  671. {
  672. m_Color[0] = (unsigned char)(r * 255.9f);
  673. m_Color[1] = (unsigned char)(g * 255.9f);
  674. m_Color[2] = (unsigned char)(b * 255.9f);
  675. }
  676. inline void StandardParticle_t::SetAlpha(float a)
  677. {
  678. m_Color[3] = (unsigned char)(a * 255.9f);
  679. }
  680. //-----------------------------------------------------------------------------
  681. // List functions.
  682. //-----------------------------------------------------------------------------
  683. inline void UnlinkParticle( Particle *pParticle )
  684. {
  685. pParticle->m_pPrev->m_pNext = pParticle->m_pNext;
  686. pParticle->m_pNext->m_pPrev = pParticle->m_pPrev;
  687. }
  688. inline void InsertParticleBefore( Particle *pInsert, Particle *pNext )
  689. {
  690. // link pCur before pPrev
  691. pInsert->m_pNext = pNext;
  692. pInsert->m_pPrev = pNext->m_pPrev;
  693. pInsert->m_pNext->m_pPrev = pInsert->m_pPrev->m_pNext = pInsert;
  694. }
  695. inline void InsertParticleAfter( Particle *pInsert, Particle *pPrev )
  696. {
  697. pInsert->m_pPrev = pPrev;
  698. pInsert->m_pNext = pPrev->m_pNext;
  699. pInsert->m_pNext->m_pPrev = pInsert->m_pPrev->m_pNext = pInsert;
  700. }
  701. inline void SwapParticles( Particle *pPrev, Particle *pCur )
  702. {
  703. // unlink pCur
  704. UnlinkParticle( pCur );
  705. InsertParticleBefore( pCur, pPrev );
  706. }
  707. #include "particle_iterators.h"
  708. #endif