Team Fortress 2 Source Code as on 22/4/2020
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.

2264 lines
75 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: particle system definitions
  4. //
  5. //===========================================================================//
  6. #ifndef PARTICLES_H
  7. #define PARTICLES_H
  8. #ifdef _WIN32
  9. #pragma once
  10. #endif
  11. #include "mathlib/mathlib.h"
  12. #include "mathlib/vector.h"
  13. #include "mathlib/ssemath.h"
  14. #include "materialsystem/imaterialsystem.h"
  15. #include "dmxloader/dmxelement.h"
  16. #include "tier1/utlintrusivelist.h"
  17. #include "vstdlib/random.h"
  18. #include "tier1/utlobjectreference.h"
  19. #include "tier1/UtlStringMap.h"
  20. #include "tier1/utlmap.h"
  21. #include "materialsystem/MaterialSystemUtil.h"
  22. #include "trace.h"
  23. #include "tier1/utlsoacontainer.h"
  24. #if defined( CLIENT_DLL )
  25. #include "c_pixel_visibility.h"
  26. #endif
  27. //-----------------------------------------------------------------------------
  28. // Forward declarations
  29. //-----------------------------------------------------------------------------
  30. struct DmxElementUnpackStructure_t;
  31. class CParticleSystemDefinition;
  32. class CParticleCollection;
  33. class CParticleOperatorInstance;
  34. class CParticleSystemDictionary;
  35. class CUtlBuffer;
  36. class IParticleOperatorDefinition;
  37. class CSheet;
  38. class CMeshBuilder;
  39. extern float s_pRandomFloats[];
  40. //-----------------------------------------------------------------------------
  41. // Random numbers
  42. //-----------------------------------------------------------------------------
  43. #define MAX_RANDOM_FLOATS 4096
  44. #define RANDOM_FLOAT_MASK ( MAX_RANDOM_FLOATS - 1 )
  45. //-----------------------------------------------------------------------------
  46. // Particle attributes
  47. //-----------------------------------------------------------------------------
  48. #define MAX_PARTICLE_ATTRIBUTES 32
  49. #define DEFPARTICLE_ATTRIBUTE( name, bit ) \
  50. const int PARTICLE_ATTRIBUTE_##name##_MASK = (1 << bit); \
  51. const int PARTICLE_ATTRIBUTE_##name = bit;
  52. // required
  53. DEFPARTICLE_ATTRIBUTE( XYZ, 0 );
  54. // particle lifetime (duration) of particle as a float.
  55. DEFPARTICLE_ATTRIBUTE( LIFE_DURATION, 1 );
  56. // prev coordinates for verlet integration
  57. DEFPARTICLE_ATTRIBUTE( PREV_XYZ, 2 );
  58. // radius of particle
  59. DEFPARTICLE_ATTRIBUTE( RADIUS, 3 );
  60. // rotation angle of particle
  61. DEFPARTICLE_ATTRIBUTE( ROTATION, 4 );
  62. // rotation speed of particle
  63. DEFPARTICLE_ATTRIBUTE( ROTATION_SPEED, 5 );
  64. // tint of particle
  65. DEFPARTICLE_ATTRIBUTE( TINT_RGB, 6 );
  66. // alpha tint of particle
  67. DEFPARTICLE_ATTRIBUTE( ALPHA, 7 );
  68. // creation time stamp (relative to particle system creation)
  69. DEFPARTICLE_ATTRIBUTE( CREATION_TIME, 8 );
  70. // sequnece # (which animation sequence number this particle uses )
  71. DEFPARTICLE_ATTRIBUTE( SEQUENCE_NUMBER, 9 );
  72. // length of the trail
  73. DEFPARTICLE_ATTRIBUTE( TRAIL_LENGTH, 10 );
  74. // unique particle identifier
  75. DEFPARTICLE_ATTRIBUTE( PARTICLE_ID, 11 );
  76. // unique rotation around up vector
  77. DEFPARTICLE_ATTRIBUTE( YAW, 12 );
  78. // second sequnece # (which animation sequence number this particle uses )
  79. DEFPARTICLE_ATTRIBUTE( SEQUENCE_NUMBER1, 13 );
  80. // hit box index
  81. DEFPARTICLE_ATTRIBUTE( HITBOX_INDEX, 14 );
  82. DEFPARTICLE_ATTRIBUTE( HITBOX_RELATIVE_XYZ, 15 );
  83. DEFPARTICLE_ATTRIBUTE( ALPHA2, 16 );
  84. // particle trace caching fields
  85. DEFPARTICLE_ATTRIBUTE( TRACE_P0, 17 ); // start pnt of trace
  86. DEFPARTICLE_ATTRIBUTE( TRACE_P1, 18 ); // end pnt of trace
  87. DEFPARTICLE_ATTRIBUTE( TRACE_HIT_T, 19 ); // 0..1 if hit
  88. DEFPARTICLE_ATTRIBUTE( TRACE_HIT_NORMAL, 20 ); // 0 0 0 if no hit
  89. #define MAX_PARTICLE_CONTROL_POINTS 64
  90. #define ATTRIBUTES_WHICH_ARE_VEC3S_MASK ( PARTICLE_ATTRIBUTE_TRACE_P0_MASK | PARTICLE_ATTRIBUTE_TRACE_P1_MASK | \
  91. PARTICLE_ATTRIBUTE_TRACE_HIT_NORMAL | PARTICLE_ATTRIBUTE_XYZ_MASK | \
  92. PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_TINT_RGB_MASK | \
  93. PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK )
  94. #define ATTRIBUTES_WHICH_ARE_0_TO_1 (PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_ALPHA2_MASK)
  95. #define ATTRIBUTES_WHICH_ARE_ANGLES (PARTICLE_ATTRIBUTE_ROTATION_MASK | PARTICLE_ATTRIBUTE_YAW_MASK )
  96. #define ATTRIBUTES_WHICH_ARE_INTS (PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK | PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK )
  97. #if defined( _X360 )
  98. #define MAX_PARTICLES_IN_A_SYSTEM 2000
  99. #else
  100. #define MAX_PARTICLES_IN_A_SYSTEM 5000
  101. #endif
  102. // Set this to 1 or 0 to enable or disable particle profiling.
  103. // Note that this profiling is expensive on Linux, and some anti-virus
  104. // products can make this *extremely* expensive on Windows.
  105. #define MEASURE_PARTICLE_PERF 0
  106. //-----------------------------------------------------------------------------
  107. // Particle function types
  108. //-----------------------------------------------------------------------------
  109. enum ParticleFunctionType_t
  110. {
  111. FUNCTION_RENDERER = 0,
  112. FUNCTION_OPERATOR,
  113. FUNCTION_INITIALIZER,
  114. FUNCTION_EMITTER,
  115. FUNCTION_CHILDREN, // NOTE: This one is a fake function type, only here to help eliminate a ton of duplicated code in the editor
  116. FUNCTION_FORCEGENERATOR,
  117. FUNCTION_CONSTRAINT,
  118. PARTICLE_FUNCTION_COUNT
  119. };
  120. struct CParticleVisibilityInputs
  121. {
  122. float m_flCameraBias;
  123. float m_flInputMin;
  124. float m_flInputMax;
  125. float m_flAlphaScaleMin;
  126. float m_flAlphaScaleMax;
  127. float m_flRadiusScaleMin;
  128. float m_flRadiusScaleMax;
  129. float m_flProxyRadius;
  130. float m_flBBoxScale;
  131. bool m_bUseBBox;
  132. int m_nCPin;
  133. };
  134. struct ModelHitBoxInfo_t
  135. {
  136. Vector m_vecBoxMins;
  137. Vector m_vecBoxMaxes;
  138. matrix3x4_t m_Transform;
  139. };
  140. class CModelHitBoxesInfo
  141. {
  142. public:
  143. float m_flLastUpdateTime;
  144. float m_flPrevLastUpdateTime;
  145. int m_nNumHitBoxes;
  146. int m_nNumPrevHitBoxes;
  147. ModelHitBoxInfo_t *m_pHitBoxes;
  148. ModelHitBoxInfo_t *m_pPrevBoxes;
  149. bool CurAndPrevValid( void ) const
  150. {
  151. return ( m_nNumHitBoxes && ( m_nNumPrevHitBoxes == m_nNumHitBoxes ) );
  152. }
  153. CModelHitBoxesInfo( void )
  154. {
  155. m_flLastUpdateTime = -1;
  156. m_nNumHitBoxes = 0;
  157. m_nNumPrevHitBoxes = 0;
  158. m_pHitBoxes = NULL;
  159. m_pPrevBoxes = NULL;
  160. }
  161. ~CModelHitBoxesInfo( void )
  162. {
  163. if ( m_pHitBoxes )
  164. delete[] m_pHitBoxes;
  165. if ( m_pPrevBoxes )
  166. delete[] m_pPrevBoxes;
  167. }
  168. };
  169. //-----------------------------------------------------------------------------
  170. // Interface to allow the particle system to call back into the client
  171. //-----------------------------------------------------------------------------
  172. #define PARTICLE_SYSTEM_QUERY_INTERFACE_VERSION "VParticleSystemQuery001"
  173. class IParticleSystemQuery : public IAppSystem
  174. {
  175. public:
  176. virtual void GetLightingAtPoint( const Vector& vecOrigin, Color &tint ) = 0;
  177. virtual void TraceLine( const Vector& vecAbsStart,
  178. const Vector& vecAbsEnd, unsigned int mask,
  179. const class IHandleEntity *ignore,
  180. int collisionGroup,
  181. CBaseTrace *ptr ) = 0;
  182. // given a possible spawn point, tries to movie it to be on or in the source object. returns
  183. // true if it succeeded
  184. virtual bool MovePointInsideControllingObject( CParticleCollection *pParticles,
  185. void *pObject,
  186. Vector *pPnt )
  187. {
  188. return true;
  189. }
  190. virtual bool IsPointInControllingObjectHitBox(
  191. CParticleCollection *pParticles,
  192. int nControlPointNumber, Vector vecPos, bool bBBoxOnly = false )
  193. {
  194. return true;
  195. }
  196. virtual int GetCollisionGroupFromName( const char *pszCollisionGroupName )
  197. {
  198. return 0; // == COLLISION_GROUP_NONE
  199. }
  200. virtual void GetRandomPointsOnControllingObjectHitBox(
  201. CParticleCollection *pParticles,
  202. int nControlPointNumber,
  203. int nNumPtsOut,
  204. float flBBoxScale,
  205. int nNumTrysToGetAPointInsideTheModel,
  206. Vector *pPntsOut,
  207. Vector vecDirectionBias,
  208. Vector *pHitBoxRelativeCoordOut = NULL,
  209. int *pHitBoxIndexOut = NULL ) = 0;
  210. virtual int GetControllingObjectHitBoxInfo(
  211. CParticleCollection *pParticles,
  212. int nControlPointNumber,
  213. int nBufSize, // # of output slots available
  214. ModelHitBoxInfo_t *pHitBoxOutputBuffer )
  215. {
  216. // returns number of hit boxes output
  217. return 0;
  218. }
  219. virtual Vector GetLocalPlayerPos( void )
  220. {
  221. return vec3_origin;
  222. }
  223. virtual void GetLocalPlayerEyeVectors( Vector *pForward, Vector *pRight = NULL, Vector *pUp = NULL )
  224. {
  225. *pForward = vec3_origin;
  226. *pRight = vec3_origin;
  227. *pUp = vec3_origin;
  228. }
  229. virtual float GetPixelVisibility( int *pQueryHandle, const Vector &vecOrigin, float flScale ) = 0;
  230. virtual void SetUpLightingEnvironment( const Vector& pos )
  231. {
  232. }
  233. };
  234. //-----------------------------------------------------------------------------
  235. //
  236. // Particle system manager. Using a class because tools need it that way
  237. // so the SFM and PET tools can share managers despite being linked to
  238. // separate particle system .libs
  239. //
  240. //-----------------------------------------------------------------------------
  241. typedef int ParticleSystemHandle_t;
  242. class CParticleSystemMgr
  243. {
  244. public:
  245. // Constructor, destructor
  246. CParticleSystemMgr();
  247. ~CParticleSystemMgr();
  248. // Initialize the particle system
  249. bool Init( IParticleSystemQuery *pQuery );
  250. // methods to add builtin operators. If you don't call these at startup, you won't be able to sim or draw. These are done separately from Init, so that
  251. // the server can omit the code needed for rendering/simulation, if desired.
  252. void AddBuiltinSimulationOperators( void );
  253. void AddBuiltinRenderingOperators( void );
  254. // Registration of known operators
  255. void AddParticleOperator( ParticleFunctionType_t nOpType, IParticleOperatorDefinition *pOpFactory );
  256. // Read a particle config file, add it to the list of particle configs
  257. bool ReadParticleConfigFile( const char *pFileName, bool bPrecache, bool bDecommitTempMemory = true );
  258. bool ReadParticleConfigFile( CUtlBuffer &buf, bool bPrecache, bool bDecommitTempMemory = true, const char *pFileName = NULL );
  259. void DecommitTempMemory();
  260. // For recording, write a specific particle system to a CUtlBuffer in DMX format
  261. bool WriteParticleConfigFile( const char *pParticleSystemName, CUtlBuffer &buf, bool bPreventNameBasedLookup = false );
  262. bool WriteParticleConfigFile( const DmObjectId_t& id, CUtlBuffer &buf, bool bPreventNameBasedLookup = false );
  263. // create a particle system by name. returns null if one of that name does not exist
  264. CParticleCollection *CreateParticleCollection( const char *pParticleSystemName, float flDelay = 0.0f, int nRandomSeed = 0 );
  265. // create a particle system given a particle system id
  266. CParticleCollection *CreateParticleCollection( const DmObjectId_t &id, float flDelay = 0.0f, int nRandomSeed = 0 );
  267. // Is a particular particle system defined?
  268. bool IsParticleSystemDefined( const char *pParticleSystemName );
  269. bool IsParticleSystemDefined( const DmObjectId_t &id );
  270. // Returns the index of the specified particle system.
  271. ParticleSystemHandle_t GetParticleSystemIndex( const char *pParticleSystemName );
  272. // Returns the name of the specified particle system.
  273. const char *GetParticleSystemNameFromIndex( ParticleSystemHandle_t iIndex );
  274. // Return the number of particle systems in our dictionary
  275. int GetParticleSystemCount( void );
  276. // call to get available particle operator definitions
  277. // NOTE: FUNCTION_CHILDREN will return a faked one, for ease of writing the editor
  278. CUtlVector< IParticleOperatorDefinition *> &GetAvailableParticleOperatorList( ParticleFunctionType_t nWhichList );
  279. // Returns the unpack structure for a particle system definition
  280. const DmxElementUnpackStructure_t *GetParticleSystemDefinitionUnpackStructure();
  281. // Particle sheet management
  282. void ShouldLoadSheets( bool bLoadSheets );
  283. CSheet *FindOrLoadSheet( char const *pszFname, ITexture *pTexture );
  284. CSheet *FindOrLoadSheet( IMaterial *pMaterial );
  285. void FlushAllSheets( void );
  286. // Render cache used to render opaque particle collections
  287. void ResetRenderCache( void );
  288. void AddToRenderCache( CParticleCollection *pParticles );
  289. void DrawRenderCache( bool bShadowDepth );
  290. IParticleSystemQuery *Query( void ) { return m_pQuery; }
  291. // return the particle field name
  292. const char* GetParticleFieldName( int nParticleField ) const;
  293. // WARNING: the pointer returned by this function may be invalidated
  294. // *at any time* by the editor, so do not ever cache it.
  295. CParticleSystemDefinition* FindParticleSystem( const char *pName );
  296. CParticleSystemDefinition* FindParticleSystem( const DmObjectId_t& id );
  297. void CommitProfileInformation( bool bCommit ); // call after simulation, if you want
  298. // sim time recorded. if oyu pass
  299. // flase, info will be thrown away and
  300. // uncomitted time reset. Having this
  301. // function lets you only record
  302. // profile data for slow frames if
  303. // desired.
  304. void DumpProfileInformation( void ); // write particle_profile.csv
  305. // Cache/uncache materials used by particle systems
  306. void PrecacheParticleSystem( const char *pName );
  307. void UncacheAllParticleSystems();
  308. // Sets the last simulation time, used for particle system sleeping logic
  309. void SetLastSimulationTime( float flTime );
  310. float GetLastSimulationTime() const;
  311. int Debug_GetTotalParticleCount() const;
  312. bool Debug_FrameWarningNeededTestAndReset();
  313. float ParticleThrottleScaling() const; // Returns 1.0 = not restricted, 0.0 = fully restricted (i.e. don't draw!)
  314. bool ParticleThrottleRandomEnable() const; // Retruns a randomish bool to say if you should draw this particle.
  315. void TallyParticlesRendered( int nVertexCount, int nIndexCount = 0 );
  316. private:
  317. struct RenderCache_t
  318. {
  319. IMaterial *m_pMaterial;
  320. CUtlVector< CParticleCollection * > m_ParticleCollections;
  321. };
  322. struct BatchStep_t
  323. {
  324. CParticleCollection *m_pParticles;
  325. CParticleOperatorInstance *m_pRenderer;
  326. void *m_pContext;
  327. int m_nFirstParticle;
  328. int m_nParticleCount;
  329. int m_nVertCount;
  330. };
  331. struct Batch_t
  332. {
  333. int m_nVertCount;
  334. int m_nIndexCount;
  335. CUtlVector< BatchStep_t > m_BatchStep;
  336. };
  337. // Unserialization-related methods
  338. bool ReadParticleDefinitions( CUtlBuffer &buf, const char *pFileName, bool bPrecache, bool bDecommitTempMemory );
  339. void AddParticleSystem( CDmxElement *pParticleSystem );
  340. // Serialization-related methods
  341. CDmxElement *CreateParticleDmxElement( const DmObjectId_t &id );
  342. CDmxElement *CreateParticleDmxElement( const char *pParticleSystemName );
  343. bool WriteParticleConfigFile( CDmxElement *pParticleSystem, CUtlBuffer &buf, bool bPreventNameBasedLookup );
  344. // Builds a list of batches to render
  345. void BuildBatchList( int iRenderCache, IMatRenderContext *pRenderContext, CUtlVector< Batch_t >& batches );
  346. // Known operators
  347. CUtlVector<IParticleOperatorDefinition *> m_ParticleOperators[PARTICLE_FUNCTION_COUNT];
  348. // Particle system dictionary
  349. CParticleSystemDictionary *m_pParticleSystemDictionary;
  350. // typedef CUtlMap< ITexture *, CSheet* > SheetsCache;
  351. typedef CUtlStringMap< CSheet* > SheetsCache_t;
  352. SheetsCache_t m_SheetList;
  353. // attaching and dtaching killlists. when simulating, a particle system gets a kill list. after
  354. // simulating, the memory for that will be used for the next particle system. This matters for
  355. // threaded particles, because we don't want to share the same kill list between simultaneously
  356. // simulating particle systems.
  357. void AttachKillList( CParticleCollection *pParticles);
  358. void DetachKillList( CParticleCollection *pParticles);
  359. // For visualization (currently can only visualize one operator at a time)
  360. CParticleCollection *m_pVisualizedParticles;
  361. DmObjectId_t m_VisualizedOperatorId;
  362. IParticleSystemQuery *m_pQuery;
  363. CUtlVector< RenderCache_t > m_RenderCache;
  364. IMaterial *m_pShadowDepthMaterial;
  365. float m_flLastSimulationTime;
  366. bool m_bDidInit;
  367. bool m_bUsingDefaultQuery;
  368. bool m_bShouldLoadSheets;
  369. int m_nNumFramesMeasured;
  370. enum { c_nNumFramesTracked = 10 };
  371. int m_nParticleVertexCountHistory[c_nNumFramesTracked];
  372. float m_fParticleCountScaling;
  373. int m_nParticleIndexCount;
  374. int m_nParticleVertexCount;
  375. bool m_bFrameWarningNeeded;
  376. friend class CParticleSystemDefinition;
  377. friend class CParticleCollection;
  378. };
  379. extern CParticleSystemMgr *g_pParticleSystemMgr;
  380. //-----------------------------------------------------------------------------
  381. // A particle system can only have 1 operator using a particular ID
  382. //-----------------------------------------------------------------------------
  383. enum ParticleOperatorId_t
  384. {
  385. // Generic IDs
  386. OPERATOR_GENERIC = -2, // Can have as many of these as you want
  387. OPERATOR_SINGLETON = -1, // Can only have 1 operator with the same name as this one
  388. // Renderer operator IDs
  389. // Operator IDs
  390. // Initializer operator IDs
  391. OPERATOR_PI_POSITION, // Particle initializer: position (can only have 1 position setter)
  392. OPERATOR_PI_RADIUS,
  393. OPERATOR_PI_ALPHA,
  394. OPERATOR_PI_TINT_RGB,
  395. OPERATOR_PI_ROTATION,
  396. OPERATOR_PI_YAW,
  397. // Emitter IDs
  398. OPERATOR_ID_COUNT,
  399. };
  400. //-----------------------------------------------------------------------------
  401. // Class factory for particle operators
  402. //-----------------------------------------------------------------------------
  403. class IParticleOperatorDefinition
  404. {
  405. public:
  406. virtual const char *GetName() const = 0;
  407. virtual CParticleOperatorInstance *CreateInstance( const DmObjectId_t &id ) const = 0;
  408. // virtual void DestroyInstance( CParticleOperatorInstance *pInstance ) const = 0;
  409. virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const = 0;
  410. virtual ParticleOperatorId_t GetId() const = 0;
  411. virtual bool IsObsolete() const = 0;
  412. virtual size_t GetClassSize() const = 0;
  413. #if MEASURE_PARTICLE_PERF
  414. // performance monitoring
  415. float m_flMaxExecutionTime;
  416. float m_flTotalExecutionTime;
  417. float m_flUncomittedTime;
  418. FORCEINLINE void RecordExecutionTime( float flETime )
  419. {
  420. m_flUncomittedTime += flETime;
  421. m_flMaxExecutionTime = MAX( m_flMaxExecutionTime, flETime );
  422. }
  423. FORCEINLINE float TotalRecordedExecutionTime( void ) const
  424. {
  425. return m_flTotalExecutionTime;
  426. }
  427. FORCEINLINE float MaximumRecordedExecutionTime( void ) const
  428. {
  429. return m_flMaxExecutionTime;
  430. }
  431. #endif
  432. };
  433. //-----------------------------------------------------------------------------
  434. // Particle operators
  435. //-----------------------------------------------------------------------------
  436. class CParticleOperatorInstance
  437. {
  438. public:
  439. // custom allocators so we can be simd aligned
  440. void *operator new( size_t nSize );
  441. void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine );
  442. void operator delete( void *pData );
  443. void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine );
  444. // unpack structure will be applied by creator. add extra initialization needed here
  445. virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
  446. {
  447. }
  448. virtual size_t GetRequiredContextBytes( ) const
  449. {
  450. return 0;
  451. }
  452. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  453. {
  454. }
  455. virtual uint32 GetWrittenAttributes( void ) const = 0;
  456. virtual uint32 GetReadAttributes( void ) const = 0;
  457. virtual uint64 GetReadControlPointMask() const
  458. {
  459. return 0;
  460. }
  461. // Used when an operator needs to read the attributes of a particle at spawn time
  462. virtual uint32 GetReadInitialAttributes( void ) const
  463. {
  464. return 0;
  465. }
  466. // a particle simulator does this
  467. virtual void Operate( CParticleCollection *pParticles, float flOpStrength, void *pContext ) const
  468. {
  469. }
  470. // a renderer overrides this
  471. virtual void Render( IMatRenderContext *pRenderContext,
  472. CParticleCollection *pParticles, void *pContext ) const
  473. {
  474. }
  475. virtual bool IsBatchable() const
  476. {
  477. return true;
  478. }
  479. virtual void RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  480. {
  481. }
  482. // Returns the number of verts + indices to render
  483. virtual int GetParticlesToRender( CParticleCollection *pParticles, void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int *pVertsUsed, int *pIndicesUsed ) const
  484. {
  485. *pVertsUsed = 0;
  486. *pIndicesUsed = 0;
  487. return 0;
  488. }
  489. // emitters over-ride this. Return a mask of what fields you initted
  490. virtual uint32 Emit( CParticleCollection *pParticles, float flOpCurStrength,
  491. void *pContext ) const
  492. {
  493. return 0;
  494. }
  495. // emitters over-ride this.
  496. virtual void StopEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly = false ) const
  497. {
  498. }
  499. virtual void StartEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly = false ) const
  500. {
  501. }
  502. virtual void Restart( CParticleCollection *pParticles, void *pContext ) {}
  503. // initters over-ride this
  504. virtual void InitParticleSystem( CParticleCollection *pParticles, void *pContext ) const
  505. {
  506. }
  507. // a force generator does this. It accumulates in the force array
  508. virtual void AddForces( FourVectors *AccumulatedForces,
  509. CParticleCollection *pParticles,
  510. int nBlocks,
  511. float flCurStrength,
  512. void *pContext ) const
  513. {
  514. }
  515. // this is called for each constarint every frame. It can set up data like nearby world traces,
  516. // etc
  517. virtual void SetupConstraintPerFrameData( CParticleCollection *pParticles,
  518. void *pContext ) const
  519. {
  520. }
  521. // a constraint overrides this. It shold return a true if it did anything
  522. virtual bool EnforceConstraint( int nStartBlock,
  523. int nNumBlocks,
  524. CParticleCollection *pParticles,
  525. void *pContext,
  526. int nNumValidParticlesInLastChunk ) const
  527. {
  528. return false;
  529. }
  530. // should the constraint be run only once after all other constraints?
  531. virtual bool IsFinalConstraint( void ) const
  532. {
  533. return false;
  534. }
  535. // determines if a mask needs to be initialized multiple times.
  536. virtual bool InitMultipleOverride()
  537. {
  538. return false;
  539. }
  540. // Indicates if this initializer is scrub-safe (initializers don't use random numbers, for example)
  541. virtual bool IsScrubSafe()
  542. {
  543. return false;
  544. }
  545. // particle-initters over-ride this
  546. virtual void InitNewParticlesScalar( CParticleCollection *pParticles, int nFirstParticle, int n_particles, int attribute_write_mask, void *pContext ) const
  547. {
  548. }
  549. // init new particles in blocks of 4. initters that have sse smarts should over ride this. the scalar particle initter will still be cllaed for head/tail.
  550. virtual void InitNewParticlesBlock( CParticleCollection *pParticles, int start_block, int n_blocks, int attribute_write_mask, void *pContext ) const
  551. {
  552. // default behaviour is to call the scalar one 4x times
  553. InitNewParticlesScalar( pParticles, 4*start_block, 4*n_blocks, attribute_write_mask, pContext );
  554. }
  555. // splits particle initialization up into scalar and block sections, callingt he right code
  556. void InitNewParticles( CParticleCollection *pParticles, int nFirstParticle, int n_particles, int attribute_write_mask , void *pContext) const;
  557. // this function is queried to determine if a particle system is over and doen with. A particle
  558. // system is done with when it has noparticles and no operators intend to create any more
  559. virtual bool MayCreateMoreParticles( CParticleCollection *pParticles, void *pContext ) const
  560. {
  561. return false;
  562. }
  563. // Returns the operator definition that spawned this operator
  564. const IParticleOperatorDefinition *GetDefinition()
  565. {
  566. return m_pDef;
  567. }
  568. virtual bool ShouldRunBeforeEmitters( void ) const
  569. {
  570. return false;
  571. }
  572. // Does this operator require that particles remain in the order they were emitted?
  573. virtual bool RequiresOrderInvariance( void ) const
  574. {
  575. return false;
  576. }
  577. // Called when the SFM wants to skip forward in time
  578. virtual void SkipToTime( float flTime, CParticleCollection *pParticles, void *pContext ) const {}
  579. // Returns a unique ID for this definition
  580. const DmObjectId_t& GetId() { return m_Id; }
  581. // Used for editing + debugging to visualize the operator in 3D
  582. virtual void Render( CParticleCollection *pParticles ) const {}
  583. // Used as a debugging mechanism to prevent bogus calls to RandomInt or RandomFloat inside operators
  584. // Use CParticleCollection::RandomInt/RandomFloat instead
  585. int RandomInt( int nMin, int nMax )
  586. {
  587. // NOTE: Use CParticleCollection::RandomInt!
  588. Assert(0);
  589. return 0;
  590. }
  591. float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f )
  592. {
  593. // NOTE: Use CParticleCollection::RandomFloat!
  594. Assert(0);
  595. return 0.0f;
  596. }
  597. float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f )
  598. {
  599. // NOTE: Use CParticleCollection::RandomFloatExp!
  600. Assert(0);
  601. return 0.0f;
  602. }
  603. float m_flOpStartFadeInTime;
  604. float m_flOpEndFadeInTime;
  605. float m_flOpStartFadeOutTime;
  606. float m_flOpEndFadeOutTime;
  607. float m_flOpFadeOscillatePeriod;
  608. virtual ~CParticleOperatorInstance( void )
  609. {
  610. // so that sheet references, etc can be cleaned up
  611. }
  612. protected:
  613. // utility function for initting a scalar attribute to a random range in an sse fashion
  614. void InitScalarAttributeRandomRangeBlock( int nAttributeId, float fMinValue, float fMaxValue,
  615. CParticleCollection *pParticles, int nStartBlock, int nBlockCount ) const;
  616. void InitScalarAttributeRandomRangeExpBlock( int nAttributeId, float fMinValue, float fMaxValue, float fExp,
  617. CParticleCollection *pParticles, int nStartBlock, int nBlockCount ) const;
  618. void AddScalarAttributeRandomRangeBlock( int nAttributeId, float fMinValue, float fMaxValue, float fExp,
  619. CParticleCollection *pParticles, int nStartBlock, int nBlockCount, bool bRandomlyInvert ) const;
  620. private:
  621. friend class CParticleCollection;
  622. const IParticleOperatorDefinition *m_pDef;
  623. void SetDefinition( const IParticleOperatorDefinition * pDef, const DmObjectId_t &id )
  624. {
  625. m_pDef = pDef;
  626. CopyUniqueId( id, &m_Id );
  627. }
  628. DmObjectId_t m_Id;
  629. template <typename T> friend class CParticleOperatorDefinition;
  630. };
  631. class CParticleRenderOperatorInstance : public CParticleOperatorInstance
  632. {
  633. public:
  634. CParticleVisibilityInputs VisibilityInputs;
  635. };
  636. //-----------------------------------------------------------------------------
  637. // Helper macro for creating particle operator factories
  638. //-----------------------------------------------------------------------------
  639. template < class T >
  640. class CParticleOperatorDefinition : public IParticleOperatorDefinition
  641. {
  642. public:
  643. CParticleOperatorDefinition( const char *pFactoryName, ParticleOperatorId_t id, bool bIsObsolete ) : m_pFactoryName( pFactoryName ), m_Id( id )
  644. {
  645. #if MEASURE_PARTICLE_PERF
  646. m_flTotalExecutionTime = 0.0f;
  647. m_flMaxExecutionTime = 0.0f;
  648. m_flUncomittedTime = 0.0f;
  649. #endif
  650. m_bIsObsolete = bIsObsolete;
  651. }
  652. virtual const char *GetName() const
  653. {
  654. return m_pFactoryName;
  655. }
  656. virtual ParticleOperatorId_t GetId() const
  657. {
  658. return m_Id;
  659. }
  660. virtual CParticleOperatorInstance *CreateInstance( const DmObjectId_t &id ) const
  661. {
  662. CParticleOperatorInstance *pOp = new T;
  663. pOp->SetDefinition( this, id );
  664. return pOp;
  665. }
  666. virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const
  667. {
  668. return m_pUnpackParams;
  669. }
  670. // Editor won't display obsolete operators
  671. virtual bool IsObsolete() const
  672. {
  673. return m_bIsObsolete;
  674. }
  675. virtual size_t GetClassSize() const
  676. {
  677. return sizeof( T );
  678. }
  679. private:
  680. const char *m_pFactoryName;
  681. ParticleOperatorId_t m_Id;
  682. bool m_bIsObsolete;
  683. static DmxElementUnpackStructure_t *m_pUnpackParams;
  684. };
  685. #define DECLARE_PARTICLE_OPERATOR( _className ) \
  686. DECLARE_DMXELEMENT_UNPACK() \
  687. friend class CParticleOperatorDefinition<_className >
  688. #define DEFINE_PARTICLE_OPERATOR( _className, _operatorName, _id ) \
  689. static CParticleOperatorDefinition<_className> s_##_className##Factory( _operatorName, _id, false )
  690. #define DEFINE_PARTICLE_OPERATOR_OBSOLETE( _className, _operatorName, _id ) \
  691. static CParticleOperatorDefinition<_className> s_##_className##Factory( _operatorName, _id, true )
  692. #define BEGIN_PARTICLE_OPERATOR_UNPACK( _className ) \
  693. BEGIN_DMXELEMENT_UNPACK( _className ) \
  694. DMXELEMENT_UNPACK_FIELD( "operator start fadein","0", float, m_flOpStartFadeInTime ) \
  695. DMXELEMENT_UNPACK_FIELD( "operator end fadein","0", float, m_flOpEndFadeInTime ) \
  696. DMXELEMENT_UNPACK_FIELD( "operator start fadeout","0", float, m_flOpStartFadeOutTime ) \
  697. DMXELEMENT_UNPACK_FIELD( "operator end fadeout","0", float, m_flOpEndFadeOutTime ) \
  698. DMXELEMENT_UNPACK_FIELD( "operator fade oscillate","0", float, m_flOpFadeOscillatePeriod )
  699. #define END_PARTICLE_OPERATOR_UNPACK( _className ) \
  700. END_DMXELEMENT_UNPACK_TEMPLATE( _className, CParticleOperatorDefinition<_className>::m_pUnpackParams )
  701. #define BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( _className ) \
  702. BEGIN_PARTICLE_OPERATOR_UNPACK( _className ) \
  703. DMXELEMENT_UNPACK_FIELD( "Visibility Proxy Input Control Point Number", "-1", int, VisibilityInputs.m_nCPin ) \
  704. DMXELEMENT_UNPACK_FIELD( "Visibility Proxy Radius", "1.0", float, VisibilityInputs.m_flProxyRadius ) \
  705. DMXELEMENT_UNPACK_FIELD( "Visibility input minimum","0", float, VisibilityInputs.m_flInputMin ) \
  706. DMXELEMENT_UNPACK_FIELD( "Visibility input maximum","1", float, VisibilityInputs.m_flInputMax ) \
  707. DMXELEMENT_UNPACK_FIELD( "Visibility Alpha Scale minimum","0", float, VisibilityInputs.m_flAlphaScaleMin ) \
  708. DMXELEMENT_UNPACK_FIELD( "Visibility Alpha Scale maximum","1", float, VisibilityInputs.m_flAlphaScaleMax ) \
  709. DMXELEMENT_UNPACK_FIELD( "Visibility Radius Scale minimum","1", float, VisibilityInputs.m_flRadiusScaleMin ) \
  710. DMXELEMENT_UNPACK_FIELD( "Visibility Radius Scale maximum","1", float, VisibilityInputs.m_flRadiusScaleMax ) \
  711. DMXELEMENT_UNPACK_FIELD( "Visibility Camera Depth Bias", "0", float, VisibilityInputs.m_flCameraBias )
  712. // DMXELEMENT_UNPACK_FIELD( "Visibility Use Bounding Box for Proxy", "0", bool, VisibilityInputs.m_bUseBBox )
  713. // DMXELEMENT_UNPACK_FIELD( "Visibility Bounding Box Scale", "1.0", float, VisibilityInputs.m_flBBoxScale )
  714. #define REGISTER_PARTICLE_OPERATOR( _type, _className ) \
  715. g_pParticleSystemMgr->AddParticleOperator( _type, &s_##_className##Factory )
  716. // need to think about particle constraints in terms of segregating affected particles so as to
  717. // run multi-pass constraints on only a subset
  718. //-----------------------------------------------------------------------------
  719. // flags for particle systems
  720. //-----------------------------------------------------------------------------
  721. enum
  722. {
  723. PCFLAGS_FIRST_FRAME = 0x1,
  724. PCFLAGS_PREV_CONTROL_POINTS_INITIALIZED = 0x2,
  725. };
  726. #define DEBUG_PARTICLE_SORT 0
  727. // sorting functionality for rendering. Call GetRenderList( bool bSorted ) to get the list of
  728. // particles to render (sorted or not, including children).
  729. // **do not casually change this structure**. The sorting code treats it interchangably as an SOA
  730. // and accesses it using sse. Any changes to this struct need the sort code updated.**
  731. struct ParticleRenderData_t
  732. {
  733. float m_flSortKey; // what we sort by
  734. int m_nIndex; // index or fudged index (for child particles)
  735. float m_flRadius; // effective radius, using visibility
  736. #if VALVE_LITTLE_ENDIAN
  737. uint8 m_nAlpha; // effective alpha, combining alpha and alpha2 and vis. 0 - 255
  738. uint8 m_nAlphaPad[3]; // this will be written to
  739. #else
  740. uint8 m_nAlphaPad[3]; // this will be written to
  741. uint8 m_nAlpha; // effective alpha, combining alpha and alpha2 and vis. 0 - 255
  742. #endif
  743. };
  744. struct ExtendedParticleRenderData_t : ParticleRenderData_t
  745. {
  746. float m_flX;
  747. float m_flY;
  748. float m_flZ;
  749. float m_flPad;
  750. };
  751. typedef struct ALIGN16 _FourInts
  752. {
  753. int32 m_nValue[4];
  754. } ALIGN16_POST FourInts;
  755. // structure describing the parameter block used by operators which use the path between two points to
  756. // control particles.
  757. struct CPathParameters
  758. {
  759. int m_nStartControlPointNumber;
  760. int m_nEndControlPointNumber;
  761. int m_nBulgeControl;
  762. float m_flBulge;
  763. float m_flMidPoint;
  764. void ClampControlPointIndices( void )
  765. {
  766. m_nStartControlPointNumber = MAX(0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartControlPointNumber ) );
  767. m_nEndControlPointNumber = MAX(0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nEndControlPointNumber ) );
  768. }
  769. };
  770. struct CParticleVisibilityData
  771. {
  772. float m_flAlphaVisibility;
  773. float m_flRadiusVisibility;
  774. float m_flCameraBias;
  775. bool m_bUseVisibility;
  776. };
  777. struct CParticleControlPoint
  778. {
  779. Vector m_Position;
  780. Vector m_PrevPosition;
  781. // orientation
  782. Vector m_ForwardVector;
  783. Vector m_UpVector;
  784. Vector m_RightVector;
  785. // reference to entity or whatever this control point comes from
  786. void *m_pObject;
  787. // parent for hierarchies
  788. int m_nParent;
  789. };
  790. // struct for simd xform to transform a point from an identitiy coordinate system to that of the control point
  791. struct CParticleSIMDTransformation
  792. {
  793. FourVectors m_v4Origin;
  794. FourVectors m_v4Fwd;
  795. FourVectors m_v4Up;
  796. FourVectors m_v4Right;
  797. FORCEINLINE void VectorRotate( FourVectors &InPnt )
  798. {
  799. fltx4 fl4OutX = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.x ), MulSIMD( InPnt.z, m_v4Up.x ) ), MulSIMD( InPnt.y, m_v4Right.x ) );
  800. fltx4 fl4OutY = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.y ), MulSIMD( InPnt.z, m_v4Up.y ) ), MulSIMD( InPnt.y, m_v4Right.y ) );
  801. InPnt.z = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.z ), MulSIMD( InPnt.z, m_v4Up.z ) ), MulSIMD( InPnt.y, m_v4Right.z ) );
  802. InPnt.x = fl4OutX;
  803. InPnt.y = fl4OutY;
  804. }
  805. FORCEINLINE void VectorTransform( FourVectors &InPnt )
  806. {
  807. VectorRotate( InPnt );
  808. InPnt.x = AddSIMD( InPnt.x, m_v4Origin.x );
  809. InPnt.y = AddSIMD( InPnt.y, m_v4Origin.y );
  810. InPnt.z = AddSIMD( InPnt.z, m_v4Origin.z );
  811. }
  812. };
  813. #define NUM_COLLISION_CACHE_MODES 4
  814. //-----------------------------------------------------------------------------
  815. //
  816. // CParticleCollection
  817. //
  818. //-----------------------------------------------------------------------------
  819. class CParticleCollection
  820. {
  821. public:
  822. ~CParticleCollection( void );
  823. // Restarts the particle collection, stopping all non-continuous emitters
  824. void Restart();
  825. // compute bounds from particle list
  826. void RecomputeBounds( void );
  827. void SetControlPoint( int nWhichPoint, const Vector &v );
  828. void SetControlPointObject( int nWhichPoint, void *pObject );
  829. void SetControlPointOrientation( int nWhichPoint, const Vector &forward,
  830. const Vector &right, const Vector &up );
  831. void SetControlPointOrientation( int nWhichPoint, const Quaternion &q );
  832. void SetControlPointForwardVector( int nWhichPoint, const Vector &v );
  833. void SetControlPointUpVector( int nWhichPoint, const Vector &v );
  834. void SetControlPointRightVector( int nWhichPoint, const Vector &v );
  835. void SetControlPointParent( int nWhichPoint, int n );
  836. // get the pointer to an attribute for a given particle.
  837. // !!speed!! if you find yourself calling this anywhere that matters,
  838. // you're not handling the simd-ness of the particle system well
  839. // and will have bad perf.
  840. const float *GetFloatAttributePtr( int nAttribute, int nParticleNumber ) const;
  841. const int *GetIntAttributePtr( int nAttribute, int nParticleNumber ) const;
  842. const fltx4 *GetM128AttributePtr( int nAttribute, size_t *pStrideOut ) const;
  843. const FourVectors *Get4VAttributePtr( int nAttribute, size_t *pStrideOut ) const;
  844. const FourInts *Get4IAttributePtr( int nAttribute, size_t *pStrideOut ) const;
  845. const int *GetIntAttributePtr( int nAttribute, size_t *pStrideOut ) const;
  846. int *GetIntAttributePtrForWrite( int nAttribute, int nParticleNumber );
  847. float *GetFloatAttributePtrForWrite( int nAttribute, int nParticleNumber );
  848. fltx4 *GetM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut );
  849. FourVectors *Get4VAttributePtrForWrite( int nAttribute, size_t *pStrideOut );
  850. const float *GetInitialFloatAttributePtr( int nAttribute, int nParticleNumber ) const;
  851. const fltx4 *GetInitialM128AttributePtr( int nAttribute, size_t *pStrideOut ) const;
  852. const FourVectors *GetInitial4VAttributePtr( int nAttribute, size_t *pStrideOut ) const;
  853. float *GetInitialFloatAttributePtrForWrite( int nAttribute, int nParticleNumber );
  854. fltx4 *GetInitialM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut );
  855. void Simulate( float dt, bool updateBboxOnly );
  856. void SkipToTime( float t );
  857. // the camera objetc may be compared for equality against control point objects
  858. void Render( IMatRenderContext *pRenderContext, bool bTranslucentOnly = false, void *pCameraObject = NULL );
  859. bool IsValid( void ) const;
  860. const char *GetName() const;
  861. // IsFinished returns true when a system has no particles and won't be creating any more
  862. bool IsFinished( void );
  863. // Used to make sure we're accessing valid memory
  864. bool IsValidAttributePtr( int nAttribute, const void *pPtr ) const;
  865. void SwapPosAndPrevPos( void );
  866. void SetNActiveParticles( int nCount );
  867. void KillParticle(int nPidx);
  868. void StopEmission( bool bInfiniteOnly = false, bool bRemoveAllParticles = false, bool bWakeOnStop = false );
  869. void StartEmission( bool bInfiniteOnly = false );
  870. void SetDormant( bool bDormant );
  871. const Vector& GetControlPointAtCurrentTime( int nControlPoint ) const;
  872. void GetControlPointOrientationAtCurrentTime( int nControlPoint, Vector *pForward, Vector *pRight, Vector *pUp ) const;
  873. void GetControlPointTransformAtCurrentTime( int nControlPoint, matrix3x4_t *pMat );
  874. void GetControlPointTransformAtCurrentTime( int nControlPoint, VMatrix *pMat );
  875. int GetControlPointParent( int nControlPoint ) const;
  876. // Used to retrieve the position of a control point
  877. // somewhere between m_fCurTime and m_fCurTime - m_fPreviousDT
  878. void GetControlPointAtTime( int nControlPoint, float flTime, Vector *pControlPoint ) const;
  879. void GetControlPointAtPrevTime( int nControlPoint, Vector *pControlPoint ) const;
  880. void GetControlPointOrientationAtTime( int nControlPoint, float flTime, Vector *pForward, Vector *pRight, Vector *pUp );
  881. void GetControlPointTransformAtTime( int nControlPoint, float flTime, matrix3x4_t *pMat );
  882. void GetControlPointTransformAtTime( int nControlPoint, float flTime, VMatrix *pMat );
  883. void GetControlPointTransformAtTime( int nControlPoint, float flTime, CParticleSIMDTransformation *pXForm );
  884. int GetHighestControlPoint( void ) const;
  885. // Has this particle moved recently (since the last simulation?)
  886. bool HasMoved() const;
  887. // Control point accessed:
  888. // NOTE: Unlike the definition's version of these methods,
  889. // these OR-in the masks of their children.
  890. bool ReadsControlPoint( int nPoint ) const;
  891. // Used by particle systems to generate random numbers. Do not call these methods - use sse
  892. // code
  893. int RandomInt( int nMin, int nMax );
  894. float RandomFloat( float flMin, float flMax );
  895. float RandomFloatExp( float flMin, float flMax, float flExponent );
  896. void RandomVector( float flMin, float flMax, Vector *pVector );
  897. void RandomVector( const Vector &vecMin, const Vector &vecMax, Vector *pVector );
  898. float RandomVectorInUnitSphere( Vector *pVector ); // Returns the length sqr of the vector
  899. // NOTE: These versions will produce the *same random numbers* if you give it the same random
  900. // sample id. do not use these methods.
  901. int RandomInt( int nRandomSampleId, int nMin, int nMax );
  902. float RandomFloat( int nRandomSampleId, float flMin, float flMax );
  903. float RandomFloatExp( int nRandomSampleId, float flMin, float flMax, float flExponent );
  904. void RandomVector( int nRandomSampleId, float flMin, float flMax, Vector *pVector );
  905. void RandomVector( int nRandomSampleId, const Vector &vecMin, const Vector &vecMax, Vector *pVector );
  906. float RandomVectorInUnitSphere( int nRandomSampleId, Vector *pVector ); // Returns the length sqr of the vector
  907. fltx4 RandomFloat( const FourInts &ParticleID, int nRandomSampleOffset );
  908. // Random number offset (for use in getting Random #s in operators)
  909. int OperatorRandomSampleOffset() const;
  910. // Returns the render bounds
  911. void GetBounds( Vector *pMin, Vector *pMax );
  912. // Visualize operators (for editing/debugging)
  913. void VisualizeOperator( const DmObjectId_t *pOpId = NULL );
  914. // Does the particle system use the power of two frame buffer texture (refraction?)
  915. bool UsesPowerOfTwoFrameBufferTexture( bool bThisFrame ) const;
  916. // Does the particle system use the full frame buffer texture (soft particles)
  917. bool UsesFullFrameBufferTexture( bool bThisFrame ) const;
  918. // Is the particle system translucent?
  919. bool IsTranslucent() const;
  920. // Is the particle system two-pass?
  921. bool IsTwoPass() const;
  922. // Is the particle system batchable?
  923. bool IsBatchable() const;
  924. // Renderer iteration
  925. int GetRendererCount() const;
  926. CParticleOperatorInstance *GetRenderer( int i );
  927. void *GetRendererContext( int i );
  928. bool CheckIfOperatorShouldRun( CParticleOperatorInstance const * op, float *pflCurStrength = NULL );
  929. Vector TransformAxis( const Vector &SrcAxis, bool bLocalSpace, int nControlPointNumber = 0);
  930. // return backwards-sorted particle list. use --addressing
  931. const ParticleRenderData_t *GetRenderList( IMatRenderContext *pRenderContext, bool bSorted, int *pNparticles, CParticleVisibilityData *pVisibilityData );
  932. // calculate the points of a curve for a path
  933. void CalculatePathValues( CPathParameters const &PathIn,
  934. float flTimeStamp,
  935. Vector *pStartPnt,
  936. Vector *pMidPnt,
  937. Vector *pEndPnt
  938. );
  939. int GetGroupID() const;
  940. void InitializeNewParticles( int nFirstParticle, int nParticleCount, uint32 nInittedMask );
  941. // update hit boxes for control point if not updated yet for this sim step
  942. void UpdateHitBoxInfo( int nControlPointNumber );
  943. // Used by particle system definitions to manage particle collection lists
  944. void UnlinkFromDefList( );
  945. CParticleCollection *GetNextCollectionUsingSameDef() { return m_pNextDef; }
  946. CUtlReference< CSheet > m_Sheet;
  947. protected:
  948. CParticleCollection( );
  949. // Used by client code
  950. bool Init( const char *pParticleSystemName );
  951. bool Init( CParticleSystemDefinition *pDef );
  952. // Bloat the bounding box by bounds around the control point
  953. void BloatBoundsUsingControlPoint();
  954. private:
  955. void GenerateSortedIndexList( Vector vecCameraPos, CParticleVisibilityData *pVisibilityData, bool bSorted );
  956. void Init( CParticleSystemDefinition *pDef, float flDelay, int nRandomSeed );
  957. void InitStorage( CParticleSystemDefinition *pDef );
  958. void InitParticleCreationTime( int nFirstParticle, int nNumToInit );
  959. void CopyInitialAttributeValues( int nStartParticle, int nNumParticles );
  960. void ApplyKillList( void );
  961. void SetAttributeToConstant( int nAttribute, float fValue );
  962. void SetAttributeToConstant( int nAttribute, float fValueX, float fValueY, float fValueZ );
  963. void InitParticleAttributes( int nStartParticle, int nNumParticles, int nAttrsLeftToInit );
  964. // initialize this attribute for all active particles
  965. void FillAttributeWithConstant( int nAttribute, float fValue );
  966. // Updates the previous control points
  967. void UpdatePrevControlPoints( float dt );
  968. // Returns the memory for a particular constant attribute
  969. float *GetConstantAttributeMemory( int nAttribute );
  970. // Swaps two particles in the particle list
  971. void SwapAdjacentParticles( int hParticle );
  972. // Unlinks a particle from the list
  973. void UnlinkParticle( int hParticle );
  974. // Inserts a particle before another particle in the list
  975. void InsertParticleBefore( int hParticle, int hBefore );
  976. // Move a particle from one index to another
  977. void MoveParticle( int nInitialIndex, int nNewIndex );
  978. // Computes the sq distance to a particle position
  979. float ComputeSqrDistanceToParticle( int hParticle, const Vector &vecPosition ) const;
  980. // Grows the dist sq range for all particles
  981. void GrowDistSqrBounds( float flDistSqr );
  982. // Simulates the first frame
  983. void SimulateFirstFrame( );
  984. bool SystemContainsParticlesWithBoolSet( bool CParticleCollection::*pField ) const;
  985. // Does the particle collection contain opaque particle systems
  986. bool ContainsOpaqueCollections();
  987. bool ComputeUsesPowerOfTwoFrameBufferTexture();
  988. bool ComputeUsesFullFrameBufferTexture();
  989. bool ComputeIsTranslucent();
  990. bool ComputeIsTwoPass();
  991. bool ComputeIsBatchable();
  992. bool ComputeRequiresOrderInvariance();
  993. void LabelTextureUsage( void );
  994. void LinkIntoDefList( );
  995. public:
  996. fltx4 m_fl4CurTime; // accumulated time
  997. int m_nPaddedActiveParticles; // # of groups of 4 particles
  998. float m_flCurTime; // accumulated time
  999. int m_nActiveParticles; // # of active particles
  1000. float m_flDt;
  1001. float m_flPreviousDt;
  1002. float m_flNextSleepTime; // time to go to sleep if not drawn
  1003. CUtlReference< CParticleSystemDefinition > m_pDef;
  1004. int m_nAllocatedParticles;
  1005. int m_nMaxAllowedParticles;
  1006. bool m_bDormant;
  1007. bool m_bEmissionStopped;
  1008. bool m_bRequiresOrderInvariance;
  1009. int m_LocalLightingCP;
  1010. Color m_LocalLighting;
  1011. // control point data. Don't set these directly, or they won't propagate down to children
  1012. // particle control points can act as emitter centers, repulsions points, etc. what they are
  1013. // used for depends on what operators and parameters your system has.
  1014. CParticleControlPoint m_ControlPoints[MAX_PARTICLE_CONTROL_POINTS];
  1015. CModelHitBoxesInfo m_ControlPointHitBoxes[MAX_PARTICLE_CONTROL_POINTS];
  1016. // public so people can call methods
  1017. uint8 *m_pOperatorContextData;
  1018. CParticleCollection *m_pNext; // for linking children together
  1019. CParticleCollection *m_pPrev; // for linking children together
  1020. struct CWorldCollideContextData *m_pCollisionCacheData[NUM_COLLISION_CACHE_MODES]; // children can share collision caches w/ parent
  1021. CParticleCollection *m_pParent;
  1022. CUtlIntrusiveDList<CParticleCollection> m_Children; // list for all child particle systems
  1023. void *operator new(size_t nSize);
  1024. void *operator new( size_t size, int nBlockUse, const char *pFileName, int nLine );
  1025. void operator delete(void *pData);
  1026. void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine );
  1027. protected:
  1028. // current bounds for the particle system
  1029. bool m_bBoundsValid;
  1030. Vector m_MinBounds;
  1031. Vector m_MaxBounds;
  1032. int m_nHighestCP; //Highest CP set externally. Needs to assert if a system calls to an unassigned CP.
  1033. private:
  1034. unsigned char *m_pParticleMemory; // fixed size at initialization. Must be aligned for SSE
  1035. unsigned char *m_pParticleInitialMemory; // fixed size at initialization. Must be aligned for SSE
  1036. unsigned char *m_pConstantMemory;
  1037. int m_nPerParticleInitializedAttributeMask;
  1038. int m_nPerParticleUpdatedAttributeMask;
  1039. int m_nPerParticleReadInitialAttributeMask; // What fields do operators want to see initial attribute values for?
  1040. float *m_pParticleAttributes[MAX_PARTICLE_ATTRIBUTES];
  1041. float *m_pParticleInitialAttributes[MAX_PARTICLE_ATTRIBUTES];
  1042. size_t m_nParticleFloatStrides[MAX_PARTICLE_ATTRIBUTES];
  1043. size_t m_nParticleInitialFloatStrides[MAX_PARTICLE_ATTRIBUTES];
  1044. float *m_pConstantAttributes;
  1045. uint64 m_nControlPointReadMask; // Mask indicating which control points have been accessed
  1046. int m_nParticleFlags; // PCFLAGS_xxx
  1047. bool m_bIsScrubbable : 1;
  1048. bool m_bIsRunningInitializers : 1;
  1049. bool m_bIsRunningOperators : 1;
  1050. bool m_bIsTranslucent : 1;
  1051. bool m_bIsTwoPass : 1;
  1052. bool m_bAnyUsesPowerOfTwoFrameBufferTexture : 1; // whether or not we or any children use this
  1053. bool m_bAnyUsesFullFrameBufferTexture : 1;
  1054. bool m_bIsBatchable : 1;
  1055. bool m_bUsesPowerOfTwoFrameBufferTexture; // whether or not we use this, _not_ our children
  1056. bool m_bUsesFullFrameBufferTexture;
  1057. // How many frames have we drawn?
  1058. int m_nDrawnFrames;
  1059. int m_nSimulatedFrames;
  1060. Vector m_Center; // average of particle centers
  1061. // Used to assign unique ids to each particle
  1062. int m_nUniqueParticleId;
  1063. // Used to generate random numbers
  1064. int m_nRandomQueryCount;
  1065. int m_nRandomSeed;
  1066. int m_nOperatorRandomSampleOffset;
  1067. float m_flMinDistSqr;
  1068. float m_flMaxDistSqr;
  1069. float m_flOOMaxDistSqr;
  1070. Vector m_vecLastCameraPos;
  1071. float m_flLastMinDistSqr;
  1072. float m_flLastMaxDistSqr;
  1073. // Particle collection kill list. set up by particle system mgr
  1074. int m_nNumParticlesToKill;
  1075. int *m_pParticleKillList;
  1076. // Used to build a list of all particle collections that have the same particle def
  1077. CParticleCollection *m_pNextDef;
  1078. CParticleCollection *m_pPrevDef;
  1079. void LoanKillListTo( CParticleCollection *pBorrower ) const;
  1080. bool HasAttachedKillList( void ) const;
  1081. // For debugging
  1082. CParticleOperatorInstance *m_pRenderOp;
  1083. friend class CParticleSystemMgr;
  1084. friend class CParticleOperatorInstance;
  1085. };
  1086. class CM128InitialAttributeIterator : public CStridedConstPtr<fltx4>
  1087. {
  1088. public:
  1089. FORCEINLINE CM128InitialAttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1090. {
  1091. m_pData = pParticles->GetInitialM128AttributePtr( nAttribute, &m_nStride );
  1092. }
  1093. };
  1094. class CM128AttributeIterator : public CStridedConstPtr<fltx4>
  1095. {
  1096. public:
  1097. FORCEINLINE CM128AttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1098. {
  1099. m_pData = pParticles->GetM128AttributePtr( nAttribute, &m_nStride );
  1100. }
  1101. };
  1102. class C4IAttributeIterator : public CStridedConstPtr<FourInts>
  1103. {
  1104. public:
  1105. FORCEINLINE C4IAttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1106. {
  1107. m_pData = pParticles->Get4IAttributePtr( nAttribute, &m_nStride );
  1108. }
  1109. };
  1110. class CM128AttributeWriteIterator : public CStridedPtr<fltx4>
  1111. {
  1112. public:
  1113. FORCEINLINE CM128AttributeWriteIterator( void )
  1114. {
  1115. }
  1116. FORCEINLINE void Init ( int nAttribute, CParticleCollection *pParticles )
  1117. {
  1118. m_pData = pParticles->GetM128AttributePtrForWrite( nAttribute, &m_nStride );
  1119. }
  1120. FORCEINLINE CM128AttributeWriteIterator( int nAttribute, CParticleCollection *pParticles )
  1121. {
  1122. Init( nAttribute, pParticles );
  1123. }
  1124. };
  1125. class C4VAttributeIterator : public CStridedConstPtr<FourVectors>
  1126. {
  1127. public:
  1128. FORCEINLINE C4VAttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1129. {
  1130. m_pData = pParticles->Get4VAttributePtr( nAttribute, &m_nStride );
  1131. }
  1132. };
  1133. class C4VInitialAttributeIterator : public CStridedConstPtr<FourVectors>
  1134. {
  1135. public:
  1136. FORCEINLINE C4VInitialAttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1137. {
  1138. m_pData = pParticles->GetInitial4VAttributePtr( nAttribute, &m_nStride );
  1139. }
  1140. };
  1141. class C4VAttributeWriteIterator : public CStridedPtr<FourVectors>
  1142. {
  1143. public:
  1144. FORCEINLINE C4VAttributeWriteIterator( int nAttribute, CParticleCollection *pParticles )
  1145. {
  1146. m_pData = pParticles->Get4VAttributePtrForWrite( nAttribute, &m_nStride );
  1147. }
  1148. };
  1149. //-----------------------------------------------------------------------------
  1150. // Inline methods of CParticleCollection
  1151. //-----------------------------------------------------------------------------
  1152. inline bool CParticleCollection::HasAttachedKillList( void ) const
  1153. {
  1154. return m_pParticleKillList != NULL;
  1155. }
  1156. inline bool CParticleCollection::ReadsControlPoint( int nPoint ) const
  1157. {
  1158. return ( m_nControlPointReadMask & ( 1ULL << nPoint ) ) != 0;
  1159. }
  1160. inline void CParticleCollection::SetNActiveParticles( int nCount )
  1161. {
  1162. Assert( nCount <= m_nMaxAllowedParticles );
  1163. m_nActiveParticles = nCount;
  1164. m_nPaddedActiveParticles = ( nCount+3 )/4;
  1165. }
  1166. inline void CParticleCollection::SwapPosAndPrevPos( void )
  1167. {
  1168. // strides better be the same!
  1169. Assert( m_nParticleFloatStrides[PARTICLE_ATTRIBUTE_XYZ] == m_nParticleFloatStrides[ PARTICLE_ATTRIBUTE_PREV_XYZ ] );
  1170. V_swap( m_pParticleAttributes[ PARTICLE_ATTRIBUTE_XYZ ], m_pParticleAttributes[ PARTICLE_ATTRIBUTE_PREV_XYZ ] );
  1171. }
  1172. inline void CParticleCollection::LoanKillListTo( CParticleCollection *pBorrower ) const
  1173. {
  1174. Assert(! pBorrower->m_pParticleKillList );
  1175. pBorrower->m_nNumParticlesToKill = 0;
  1176. pBorrower->m_pParticleKillList = m_pParticleKillList;
  1177. }
  1178. inline void CParticleCollection::SetAttributeToConstant( int nAttribute, float fValue )
  1179. {
  1180. float *fconst = m_pConstantAttributes + 4*3*nAttribute;
  1181. fconst[0] = fconst[1] = fconst[2] = fconst[3] = fValue;
  1182. }
  1183. inline void CParticleCollection::SetAttributeToConstant( int nAttribute, float fValueX, float fValueY, float fValueZ )
  1184. {
  1185. float *fconst = m_pConstantAttributes + 4*3*nAttribute;
  1186. fconst[0] = fconst[1] = fconst[2] = fconst[3] = fValueX;
  1187. fconst[4] = fconst[5] = fconst[6] = fconst[7] = fValueY;
  1188. fconst[8] = fconst[9] = fconst[10] = fconst[11] = fValueZ;
  1189. }
  1190. inline void CParticleCollection::SetControlPoint( int nWhichPoint, const Vector &v )
  1191. {
  1192. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  1193. m_nHighestCP = MAX( m_nHighestCP, nWhichPoint );
  1194. m_ControlPoints[ nWhichPoint ].m_Position = v;
  1195. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  1196. {
  1197. i->SetControlPoint( nWhichPoint, v );
  1198. }
  1199. }
  1200. inline void CParticleCollection::SetControlPointObject( int nWhichPoint, void *pObject )
  1201. {
  1202. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  1203. m_ControlPoints[ nWhichPoint ].m_pObject = pObject;
  1204. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  1205. {
  1206. i->SetControlPointObject( nWhichPoint, pObject );
  1207. }
  1208. }
  1209. inline void CParticleCollection::SetControlPointOrientation( int nWhichPoint, const Vector &forward,
  1210. const Vector &right, const Vector &up )
  1211. {
  1212. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  1213. // check perpendicular
  1214. if ( fabs( DotProduct( forward, up ) ) <= 0.1f
  1215. && fabs( DotProduct( forward, right ) ) <= 0.1f
  1216. && fabs( DotProduct( right, up ) ) <= 0.1f )
  1217. {
  1218. m_ControlPoints[ nWhichPoint ].m_ForwardVector = forward;
  1219. m_ControlPoints[ nWhichPoint ].m_UpVector = up;
  1220. m_ControlPoints[ nWhichPoint ].m_RightVector = right;
  1221. // make sure all children are finished
  1222. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  1223. {
  1224. i->SetControlPointOrientation( nWhichPoint, forward, right, up );
  1225. }
  1226. }
  1227. else
  1228. {
  1229. Warning( "Attempt to set particle collection %s to invalid orientation matrix\n", GetName() );
  1230. }
  1231. }
  1232. inline Vector CParticleCollection::TransformAxis( const Vector &SrcAxis, bool bLocalSpace,
  1233. int nControlPointNumber)
  1234. {
  1235. if ( bLocalSpace )
  1236. {
  1237. return // mxmul
  1238. ( SrcAxis.x*m_ControlPoints[nControlPointNumber].m_RightVector )+
  1239. ( SrcAxis.y*m_ControlPoints[nControlPointNumber].m_ForwardVector )+
  1240. ( SrcAxis.z*m_ControlPoints[nControlPointNumber].m_UpVector );
  1241. }
  1242. else
  1243. return SrcAxis;
  1244. }
  1245. inline void CParticleCollection::SetControlPointOrientation( int nWhichPoint, const Quaternion &q )
  1246. {
  1247. matrix3x4_t mat;
  1248. Vector vecForward, vecUp, vecRight;
  1249. QuaternionMatrix( q, mat );
  1250. MatrixVectors( mat, &vecForward, &vecRight, &vecUp );
  1251. SetControlPointOrientation( nWhichPoint, vecForward, vecRight, vecUp );
  1252. }
  1253. inline void CParticleCollection::SetControlPointForwardVector( int nWhichPoint, const Vector &v)
  1254. {
  1255. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  1256. m_ControlPoints[ nWhichPoint ].m_ForwardVector = v;
  1257. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  1258. {
  1259. i->SetControlPointForwardVector( nWhichPoint, v );
  1260. }
  1261. }
  1262. inline void CParticleCollection::SetControlPointUpVector( int nWhichPoint, const Vector &v)
  1263. {
  1264. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  1265. m_ControlPoints[ nWhichPoint ].m_UpVector = v;
  1266. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  1267. {
  1268. i->SetControlPointUpVector( nWhichPoint, v );
  1269. }
  1270. }
  1271. inline void CParticleCollection::SetControlPointRightVector( int nWhichPoint, const Vector &v)
  1272. {
  1273. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  1274. m_ControlPoints[ nWhichPoint ].m_RightVector = v;
  1275. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  1276. {
  1277. i->SetControlPointRightVector( nWhichPoint, v );
  1278. }
  1279. }
  1280. inline void CParticleCollection::SetControlPointParent( int nWhichPoint, int n )
  1281. {
  1282. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  1283. m_ControlPoints[ nWhichPoint ].m_nParent = n;
  1284. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  1285. {
  1286. i->SetControlPointParent( nWhichPoint, n );
  1287. }
  1288. }
  1289. // Returns the memory for a particular constant attribute
  1290. inline float *CParticleCollection::GetConstantAttributeMemory( int nAttribute )
  1291. {
  1292. return m_pConstantAttributes + 3 * 4 * nAttribute;
  1293. }
  1294. // Random number offset (for use in getting Random #s in operators)
  1295. inline int CParticleCollection::OperatorRandomSampleOffset() const
  1296. {
  1297. return m_nOperatorRandomSampleOffset;
  1298. }
  1299. // Used by particle systems to generate random numbers
  1300. inline int CParticleCollection::RandomInt( int nRandomSampleId, int nMin, int nMax )
  1301. {
  1302. // do not call
  1303. float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ];
  1304. flRand *= ( nMax + 1 - nMin );
  1305. int nRand = (int)flRand + nMin;
  1306. return nRand;
  1307. }
  1308. inline float CParticleCollection::RandomFloat( int nRandomSampleId, float flMin, float flMax )
  1309. {
  1310. // do not call
  1311. float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ];
  1312. flRand *= ( flMax - flMin );
  1313. flRand += flMin;
  1314. return flRand;
  1315. }
  1316. inline fltx4 CParticleCollection::RandomFloat( const FourInts &ParticleID, int nRandomSampleOffset )
  1317. {
  1318. fltx4 Retval;
  1319. int nOfs=m_nRandomSeed+nRandomSampleOffset;
  1320. SubFloat( Retval, 0 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[0] ) & RANDOM_FLOAT_MASK ];
  1321. SubFloat( Retval, 1 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[1] ) & RANDOM_FLOAT_MASK ];
  1322. SubFloat( Retval, 2 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[2] ) & RANDOM_FLOAT_MASK ];
  1323. SubFloat( Retval, 3 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[3] ) & RANDOM_FLOAT_MASK ];
  1324. return Retval;
  1325. }
  1326. inline float CParticleCollection::RandomFloatExp( int nRandomSampleId, float flMin, float flMax, float flExponent )
  1327. {
  1328. // do not call
  1329. float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ];
  1330. flRand = powf( flRand, flExponent );
  1331. flRand *= ( flMax - flMin );
  1332. flRand += flMin;
  1333. return flRand;
  1334. }
  1335. inline void CParticleCollection::RandomVector( int nRandomSampleId, float flMin, float flMax, Vector *pVector )
  1336. {
  1337. // do not call
  1338. float flDelta = flMax - flMin;
  1339. int nBaseId = m_nRandomSeed + nRandomSampleId;
  1340. pVector->x = s_pRandomFloats[ nBaseId & RANDOM_FLOAT_MASK ];
  1341. pVector->x *= flDelta;
  1342. pVector->x += flMin;
  1343. pVector->y = s_pRandomFloats[ ( nBaseId + 1 ) & RANDOM_FLOAT_MASK ];
  1344. pVector->y *= flDelta;
  1345. pVector->y += flMin;
  1346. pVector->z = s_pRandomFloats[ ( nBaseId + 2 ) & RANDOM_FLOAT_MASK ];
  1347. pVector->z *= flDelta;
  1348. pVector->z += flMin;
  1349. }
  1350. inline void CParticleCollection::RandomVector( int nRandomSampleId, const Vector &vecMin, const Vector &vecMax, Vector *pVector )
  1351. {
  1352. // do not call
  1353. int nBaseId = m_nRandomSeed + nRandomSampleId;
  1354. pVector->x = RandomFloat( nBaseId, vecMin.x, vecMax.x );
  1355. pVector->y = RandomFloat( nBaseId + 1, vecMin.y, vecMax.y );
  1356. pVector->z = RandomFloat( nBaseId + 2, vecMin.z, vecMax.z );
  1357. }
  1358. // Used by particle systems to generate random numbers
  1359. inline int CParticleCollection::RandomInt( int nMin, int nMax )
  1360. {
  1361. // do not call
  1362. return RandomInt( m_nRandomQueryCount++, nMin, nMax );
  1363. }
  1364. inline float CParticleCollection::RandomFloat( float flMin, float flMax )
  1365. {
  1366. // do not call
  1367. return RandomFloat( m_nRandomQueryCount++, flMin, flMax );
  1368. }
  1369. inline float CParticleCollection::RandomFloatExp( float flMin, float flMax, float flExponent )
  1370. {
  1371. // do not call
  1372. return RandomFloatExp( m_nRandomQueryCount++, flMin, flMax, flExponent );
  1373. }
  1374. inline void CParticleCollection::RandomVector( float flMin, float flMax, Vector *pVector )
  1375. {
  1376. // do not call
  1377. RandomVector( m_nRandomQueryCount++, flMin, flMax, pVector );
  1378. }
  1379. inline void CParticleCollection::RandomVector( const Vector &vecMin, const Vector &vecMax, Vector *pVector )
  1380. {
  1381. // do not call
  1382. RandomVector( m_nRandomQueryCount++, vecMin, vecMax, pVector );
  1383. }
  1384. inline float CParticleCollection::RandomVectorInUnitSphere( Vector *pVector )
  1385. {
  1386. // do not call
  1387. return RandomVectorInUnitSphere( m_nRandomQueryCount++, pVector );
  1388. }
  1389. // get the pointer to an attribute for a given particle. !!speed!! if you find yourself
  1390. // calling this anywhere that matters, you're not handling the simd-ness of the particle system
  1391. // well and will have bad perf.
  1392. inline const float *CParticleCollection::GetFloatAttributePtr( int nAttribute, int nParticleNumber ) const
  1393. {
  1394. Assert( nParticleNumber < m_nAllocatedParticles );
  1395. int block_ofs = nParticleNumber/4;
  1396. return m_pParticleAttributes[ nAttribute ] +
  1397. m_nParticleFloatStrides[ nAttribute ] * block_ofs +
  1398. ( nParticleNumber & 3 );
  1399. }
  1400. inline int *CParticleCollection::GetIntAttributePtrForWrite( int nAttribute, int nParticleNumber )
  1401. {
  1402. return reinterpret_cast< int* >( GetFloatAttributePtrForWrite( nAttribute, nParticleNumber ) );
  1403. }
  1404. inline const int *CParticleCollection::GetIntAttributePtr( int nAttribute, int nParticleNumber ) const
  1405. {
  1406. return (int*)GetFloatAttributePtr( nAttribute, nParticleNumber );
  1407. }
  1408. inline const fltx4 *CParticleCollection::GetM128AttributePtr( int nAttribute, size_t *pStrideOut ) const
  1409. {
  1410. *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/4;
  1411. return reinterpret_cast<fltx4 *>( m_pParticleAttributes[ nAttribute ] );
  1412. }
  1413. inline const FourInts *CParticleCollection::Get4IAttributePtr( int nAttribute, size_t *pStrideOut ) const
  1414. {
  1415. *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/4;
  1416. return reinterpret_cast<FourInts *>( m_pParticleAttributes[ nAttribute ] );
  1417. }
  1418. inline const int32 *CParticleCollection::GetIntAttributePtr( int nAttribute, size_t *pStrideOut ) const
  1419. {
  1420. *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ];
  1421. return reinterpret_cast<int32 *>( m_pParticleAttributes[ nAttribute ] );
  1422. }
  1423. inline const FourVectors *CParticleCollection::Get4VAttributePtr( int nAttribute, size_t *pStrideOut ) const
  1424. {
  1425. *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/12;
  1426. return reinterpret_cast<const FourVectors *>( m_pParticleAttributes[ nAttribute ] );
  1427. }
  1428. inline FourVectors *CParticleCollection::Get4VAttributePtrForWrite( int nAttribute, size_t *pStrideOut )
  1429. {
  1430. *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/12;
  1431. return reinterpret_cast<FourVectors *>( m_pParticleAttributes[ nAttribute ] );
  1432. }
  1433. inline const FourVectors *CParticleCollection::GetInitial4VAttributePtr( int nAttribute, size_t *pStrideOut ) const
  1434. {
  1435. *(pStrideOut) = m_nParticleInitialFloatStrides[ nAttribute ]/12;
  1436. return reinterpret_cast<FourVectors *>( m_pParticleInitialAttributes[ nAttribute ] );
  1437. }
  1438. inline float *CParticleCollection::GetFloatAttributePtrForWrite( int nAttribute, int nParticleNumber )
  1439. {
  1440. // NOTE: If you hit this assertion, it means your particle operator isn't returning
  1441. // the appropriate fields in the RequiredAttributesMask call
  1442. Assert( !m_bIsRunningInitializers || ( m_nPerParticleInitializedAttributeMask & (1 << nAttribute) ) );
  1443. Assert( !m_bIsRunningOperators || ( m_nPerParticleUpdatedAttributeMask & (1 << nAttribute) ) );
  1444. Assert( m_nParticleFloatStrides[nAttribute] != 0 );
  1445. Assert( nParticleNumber < m_nAllocatedParticles );
  1446. int block_ofs = nParticleNumber/4;
  1447. return m_pParticleAttributes[ nAttribute ] +
  1448. m_nParticleFloatStrides[ nAttribute ] * block_ofs +
  1449. ( nParticleNumber & 3 );
  1450. }
  1451. inline fltx4 *CParticleCollection::GetM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut )
  1452. {
  1453. // NOTE: If you hit this assertion, it means your particle operator isn't returning
  1454. // the appropriate fields in the RequiredAttributesMask call
  1455. if ( !HushAsserts() )
  1456. {
  1457. Assert( !m_bIsRunningInitializers || ( m_nPerParticleInitializedAttributeMask & (1 << nAttribute) ) );
  1458. Assert( !m_bIsRunningOperators || ( m_nPerParticleUpdatedAttributeMask & (1 << nAttribute) ) );
  1459. Assert( m_nParticleFloatStrides[nAttribute] != 0 );
  1460. }
  1461. *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/4;
  1462. return reinterpret_cast<fltx4 *>( m_pParticleAttributes[ nAttribute ] );
  1463. }
  1464. inline const float *CParticleCollection::GetInitialFloatAttributePtr( int nAttribute, int nParticleNumber ) const
  1465. {
  1466. Assert( nParticleNumber < m_nAllocatedParticles );
  1467. int block_ofs = nParticleNumber / 4;
  1468. return m_pParticleInitialAttributes[ nAttribute ] + m_nParticleInitialFloatStrides[ nAttribute ] * block_ofs + ( nParticleNumber & 3 );
  1469. }
  1470. inline const fltx4 *CParticleCollection::GetInitialM128AttributePtr( int nAttribute, size_t *pStrideOut ) const
  1471. {
  1472. *(pStrideOut) = m_nParticleInitialFloatStrides[ nAttribute ]/4;
  1473. return reinterpret_cast<fltx4 *>( m_pParticleInitialAttributes[ nAttribute ] );
  1474. }
  1475. inline float *CParticleCollection::GetInitialFloatAttributePtrForWrite( int nAttribute, int nParticleNumber )
  1476. {
  1477. Assert( nParticleNumber < m_nAllocatedParticles );
  1478. Assert( m_nPerParticleReadInitialAttributeMask & ( 1 << nAttribute ) );
  1479. int block_ofs = nParticleNumber / 4;
  1480. return m_pParticleInitialAttributes[ nAttribute ] + m_nParticleInitialFloatStrides[ nAttribute ] * block_ofs + ( nParticleNumber & 3 );
  1481. }
  1482. inline fltx4 *CParticleCollection::GetInitialM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut )
  1483. {
  1484. Assert( m_nPerParticleReadInitialAttributeMask & ( 1 << nAttribute ) );
  1485. *(pStrideOut) = m_nParticleInitialFloatStrides[ nAttribute ] / 4;
  1486. return reinterpret_cast<fltx4 *>( m_pParticleInitialAttributes[ nAttribute ] );
  1487. }
  1488. // Used to make sure we're accessing valid memory
  1489. inline bool CParticleCollection::IsValidAttributePtr( int nAttribute, const void *pPtr ) const
  1490. {
  1491. if ( pPtr < m_pParticleAttributes[nAttribute] )
  1492. return false;
  1493. size_t nArraySize = m_nParticleFloatStrides[nAttribute] * m_nAllocatedParticles / 4;
  1494. void *pMaxPtr = m_pParticleAttributes[nAttribute] + nArraySize;
  1495. return ( pPtr <= pMaxPtr );
  1496. }
  1497. FORCEINLINE void CParticleCollection::KillParticle( int nPidx )
  1498. {
  1499. // add a particle to the sorted kill list. entries must be added in sorted order.
  1500. // within a particle operator, this is safe to call. Outside of one, you have to call
  1501. // the ApplyKillList() method yourself. The storage for the kill list is global between
  1502. // all particle systems, so you can't kill a particle in 2 different CParticleCollections
  1503. // w/o calling ApplyKillList
  1504. // That said, we only expect the particle index to be at most more than 3 larger than the
  1505. // particle count
  1506. Assert( nPidx < m_nActiveParticles + 4 );
  1507. // note that it is permissible to kill particles with indices>the number of active
  1508. // particles, in order to faciliate easy sse coding
  1509. Assert( m_nNumParticlesToKill < MAX_PARTICLES_IN_A_SYSTEM );
  1510. m_pParticleKillList[ m_nNumParticlesToKill++ ] = nPidx;
  1511. }
  1512. // initialize this attribute for all active particles
  1513. inline void CParticleCollection::FillAttributeWithConstant( int nAttribute, float fValue )
  1514. {
  1515. size_t stride;
  1516. fltx4 *pAttr = GetM128AttributePtrForWrite( nAttribute, &stride );
  1517. fltx4 fill=ReplicateX4( fValue );
  1518. for( int i = 0; i < m_nPaddedActiveParticles; i++ )
  1519. {
  1520. *(pAttr) = fill;
  1521. pAttr += stride;
  1522. }
  1523. }
  1524. //-----------------------------------------------------------------------------
  1525. // Helper to set vector attribute values
  1526. //-----------------------------------------------------------------------------
  1527. FORCEINLINE void SetVectorAttribute( float *pAttribute, float x, float y, float z )
  1528. {
  1529. pAttribute[0] = x;
  1530. pAttribute[4] = y;
  1531. pAttribute[8] = z;
  1532. }
  1533. FORCEINLINE void SetVectorAttribute( float *pAttribute, const Vector &v )
  1534. {
  1535. pAttribute[0] = v.x;
  1536. pAttribute[4] = v.y;
  1537. pAttribute[8] = v.z;
  1538. }
  1539. FORCEINLINE void SetVectorFromAttribute( Vector &v, const float *pAttribute )
  1540. {
  1541. v.x = pAttribute[0];
  1542. v.y = pAttribute[4];
  1543. v.z = pAttribute[8];
  1544. }
  1545. //-----------------------------------------------------------------------------
  1546. // Computes the sq distance to a particle position
  1547. //-----------------------------------------------------------------------------
  1548. FORCEINLINE float CParticleCollection::ComputeSqrDistanceToParticle( int hParticle, const Vector &vecPosition ) const
  1549. {
  1550. const float *xyz = GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, hParticle );
  1551. Vector vecParticlePosition( xyz[0], xyz[4], xyz[8] );
  1552. return vecParticlePosition.DistToSqr( vecPosition );
  1553. }
  1554. //-----------------------------------------------------------------------------
  1555. // Grows the dist sq range for all particles
  1556. //-----------------------------------------------------------------------------
  1557. FORCEINLINE void CParticleCollection::GrowDistSqrBounds( float flDistSqr )
  1558. {
  1559. if ( m_flLastMinDistSqr > flDistSqr )
  1560. {
  1561. m_flLastMinDistSqr = flDistSqr;
  1562. }
  1563. else if ( m_flLastMaxDistSqr < flDistSqr )
  1564. {
  1565. m_flLastMaxDistSqr = flDistSqr;
  1566. }
  1567. }
  1568. //-----------------------------------------------------------------------------
  1569. // Data associated with children particle systems
  1570. //-----------------------------------------------------------------------------
  1571. struct ParticleChildrenInfo_t
  1572. {
  1573. DmObjectId_t m_Id;
  1574. CUtlString m_Name;
  1575. bool m_bUseNameBasedLookup;
  1576. float m_flDelay; // How much to delay this system after the parent starts
  1577. };
  1578. //-----------------------------------------------------------------------------
  1579. // A template describing how a particle system will function
  1580. //-----------------------------------------------------------------------------
  1581. class CParticleSystemDefinition
  1582. {
  1583. DECLARE_DMXELEMENT_UNPACK();
  1584. DECLARE_REFERENCED_CLASS( CParticleSystemDefinition );
  1585. public:
  1586. CParticleSystemDefinition( void );
  1587. ~CParticleSystemDefinition( void );
  1588. // Serialization, unserialization
  1589. void Read( CDmxElement *pElement );
  1590. CDmxElement *Write();
  1591. const char *MaterialName() const;
  1592. IMaterial *GetMaterial() const;
  1593. const char *GetName() const;
  1594. const DmObjectId_t& GetId() const;
  1595. // Does the particle system use the power of two frame buffer texture (refraction?)
  1596. bool UsesPowerOfTwoFrameBufferTexture();
  1597. // Does the particle system use the full frame buffer texture (soft particles)
  1598. bool UsesFullFrameBufferTexture();
  1599. // Should we always precache this?
  1600. bool ShouldAlwaysPrecache() const;
  1601. // Should we batch particle collections using this definition up?
  1602. bool ShouldBatch() const;
  1603. // Is the particle system rendered on the viewmodel?
  1604. bool IsViewModelEffect() const;
  1605. // Used to iterate over all particle collections using the same def
  1606. CParticleCollection *FirstCollection();
  1607. // What's the effective cull size + fill cost?
  1608. // Used for early retirement
  1609. float GetCullRadius() const;
  1610. float GetCullFillCost() const;
  1611. int GetCullControlPoint() const;
  1612. const char *GetCullReplacementDefinition() const;
  1613. // Retirement
  1614. bool HasRetirementBeenChecked( int nFrame ) const;
  1615. void MarkRetirementCheck( int nFrame );
  1616. // Control point read
  1617. void MarkReadsControlPoint( int nPoint );
  1618. bool ReadsControlPoint( int nPoint ) const;
  1619. private:
  1620. void Precache();
  1621. void Uncache();
  1622. bool IsPrecached() const;
  1623. void UnlinkAllCollections();
  1624. void SetupContextData( );
  1625. void ParseChildren( CDmxElement *pElement );
  1626. void ParseOperators( const char *pszName, ParticleFunctionType_t nFunctionType,
  1627. CDmxElement *pElement, CUtlVector<CParticleOperatorInstance *> &out_list );
  1628. void WriteChildren( CDmxElement *pElement );
  1629. void WriteOperators( CDmxElement *pElement, const char *pOpKeyName,
  1630. const CUtlVector<CParticleOperatorInstance *> &inList );
  1631. CUtlVector<CParticleOperatorInstance *> *GetOperatorList( ParticleFunctionType_t type );
  1632. CParticleOperatorInstance *FindOperatorById( ParticleFunctionType_t type, const DmObjectId_t &id );
  1633. private:
  1634. int m_nInitialParticles;
  1635. int m_nPerParticleUpdatedAttributeMask;
  1636. int m_nPerParticleInitializedAttributeMask;
  1637. int m_nInitialAttributeReadMask;
  1638. int m_nAttributeReadMask;
  1639. uint64 m_nControlPointReadMask;
  1640. Vector m_BoundingBoxMin;
  1641. Vector m_BoundingBoxMax;
  1642. char m_pszMaterialName[MAX_PATH];
  1643. CMaterialReference m_Material;
  1644. CParticleCollection *m_pFirstCollection;
  1645. char m_pszCullReplacementName[128];
  1646. float m_flCullRadius;
  1647. float m_flCullFillCost;
  1648. int m_nCullControlPoint;
  1649. int m_nRetireCheckFrame;
  1650. // Default attribute values
  1651. Color m_ConstantColor;
  1652. float m_flConstantRadius;
  1653. float m_flConstantRotation;
  1654. float m_flConstantRotationSpeed;
  1655. int m_nConstantSequenceNumber;
  1656. int m_nConstantSequenceNumber1;
  1657. int m_nGroupID;
  1658. float m_flMaximumTimeStep;
  1659. float m_flMaximumSimTime; // maximum time to sim before drawing first frame.
  1660. float m_flMinimumSimTime; // minimum time to sim before drawing first frame - prevents all
  1661. // capped particles from drawing at 0 time.
  1662. int m_nMinimumFrames; // number of frames to apply max/min simulation times
  1663. // Is the particle system rendered on the viewmodel?
  1664. bool m_bViewModelEffect;
  1665. size_t m_nContextDataSize;
  1666. DmObjectId_t m_Id;
  1667. public:
  1668. float m_flMaxDrawDistance; // distance at which to not draw.
  1669. float m_flNoDrawTimeToGoToSleep; // after not beeing seen for this long, the system will sleep
  1670. int m_nMaxParticles;
  1671. int m_nSkipRenderControlPoint; // if the camera is attached to the
  1672. // object associated with this control
  1673. // point, don't render the system
  1674. CUtlString m_Name;
  1675. CUtlVector<CParticleOperatorInstance *> m_Operators;
  1676. CUtlVector<CParticleOperatorInstance *> m_Renderers;
  1677. CUtlVector<CParticleOperatorInstance *> m_Initializers;
  1678. CUtlVector<CParticleOperatorInstance *> m_Emitters;
  1679. CUtlVector<CParticleOperatorInstance *> m_ForceGenerators;
  1680. CUtlVector<CParticleOperatorInstance *> m_Constraints;
  1681. CUtlVector<ParticleChildrenInfo_t> m_Children;
  1682. CUtlVector<size_t> m_nOperatorsCtxOffsets;
  1683. CUtlVector<size_t> m_nRenderersCtxOffsets;
  1684. CUtlVector<size_t> m_nInitializersCtxOffsets;
  1685. CUtlVector<size_t> m_nEmittersCtxOffsets;
  1686. CUtlVector<size_t> m_nForceGeneratorsCtxOffsets;
  1687. CUtlVector<size_t> m_nConstraintsCtxOffsets;
  1688. // profiling information
  1689. float m_flTotalSimTime;
  1690. float m_flUncomittedTotalSimTime;
  1691. float m_flMaxMeasuredSimTime;
  1692. int m_nMaximumActiveParticles;
  1693. bool m_bShouldSort;
  1694. bool m_bShouldBatch;
  1695. bool m_bIsPrecached : 1;
  1696. bool m_bAlwaysPrecache : 1;
  1697. friend class CParticleCollection;
  1698. friend class CParticleSystemMgr;
  1699. };
  1700. //-----------------------------------------------------------------------------
  1701. // Inline methods
  1702. //-----------------------------------------------------------------------------
  1703. inline CParticleSystemDefinition::CParticleSystemDefinition( void )
  1704. {
  1705. m_nControlPointReadMask = 0;
  1706. m_nInitialAttributeReadMask = 0;
  1707. m_nPerParticleInitializedAttributeMask = 0;
  1708. m_nPerParticleUpdatedAttributeMask = 0;
  1709. m_nAttributeReadMask = 0;
  1710. m_flTotalSimTime = 0.0;
  1711. m_flMaxMeasuredSimTime = 0.0;
  1712. m_nMaximumActiveParticles = 0;
  1713. m_bIsPrecached = false;
  1714. m_bAlwaysPrecache = false;
  1715. m_bShouldBatch = false;
  1716. m_bShouldSort = true;
  1717. m_pFirstCollection = NULL;
  1718. m_flCullRadius = 0.0f;
  1719. m_flCullFillCost = 1.0f;
  1720. m_nRetireCheckFrame = 0;
  1721. }
  1722. inline CParticleSystemDefinition::~CParticleSystemDefinition( void )
  1723. {
  1724. UnlinkAllCollections();
  1725. m_Operators.PurgeAndDeleteElements();
  1726. m_Renderers.PurgeAndDeleteElements();
  1727. m_Initializers.PurgeAndDeleteElements();
  1728. m_Emitters.PurgeAndDeleteElements();
  1729. m_ForceGenerators.PurgeAndDeleteElements();
  1730. m_Constraints.PurgeAndDeleteElements();
  1731. }
  1732. // Used to iterate over all particle collections using the same def
  1733. inline CParticleCollection *CParticleSystemDefinition::FirstCollection()
  1734. {
  1735. return m_pFirstCollection;
  1736. }
  1737. inline float CParticleSystemDefinition::GetCullRadius() const
  1738. {
  1739. return m_flCullRadius;
  1740. }
  1741. inline float CParticleSystemDefinition::GetCullFillCost() const
  1742. {
  1743. return m_flCullFillCost;
  1744. }
  1745. inline const char *CParticleSystemDefinition::GetCullReplacementDefinition() const
  1746. {
  1747. return m_pszCullReplacementName;
  1748. }
  1749. inline int CParticleSystemDefinition::GetCullControlPoint() const
  1750. {
  1751. return m_nCullControlPoint;
  1752. }
  1753. inline void CParticleSystemDefinition::MarkReadsControlPoint( int nPoint )
  1754. {
  1755. m_nControlPointReadMask |= ( 1ULL << nPoint );
  1756. }
  1757. inline bool CParticleSystemDefinition::ReadsControlPoint( int nPoint ) const
  1758. {
  1759. return ( m_nControlPointReadMask & ( 1ULL << nPoint ) ) != 0;
  1760. }
  1761. // Retirement
  1762. inline bool CParticleSystemDefinition::HasRetirementBeenChecked( int nFrame ) const
  1763. {
  1764. return m_nRetireCheckFrame == nFrame;
  1765. }
  1766. inline void CParticleSystemDefinition::MarkRetirementCheck( int nFrame )
  1767. {
  1768. m_nRetireCheckFrame = nFrame;
  1769. }
  1770. inline bool CParticleSystemDefinition::ShouldBatch() const
  1771. {
  1772. return m_bShouldBatch;
  1773. }
  1774. inline bool CParticleSystemDefinition::IsViewModelEffect() const
  1775. {
  1776. return m_bViewModelEffect;
  1777. }
  1778. inline const char *CParticleSystemDefinition::MaterialName() const
  1779. {
  1780. return m_pszMaterialName;
  1781. }
  1782. inline const DmObjectId_t& CParticleSystemDefinition::GetId() const
  1783. {
  1784. return m_Id;
  1785. }
  1786. inline int CParticleCollection::GetGroupID( void ) const
  1787. {
  1788. return m_pDef->m_nGroupID;
  1789. }
  1790. FORCEINLINE const Vector& CParticleCollection::GetControlPointAtCurrentTime( int nControlPoint ) const
  1791. {
  1792. Assert( nControlPoint <= GetHighestControlPoint() );
  1793. Assert( m_pDef->ReadsControlPoint( nControlPoint ) );
  1794. return m_ControlPoints[nControlPoint].m_Position;
  1795. }
  1796. FORCEINLINE void CParticleCollection::GetControlPointOrientationAtCurrentTime( int nControlPoint, Vector *pForward, Vector *pRight, Vector *pUp ) const
  1797. {
  1798. Assert( nControlPoint <= GetHighestControlPoint() );
  1799. Assert( m_pDef->ReadsControlPoint( nControlPoint ) );
  1800. // FIXME: Use quaternion lerp to get control point transform at time
  1801. *pForward = m_ControlPoints[nControlPoint].m_ForwardVector;
  1802. *pRight = m_ControlPoints[nControlPoint].m_RightVector;
  1803. *pUp = m_ControlPoints[nControlPoint].m_UpVector;
  1804. }
  1805. FORCEINLINE int CParticleCollection::GetControlPointParent( int nControlPoint ) const
  1806. {
  1807. Assert( nControlPoint <= GetHighestControlPoint() );
  1808. Assert( m_pDef->ReadsControlPoint( nControlPoint ) );
  1809. return m_ControlPoints[nControlPoint].m_nParent;
  1810. }
  1811. FORCEINLINE bool CParticleCollection::IsValid( void ) const
  1812. {
  1813. return ( m_pDef != NULL && m_pDef->GetMaterial() );
  1814. }
  1815. #endif // PARTICLES_H