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.

3390 lines
114 KiB

  1. //===== Copyright (c) 1996-2006, 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 "appframework/iappsystem.h"
  15. #if 1
  16. #include "materialsystem/imaterialsystem.h"
  17. #include "materialsystem/MaterialSystemUtil.h"
  18. #else
  19. class IMaterial;
  20. class IMatRenderContext;
  21. #endif
  22. #include "dmxloader/dmxelement.h"
  23. #include "tier1/utlintrusivelist.h"
  24. #include "vstdlib/random.h"
  25. #include "tier1/utlobjectreference.h"
  26. #include "tier1/UtlStringMap.h"
  27. #include "tier1/utlmap.h"
  28. #include "trace.h"
  29. #include "tier1/utlsoacontainer.h"
  30. #include "raytrace.h"
  31. #include "materialsystem/imesh.h"
  32. #if defined( CLIENT_DLL )
  33. #include "c_pixel_visibility.h"
  34. #endif
  35. //-----------------------------------------------------------------------------
  36. // Forward declarations
  37. //-----------------------------------------------------------------------------
  38. struct DmxElementUnpackStructure_t;
  39. class CParticleSystemDefinition;
  40. class CParticleCollection;
  41. class CParticleOperatorInstance;
  42. class CParticleSystemDictionary;
  43. class CUtlBuffer;
  44. class IParticleOperatorDefinition;
  45. class CSheet;
  46. class CMeshBuilder;
  47. extern float s_pRandomFloats[];
  48. //-----------------------------------------------------------------------------
  49. // Random numbers
  50. //-----------------------------------------------------------------------------
  51. #define MAX_RANDOM_FLOATS 4096
  52. #define RANDOM_FLOAT_MASK ( MAX_RANDOM_FLOATS - 1 )
  53. //-----------------------------------------------------------------------------
  54. // Helpers
  55. //-----------------------------------------------------------------------------
  56. // Get a list of the files inside the particle manifest file
  57. void GetParticleManifest( CUtlVector<CUtlString>& list );
  58. void GetParticleManifest( CUtlVector<CUtlString>& list, const char *pFile );
  59. //-----------------------------------------------------------------------------
  60. // Particle attributes
  61. //-----------------------------------------------------------------------------
  62. #define MAX_PARTICLE_ATTRIBUTES 24
  63. #define DEFPARTICLE_ATTRIBUTE( name, bit, datatype ) \
  64. const int PARTICLE_ATTRIBUTE_##name##_MASK = (1 << bit); \
  65. const int PARTICLE_ATTRIBUTE_##name = bit; \
  66. const EAttributeDataType PARTICLE_ATTRIBUTE_##name##_DATATYPE = datatype;
  67. // required
  68. DEFPARTICLE_ATTRIBUTE( XYZ, 0, ATTRDATATYPE_4V );
  69. // particle lifetime (duration) of particle as a float.
  70. DEFPARTICLE_ATTRIBUTE( LIFE_DURATION, 1, ATTRDATATYPE_FLOAT );
  71. // prev coordinates for verlet integration
  72. DEFPARTICLE_ATTRIBUTE( PREV_XYZ, 2, ATTRDATATYPE_4V );
  73. // radius of particle
  74. DEFPARTICLE_ATTRIBUTE( RADIUS, 3, ATTRDATATYPE_FLOAT );
  75. // rotation angle of particle
  76. DEFPARTICLE_ATTRIBUTE( ROTATION, 4, ATTRDATATYPE_FLOAT );
  77. // rotation speed of particle
  78. DEFPARTICLE_ATTRIBUTE( ROTATION_SPEED, 5, ATTRDATATYPE_FLOAT );
  79. // tint of particle
  80. DEFPARTICLE_ATTRIBUTE( TINT_RGB, 6, ATTRDATATYPE_4V );
  81. // alpha tint of particle
  82. DEFPARTICLE_ATTRIBUTE( ALPHA, 7, ATTRDATATYPE_FLOAT );
  83. // creation time stamp (relative to particle system creation)
  84. DEFPARTICLE_ATTRIBUTE( CREATION_TIME, 8, ATTRDATATYPE_FLOAT );
  85. // sequnece # (which animation sequence number this particle uses )
  86. DEFPARTICLE_ATTRIBUTE( SEQUENCE_NUMBER, 9, ATTRDATATYPE_FLOAT );
  87. // length of the trail
  88. DEFPARTICLE_ATTRIBUTE( TRAIL_LENGTH, 10, ATTRDATATYPE_FLOAT );
  89. // unique particle identifier
  90. DEFPARTICLE_ATTRIBUTE( PARTICLE_ID, 11, ATTRDATATYPE_INT );
  91. // unique rotation around up vector
  92. DEFPARTICLE_ATTRIBUTE( YAW, 12, ATTRDATATYPE_FLOAT );
  93. // second sequnece # (which animation sequence number this particle uses )
  94. DEFPARTICLE_ATTRIBUTE( SEQUENCE_NUMBER1, 13, ATTRDATATYPE_FLOAT );
  95. // hit box index
  96. DEFPARTICLE_ATTRIBUTE( HITBOX_INDEX, 14, ATTRDATATYPE_INT );
  97. DEFPARTICLE_ATTRIBUTE( HITBOX_RELATIVE_XYZ, 15, ATTRDATATYPE_4V );
  98. DEFPARTICLE_ATTRIBUTE( ALPHA2, 16, ATTRDATATYPE_FLOAT );
  99. // particle trace caching fields
  100. DEFPARTICLE_ATTRIBUTE( SCRATCH_VEC, 17, ATTRDATATYPE_4V ); //scratch field used for storing arbitraty vec data
  101. DEFPARTICLE_ATTRIBUTE( SCRATCH_FLOAT, 18, ATTRDATATYPE_4V ); //scratch field used for storing arbitraty float data
  102. DEFPARTICLE_ATTRIBUTE( UNUSED, 19, ATTRDATATYPE_FLOAT );
  103. DEFPARTICLE_ATTRIBUTE( PITCH, 20, ATTRDATATYPE_4V );
  104. DEFPARTICLE_ATTRIBUTE( NORMAL, 21, ATTRDATATYPE_4V ); // 0 0 0 if none
  105. DEFPARTICLE_ATTRIBUTE( GLOW_RGB, 22, ATTRDATATYPE_4V ); // glow color
  106. DEFPARTICLE_ATTRIBUTE( GLOW_ALPHA, 23, ATTRDATATYPE_FLOAT ); // glow alpha
  107. #define MAX_PARTICLE_CONTROL_POINTS 64
  108. #define ATTRIBUTES_WHICH_ARE_VEC3S_MASK ( PARTICLE_ATTRIBUTE_SCRATCH_VEC_MASK | PARTICLE_ATTRIBUTE_XYZ_MASK | \
  109. PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_TINT_RGB_MASK | \
  110. PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK | PARTICLE_ATTRIBUTE_NORMAL_MASK | \
  111. PARTICLE_ATTRIBUTE_GLOW_RGB_MASK )
  112. #define ATTRIBUTES_WHICH_ARE_0_TO_1 (PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_ALPHA2_MASK)
  113. #define ATTRIBUTES_WHICH_ARE_ANGLES (PARTICLE_ATTRIBUTE_ROTATION_MASK | PARTICLE_ATTRIBUTE_YAW_MASK | PARTICLE_ATTRIBUTE_PITCH_MASK )
  114. #define ATTRIBUTES_WHICH_ARE_INTS (PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK | PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK )
  115. // Auto filters
  116. #define ATTRIBUTES_WHICH_ARE_POSITION_AND_VELOCITY (PARTICLE_ATTRIBUTE_XYZ_MASK | PARTICLE_ATTRIBUTE_PREV_XYZ_MASK)
  117. #define ATTRIBUTES_WHICH_ARE_LIFE_DURATION (PARTICLE_ATTRIBUTE_LIFE_DURATION_MASK | PARTICLE_ATTRIBUTE_CREATION_TIME_MASK)
  118. #define ATTRIBUTES_WHICH_ARE_ROTATION (PARTICLE_ATTRIBUTE_ROTATION_MASK | PARTICLE_ATTRIBUTE_YAW_MASK | PARTICLE_ATTRIBUTE_ROTATION_SPEED_MASK | PARTICLE_ATTRIBUTE_PITCH_MASK )
  119. #define ATTRIBUTES_WHICH_ARE_SIZE (PARTICLE_ATTRIBUTE_RADIUS_MASK | PARTICLE_ATTRIBUTE_TRAIL_LENGTH_MASK)
  120. #define ATTRIBUTES_WHICH_ARE_COLOR_AND_OPACITY (PARTICLE_ATTRIBUTE_TINT_RGB_MASK | PARTICLE_ATTRIBUTE_GLOW_RGB_MASK | PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_ALPHA2_MASK | PARTICLE_ATTRIBUTE_GLOW_ALPHA_MASK )
  121. #define ATTRIBUTES_WHICH_ARE_ANIMATION_SEQUENCE (PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER_MASK | PARTICLE_ATTRIBUTE_SEQUENCE_NUMBER1_MASK)
  122. #define ATTRIBUTES_WHICH_ARE_HITBOX (PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK | PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK)
  123. #define ATTRIBUTES_WHICH_ARE_NORMAL (PARTICLE_ATTRIBUTE_NORMAL_MASK)
  124. #if defined( _GAMECONSOLE )
  125. #define MAX_PARTICLES_IN_A_SYSTEM 2000
  126. #else
  127. #define MAX_PARTICLES_IN_A_SYSTEM 5000
  128. #endif
  129. // Set this to 1 or 0 to enable or disable particle profiling.
  130. // Note that this profiling is expensive on Linux, and some anti-virus
  131. // products can make this very expensive on Windows.
  132. #define MEASURE_PARTICLE_PERF 0
  133. #define MIN_PARTICLE_SPEED 0.001
  134. #define MAX_PARTICLE_ORIENTATION_TYPES 3
  135. //-----------------------------------------------------------------------------
  136. // Particle function types
  137. //-----------------------------------------------------------------------------
  138. enum ParticleFunctionType_t
  139. {
  140. FUNCTION_RENDERER = 0,
  141. FUNCTION_OPERATOR,
  142. FUNCTION_INITIALIZER,
  143. FUNCTION_EMITTER,
  144. FUNCTION_CHILDREN, // NOTE: This one is a fake function type, only here to help eliminate a ton of duplicated code in the editor
  145. FUNCTION_FORCEGENERATOR,
  146. FUNCTION_CONSTRAINT,
  147. PARTICLE_FUNCTION_COUNT
  148. };
  149. //-----------------------------------------------------------------------------
  150. // Particle filter types
  151. // Used for classifying operators in the interface
  152. // Can only have 32 altogether
  153. //-----------------------------------------------------------------------------
  154. enum ParticleFilterType_t
  155. {
  156. FILTER_NOT_SPECIAL = 0,
  157. FILTER_POSITION_AND_VELOCITY,
  158. FILTER_LIFE_DURATION,
  159. FILTER_PARAMETER_REMAPPING,
  160. FILTER_ROTATION,
  161. FILTER_SIZE,
  162. FILTER_COLOR_AND_OPACITY,
  163. FILTER_ANIMATION_SEQUENCE,
  164. FILTER_HITBOX,
  165. FILTER_NORMAL,
  166. FILTER_CONTROL_POINTS,
  167. FILTER_COUNT
  168. };
  169. enum ParticleFilterMask_t
  170. {
  171. FILTER_NOT_SPECIAL_MASK = 0,
  172. FILTER_POSITION_AND_VELOCITY_MASK = 1 << 1,
  173. FILTER_LIFE_DURATION_MASK = 1 << 2,
  174. FILTER_PARAMETER_REMAPPING_MASK = 1 << 3,
  175. FILTER_ROTATION_MASK = 1 << 4,
  176. FILTER_SIZE_MASK = 1 << 5,
  177. FILTER_COLOR_AND_OPACITY_MASK = 1 << 6,
  178. FILTER_ANIMATION_SEQUENCE_MASK = 1 << 7,
  179. FILTER_HITBOX_MASK = 1 << 8,
  180. FILTER_NORMAL_MASK = 1 << 9,
  181. FILTER_CONTROL_POINTS_MASK = 1 << 10
  182. };
  183. struct CParticleVisibilityInputs
  184. {
  185. float m_flInputMin;
  186. float m_flInputMax;
  187. float m_flAlphaScaleMin;
  188. float m_flAlphaScaleMax;
  189. float m_flRadiusScaleMin;
  190. float m_flRadiusScaleMax;
  191. float m_flRadiusScaleFOVBase;
  192. float m_flProxyRadius;
  193. float m_flDistanceInputMin;
  194. float m_flDistanceInputMax;
  195. float m_flDotInputMin;
  196. float m_flDotInputMax;
  197. int m_nCPin;
  198. };
  199. struct ModelHitBoxInfo_t
  200. {
  201. Vector m_vecBoxMins;
  202. Vector m_vecBoxMaxes;
  203. matrix3x4_t m_Transform;
  204. };
  205. class CModelHitBoxesInfo
  206. {
  207. public:
  208. float m_flLastUpdateTime;
  209. float m_flPrevLastUpdateTime;
  210. int m_nNumHitBoxes;
  211. int m_nNumPrevHitBoxes;
  212. ModelHitBoxInfo_t *m_pHitBoxes;
  213. ModelHitBoxInfo_t *m_pPrevBoxes;
  214. bool CurAndPrevValid( void ) const
  215. {
  216. return ( m_nNumHitBoxes && ( m_nNumPrevHitBoxes == m_nNumHitBoxes ) );
  217. }
  218. CModelHitBoxesInfo( void )
  219. {
  220. m_flLastUpdateTime = -1;
  221. m_nNumHitBoxes = 0;
  222. m_nNumPrevHitBoxes = 0;
  223. m_pHitBoxes = NULL;
  224. m_pPrevBoxes = NULL;
  225. }
  226. ~CModelHitBoxesInfo( void )
  227. {
  228. if ( m_pHitBoxes )
  229. delete[] m_pHitBoxes;
  230. if ( m_pPrevBoxes )
  231. delete[] m_pPrevBoxes;
  232. }
  233. };
  234. //-----------------------------------------------------------------------------
  235. // Particle kill list
  236. //-----------------------------------------------------------------------------
  237. #define KILL_LIST_INDEX_BITS 24
  238. #define KILL_LIST_FLAGS_BITS ( 32 - KILL_LIST_INDEX_BITS )
  239. #define KILL_LIST_INDEX_MASK ( ( 1 << KILL_LIST_INDEX_BITS ) - 1 )
  240. #define KILL_LIST_FLAGS_MASK ( ( 1 << KILL_LIST_FLAGS_BITS ) - 1 )
  241. struct KillListItem_t
  242. {
  243. unsigned int nIndex : KILL_LIST_INDEX_BITS;
  244. unsigned int nFlags : KILL_LIST_FLAGS_BITS;
  245. };
  246. enum KillListFlags
  247. {
  248. // TODO: use this in ApplyKillList (the idea: pass particles to a child system, but dont then kill them)
  249. KILL_LIST_FLAG_DONT_KILL = ( 1 << 0 )
  250. };
  251. //-----------------------------------------------------------------------------
  252. // Interface to allow the particle system to call back into the client
  253. //-----------------------------------------------------------------------------
  254. #define PARTICLE_SYSTEM_QUERY_INTERFACE_VERSION "VParticleSystemQuery004"
  255. class IParticleSystemQuery : public IAppSystem
  256. {
  257. public:
  258. virtual bool IsEditor( ) = 0;
  259. virtual void GetLightingAtPoint( const Vector& vecOrigin, Color &tint ) = 0;
  260. virtual void TraceLine( const Vector& vecAbsStart,
  261. const Vector& vecAbsEnd, unsigned int mask,
  262. const class IHandleEntity *ignore,
  263. int collisionGroup,
  264. CBaseTrace *ptr ) = 0;
  265. virtual bool IsPointInSolid( const Vector& vecPos, const int nContentsMask ) = 0;
  266. // given a possible spawn point, tries to movie it to be on or in the source object. returns
  267. // true if it succeeded
  268. virtual bool MovePointInsideControllingObject( CParticleCollection *pParticles,
  269. void *pObject,
  270. Vector *pPnt )
  271. {
  272. return true;
  273. }
  274. virtual bool IsPointInControllingObjectHitBox(
  275. CParticleCollection *pParticles,
  276. int nControlPointNumber, Vector vecPos, bool bBBoxOnly = false )
  277. {
  278. return true;
  279. }
  280. virtual int GetRayTraceEnvironmentFromName( const char *pszRtEnvName )
  281. {
  282. return 0; // == PRECIPITATION
  283. }
  284. virtual int GetCollisionGroupFromName( const char *pszCollisionGroupName )
  285. {
  286. return 0; // == COLLISION_GROUP_NONE
  287. }
  288. virtual void GetRandomPointsOnControllingObjectHitBox(
  289. CParticleCollection *pParticles,
  290. int nControlPointNumber,
  291. int nNumPtsOut,
  292. float flBBoxScale,
  293. int nNumTrysToGetAPointInsideTheModel,
  294. Vector *pPntsOut,
  295. Vector vecDirectionBias,
  296. Vector *pHitBoxRelativeCoordOut = NULL,
  297. int *pHitBoxIndexOut = NULL,
  298. int nDesiredHitbox = -1,
  299. const char *pszHitboxSetName = NULL ) = 0;
  300. virtual void GetClosestControllingObjectHitBox(
  301. CParticleCollection *pParticles,
  302. int nControlPointNumber,
  303. int nNumPtsIn,
  304. float flBBoxScale,
  305. Vector *pPntsIn,
  306. Vector *pHitBoxRelativeCoordOut = NULL,
  307. int *pHitBoxIndexOut = NULL,
  308. int nDesiredHitbox = -1,
  309. const char *pszHitboxSetName = NULL ) = 0;
  310. virtual int GetControllingObjectHitBoxInfo(
  311. CParticleCollection *pParticles,
  312. int nControlPointNumber,
  313. int nBufSize, // # of output slots available
  314. ModelHitBoxInfo_t *pHitBoxOutputBuffer,
  315. const char *pszHitboxSetName )
  316. {
  317. // returns number of hit boxes output
  318. return 0;
  319. }
  320. virtual void GetControllingObjectOBBox( CParticleCollection *pParticles,
  321. int nControlPointNumber,
  322. Vector vecMin, Vector vecMax )
  323. {
  324. vecMin = vecMax = vec3_origin;
  325. }
  326. // Traces Four Rays against a defined RayTraceEnvironment
  327. virtual void TraceAgainstRayTraceEnv(
  328. int envnumber,
  329. const FourRays &rays, fltx4 TMin, fltx4 TMax,
  330. RayTracingResult *rslt_out, int32 skip_id ) const = 0;
  331. virtual Vector GetLocalPlayerPos( void )
  332. {
  333. return vec3_origin;
  334. }
  335. virtual void GetLocalPlayerEyeVectors( Vector *pForward, Vector *pRight = NULL, Vector *pUp = NULL )
  336. {
  337. *pForward = vec3_origin;
  338. *pRight = vec3_origin;
  339. *pUp = vec3_origin;
  340. }
  341. virtual Vector GetCurrentViewOrigin()
  342. {
  343. return vec3_origin;
  344. }
  345. virtual int GetActivityCount() = 0;
  346. virtual const char *GetActivityNameFromIndex( int nActivityIndex ) { return 0; }
  347. virtual int GetActivityNumber( void *pModel, const char *m_pszActivityName ) { return -1; }
  348. virtual float GetPixelVisibility( int *pQueryHandle, const Vector &vecOrigin, float flScale ) = 0;
  349. virtual void SetUpLightingEnvironment( const Vector& pos )
  350. {
  351. }
  352. virtual void PreSimulate( ) = 0;
  353. virtual void PostSimulate( ) = 0;
  354. virtual void DebugDrawLine(const Vector& origin, const Vector& dest, int r, int g, int b,bool noDepthTest, float duration) = 0;
  355. virtual void *GetModel( char const *pMdlName ) { return NULL; }
  356. virtual void DrawModel( void *pModel, const matrix3x4_t &DrawMatrix, CParticleCollection *pParticles, int nParticleNumber, int nBodyPart, int nSubModel,
  357. int nSkin, int nAnimationSequence = 0, float flAnimationRate = 30.0f, float r = 1.0f, float g = 1.0f, float b = 1.0f, float a = 1.0f ) = 0;
  358. virtual void BeginDrawModels( int nNumModels, Vector const &vecCenter, CParticleCollection *pParticles ) {}
  359. virtual void FinishDrawModels( CParticleCollection *pParticles ) {}
  360. virtual void UpdateProjectedTexture( const int nParticleID, IMaterial *pMaterial, Vector &vOrigin, float flRadius, float flRotation, float r, float g, float b, float a, void *&pUserVar ) = 0;
  361. };
  362. //-----------------------------------------------------------------------------
  363. //
  364. // Particle system manager. Using a class because tools need it that way
  365. // so the SFM and PET tools can share managers despite being linked to
  366. // separate particle system .libs
  367. //
  368. //-----------------------------------------------------------------------------
  369. typedef int ParticleSystemHandle_t;
  370. class CParticleSystemMgr
  371. {
  372. public:
  373. // Constructor, destructor
  374. CParticleSystemMgr();
  375. ~CParticleSystemMgr();
  376. // Initialize the particle system
  377. bool Init( IParticleSystemQuery *pQuery, bool bAllowPrecache );
  378. void Shutdown();
  379. // 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
  380. // the server can omit the code needed for rendering/simulation, if desired.
  381. void AddBuiltinSimulationOperators( void );
  382. void AddBuiltinRenderingOperators( void );
  383. // Registration of known operators
  384. void AddParticleOperator( ParticleFunctionType_t nOpType, IParticleOperatorDefinition *pOpFactory );
  385. // Read a particle config file, add it to the list of particle configs
  386. bool ReadParticleConfigFile( const char *pFileName, bool bPrecache, bool bDecommitTempMemory = true );
  387. bool ReadParticleConfigFile( CUtlBuffer &buf, bool bPrecache, bool bDecommitTempMemory = true, const char *pFileName = NULL );
  388. void DecommitTempMemory();
  389. // For recording, write a specific particle system to a CUtlBuffer in DMX format
  390. bool WriteParticleConfigFile( const char *pParticleSystemName, CUtlBuffer &buf, bool bPreventNameBasedLookup = false );
  391. bool WriteParticleConfigFile( const DmObjectId_t& id, CUtlBuffer &buf, bool bPreventNameBasedLookup = false );
  392. // create a particle system by name. returns null if one of that name does not exist
  393. CParticleCollection *CreateParticleCollection( const char *pParticleSystemName, float flDelay = 0.0f, int nRandomSeed = 0 );
  394. CParticleCollection *CreateParticleCollection( ParticleSystemHandle_t particleSystemName, float flDelay = 0.0f, int nRandomSeed = 0 );
  395. // create a particle system given a particle system id
  396. CParticleCollection *CreateParticleCollection( const DmObjectId_t &id, float flDelay = 0.0f, int nRandomSeed = 0 );
  397. // Is a particular particle system defined?
  398. bool IsParticleSystemDefined( const char *pParticleSystemName );
  399. bool IsParticleSystemDefined( const DmObjectId_t &id );
  400. // Returns the index of the specified particle system.
  401. ParticleSystemHandle_t GetParticleSystemIndex( const char *pParticleSystemName );
  402. ParticleSystemHandle_t FindOrAddParticleSystemIndex( const char *pParticleSystemName );
  403. // Returns the name of the specified particle system.
  404. const char *GetParticleSystemNameFromIndex( ParticleSystemHandle_t iIndex );
  405. // Return the number of particle systems in our dictionary
  406. int GetParticleSystemCount( void );
  407. // Get the label for a filter
  408. const char *GetFilterName( ParticleFilterType_t nFilterType ) const;
  409. // call to get available particle operator definitions
  410. // NOTE: FUNCTION_CHILDREN will return a faked one, for ease of writing the editor
  411. CUtlVector< IParticleOperatorDefinition *> &GetAvailableParticleOperatorList( ParticleFunctionType_t nWhichList );
  412. void GetParticleSystemsInFile( const char *pFileName, CUtlVector<CUtlString> *pOutSystemNameList );
  413. void GetParticleSystemsInBuffer( CUtlBuffer &buf, CUtlVector<CUtlString> *pOutSystemNameList );
  414. // Returns the unpack structure for a particle system definition
  415. const DmxElementUnpackStructure_t *GetParticleSystemDefinitionUnpackStructure();
  416. // Particle sheet management
  417. void ShouldLoadSheets( bool bLoadSheets );
  418. CSheet *FindOrLoadSheet( CParticleSystemDefinition *pDef, bool bTryReloading = false );
  419. void FlushAllSheets( void );
  420. // Render cache used to render opaque particle collections
  421. void ResetRenderCache( void );
  422. void AddToRenderCache( CParticleCollection *pParticles );
  423. void DrawRenderCache( IMatRenderContext *pRenderContext, bool bShadowDepth );
  424. IParticleSystemQuery *Query( void ) { return m_pQuery; }
  425. // return the particle field name
  426. const char* GetParticleFieldName( int nParticleField ) const;
  427. // WARNING: the pointer returned by this function may be invalidated
  428. // *at any time* by the editor, so do not ever cache it.
  429. CParticleSystemDefinition* FindParticleSystem( const char *pName );
  430. CParticleSystemDefinition* FindParticleSystem( const DmObjectId_t& id );
  431. CParticleSystemDefinition* FindParticleSystem( ParticleSystemHandle_t hParticleSystem );
  432. CParticleSystemDefinition* FindPrecachedParticleSystem( int nPrecacheIndex );
  433. void CommitProfileInformation( bool bCommit ); // call after simulation, if you want
  434. // sim time recorded. if oyu pass
  435. // flase, info will be thrown away and
  436. // uncomitted time reset. Having this
  437. // function lets you only record
  438. // profile data for slow frames if
  439. // desired.
  440. void DumpProfileInformation( void ); // write particle_profile.csv
  441. void DumpParticleList( const char *pNameSubstring );
  442. // Cache/uncache materials used by particle systems
  443. void PrecacheParticleSystem( int nStringNumber, const char *pName );
  444. void UncacheAllParticleSystems();
  445. // Sets the last simulation time, used for particle system sleeping logic
  446. void SetLastSimulationTime( float flTime );
  447. float GetLastSimulationTime() const;
  448. // Sets the last simulation duration ( the amount of time we spent simulating particle ) last frame
  449. // Used to fallback to cheaper particle systems under load
  450. void SetLastSimulationDuration( float flDuration );
  451. float GetLastSimulationDuration() const;
  452. void SetFallbackParameters( float flBase, float flMultiplier, float flSimFallbackBaseMultiplier, float flSimThresholdMs );
  453. float GetFallbackBase() const;
  454. float GetFallbackMultiplier() const;
  455. float GetSimFallbackThresholdMs() const;
  456. float GetSimFallbackBaseMultiplier() const;
  457. void SetSystemLevel( int nCPULevel, int nGPULevel );
  458. int GetParticleCPULevel() const;
  459. int GetParticleGPULevel() const;
  460. void LevelShutdown( void ); // called at level unload time
  461. void FrameUpdate( void ); // call this once per frame on main thread
  462. // Particle attribute query funcs
  463. int GetParticleAttributeByName( const char *pAttribute ) const; // SLOW! returns -1 on error
  464. const char *GetParticleAttributeName( int nAttribute ) const; // returns 'unknown' on error
  465. EAttributeDataType GetParticleAttributeDataType( int nAttribute ) const;
  466. private:
  467. struct RenderCache_t
  468. {
  469. IMaterial *m_pMaterial;
  470. CUtlVector< CParticleCollection * > m_ParticleCollections;
  471. };
  472. struct BatchStep_t
  473. {
  474. CParticleCollection *m_pParticles;
  475. CParticleOperatorInstance *m_pRenderer;
  476. void *m_pContext;
  477. int m_nFirstParticle;
  478. int m_nParticleCount;
  479. int m_nVertCount;
  480. };
  481. struct Batch_t
  482. {
  483. int m_nVertCount;
  484. int m_nIndexCount;
  485. CUtlVector< BatchStep_t > m_BatchStep;
  486. };
  487. struct ParticleAttribute_t
  488. {
  489. EAttributeDataType nDataType;
  490. const char *pName;
  491. };
  492. // Unserialization-related methods
  493. bool ReadParticleDefinitions( CUtlBuffer &buf, const char *pFileName, bool bPrecache, bool bDecommitTempMemory );
  494. void AddParticleSystem( CDmxElement *pParticleSystem );
  495. // Serialization-related methods
  496. CDmxElement *CreateParticleDmxElement( const DmObjectId_t &id );
  497. CDmxElement *CreateParticleDmxElement( const char *pParticleSystemName );
  498. bool WriteParticleConfigFile( CDmxElement *pParticleSystem, CUtlBuffer &buf, bool bPreventNameBasedLookup );
  499. // Builds a list of batches to render
  500. void BuildBatchList( int iRenderCache, IMatRenderContext *pRenderContext, CUtlVector< Batch_t >& batches );
  501. // Known operators
  502. CUtlVector<IParticleOperatorDefinition *> m_ParticleOperators[PARTICLE_FUNCTION_COUNT];
  503. // Particle system dictionary
  504. CParticleSystemDictionary *m_pParticleSystemDictionary;
  505. // typedef CUtlMap< ITexture *, CSheet* > SheetsCache;
  506. typedef CUtlStringMap< CSheet* > SheetsCache_t;
  507. SheetsCache_t m_SheetList;
  508. // attaching and dtaching killlists. when simulating, a particle system gets a kill list. after
  509. // simulating, the memory for that will be used for the next particle system. This matters for
  510. // threaded particles, because we don't want to share the same kill list between simultaneously
  511. // simulating particle systems.
  512. void AttachKillList( CParticleCollection *pParticles);
  513. void DetachKillList( CParticleCollection *pParticles);
  514. // Set up s_AttributeTable
  515. void InitAttributeTable( void );
  516. // For visualization (currently can only visualize one operator at a time)
  517. CParticleCollection *m_pVisualizedParticles;
  518. DmObjectId_t m_VisualizedOperatorId;
  519. IParticleSystemQuery *m_pQuery;
  520. CUtlVector< RenderCache_t > m_RenderCache;
  521. IMaterial *m_pShadowDepthMaterial;
  522. float m_flLastSimulationTime;
  523. float m_flLastSimulationDuration;
  524. CUtlVector< ParticleSystemHandle_t > m_PrecacheLookup;
  525. CUtlVector< ParticleSystemHandle_t > m_ClientPrecacheLookup;
  526. bool m_bDidInit;
  527. bool m_bUsingDefaultQuery;
  528. bool m_bShouldLoadSheets;
  529. bool m_bAllowPrecache;
  530. int m_nNumFramesMeasured;
  531. float m_flFallbackBase;
  532. float m_flFallbackMultiplier;
  533. float m_flSimFallbackBaseMultiplier;
  534. float m_flSimThresholdMs;
  535. int m_nCPULevel;
  536. int m_nGPULevel;
  537. static ParticleAttribute_t s_AttributeTable[MAX_PARTICLE_ATTRIBUTES];
  538. friend class CParticleSystemDefinition;
  539. friend class CParticleCollection;
  540. };
  541. extern CParticleSystemMgr *g_pParticleSystemMgr;
  542. //-----------------------------------------------------------------------------
  543. // A particle system can only have 1 operator using a particular ID
  544. //-----------------------------------------------------------------------------
  545. enum ParticleOperatorId_t
  546. {
  547. // Generic IDs
  548. OPERATOR_GENERIC = -2, // Can have as many of these as you want
  549. OPERATOR_SINGLETON = -1, // Can only have 1 operator with the same name as this one
  550. // Renderer operator IDs
  551. // Operator IDs
  552. // Initializer operator IDs
  553. OPERATOR_PI_POSITION, // Particle initializer: position (can only have 1 position setter)
  554. OPERATOR_PI_RADIUS,
  555. OPERATOR_PI_ALPHA,
  556. OPERATOR_PI_TINT_RGB,
  557. OPERATOR_PI_ROTATION,
  558. OPERATOR_PI_YAW,
  559. // Emitter IDs
  560. OPERATOR_ID_COUNT,
  561. };
  562. //-----------------------------------------------------------------------------
  563. // Class factory for particle operators
  564. //-----------------------------------------------------------------------------
  565. class IParticleOperatorDefinition
  566. {
  567. public:
  568. virtual const char *GetName() const = 0;
  569. virtual CParticleOperatorInstance *CreateInstance( const DmObjectId_t &id ) const = 0;
  570. // virtual void DestroyInstance( CParticleOperatorInstance *pInstance ) const = 0;
  571. virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const = 0;
  572. virtual ParticleOperatorId_t GetId() const = 0;
  573. virtual uint32 GetFilter() const = 0;
  574. virtual bool IsObsolete() const = 0;
  575. #if MEASURE_PARTICLE_PERF
  576. // performance monitoring
  577. float m_flMaxExecutionTime;
  578. float m_flTotalExecutionTime;
  579. float m_flUncomittedTime;
  580. FORCEINLINE void RecordExecutionTime( float flETime )
  581. {
  582. m_flUncomittedTime += flETime;
  583. m_flMaxExecutionTime = MAX( m_flMaxExecutionTime, flETime );
  584. }
  585. FORCEINLINE float TotalRecordedExecutionTime( void ) const
  586. {
  587. return m_flTotalExecutionTime;
  588. }
  589. FORCEINLINE float MaximumRecordedExecutionTime( void ) const
  590. {
  591. return m_flMaxExecutionTime;
  592. }
  593. #else
  594. FORCEINLINE void RecordExecutionTime( float flETime )
  595. {
  596. }
  597. #endif
  598. };
  599. //-----------------------------------------------------------------------------
  600. // Particle operators
  601. //-----------------------------------------------------------------------------
  602. class CParticleOperatorInstance
  603. {
  604. public:
  605. // custom allocators so we can be simd aligned
  606. void *operator new( size_t nSize );
  607. void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine );
  608. void operator delete( void *pData );
  609. void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine );
  610. // unpack structure will be applied by creator. add extra initialization needed here
  611. virtual void InitParams( CParticleSystemDefinition *pDef )
  612. {
  613. }
  614. virtual size_t GetRequiredContextBytes( ) const
  615. {
  616. return 0;
  617. }
  618. virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
  619. {
  620. }
  621. virtual uint32 GetWrittenAttributes( void ) const = 0;
  622. virtual uint32 GetReadAttributes( void ) const = 0;
  623. virtual uint64 GetReadControlPointMask() const
  624. {
  625. return 0;
  626. }
  627. virtual uint32 GetFilter( void ) const
  628. {
  629. uint32 filter = 0;
  630. uint32 wrAttrib = GetWrittenAttributes();
  631. if (wrAttrib & ATTRIBUTES_WHICH_ARE_POSITION_AND_VELOCITY)
  632. {
  633. filter = filter | FILTER_POSITION_AND_VELOCITY_MASK;
  634. }
  635. if (wrAttrib & ATTRIBUTES_WHICH_ARE_LIFE_DURATION)
  636. {
  637. filter = filter | FILTER_LIFE_DURATION_MASK;
  638. }
  639. if (wrAttrib & ATTRIBUTES_WHICH_ARE_ROTATION)
  640. {
  641. filter = filter | FILTER_ROTATION_MASK;
  642. }
  643. if (wrAttrib & ATTRIBUTES_WHICH_ARE_SIZE)
  644. {
  645. filter = filter | FILTER_SIZE_MASK;
  646. }
  647. if (wrAttrib & ATTRIBUTES_WHICH_ARE_COLOR_AND_OPACITY)
  648. {
  649. filter = filter | FILTER_COLOR_AND_OPACITY_MASK;
  650. }
  651. if (wrAttrib & ATTRIBUTES_WHICH_ARE_ANIMATION_SEQUENCE)
  652. {
  653. filter = filter | FILTER_ANIMATION_SEQUENCE_MASK;
  654. }
  655. if (wrAttrib & ATTRIBUTES_WHICH_ARE_HITBOX)
  656. {
  657. filter = filter | FILTER_HITBOX_MASK;
  658. }
  659. if (wrAttrib & ATTRIBUTES_WHICH_ARE_NORMAL)
  660. {
  661. filter = filter | FILTER_NORMAL_MASK;
  662. }
  663. return filter;
  664. }
  665. // these control points are NOT positions or matrices (ie don't try to transform them)
  666. virtual uint64 GetNonPositionalControlPointMask() const
  667. {
  668. return 0;
  669. }
  670. // Used when an operator needs to read the attributes of a particle at spawn time
  671. virtual uint32 GetReadInitialAttributes( void ) const
  672. {
  673. return 0;
  674. }
  675. // a particle simulator does this
  676. virtual void Operate( CParticleCollection *pParticles, float flOpStrength, void *pContext ) const
  677. {
  678. }
  679. virtual void PostSimulate( CParticleCollection *pParticles, void *pContext ) const
  680. {
  681. }
  682. // a renderer overrides this
  683. virtual void Render( IMatRenderContext *pRenderContext,
  684. CParticleCollection *pParticles, const Vector4D &vecDiffuseModulation, void *pContext, int nViewRecursionDepth ) const
  685. {
  686. }
  687. virtual bool IsBatchable() const
  688. {
  689. return true;
  690. }
  691. virtual bool IsOrderImportant() const
  692. {
  693. return false;
  694. }
  695. virtual bool ShouldRun( bool bApplyingParentKillList ) const
  696. {
  697. return !bApplyingParentKillList;
  698. }
  699. virtual void RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
  700. {
  701. }
  702. // Returns the number of verts + indices to render
  703. virtual int GetParticlesToRender( CParticleCollection *pParticles, void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int *pVertsUsed, int *pIndicesUsed ) const
  704. {
  705. *pVertsUsed = 0;
  706. *pIndicesUsed = 0;
  707. return 0;
  708. }
  709. // emitters over-ride this. Return a mask of what fields you initted
  710. virtual uint32 Emit( CParticleCollection *pParticles, float flOpCurStrength,
  711. void *pContext ) const
  712. {
  713. return 0;
  714. }
  715. // emitters over-ride this.
  716. virtual void StopEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly = false ) const
  717. {
  718. }
  719. virtual void StartEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly = false ) const
  720. {
  721. }
  722. virtual void Restart( CParticleCollection *pParticles, void *pContext ) {}
  723. // initters over-ride this
  724. virtual void InitParticleSystem( CParticleCollection *pParticles, void *pContext ) const
  725. {
  726. }
  727. // a force generator does this. It accumulates in the force array
  728. virtual void AddForces( FourVectors *AccumulatedForces,
  729. CParticleCollection *pParticles,
  730. int nBlocks,
  731. float flCurStrength,
  732. void *pContext ) const
  733. {
  734. }
  735. // this is called for each constarint every frame. It can set up data like nearby world traces,
  736. // etc
  737. virtual void SetupConstraintPerFrameData( CParticleCollection *pParticles,
  738. void *pContext ) const
  739. {
  740. }
  741. // a constraint overrides this. It shold return a true if it did anything
  742. virtual bool EnforceConstraint( int nStartBlock,
  743. int nNumBlocks,
  744. CParticleCollection *pParticles,
  745. void *pContext,
  746. int nNumValidParticlesInLastChunk ) const
  747. {
  748. return false;
  749. }
  750. // should the constraint be run only once after all other constraints?
  751. virtual bool IsFinalConstaint( void ) const
  752. {
  753. return false;
  754. }
  755. // determines if a mask needs to be initialized multiple times.
  756. virtual bool InitMultipleOverride()
  757. {
  758. return false;
  759. }
  760. // Indicates if this initializer is scrub-safe (initializers don't use random numbers, for example)
  761. virtual bool IsScrubSafe()
  762. {
  763. return false;
  764. }
  765. // particle-initters over-ride this
  766. virtual void InitNewParticlesScalar( CParticleCollection *pParticles, int nFirstParticle, int n_particles, int attribute_write_mask, void *pContext ) const
  767. {
  768. }
  769. // 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.
  770. virtual void InitNewParticlesBlock( CParticleCollection *pParticles, int start_block, int n_blocks, int attribute_write_mask, void *pContext ) const
  771. {
  772. // default behaviour is to call the scalar one 4x times
  773. InitNewParticlesScalar( pParticles, 4*start_block, 4*n_blocks, attribute_write_mask, pContext );
  774. }
  775. // splits particle initialization up into scalar and block sections, callingt he right code
  776. void InitNewParticles( CParticleCollection *pParticles, int nFirstParticle, int n_particles, int attribute_write_mask , void *pContext) const;
  777. // this function is queried to determine if a particle system is over and doen with. A particle
  778. // system is done with when it has noparticles and no operators intend to create any more
  779. virtual bool MayCreateMoreParticles( CParticleCollection const *pParticles, void *pContext ) const
  780. {
  781. return false;
  782. }
  783. // Returns the operator definition that spawned this operator
  784. const IParticleOperatorDefinition *GetDefinition()
  785. {
  786. return m_pDef;
  787. }
  788. virtual bool ShouldRunBeforeEmitters( void ) const
  789. {
  790. return false;
  791. }
  792. // Called when the SFM wants to skip forward in time
  793. virtual void SkipToTime( float flTime, CParticleCollection *pParticles, void *pContext ) const {}
  794. // Returns a unique ID for this definition
  795. const DmObjectId_t& GetId() { return m_Id; }
  796. // Used for editing + debugging to visualize the operator in 3D
  797. virtual void Render( CParticleCollection *pParticles ) const {}
  798. // Used as a debugging mechanism to prevent bogus calls to RandomInt or RandomFloat inside operators
  799. // Use CParticleCollection::RandomInt/RandomFloat instead
  800. int RandomInt( int nMin, int nMax )
  801. {
  802. // NOTE: Use CParticleCollection::RandomInt!
  803. Assert(0);
  804. return 0;
  805. }
  806. float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f )
  807. {
  808. // NOTE: Use CParticleCollection::RandomFloat!
  809. Assert(0);
  810. return 0.0f;
  811. }
  812. float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f )
  813. {
  814. // NOTE: Use CParticleCollection::RandomFloatExp!
  815. Assert(0);
  816. return 0.0f;
  817. }
  818. float m_flOpStartFadeInTime;
  819. float m_flOpEndFadeInTime;
  820. float m_flOpStartFadeOutTime;
  821. float m_flOpEndFadeOutTime;
  822. float m_flOpFadeOscillatePeriod;
  823. float m_flOpTimeOffsetMin;
  824. float m_flOpTimeOffsetMax;
  825. int m_nOpTimeOffsetSeed;
  826. int m_nOpStrengthScaleSeed;
  827. float m_flOpStrengthMinScale;
  828. float m_flOpStrengthMaxScale;
  829. int m_nOpTimeScaleSeed;
  830. float m_flOpTimeScaleMin;
  831. float m_flOpTimeScaleMax;
  832. bool m_bStrengthFastPath; // set for operators which just always have strengh = 0
  833. int m_nOpEndCapState;
  834. virtual void Precache( void )
  835. {
  836. }
  837. virtual void Uncache( void )
  838. {
  839. }
  840. virtual ~CParticleOperatorInstance( void )
  841. {
  842. // so that sheet references, etc can be cleaned up
  843. }
  844. protected:
  845. // utility function for initting a scalar attribute to a random range in an sse fashion
  846. void InitScalarAttributeRandomRangeExpBlock( int nAttributeId, float fMinValue, float fMaxValue, float fExp,
  847. CParticleCollection *pParticles, int nStartBlock, int nBlockCount, bool bRandomlyInvert = false ) const;
  848. void AddScalarAttributeRandomRangeExpBlock( int nAttributeId, float fMinValue, float fMaxValue, float fExp,
  849. CParticleCollection *pParticles, int nStartBlock, int nBlockCount, bool bRandomlyInvert = false ) const;
  850. void InitScalarAttributeRandomRangeExpScalar( int nAttributeId, float fMinValue, float fMaxValue, float fExp,
  851. CParticleCollection *pParticles, int nStartParticle, int nParticleCount ) const;
  852. void CheckForFastPath( void ); // call at operator init time
  853. // utility funcs to access CParticleCollection data:
  854. bool HasAttribute( CParticleCollection *pParticles, int nAttribute ) const;
  855. KillListItem_t *GetParentKillList( CParticleCollection *pParticles, int &nNumParticlesToKill ) const;
  856. private:
  857. friend class CParticleCollection;
  858. friend class CParticleSystemDefinition;
  859. friend class CParticleSystemMgr;
  860. const IParticleOperatorDefinition *m_pDef;
  861. void SetDefinition( const IParticleOperatorDefinition * pDef, const DmObjectId_t &id )
  862. {
  863. m_pDef = pDef;
  864. CopyUniqueId( id, &m_Id );
  865. }
  866. DmObjectId_t m_Id;
  867. template <typename T> friend class CParticleOperatorDefinition;
  868. };
  869. class CParticleInitializerOperatorInstance : public CParticleOperatorInstance
  870. {
  871. public:
  872. virtual bool ShouldRun( bool bApplyingParentKillList ) const
  873. {
  874. return ( !bApplyingParentKillList ) || m_bRunForParentApplyKillList;
  875. }
  876. bool m_bRunForParentApplyKillList;
  877. };
  878. class CParticleRenderOperatorInstance : public CParticleOperatorInstance
  879. {
  880. public:
  881. CParticleVisibilityInputs VisibilityInputs;
  882. };
  883. //-----------------------------------------------------------------------------
  884. // Helper macro for creating particle operator factories
  885. //-----------------------------------------------------------------------------
  886. template < class T >
  887. class CParticleOperatorDefinition : public IParticleOperatorDefinition
  888. {
  889. public:
  890. CParticleOperatorDefinition( const char *pFactoryName, ParticleOperatorId_t id, bool bIsObsolete ) : m_pFactoryName( pFactoryName ), m_Id( id )
  891. {
  892. #if MEASURE_PARTICLE_PERF
  893. m_flTotalExecutionTime = 0.0f;
  894. m_flMaxExecutionTime = 0.0f;
  895. m_flUncomittedTime = 0.0f;
  896. #endif
  897. m_bIsObsolete = bIsObsolete;
  898. }
  899. virtual const char *GetName() const
  900. {
  901. return m_pFactoryName;
  902. }
  903. virtual ParticleOperatorId_t GetId() const
  904. {
  905. return m_Id;
  906. }
  907. virtual CParticleOperatorInstance *CreateInstance( const DmObjectId_t &id ) const
  908. {
  909. CParticleOperatorInstance *pOp = new T;
  910. pOp->SetDefinition( this, id );
  911. return pOp;
  912. }
  913. virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const
  914. {
  915. return m_pUnpackParams;
  916. }
  917. // Editor won't display obsolete operators
  918. virtual bool IsObsolete() const
  919. {
  920. return m_bIsObsolete;
  921. }
  922. virtual uint32 GetFilter() const { T temp; return temp.GetFilter(); }
  923. private:
  924. const char *m_pFactoryName;
  925. ParticleOperatorId_t m_Id;
  926. bool m_bIsObsolete;
  927. static DmxElementUnpackStructure_t *m_pUnpackParams;
  928. };
  929. #define DECLARE_PARTICLE_OPERATOR( _className ) \
  930. DECLARE_DMXELEMENT_UNPACK() \
  931. friend class CParticleOperatorDefinition<_className >
  932. #define DEFINE_PARTICLE_OPERATOR( _className, _operatorName, _id ) \
  933. static CParticleOperatorDefinition<_className> s_##_className##Factory( _operatorName, _id, false )
  934. #define DEFINE_PARTICLE_OPERATOR_OBSOLETE( _className, _operatorName, _id ) \
  935. static CParticleOperatorDefinition<_className> s_##_className##Factory( _operatorName, _id, true )
  936. #define BEGIN_PARTICLE_OPERATOR_UNPACK( _className ) \
  937. BEGIN_DMXELEMENT_UNPACK( _className ) \
  938. DMXELEMENT_UNPACK_FIELD( "operator start fadein","0", float, m_flOpStartFadeInTime ) \
  939. DMXELEMENT_UNPACK_FIELD( "operator end fadein","0", float, m_flOpEndFadeInTime ) \
  940. DMXELEMENT_UNPACK_FIELD( "operator start fadeout","0", float, m_flOpStartFadeOutTime ) \
  941. DMXELEMENT_UNPACK_FIELD( "operator end fadeout","0", float, m_flOpEndFadeOutTime ) \
  942. DMXELEMENT_UNPACK_FIELD( "operator fade oscillate","0", float, m_flOpFadeOscillatePeriod ) \
  943. DMXELEMENT_UNPACK_FIELD( "operator time offset seed","0", int, m_nOpTimeOffsetSeed ) \
  944. DMXELEMENT_UNPACK_FIELD( "operator time offset min","0", float, m_flOpTimeOffsetMin ) \
  945. DMXELEMENT_UNPACK_FIELD( "operator time offset max","0", float, m_flOpTimeOffsetMax ) \
  946. DMXELEMENT_UNPACK_FIELD( "operator time scale seed","0", int, m_nOpTimeScaleSeed ) \
  947. DMXELEMENT_UNPACK_FIELD( "operator time scale min","1", float, m_flOpTimeScaleMin ) \
  948. DMXELEMENT_UNPACK_FIELD( "operator time scale max","1", float, m_flOpTimeScaleMax ) \
  949. DMXELEMENT_UNPACK_FIELD( "operator time strength random scale max", "1", float, m_flOpStrengthMaxScale ) \
  950. DMXELEMENT_UNPACK_FIELD( "operator strength scale seed","0", int, m_nOpStrengthScaleSeed ) \
  951. DMXELEMENT_UNPACK_FIELD( "operator strength random scale min", "1", float, m_flOpStrengthMinScale ) \
  952. DMXELEMENT_UNPACK_FIELD( "operator strength random scale max", "1", float, m_flOpStrengthMaxScale ) \
  953. DMXELEMENT_UNPACK_FIELD( "operator end cap state", "-1", int, m_nOpEndCapState )
  954. #define END_PARTICLE_OPERATOR_UNPACK( _className ) \
  955. END_DMXELEMENT_UNPACK_TEMPLATE( _className, CParticleOperatorDefinition<_className>::m_pUnpackParams )
  956. #define BEGIN_PARTICLE_INITIALIZER_OPERATOR_UNPACK( _className ) \
  957. BEGIN_PARTICLE_OPERATOR_UNPACK( _className ) \
  958. DMXELEMENT_UNPACK_FIELD( "run for killed parent particles", "1", bool, m_bRunForParentApplyKillList )
  959. #define BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( _className ) \
  960. BEGIN_PARTICLE_OPERATOR_UNPACK( _className ) \
  961. DMXELEMENT_UNPACK_FIELD( "Visibility Proxy Input Control Point Number", "-1", int, VisibilityInputs.m_nCPin ) \
  962. DMXELEMENT_UNPACK_FIELD( "Visibility Proxy Radius", "1.0", float, VisibilityInputs.m_flProxyRadius ) \
  963. DMXELEMENT_UNPACK_FIELD( "Visibility input minimum","0", float, VisibilityInputs.m_flInputMin ) \
  964. DMXELEMENT_UNPACK_FIELD( "Visibility input maximum","1", float, VisibilityInputs.m_flInputMax ) \
  965. DMXELEMENT_UNPACK_FIELD( "Visibility input dot minimum","0", float, VisibilityInputs.m_flDotInputMin ) \
  966. DMXELEMENT_UNPACK_FIELD( "Visibility input dot maximum","0", float, VisibilityInputs.m_flDotInputMax ) \
  967. DMXELEMENT_UNPACK_FIELD( "Visibility input distance minimum","0", float, VisibilityInputs.m_flDistanceInputMin ) \
  968. DMXELEMENT_UNPACK_FIELD( "Visibility input distance maximum","0", float, VisibilityInputs.m_flDistanceInputMax ) \
  969. DMXELEMENT_UNPACK_FIELD( "Visibility Alpha Scale minimum","0", float, VisibilityInputs.m_flAlphaScaleMin ) \
  970. DMXELEMENT_UNPACK_FIELD( "Visibility Alpha Scale maximum","1", float, VisibilityInputs.m_flAlphaScaleMax ) \
  971. DMXELEMENT_UNPACK_FIELD( "Visibility Radius Scale minimum","1", float, VisibilityInputs.m_flRadiusScaleMin ) \
  972. DMXELEMENT_UNPACK_FIELD( "Visibility Radius Scale maximum","1", float, VisibilityInputs.m_flRadiusScaleMax ) \
  973. DMXELEMENT_UNPACK_FIELD( "Visibility Radius FOV Scale base","0", float, VisibilityInputs.m_flRadiusScaleFOVBase )
  974. #define REGISTER_PARTICLE_OPERATOR( _type, _className ) \
  975. g_pParticleSystemMgr->AddParticleOperator( _type, &s_##_className##Factory )
  976. // need to think about particle constraints in terms of segregating affected particles so as to
  977. // run multi-pass constraints on only a subset
  978. //-----------------------------------------------------------------------------
  979. // flags for particle systems
  980. //-----------------------------------------------------------------------------
  981. enum
  982. {
  983. PCFLAGS_FIRST_FRAME = 0x1,
  984. PCFLAGS_PREV_CONTROL_POINTS_INITIALIZED = 0x2,
  985. };
  986. #define DEBUG_PARTICLE_SORT 0
  987. //------------------------------------------------------------------------------
  988. // particle render helpers
  989. //------------------------------------------------------------------------------
  990. struct CParticleVisibilityData
  991. {
  992. float m_flAlphaVisibility;
  993. float m_flRadiusVisibility;
  994. bool m_bUseVisibility;
  995. };
  996. // sorting functionality for rendering. Call GetRenderList( bool bSorted ) to get the list of
  997. // particles to render (sorted or not, including children).
  998. // **do not casually change this structure**. The sorting code treats it interchangably as an SOA
  999. // and accesses it using sse. Any changes to this struct need the sort code updated.**
  1000. struct ParticleRenderData_t
  1001. {
  1002. float m_flSortKey; // what we sort by
  1003. int m_nIndex; // index or fudged index (for child particles)
  1004. float m_flRadius; // effective radius, using visibility
  1005. #if PLAT_LITTLE_ENDIAN
  1006. uint8 m_nAlpha; // effective alpha, combining alpha and alpha2 and vis. 0 - 255
  1007. uint8 m_nAlphaPad[3]; // this will be written to
  1008. #endif
  1009. #if PLAT_BIG_ENDIAN
  1010. uint8 m_nAlphaPad[3]; // this will be written to
  1011. uint8 m_nAlpha; // effective alpha, combining alpha and alpha2 and vis. 0 - 255
  1012. #endif
  1013. };
  1014. struct ExtendedParticleRenderData_t : ParticleRenderData_t
  1015. {
  1016. float m_flX;
  1017. float m_flY;
  1018. float m_flZ;
  1019. float m_flPad;
  1020. };
  1021. typedef struct ALIGN16 _FourInts
  1022. {
  1023. int32 m_nValue[4];
  1024. } ALIGN16_POST FourInts;
  1025. struct ParticleBaseRenderData_SIMD_View
  1026. {
  1027. fltx4 m_fl4SortKey;
  1028. FourVectors m_fl4XYZ;
  1029. fltx4 m_fl4Alpha;
  1030. fltx4 m_fl4Red;
  1031. fltx4 m_fl4Green;
  1032. fltx4 m_fl4Blue;
  1033. fltx4 m_fl4Radius;
  1034. fltx4 m_fl4AnimationTimeValue;
  1035. fltx4 m_fl4SequenceID; // 56 bytes per particle
  1036. };
  1037. struct ParticleFullRenderData_SIMD_View : public ParticleBaseRenderData_SIMD_View
  1038. {
  1039. fltx4 m_fl4Rotation;
  1040. fltx4 m_fl4Yaw;
  1041. // no-op operation so templates can compile
  1042. FORCEINLINE void SetARGB2( fltx4 const &fl4Red, fltx4 const &fl4Green, fltx4 const &fl4Blue, fltx4 const &fl4Alpha )
  1043. {
  1044. }
  1045. FORCEINLINE void SetNormal( fltx4 const &fl4NormalX, fltx4 const &fl4NormalY, fltx4 const &fl4NormalZ )
  1046. {
  1047. }
  1048. };
  1049. struct ParticleRenderDataWithOutlineInformation_SIMD_View : public ParticleFullRenderData_SIMD_View
  1050. {
  1051. FourVectors m_v4Color2;
  1052. fltx4 m_fl4Alpha2;
  1053. FORCEINLINE void SetARGB2( fltx4 const &fl4Red, fltx4 const &fl4Green, fltx4 const &fl4Blue, fltx4 const &fl4Alpha )
  1054. {
  1055. m_v4Color2.x = fl4Red;
  1056. m_v4Color2.y = fl4Green;
  1057. m_v4Color2.z = fl4Blue;
  1058. m_fl4Alpha2 = fl4Alpha;
  1059. }
  1060. };
  1061. struct ParticleRenderDataWithNormal_SIMD_View : public ParticleFullRenderData_SIMD_View
  1062. {
  1063. FourVectors m_v4Normal;
  1064. FORCEINLINE void SetNormal( fltx4 const &fl4NormalX, fltx4 const &fl4NormalY, fltx4 const &fl4NormalZ )
  1065. {
  1066. m_v4Normal.x = fl4NormalX;
  1067. m_v4Normal.y = fl4NormalY;
  1068. m_v4Normal.z = fl4NormalZ;
  1069. }
  1070. };
  1071. // definitions for byte fields ( colors ). endian-ness matters here.
  1072. #if PLAT_LITTLE_ENDIAN
  1073. #define BYTE_FIELD(x) \
  1074. uint8 x; \
  1075. uint8 x##_Pad[3 + 3 * 4 ];
  1076. #endif
  1077. #if PLAT_BIG_ENDIAN
  1078. #define BYTE_FIELD(x) \
  1079. uint8 x##_Pad0[3]; \
  1080. uint8 x; \
  1081. uint8 x##_Pad[3 * 4 ];
  1082. #endif
  1083. #define FLOAT_FIELD( x ) \
  1084. float x; \
  1085. float x##_Pad[3];
  1086. struct ParticleBaseRenderData_Scalar_View
  1087. {
  1088. int32 m_nSortKey;
  1089. int32 m_nPad00[3];
  1090. FLOAT_FIELD( m_flX );
  1091. FLOAT_FIELD( m_flY );
  1092. FLOAT_FIELD( m_flZ );
  1093. BYTE_FIELD( m_nAlpha );
  1094. BYTE_FIELD( m_nRed );
  1095. BYTE_FIELD( m_nGreen );
  1096. BYTE_FIELD( m_nBlue );
  1097. FLOAT_FIELD( m_flRadius );
  1098. FLOAT_FIELD( m_flAnimationTimeValue );
  1099. #if PLAT_LITTLE_ENDIAN
  1100. uint8 m_nSequenceID;
  1101. uint8 m_nSequenceID1;
  1102. uint8 m_nPadSequence[2 + 3 * 4];
  1103. #endif
  1104. #if PLAT_BIG_ENDIAN
  1105. uint8 m_nPadSequence[2];
  1106. uint8 m_nSequenceID1;
  1107. uint8 m_nSequenceID;
  1108. uint8 m_nPadSequence1[ 3 * 4];
  1109. #endif
  1110. };
  1111. struct ParticleFullRenderData_Scalar_View : public ParticleBaseRenderData_Scalar_View
  1112. {
  1113. FLOAT_FIELD( m_flRotation );
  1114. FLOAT_FIELD( m_flYaw );
  1115. float Red2( void ) const { return 1.0; }
  1116. float Green2( void ) const { return 1.0; }
  1117. float Blue2( void ) const { return 1.0; }
  1118. float Alpha2( void ) const { return 1.0; }
  1119. float NormalX( void ) const { return 1.0; }
  1120. float NormalY( void ) const { return 1.0; }
  1121. float NormalZ( void ) const { return 1.0; }
  1122. };
  1123. struct ParticleRenderDataWithOutlineInformation_Scalar_View : public ParticleFullRenderData_Scalar_View
  1124. {
  1125. FLOAT_FIELD( m_flRed2 );
  1126. FLOAT_FIELD( m_flGreen2 );
  1127. FLOAT_FIELD( m_flBlue2 );
  1128. FLOAT_FIELD( m_flAlpha2 );
  1129. float Red2( void ) const { return m_flRed2; }
  1130. float Green2( void ) const { return m_flGreen2; }
  1131. float Blue2( void ) const { return m_flBlue2; }
  1132. float Alpha2( void ) const { return m_flAlpha2; }
  1133. };
  1134. struct ParticleRenderDataWithNormal_Scalar_View : public ParticleFullRenderData_Scalar_View
  1135. {
  1136. FLOAT_FIELD( m_flNormalX );
  1137. FLOAT_FIELD( m_flNormalY );
  1138. FLOAT_FIELD( m_flNormalZ );
  1139. float NormalX( void ) const { return m_flNormalX; }
  1140. float NormalY( void ) const { return m_flNormalY; }
  1141. float NormalZ( void ) const { return m_flNormalZ; }
  1142. };
  1143. ParticleFullRenderData_Scalar_View **GetExtendedRenderList( CParticleCollection *pParticles,
  1144. IMatRenderContext *pRenderContext,
  1145. bool bSorted, int *pNparticles,
  1146. CParticleVisibilityData *pVisibilityData);
  1147. ParticleRenderDataWithOutlineInformation_Scalar_View **GetExtendedRenderListWithPerParticleGlow(
  1148. CParticleCollection *pParticles,
  1149. IMatRenderContext *pRenderContext,
  1150. bool bSorted, int *pNparticles,
  1151. CParticleVisibilityData *pVisibilityData );
  1152. ParticleRenderDataWithNormal_Scalar_View **GetExtendedRenderListWithNormals(
  1153. CParticleCollection *pParticles,
  1154. IMatRenderContext *pRenderContext,
  1155. bool bSorted, int *pNparticles,
  1156. CParticleVisibilityData *pVisibilityData );
  1157. // returns # of particles
  1158. int GenerateExtendedSortedIndexList( Vector vecCamera, Vector *pCameraFwd, CParticleVisibilityData *pVisibilityData,
  1159. CParticleCollection *pParticles, bool bSorted, void *pOutBuf,
  1160. ParticleFullRenderData_Scalar_View **pParticlePtrs );
  1161. //------------------------------------------------------------------------------
  1162. // CParticleSnapshot wraps a CSOAContainer, so that a particle system
  1163. // can write to it or read from it (e.g. this can be attached to a control point).
  1164. //------------------------------------------------------------------------------
  1165. class CParticleSnapshot
  1166. {
  1167. DECLARE_DMXELEMENT_UNPACK();
  1168. public:
  1169. CParticleSnapshot() { Purge(); }
  1170. ~CParticleSnapshot() { Purge(); }
  1171. struct AttributeMap
  1172. {
  1173. AttributeMap( int nContainerAttribute, int nParticleAttribute ) : m_nContainerAttribute( nContainerAttribute ), m_nParticleAttribute( nParticleAttribute ) {}
  1174. int m_nContainerAttribute, m_nParticleAttribute;
  1175. };
  1176. typedef CUtlVector< AttributeMap > AttributeMapVector;
  1177. // Has the CParticleSnapshot been fully initialized?
  1178. bool IsValid( void ) { return !!m_pContainer; }
  1179. // Initialize from a .psf DMX file:
  1180. bool Unserialize( const char *pFullPath );
  1181. // Serialize to a .psf DMX file (NOTE: external containers will serialize out fine, but won't be external when read back in)
  1182. bool Serialize( const char *pFullPath, bool bTextMode = true ); // TODO: once this stabilizes, switch to binary mode
  1183. // Initialize by creating a new container, with a specified attribute mapping (will clear out old data if it exists)
  1184. // - each map entry specifies container attribute and associated particle attribute
  1185. // - the mapping should be one-to-one (container attributes are 'labeled' with particle attributes),
  1186. // so each particle attribute and container field should be used *AT MOST* once
  1187. // - NOTE: many-to-one and one-to-many mappings may be implemented by particle read/write operators
  1188. bool Init( int nX, int nY, int nZ, const AttributeMapVector &attributeMaps );
  1189. // Same as the other Init, except the attribute mapping are specified with varargs instead of a vector
  1190. // (pairs of int params specify container attribute and associated particle attribute, terminated by -1)
  1191. bool Init( int nX, int nY, int nZ, ... );
  1192. // Initialize by wrapping a pre-existing container, with a specified attribute mapping
  1193. // - same conditions/parameters as above
  1194. // - existing container attributes are expected to match the particle attribute data types
  1195. // - if a new attribute is added to the external container, call InitExternal again to update the snapshot
  1196. bool InitExternal( CSOAContainer *pContainer, const AttributeMapVector &attributeMaps );
  1197. bool InitExternal( CSOAContainer *pContainer, ... );
  1198. // Clear the snapshot (and container) back to its initial state
  1199. void Purge( void );
  1200. // This provides READ-ONLY access to the snapshot's container (all write accessors should have wrappers here, to ensure
  1201. // that the container's set of attributes is not modified, which would invalidate the snapshot attribute mapping table)
  1202. const CSOAContainer *GetContainer( void ) { return m_pContainer; }
  1203. // Does the snapshot have data (of the appropriate type) for the given particle attribute?
  1204. bool HasAttribute( int nParticleAttribute, EAttributeDataType nDataType ) const
  1205. {
  1206. Assert( ( nParticleAttribute >= 0 ) && ( nParticleAttribute < MAX_PARTICLE_ATTRIBUTES ) );
  1207. int nContainerIndex = m_ParticleAttributeToContainerAttribute[ nParticleAttribute ];
  1208. return ( ( nContainerIndex != -1 ) && ( m_pContainer->GetAttributeType( nContainerIndex ) == nDataType ) );
  1209. }
  1210. // ---------- Wrappers for CSOAContainer members ----------
  1211. int NumCols( void ) { return m_pContainer->NumCols(); }
  1212. int NumRows( void ) { return m_pContainer->NumRows(); }
  1213. int NumSlices( void ) { return m_pContainer->NumSlices(); }
  1214. // Read data from the container for the given particle attribute, at index (nIndex,0,0)
  1215. template<class T> T *ElementPointer( int nParticleAttribute, int nX = 0, int nY = 0, int nZ = 0 ) const
  1216. {
  1217. Assert( ( nParticleAttribute >= 0 ) && ( nParticleAttribute < MAX_PARTICLE_ATTRIBUTES ) );
  1218. Assert( m_ParticleAttributeToContainerAttribute[ nParticleAttribute ] != -1 );
  1219. return m_pContainer->ElementPointer<T>( m_ParticleAttributeToContainerAttribute[ nParticleAttribute ], nX, nY, nZ );
  1220. }
  1221. FourVectors *ElementPointer4V( int nParticleAttribute, int nX = 0, int nY = 0, int nZ = 0 ) const
  1222. {
  1223. Assert( ( nParticleAttribute >= 0 ) && ( nParticleAttribute < MAX_PARTICLE_ATTRIBUTES ) );
  1224. Assert( m_ParticleAttributeToContainerAttribute[ nParticleAttribute ] != -1 );
  1225. return m_pContainer->ElementPointer4V( m_ParticleAttributeToContainerAttribute[ nParticleAttribute ], nX, nY, nZ );
  1226. }
  1227. // ---------- Wrappers for CSOAContainer members ----------
  1228. private:
  1229. enum ParticleSnapshotDmxVersion_t { PARTICLE_SNAPSHOT_DMX_VERSION = 1 };
  1230. // Whether we're using an external container (as opposed to our embedded one)
  1231. bool UsingExternalContainer( void ) { return ( m_pContainer && ( m_pContainer != &m_Container ) ); }
  1232. // Utility function used by the Init methods to add+validate an attribute mapping pair:
  1233. bool AddAttributeMapping( int nFieldNumber, int nParticleAttribute, const char *pFunc );
  1234. // Utility function used by the Init methods to validate data types for an attribute mapping pair:
  1235. bool ValidateAttributeMapping( int nFieldNumber, int nParticleAttribute, const char *pFunc );
  1236. // Utility function to validate the embedded container after it is unserialized
  1237. bool EmbeddedContainerIsValid( void );
  1238. // Check whether the particle system's defined attributes have been changed (this won't compile if they have), so we can update the serialization code if need be
  1239. void CheckParticleAttributesForChanges( void );
  1240. CSOAContainer m_Container; // Embedded container
  1241. CSOAContainer * m_pContainer; // Pointer either to the embedded container or an external one
  1242. // For each particle attribute, this contains the index of the corresponding container attribute (-1 means 'none')
  1243. int m_ParticleAttributeToContainerAttribute[ MAX_PARTICLE_ATTRIBUTES ];
  1244. int m_ContainerAttributeToParticleAttribute[ MAX_SOA_FIELDS ]; // Reverse mapping (used for error-checking)
  1245. };
  1246. //------------------------------------------------------------------------------
  1247. // structure describing the parameter block used by operators which use the path between two points to
  1248. // control particles.
  1249. //------------------------------------------------------------------------------
  1250. struct CPathParameters
  1251. {
  1252. int m_nStartControlPointNumber;
  1253. int m_nEndControlPointNumber;
  1254. int m_nBulgeControl;
  1255. float m_flBulge;
  1256. float m_flMidPoint;
  1257. void ClampControlPointIndices( void )
  1258. {
  1259. m_nStartControlPointNumber = MAX(0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartControlPointNumber ) );
  1260. m_nEndControlPointNumber = MAX(0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nEndControlPointNumber ) );
  1261. }
  1262. };
  1263. struct CParticleControlPoint
  1264. {
  1265. Vector m_Position;
  1266. Vector m_PrevPosition;
  1267. // orientation
  1268. Vector m_ForwardVector;
  1269. Vector m_UpVector;
  1270. Vector m_RightVector;
  1271. // reference to entity or whatever this control point comes from
  1272. void *m_pObject;
  1273. // parent for hierarchies
  1274. int m_nParent;
  1275. // CParticleSnapshot which particles can read data from or write data to:
  1276. CParticleSnapshot *m_pSnapshot;
  1277. };
  1278. struct CParticleCPInfo
  1279. {
  1280. CParticleControlPoint m_ControlPoint;
  1281. CModelHitBoxesInfo m_CPHitBox;
  1282. };
  1283. // struct for simd xform to transform a point from an identitiy coordinate system to that of the control point
  1284. struct CParticleSIMDTransformation
  1285. {
  1286. FourVectors m_v4Origin;
  1287. FourVectors m_v4Fwd;
  1288. FourVectors m_v4Up;
  1289. FourVectors m_v4Right;
  1290. FORCEINLINE void VectorRotate( FourVectors &InPnt )
  1291. {
  1292. fltx4 fl4OutX = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.x ), MulSIMD( InPnt.z, m_v4Up.x ) ), MulSIMD( InPnt.y, m_v4Right.x ) );
  1293. fltx4 fl4OutY = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.y ), MulSIMD( InPnt.z, m_v4Up.y ) ), MulSIMD( InPnt.y, m_v4Right.y ) );
  1294. InPnt.z = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.z ), MulSIMD( InPnt.z, m_v4Up.z ) ), MulSIMD( InPnt.y, m_v4Right.z ) );
  1295. InPnt.x = fl4OutX;
  1296. InPnt.y = fl4OutY;
  1297. }
  1298. FORCEINLINE void VectorTransform( FourVectors &InPnt )
  1299. {
  1300. VectorRotate( InPnt );
  1301. InPnt.x = AddSIMD( InPnt.x, m_v4Origin.x );
  1302. InPnt.y = AddSIMD( InPnt.y, m_v4Origin.y );
  1303. InPnt.z = AddSIMD( InPnt.z, m_v4Origin.z );
  1304. }
  1305. };
  1306. #define NUM_COLLISION_CACHE_MODES 4
  1307. //-----------------------------------------------------------------------------
  1308. //
  1309. // CParticleCollection
  1310. //
  1311. //-----------------------------------------------------------------------------
  1312. enum EParticleRestartMode_t
  1313. {
  1314. RESTART_NORMAL, // just reset emitters
  1315. RESTART_RESET_AND_MAKE_SURE_EMITS_HAPPEN, // reset emitters. If another restart has already happened, emit particles right now to handle multiple resets per frame.
  1316. };
  1317. struct CParticleAttributeAddressTable
  1318. {
  1319. float *m_pAttributes[MAX_PARTICLE_ATTRIBUTES];
  1320. size_t m_nFloatStrides[MAX_PARTICLE_ATTRIBUTES];
  1321. FORCEINLINE size_t Stride( int nAttr ) const
  1322. {
  1323. return m_nFloatStrides[nAttr];
  1324. }
  1325. FORCEINLINE float *Address( int nAttr ) const
  1326. {
  1327. return m_pAttributes[nAttr];
  1328. }
  1329. FORCEINLINE uint8 *ByteAddress( int nAttr ) const
  1330. {
  1331. return ( uint8 * ) m_pAttributes[nAttr];
  1332. }
  1333. FORCEINLINE float *FloatAttributePtr( int nAttribute, int nParticleNumber ) const
  1334. {
  1335. int block_ofs = nParticleNumber / 4;
  1336. return m_pAttributes[ nAttribute ] +
  1337. m_nFloatStrides[ nAttribute ] * block_ofs +
  1338. ( nParticleNumber & 3 );
  1339. }
  1340. void CopyParticleAttributes( int nSrcIndex, int nDestIndex ) const;
  1341. };
  1342. //-----------------------------------------------------------------------------
  1343. // CCachedParticleBatches
  1344. //
  1345. // Caches up to MAX_CACHED_PARTICLE_BATCHES particle batches. The
  1346. // ICachedPerFrameMeshData comes from the dynamic mesh created when rendering
  1347. // the particles the first time. This cache is only valid for a single frame.
  1348. //
  1349. // Only certain particle systems work with caching. The particle sytem must
  1350. // not sort, must not alter vertices on the CPU based upon view data, and must
  1351. // not be rendering in mat_queue_mode 0. SpriteTrail particle system that use
  1352. // the spritecard shader cache their particle batches for reuse throughout the
  1353. // frame.
  1354. //-----------------------------------------------------------------------------
  1355. #define MAX_CACHED_PARTICLE_BATCHES 8
  1356. class CCachedParticleBatches
  1357. {
  1358. public:
  1359. uint32 m_nLastValidParticleCacheFrame;
  1360. int m_nCachedRenderListCount;
  1361. ICachedPerFrameMeshData *m_pCachedBatches[ MAX_CACHED_PARTICLE_BATCHES ];
  1362. CCachedParticleBatches() : m_nLastValidParticleCacheFrame( (uint32)-1 ), m_nCachedRenderListCount( 0 )
  1363. {
  1364. Q_memset( m_pCachedBatches, 0, sizeof( ICachedPerFrameMeshData* ) * MAX_CACHED_PARTICLE_BATCHES );
  1365. }
  1366. ~CCachedParticleBatches()
  1367. {
  1368. ClearBatches();
  1369. }
  1370. FORCEINLINE void ClearBatches()
  1371. {
  1372. m_nCachedRenderListCount = 0;
  1373. for ( int i=0; i<MAX_CACHED_PARTICLE_BATCHES; ++i )
  1374. {
  1375. if ( m_pCachedBatches[ i ] )
  1376. m_pCachedBatches[ i ]->Free();
  1377. m_pCachedBatches[ i ] = NULL;
  1378. }
  1379. }
  1380. FORCEINLINE void SetCachedBatch( int nBatch, ICachedPerFrameMeshData* pBatch )
  1381. {
  1382. if ( nBatch >= MAX_CACHED_PARTICLE_BATCHES )
  1383. return;
  1384. m_pCachedBatches[ nBatch ] = pBatch;
  1385. }
  1386. FORCEINLINE ICachedPerFrameMeshData *GetCachedBatch( int nBatch )
  1387. {
  1388. if ( nBatch >= MAX_CACHED_PARTICLE_BATCHES )
  1389. return NULL;
  1390. return m_pCachedBatches[ nBatch ];
  1391. }
  1392. FORCEINLINE void SetCachedRenderListCount( int nParticleCount )
  1393. {
  1394. m_nCachedRenderListCount = nParticleCount;
  1395. }
  1396. FORCEINLINE int GetCachedRenderListCount()
  1397. {
  1398. return m_nCachedRenderListCount;
  1399. }
  1400. };
  1401. class CParticleCollection
  1402. {
  1403. public:
  1404. ~CParticleCollection( void );
  1405. // Restarts the particle collection, stopping all non-continuous emitters
  1406. void Restart( EParticleRestartMode_t eMode = RESTART_NORMAL );
  1407. // compute bounds from particle list
  1408. void RecomputeBounds( void );
  1409. void SetControlPoint( int nWhichPoint, const Vector &v );
  1410. void SetControlPointObject( int nWhichPoint, void *pObject );
  1411. void SetControlPointOrientation( int nWhichPoint, const Vector &forward,
  1412. const Vector &right, const Vector &up );
  1413. void SetControlPointForwardVector( int nWhichPoint, const Vector &v );
  1414. void SetControlPointUpVector( int nWhichPoint, const Vector &v );
  1415. void SetControlPointRightVector( int nWhichPoint, const Vector &v );
  1416. void SetControlPointParent( int nWhichPoint, int n );
  1417. void SetControlPointSnapshot( int nWhichPoint, CParticleSnapshot *pSnapshot );
  1418. void SetControlPointOrientation( int nWhichPoint, const Quaternion &q );
  1419. // get the pointer to an attribute for a given particle.
  1420. // !!speed!! if you find yourself calling this anywhere that matters,
  1421. // you're not handling the simd-ness of the particle system well
  1422. // and will have bad perf.
  1423. const float *GetFloatAttributePtr( int nAttribute, int nParticleNumber ) const;
  1424. const int *GetIntAttributePtr( int nAttribute, int nParticleNumber ) const;
  1425. const fltx4 *GetM128AttributePtr( int nAttribute, size_t *pStrideOut ) const;
  1426. const FourVectors *Get4VAttributePtr( int nAttribute, size_t *pStrideOut ) const;
  1427. const FourInts *Get4IAttributePtr( int nAttribute, size_t *pStrideOut ) const;
  1428. const int *GetIntAttributePtr( int nAttribute, size_t *pStrideOut ) const;
  1429. Vector GetVectorAttributeValue( int nAttribute, int nParticleNumber ) const;
  1430. float GetFloatAttributeValue( int nAttribute, int nParticleNumber ) const;
  1431. int *GetIntAttributePtrForWrite( int nAttribute, int nParticleNumber );
  1432. float *GetFloatAttributePtrForWrite( int nAttribute, int nParticleNumber );
  1433. fltx4 *GetM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut );
  1434. FourVectors *Get4VAttributePtrForWrite( int nAttribute, size_t *pStrideOut );
  1435. const float *GetInitialFloatAttributePtr( int nAttribute, int nParticleNumber ) const;
  1436. const fltx4 *GetInitialM128AttributePtr( int nAttribute, size_t *pStrideOut ) const;
  1437. const FourVectors *GetInitial4VAttributePtr( int nAttribute, size_t *pStrideOut ) const;
  1438. float *GetInitialFloatAttributePtrForWrite( int nAttribute, int nParticleNumber );
  1439. fltx4 *GetInitialM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut );
  1440. void Simulate( float dt );
  1441. void SkipToTime( float t );
  1442. // the camera objetc may be compared for equality against control point objects
  1443. void Render( int nViewRecursionLevel, IMatRenderContext *pRenderContext, const Vector4D &vecDiffuseModulation, bool bTranslucentOnly = false, void *pCameraObject = NULL );
  1444. bool IsValid( void ) const { return m_pDef != NULL; }
  1445. // this system and all children are valid
  1446. bool IsFullyValid( void ) const;
  1447. const char *GetName() const;
  1448. bool DependsOnSystem( const char *pName ) const;
  1449. // IsFinished returns true when a system has no particles and won't be creating any more
  1450. bool IsFinished( void ) const;
  1451. // Used to make sure we're accessing valid memory
  1452. bool IsValidAttributePtr( int nAttribute, const void *pPtr ) const;
  1453. void SwapPosAndPrevPos( void );
  1454. void SetNActiveParticles( int nCount );
  1455. void KillParticle(int nPidx, unsigned int nFlags = 0);
  1456. void StopEmission( bool bInfiniteOnly = false, bool bRemoveAllParticles = false, bool bWakeOnStop = false, bool bPlayEndCap = false );
  1457. void StartEmission( bool bInfiniteOnly = false );
  1458. void SetDormant( bool bDormant );
  1459. bool IsEmitting() const;
  1460. const Vector& GetControlPointAtCurrentTime( int nControlPoint ) const;
  1461. void GetControlPointOrientationAtCurrentTime( int nControlPoint, Vector *pForward, Vector *pRight, Vector *pUp ) const;
  1462. void GetControlPointTransformAtCurrentTime( int nControlPoint, matrix3x4_t *pMat );
  1463. void GetControlPointTransformAtCurrentTime( int nControlPoint, VMatrix *pMat );
  1464. int GetControlPointParent( int nControlPoint ) const;
  1465. CParticleSnapshot *GetControlPointSnapshot( int nWhichPoint ) const;
  1466. // Used to retrieve the position of a control point
  1467. // somewhere between m_fCurTime and m_fCurTime - m_fPreviousDT
  1468. void GetControlPointAtTime( int nControlPoint, float flTime, Vector *pControlPoint );
  1469. void GetControlPointAtPrevTime( int nControlPoint, Vector *pControlPoint );
  1470. void GetControlPointOrientationAtTime( int nControlPoint, float flTime, Vector *pForward, Vector *pRight, Vector *pUp );
  1471. void GetControlPointTransformAtTime( int nControlPoint, float flTime, matrix3x4_t *pMat );
  1472. void GetControlPointTransformAtTime( int nControlPoint, float flTime, VMatrix *pMat );
  1473. void GetControlPointTransformAtTime( int nControlPoint, float flTime, CParticleSIMDTransformation *pXForm );
  1474. int GetHighestControlPoint( void ) const;
  1475. // Control point accessed:
  1476. // NOTE: Unlike the definition's version of these methods,
  1477. // these OR-in the masks of their children.
  1478. bool ReadsControlPoint( int nPoint ) const;
  1479. bool IsNonPositionalControlPoint( int nPoint ) const;
  1480. // Used by particle systems to generate random numbers. Do not call these methods - use sse
  1481. // code
  1482. int RandomInt( int nMin, int nMax );
  1483. float RandomFloat( float flMin, float flMax );
  1484. float RandomFloatExp( float flMin, float flMax, float flExponent );
  1485. void RandomVector( float flMin, float flMax, Vector *pVector );
  1486. void RandomVector( const Vector &vecMin, const Vector &vecMax, Vector *pVector );
  1487. float RandomVectorInUnitSphere( Vector *pVector ); // Returns the length sqr of the vector
  1488. // NOTE: These versions will produce the *same random numbers* if you give it the same random
  1489. // sample id. do not use these methods.
  1490. int RandomInt( int nRandomSampleId, int nMin, int nMax );
  1491. float RandomFloat( int nRandomSampleId, float flMin, float flMax );
  1492. float RandomFloatExp( int nRandomSampleId, float flMin, float flMax, float flExponent );
  1493. void RandomVector( int nRandomSampleId, float flMin, float flMax, Vector *pVector );
  1494. void RandomVector( int nRandomSampleId, const Vector &vecMin, const Vector &vecMax, Vector *pVector );
  1495. float RandomVectorInUnitSphere( int nRandomSampleId, Vector *pVector ); // Returns the length sqr of the vector
  1496. fltx4 RandomFloat( const FourInts &ParticleID, int nRandomSampleOffset );
  1497. // Random number offset (for use in getting Random #s in operators)
  1498. int OperatorRandomSampleOffset() const;
  1499. // Returns the render bounds
  1500. void GetBounds( Vector *pMin, Vector *pMax );
  1501. // Visualize operators (for editing/debugging)
  1502. void VisualizeOperator( const DmObjectId_t *pOpId = NULL );
  1503. // Does the particle system use the power of two frame buffer texture (refraction?)
  1504. bool UsesPowerOfTwoFrameBufferTexture( bool bThisFrame ) const;
  1505. // Does the particle system use the full frame buffer texture (soft particles)
  1506. bool UsesFullFrameBufferTexture( bool bThisFrame ) const;
  1507. // Is the particle system translucent?
  1508. bool IsTranslucent() const;
  1509. // Is the particle system two-pass?
  1510. bool IsTwoPass() const;
  1511. // Is the particle system batchable?
  1512. bool IsBatchable() const;
  1513. // Is the order of the particles important
  1514. bool IsOrderImportant() const;
  1515. // Should this system be run want to read its parent's kill list inside ApplyKillList?
  1516. bool ShouldRunForParentApplyKillList( void ) const;
  1517. // Renderer iteration
  1518. int GetRendererCount() const;
  1519. CParticleOperatorInstance *GetRenderer( int i );
  1520. void *GetRendererContext( int i );
  1521. bool CheckIfOperatorShouldRun( CParticleOperatorInstance const * op, float *pflCurStrength, bool bApplyingParentKillList = false );
  1522. Vector TransformAxis( const Vector &SrcAxis, bool bLocalSpace, int nControlPointNumber = 0);
  1523. // return backwards-sorted particle list. use --addressing
  1524. const ParticleRenderData_t *GetRenderList( IMatRenderContext *pRenderContext, bool bSorted, int *pNparticles, CParticleVisibilityData *pVisibilityData );
  1525. // calculate the points of a curve for a path
  1526. void CalculatePathValues( CPathParameters const &PathIn,
  1527. float flTimeStamp,
  1528. Vector *pStartPnt,
  1529. Vector *pMidPnt,
  1530. Vector *pEndPnt
  1531. );
  1532. int GetGroupID() const;
  1533. void InitializeNewParticles( int nFirstParticle, int nParticleCount, uint32 nInittedMask, bool bApplyingParentKillList = false );
  1534. // update hit boxes for control point if not updated yet for this sim step
  1535. void UpdateHitBoxInfo( int nControlPointNumber, const char *pszHitboxSetName );
  1536. // Used by particle system definitions to manage particle collection lists
  1537. void UnlinkFromDefList( );
  1538. FORCEINLINE uint8 const *GetPrevAttributeMemory( void ) const
  1539. {
  1540. return m_pPreviousAttributeMemory;
  1541. }
  1542. FORCEINLINE uint8 const *GetAttributeMemory( void ) const
  1543. {
  1544. return m_pParticleMemory;
  1545. }
  1546. FORCEINLINE bool IsUsingInterpolatedRendering( void ) const
  1547. {
  1548. return (
  1549. ( m_flTargetDrawTime < m_flCurTime ) &&
  1550. ( m_flTargetDrawTime >= m_flPrevSimTime ) &&
  1551. ( GetPrevAttributeMemory() ) &&
  1552. ( ! m_bFrozen ) );
  1553. }
  1554. void ResetParticleCache();
  1555. CCachedParticleBatches *GetCachedParticleBatches();
  1556. // render helpers
  1557. int GenerateCulledSortedIndexList( ParticleRenderData_t *pOut, Vector vecCamera, Vector vecFwd, CParticleVisibilityData *pVisibilityData, bool bSorted );
  1558. int GenerateSortedIndexList( ParticleRenderData_t *pOut, Vector vecCameraPos, CParticleVisibilityData *pVisibilityData, bool bSorted );
  1559. CParticleCollection *GetNextCollectionUsingSameDef() { return m_pNextDef; }
  1560. CUtlReference< CSheet > m_Sheet;
  1561. bool m_bTriedLoadingSheet;
  1562. protected:
  1563. CParticleCollection( );
  1564. // Used by client code
  1565. bool Init( const char *pParticleSystemName );
  1566. bool Init( CParticleSystemDefinition *pDef );
  1567. // Bloat the bounding box by bounds around the control point
  1568. void BloatBoundsUsingControlPoint();
  1569. // to run emitters on restart, out of main sim.
  1570. void RunRestartedEmitters( void );
  1571. void SetRenderable( void *pRenderable );
  1572. private:
  1573. void Init( CParticleSystemDefinition *pDef, float flDelay, int nRandomSeed );
  1574. void InitStorage( CParticleSystemDefinition *pDef );
  1575. void InitParticleCreationTime( int nFirstParticle, int nNumToInit );
  1576. void CopyInitialAttributeValues( int nStartParticle, int nNumParticles );
  1577. void ApplyKillList( void );
  1578. void SetAttributeToConstant( int nAttribute, float fValue );
  1579. void SetAttributeToConstant( int nAttribute, float fValueX, float fValueY, float fValueZ );
  1580. void InitParticleAttributes( int nStartParticle, int nNumParticles, int nAttrsLeftToInit );
  1581. // call emitter and initializer operators on the specified system
  1582. // NOTE: this may be called from ApplyKillList, so the child can access about-to-be-killed particles
  1583. static void EmitAndInit( CParticleCollection *pCollection, bool bApplyingParentKillList = false );
  1584. // initialize this attribute for all active particles
  1585. void FillAttributeWithConstant( int nAttribute, float fValue );
  1586. // Updates the previous control points
  1587. void UpdatePrevControlPoints( float dt );
  1588. // Returns the memory for a particular constant attribute
  1589. float *GetConstantAttributeMemory( int nAttribute );
  1590. // Swaps two particles in the particle list
  1591. void SwapAdjacentParticles( int hParticle );
  1592. // Unlinks a particle from the list
  1593. void UnlinkParticle( int hParticle );
  1594. // Inserts a particle before another particle in the list
  1595. void InsertParticleBefore( int hParticle, int hBefore );
  1596. // Move a particle from one index to another
  1597. void MoveParticle( int nInitialIndex, int nNewIndex );
  1598. // Computes the sq distance to a particle position
  1599. float ComputeSqrDistanceToParticle( int hParticle, const Vector &vecPosition ) const;
  1600. // Grows the dist sq range for all particles
  1601. void GrowDistSqrBounds( float flDistSqr );
  1602. // Simulates the first frame
  1603. void SimulateFirstFrame( );
  1604. bool SystemContainsParticlesWithBoolSet( bool CParticleCollection::*pField ) const;
  1605. // Does the particle collection contain opaque particle systems
  1606. bool ContainsOpaqueCollections();
  1607. bool ComputeUsesPowerOfTwoFrameBufferTexture();
  1608. bool ComputeUsesFullFrameBufferTexture();
  1609. bool ComputeIsTranslucent();
  1610. bool ComputeIsTwoPass();
  1611. bool ComputeIsBatchable();
  1612. bool ComputeIsOrderImportant();
  1613. bool ComputeRunForParentApplyKillList();
  1614. void LabelTextureUsage( void );
  1615. void LinkIntoDefList( );
  1616. // Return the number of particle systems sharing the same definition
  1617. int GetCurrentParticleDefCount( CParticleSystemDefinition* pDef );
  1618. void CopyParticleAttributesToPreviousAttributes( void ) const;
  1619. public:
  1620. fltx4 m_fl4CurTime; // accumulated time
  1621. int m_nPaddedActiveParticles; // # of groups of 4 particles
  1622. float m_flCurTime; // accumulated time
  1623. // support for simulating particles at < the frame rate and interpolating.
  1624. // for a system simulating at lower frame rate, flDrawTime will be < m_flCurTime and >=m_flPrevSimTime
  1625. float m_flPrevSimTime; // the time of the previous sim
  1626. float m_flTargetDrawTime; // the timestamp for drawing
  1627. int m_nActiveParticles; // # of active particles
  1628. float m_flDt;
  1629. float m_flPreviousDt;
  1630. float m_flNextSleepTime; // time to go to sleep if not drawn
  1631. CUtlReference< CParticleSystemDefinition > m_pDef;
  1632. int m_nAllocatedParticles;
  1633. int m_nMaxAllowedParticles;
  1634. bool m_bDormant;
  1635. bool m_bEmissionStopped;
  1636. bool m_bPendingRestart;
  1637. bool m_bQueuedStartEmission;
  1638. bool m_bFrozen;
  1639. bool m_bInEndCap;
  1640. int m_LocalLightingCP;
  1641. Color m_LocalLighting;
  1642. // control point data. Don't set these directly, or they won't propagate down to children
  1643. // particle control points can act as emitter centers, repulsions points, etc. what they are
  1644. // used for depends on what operators and parameters your system has.
  1645. int m_nNumControlPointsAllocated;
  1646. CParticleCPInfo *m_pCPInfo;
  1647. FORCEINLINE CParticleControlPoint &ControlPoint( int nIdx ) const;
  1648. FORCEINLINE CModelHitBoxesInfo &ControlPointHitBox( int nIdx ) const;
  1649. // public so people can call methods
  1650. uint8 *m_pOperatorContextData;
  1651. CParticleCollection *m_pNext; // for linking children together
  1652. CParticleCollection *m_pPrev; // for linking children together
  1653. struct CWorldCollideContextData *m_pCollisionCacheData[NUM_COLLISION_CACHE_MODES]; // children can share collision caches w/ parent
  1654. CParticleCollection *m_pParent;
  1655. CUtlIntrusiveDList<CParticleCollection> m_Children; // list for all child particle systems
  1656. Vector m_Center; // average of particle centers
  1657. void *m_pRenderable; // for use by client
  1658. void *operator new(size_t nSize);
  1659. void *operator new( size_t size, int nBlockUse, const char *pFileName, int nLine );
  1660. void operator delete(void *pData);
  1661. void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine );
  1662. protected:
  1663. // current bounds for the particle system
  1664. bool m_bBoundsValid;
  1665. Vector m_MinBounds;
  1666. Vector m_MaxBounds;
  1667. int m_nHighestCP; //Highest CP set externally. Needs to assert if a system calls to an unassigned CP.
  1668. private:
  1669. int m_nAttributeMemorySize;
  1670. unsigned char *m_pParticleMemory; // fixed size at initialization. Must be aligned for SSE
  1671. unsigned char *m_pParticleInitialMemory; // fixed size at initialization. Must be aligned for SSE
  1672. unsigned char *m_pConstantMemory;
  1673. uint8 *m_pPreviousAttributeMemory; // for simulating at less than the display rate
  1674. int m_nPerParticleInitializedAttributeMask;
  1675. int m_nPerParticleUpdatedAttributeMask;
  1676. int m_nPerParticleReadInitialAttributeMask; // What fields do operators want to see initial attribute values for?
  1677. CParticleAttributeAddressTable m_ParticleAttributes;
  1678. CParticleAttributeAddressTable m_ParticleInitialAttributes;
  1679. CParticleAttributeAddressTable m_PreviousFrameAttributes;
  1680. float *m_pConstantAttributes;
  1681. uint64 m_nControlPointReadMask; // Mask indicating which control points have been accessed
  1682. uint64 m_nControlPointNonPositionalMask; // Mask indicating which control points are non-positional (ie shouldn't be transformed)
  1683. int m_nParticleFlags; // PCFLAGS_xxx
  1684. bool m_bIsScrubbable : 1;
  1685. bool m_bIsRunningInitializers : 1;
  1686. bool m_bIsRunningOperators : 1;
  1687. bool m_bIsTranslucent : 1;
  1688. bool m_bIsTwoPass : 1;
  1689. bool m_bAnyUsesPowerOfTwoFrameBufferTexture : 1; // whether or not we or any children use this
  1690. bool m_bAnyUsesFullFrameBufferTexture : 1;
  1691. bool m_bIsBatchable : 1;
  1692. bool m_bIsOrderImportant : 1; // is order important when deleting
  1693. bool m_bRunForParentApplyKillList : 1; // see ShouldRunForParentApplyKillList()
  1694. bool m_bUsesPowerOfTwoFrameBufferTexture; // whether or not we use this, _not_ our children
  1695. bool m_bUsesFullFrameBufferTexture;
  1696. // How many frames have we drawn?
  1697. int m_nDrawnFrames;
  1698. // Used to assign unique ids to each particle
  1699. int m_nUniqueParticleId;
  1700. // Used to generate random numbers
  1701. int m_nRandomQueryCount;
  1702. int m_nRandomSeed;
  1703. int m_nOperatorRandomSampleOffset;
  1704. float m_flMinDistSqr;
  1705. float m_flMaxDistSqr;
  1706. float m_flOOMaxDistSqr;
  1707. Vector m_vecLastCameraPos;
  1708. float m_flLastMinDistSqr;
  1709. float m_flLastMaxDistSqr;
  1710. // Particle collection kill list. set up by particle system mgr
  1711. int m_nNumParticlesToKill;
  1712. KillListItem_t *m_pParticleKillList;
  1713. // Used to build a list of all particle collections that have the same particle def
  1714. CParticleCollection *m_pNextDef;
  1715. CParticleCollection *m_pPrevDef;
  1716. void LoanKillListTo( CParticleCollection *pBorrower ) const;
  1717. bool HasAttachedKillList( void ) const;
  1718. CCachedParticleBatches *m_pCachedParticleBatches;
  1719. // For debugging
  1720. CParticleOperatorInstance *m_pRenderOp;
  1721. friend class CParticleSystemMgr;
  1722. friend class CParticleOperatorInstance;
  1723. friend class CParticleSystemDefinition;
  1724. friend class C4VInterpolatedAttributeIterator;
  1725. friend class CM128InterpolatedAttributeIterator;
  1726. };
  1727. class CM128InitialAttributeIterator : public CStridedConstPtr<fltx4>
  1728. {
  1729. public:
  1730. FORCEINLINE CM128InitialAttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1731. {
  1732. m_pData = pParticles->GetInitialM128AttributePtr( nAttribute, &m_nStride );
  1733. }
  1734. };
  1735. class CM128AttributeIterator : public CStridedConstPtr<fltx4>
  1736. {
  1737. public:
  1738. FORCEINLINE void Init( int nAttribute, CParticleCollection *pParticles )
  1739. {
  1740. m_pData = pParticles->GetM128AttributePtr( nAttribute, &m_nStride );
  1741. }
  1742. FORCEINLINE CM128AttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1743. {
  1744. Init( nAttribute, pParticles );
  1745. }
  1746. CM128AttributeIterator( void )
  1747. {
  1748. }
  1749. FORCEINLINE fltx4 operator()( fltx4 fl4T ) const
  1750. {
  1751. return *( m_pData );
  1752. }
  1753. };
  1754. class C4IAttributeIterator : public CStridedConstPtr<FourInts>
  1755. {
  1756. public:
  1757. FORCEINLINE void Init( int nAttribute, CParticleCollection *pParticles )
  1758. {
  1759. m_pData = pParticles->Get4IAttributePtr( nAttribute, &m_nStride );
  1760. }
  1761. FORCEINLINE C4IAttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1762. {
  1763. Init( nAttribute, pParticles );
  1764. }
  1765. FORCEINLINE C4IAttributeIterator( void )
  1766. {
  1767. }
  1768. };
  1769. class CM128AttributeWriteIterator : public CStridedPtr<fltx4>
  1770. {
  1771. public:
  1772. FORCEINLINE CM128AttributeWriteIterator( void )
  1773. {
  1774. }
  1775. FORCEINLINE void Init ( int nAttribute, CParticleCollection *pParticles )
  1776. {
  1777. m_pData = pParticles->GetM128AttributePtrForWrite( nAttribute, &m_nStride );
  1778. }
  1779. FORCEINLINE CM128AttributeWriteIterator( int nAttribute, CParticleCollection *pParticles )
  1780. {
  1781. Init( nAttribute, pParticles );
  1782. }
  1783. };
  1784. class C4VAttributeIterator : public CStridedConstPtr<FourVectors>
  1785. {
  1786. public:
  1787. FORCEINLINE void Init( int nAttribute, CParticleCollection *pParticles )
  1788. {
  1789. m_pData = pParticles->Get4VAttributePtr( nAttribute, &m_nStride );
  1790. }
  1791. FORCEINLINE C4VAttributeIterator( void )
  1792. {
  1793. }
  1794. FORCEINLINE C4VAttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1795. {
  1796. Init( nAttribute, pParticles );
  1797. }
  1798. FORCEINLINE fltx4 X( fltx4 T )
  1799. {
  1800. return m_pData->x;
  1801. }
  1802. FORCEINLINE fltx4 Y( fltx4 T )
  1803. {
  1804. return m_pData->y;
  1805. }
  1806. FORCEINLINE fltx4 Z( fltx4 T )
  1807. {
  1808. return m_pData->z;
  1809. }
  1810. };
  1811. class CM128InterpolatedAttributeIterator : public CM128AttributeIterator
  1812. {
  1813. protected:
  1814. intp m_nOldDataOffset;
  1815. FORCEINLINE fltx4 const *PreviousData( void ) const
  1816. {
  1817. return ( fltx4 const * ) ( ( ( uint8 const * ) m_pData ) + m_nOldDataOffset );
  1818. }
  1819. public:
  1820. FORCEINLINE void Init( int nAttribute, CParticleCollection *pParticles )
  1821. {
  1822. m_pData = pParticles->GetM128AttributePtr( nAttribute, &m_nStride );
  1823. Assert( pParticles->GetPrevAttributeMemory() );
  1824. if ( m_nStride )
  1825. {
  1826. m_nOldDataOffset =
  1827. pParticles->m_PreviousFrameAttributes.ByteAddress( nAttribute ) - pParticles->m_ParticleAttributes.ByteAddress( nAttribute );
  1828. }
  1829. else
  1830. {
  1831. m_nOldDataOffset = 0;
  1832. }
  1833. }
  1834. FORCEINLINE CM128InterpolatedAttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1835. {
  1836. Init( nAttribute, pParticles );
  1837. }
  1838. CM128InterpolatedAttributeIterator( void )
  1839. {
  1840. }
  1841. FORCEINLINE fltx4 operator()( fltx4 fl4T ) const
  1842. {
  1843. fltx4 fl4Ret = *( PreviousData() );
  1844. return AddSIMD( fl4Ret, MulSIMD( fl4T, SubSIMD( *m_pData, fl4Ret ) ) );
  1845. }
  1846. };
  1847. class C4VInterpolatedAttributeIterator : public C4VAttributeIterator
  1848. {
  1849. protected:
  1850. ptrdiff_t m_nOldDataOffset;
  1851. FORCEINLINE FourVectors const *PreviousData( void ) const
  1852. {
  1853. return ( FourVectors const * ) ( ( ( uint8 const * ) m_pData ) + m_nOldDataOffset );
  1854. }
  1855. public:
  1856. void Init( int nAttribute, CParticleCollection *pParticles );
  1857. FORCEINLINE C4VInterpolatedAttributeIterator( void )
  1858. {
  1859. }
  1860. FORCEINLINE C4VInterpolatedAttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1861. {
  1862. Init( nAttribute, pParticles );
  1863. }
  1864. FORCEINLINE fltx4 X( fltx4 fl4T ) const
  1865. {
  1866. fltx4 fl4Ret = PreviousData()->x;
  1867. return AddSIMD( fl4Ret, MulSIMD( fl4T, SubSIMD( m_pData->x, fl4Ret ) ) );
  1868. }
  1869. FORCEINLINE fltx4 Y( fltx4 fl4T ) const
  1870. {
  1871. fltx4 fl4Ret = PreviousData()->y;
  1872. return AddSIMD( fl4Ret, MulSIMD( fl4T, SubSIMD( m_pData->y, fl4Ret ) ) );
  1873. }
  1874. FORCEINLINE fltx4 Z( fltx4 fl4T ) const
  1875. {
  1876. fltx4 fl4Ret = PreviousData()->z;
  1877. return AddSIMD( fl4Ret, MulSIMD( fl4T, SubSIMD( m_pData->z, fl4Ret ) ) );
  1878. }
  1879. };
  1880. class C4VInitialAttributeIterator : public CStridedConstPtr<FourVectors>
  1881. {
  1882. public:
  1883. FORCEINLINE C4VInitialAttributeIterator( int nAttribute, CParticleCollection *pParticles )
  1884. {
  1885. m_pData = pParticles->GetInitial4VAttributePtr( nAttribute, &m_nStride );
  1886. }
  1887. };
  1888. class C4VAttributeWriteIterator : public CStridedPtr<FourVectors>
  1889. {
  1890. public:
  1891. FORCEINLINE C4VAttributeWriteIterator( int nAttribute, CParticleCollection *pParticles )
  1892. {
  1893. m_pData = pParticles->Get4VAttributePtrForWrite( nAttribute, &m_nStride );
  1894. }
  1895. };
  1896. //-----------------------------------------------------------------------------
  1897. // Inline methods of CParticleCollection
  1898. //-----------------------------------------------------------------------------
  1899. inline bool CParticleCollection::HasAttachedKillList( void ) const
  1900. {
  1901. return m_pParticleKillList != NULL;
  1902. }
  1903. inline bool CParticleCollection::ReadsControlPoint( int nPoint ) const
  1904. {
  1905. return ( m_nControlPointReadMask & ( 1ULL << nPoint ) ) != 0;
  1906. }
  1907. inline bool CParticleCollection::IsNonPositionalControlPoint( int nPoint ) const
  1908. {
  1909. return ( m_nControlPointNonPositionalMask & ( 1ULL << nPoint ) ) != 0;
  1910. }
  1911. inline void CParticleCollection::SetNActiveParticles( int nCount )
  1912. {
  1913. Assert( nCount >= 0 && nCount <= m_nMaxAllowedParticles );
  1914. m_nActiveParticles = nCount;
  1915. m_nPaddedActiveParticles = ( nCount+3 )/4;
  1916. }
  1917. inline void CParticleCollection::SwapPosAndPrevPos( void )
  1918. {
  1919. // strides better be the same!
  1920. Assert( m_ParticleAttributes.Stride( PARTICLE_ATTRIBUTE_XYZ ) == m_ParticleAttributes.Stride( PARTICLE_ATTRIBUTE_PREV_XYZ ) );
  1921. V_swap( m_ParticleAttributes.m_pAttributes[ PARTICLE_ATTRIBUTE_XYZ ], m_ParticleAttributes.m_pAttributes[ PARTICLE_ATTRIBUTE_PREV_XYZ ] );
  1922. }
  1923. FORCEINLINE CParticleControlPoint &CParticleCollection::ControlPoint( int nIdx ) const
  1924. {
  1925. Assert( nIdx >= 0 && nIdx < m_nNumControlPointsAllocated );
  1926. return m_pCPInfo[ MAX(0, MIN( nIdx, m_nNumControlPointsAllocated - 1 )) ].m_ControlPoint;
  1927. }
  1928. FORCEINLINE CModelHitBoxesInfo &CParticleCollection::ControlPointHitBox( int nIdx ) const
  1929. {
  1930. return m_pCPInfo[ MAX(0, MIN( nIdx, m_nNumControlPointsAllocated - 1 )) ].m_CPHitBox;
  1931. }
  1932. inline void CParticleCollection::LoanKillListTo( CParticleCollection *pBorrower ) const
  1933. {
  1934. Assert(! pBorrower->m_pParticleKillList );
  1935. pBorrower->m_nNumParticlesToKill = 0;
  1936. pBorrower->m_pParticleKillList = m_pParticleKillList;
  1937. }
  1938. inline void CParticleCollection::SetAttributeToConstant( int nAttribute, float fValue )
  1939. {
  1940. float *fconst = m_pConstantAttributes + 4*3*nAttribute;
  1941. fconst[0] = fconst[1] = fconst[2] = fconst[3] = fValue;
  1942. }
  1943. inline void CParticleCollection::SetAttributeToConstant( int nAttribute, float fValueX, float fValueY, float fValueZ )
  1944. {
  1945. float *fconst = m_pConstantAttributes + 4*3*nAttribute;
  1946. fconst[0] = fconst[1] = fconst[2] = fconst[3] = fValueX;
  1947. fconst[4] = fconst[5] = fconst[6] = fconst[7] = fValueY;
  1948. fconst[8] = fconst[9] = fconst[10] = fconst[11] = fValueZ;
  1949. }
  1950. inline void CParticleCollection::SetControlPoint( int nWhichPoint, const Vector &v )
  1951. {
  1952. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  1953. if ( nWhichPoint < m_nNumControlPointsAllocated )
  1954. {
  1955. ControlPoint( nWhichPoint ).m_Position = v;
  1956. m_nHighestCP = MAX( m_nHighestCP, nWhichPoint );
  1957. }
  1958. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  1959. {
  1960. i->SetControlPoint( nWhichPoint, v );
  1961. }
  1962. }
  1963. inline void CParticleCollection::SetControlPointObject( int nWhichPoint, void *pObject )
  1964. {
  1965. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  1966. if ( nWhichPoint < m_nNumControlPointsAllocated )
  1967. {
  1968. ControlPoint( nWhichPoint ).m_pObject = pObject;
  1969. m_nHighestCP = MAX( m_nHighestCP, nWhichPoint );
  1970. }
  1971. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  1972. {
  1973. i->SetControlPointObject( nWhichPoint, pObject );
  1974. }
  1975. }
  1976. inline void CParticleCollection::SetControlPointOrientation( int nWhichPoint, const Vector &forward,
  1977. const Vector &right, const Vector &up )
  1978. {
  1979. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  1980. // check perpendicular
  1981. Assert( fabs( DotProduct( forward, up ) ) <= 0.1f );
  1982. Assert( fabs( DotProduct( forward, right ) ) <= 0.1f );
  1983. Assert( fabs( DotProduct( right, up ) ) <= 0.1f );
  1984. if ( nWhichPoint < m_nNumControlPointsAllocated )
  1985. {
  1986. ControlPoint( nWhichPoint ).m_ForwardVector = forward;
  1987. ControlPoint( nWhichPoint ).m_UpVector = up;
  1988. ControlPoint( nWhichPoint ).m_RightVector = right;
  1989. m_nHighestCP = MAX( m_nHighestCP, nWhichPoint );
  1990. }
  1991. // make sure all children are finished
  1992. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  1993. {
  1994. i->SetControlPointOrientation( nWhichPoint, forward, right, up );
  1995. }
  1996. }
  1997. inline Vector CParticleCollection::TransformAxis( const Vector &SrcAxis, bool bLocalSpace,
  1998. int nControlPointNumber)
  1999. {
  2000. if ( bLocalSpace )
  2001. {
  2002. return // mxmul
  2003. ( SrcAxis.x * ControlPoint( nControlPointNumber ).m_RightVector )+
  2004. ( SrcAxis.y * ControlPoint( nControlPointNumber ).m_ForwardVector )+
  2005. ( SrcAxis.z * ControlPoint( nControlPointNumber ).m_UpVector );
  2006. }
  2007. else
  2008. return SrcAxis;
  2009. }
  2010. inline void CParticleCollection::SetControlPointOrientation( int nWhichPoint, const Quaternion &q )
  2011. {
  2012. matrix3x4_t mat;
  2013. Vector vecForward, vecUp, vecRight;
  2014. QuaternionMatrix( q, mat );
  2015. MatrixVectors( mat, &vecForward, &vecRight, &vecUp );
  2016. SetControlPointOrientation( nWhichPoint, vecForward, vecRight, vecUp );
  2017. }
  2018. inline void CParticleCollection::SetControlPointForwardVector( int nWhichPoint, const Vector &v )
  2019. {
  2020. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  2021. if ( nWhichPoint < m_nNumControlPointsAllocated )
  2022. {
  2023. ControlPoint( nWhichPoint ).m_ForwardVector = v;
  2024. m_nHighestCP = MAX( m_nHighestCP, nWhichPoint );
  2025. }
  2026. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  2027. {
  2028. i->SetControlPointForwardVector( nWhichPoint, v );
  2029. }
  2030. }
  2031. inline void CParticleCollection::SetControlPointUpVector( int nWhichPoint, const Vector &v )
  2032. {
  2033. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  2034. if ( nWhichPoint < m_nNumControlPointsAllocated )
  2035. {
  2036. ControlPoint( nWhichPoint ).m_UpVector = v;
  2037. m_nHighestCP = MAX( m_nHighestCP, nWhichPoint );
  2038. }
  2039. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  2040. {
  2041. i->SetControlPointUpVector( nWhichPoint, v );
  2042. }
  2043. }
  2044. inline void CParticleCollection::SetControlPointRightVector( int nWhichPoint, const Vector &v)
  2045. {
  2046. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  2047. if ( nWhichPoint < m_nNumControlPointsAllocated )
  2048. {
  2049. ControlPoint( nWhichPoint ).m_RightVector = v;
  2050. m_nHighestCP = MAX( m_nHighestCP, nWhichPoint );
  2051. }
  2052. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  2053. {
  2054. i->SetControlPointRightVector( nWhichPoint, v );
  2055. }
  2056. }
  2057. inline void CParticleCollection::SetControlPointParent( int nWhichPoint, int n )
  2058. {
  2059. Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  2060. if ( nWhichPoint < m_nNumControlPointsAllocated )
  2061. {
  2062. ControlPoint( nWhichPoint ).m_nParent = n;
  2063. m_nHighestCP = MAX( m_nHighestCP, nWhichPoint );
  2064. }
  2065. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  2066. {
  2067. i->SetControlPointParent( nWhichPoint, n );
  2068. }
  2069. }
  2070. inline void CParticleCollection::SetControlPointSnapshot( int nWhichPoint, CParticleSnapshot *pSnapshot )
  2071. {
  2072. Assert( ( nWhichPoint >= 0 ) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
  2073. if ( nWhichPoint < m_nNumControlPointsAllocated )
  2074. {
  2075. ControlPoint( nWhichPoint ).m_pSnapshot = pSnapshot;
  2076. }
  2077. for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
  2078. {
  2079. i->SetControlPointSnapshot( nWhichPoint, pSnapshot );
  2080. }
  2081. }
  2082. // Returns the memory for a particular constant attribute
  2083. inline float *CParticleCollection::GetConstantAttributeMemory( int nAttribute )
  2084. {
  2085. return m_pConstantAttributes + 3 * 4 * nAttribute;
  2086. }
  2087. // Random number offset (for use in getting Random #s in operators)
  2088. inline int CParticleCollection::OperatorRandomSampleOffset() const
  2089. {
  2090. return m_nOperatorRandomSampleOffset;
  2091. }
  2092. // Used by particle systems to generate random numbers
  2093. inline int CParticleCollection::RandomInt( int nRandomSampleId, int nMin, int nMax )
  2094. {
  2095. // do not call
  2096. float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ];
  2097. flRand *= ( nMax + 1 - nMin );
  2098. int nRand = (int)flRand + nMin;
  2099. return nRand;
  2100. }
  2101. inline float CParticleCollection::RandomFloat( int nRandomSampleId, float flMin, float flMax )
  2102. {
  2103. // do not call
  2104. float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ];
  2105. flRand *= ( flMax - flMin );
  2106. flRand += flMin;
  2107. return flRand;
  2108. }
  2109. inline fltx4 CParticleCollection::RandomFloat( const FourInts &ParticleID, int nRandomSampleOffset )
  2110. {
  2111. fltx4 Retval;
  2112. int nOfs=m_nRandomSeed+nRandomSampleOffset;
  2113. SubFloat( Retval, 0 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[0] ) & RANDOM_FLOAT_MASK ];
  2114. SubFloat( Retval, 1 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[1] ) & RANDOM_FLOAT_MASK ];
  2115. SubFloat( Retval, 2 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[2] ) & RANDOM_FLOAT_MASK ];
  2116. SubFloat( Retval, 3 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[3] ) & RANDOM_FLOAT_MASK ];
  2117. return Retval;
  2118. }
  2119. inline float CParticleCollection::RandomFloatExp( int nRandomSampleId, float flMin, float flMax, float flExponent )
  2120. {
  2121. // do not call
  2122. float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ];
  2123. flRand = powf( flRand, flExponent );
  2124. flRand *= ( flMax - flMin );
  2125. flRand += flMin;
  2126. return flRand;
  2127. }
  2128. inline void CParticleCollection::RandomVector( int nRandomSampleId, float flMin, float flMax, Vector *pVector )
  2129. {
  2130. // do not call
  2131. float flDelta = flMax - flMin;
  2132. int nBaseId = m_nRandomSeed + nRandomSampleId;
  2133. pVector->x = s_pRandomFloats[ nBaseId & RANDOM_FLOAT_MASK ];
  2134. pVector->x *= flDelta;
  2135. pVector->x += flMin;
  2136. pVector->y = s_pRandomFloats[ ( nBaseId + 1 ) & RANDOM_FLOAT_MASK ];
  2137. pVector->y *= flDelta;
  2138. pVector->y += flMin;
  2139. pVector->z = s_pRandomFloats[ ( nBaseId + 2 ) & RANDOM_FLOAT_MASK ];
  2140. pVector->z *= flDelta;
  2141. pVector->z += flMin;
  2142. }
  2143. inline void CParticleCollection::RandomVector( int nRandomSampleId, const Vector &vecMin, const Vector &vecMax, Vector *pVector )
  2144. {
  2145. // do not call
  2146. int nBaseId = m_nRandomSeed + nRandomSampleId;
  2147. pVector->x = RandomFloat( nBaseId, vecMin.x, vecMax.x );
  2148. pVector->y = RandomFloat( nBaseId + 1, vecMin.y, vecMax.y );
  2149. pVector->z = RandomFloat( nBaseId + 2, vecMin.z, vecMax.z );
  2150. }
  2151. // Used by particle systems to generate random numbers
  2152. inline int CParticleCollection::RandomInt( int nMin, int nMax )
  2153. {
  2154. // do not call
  2155. return RandomInt( m_nRandomQueryCount++, nMin, nMax );
  2156. }
  2157. inline float CParticleCollection::RandomFloat( float flMin, float flMax )
  2158. {
  2159. // do not call
  2160. return RandomFloat( m_nRandomQueryCount++, flMin, flMax );
  2161. }
  2162. inline float CParticleCollection::RandomFloatExp( float flMin, float flMax, float flExponent )
  2163. {
  2164. // do not call
  2165. return RandomFloatExp( m_nRandomQueryCount++, flMin, flMax, flExponent );
  2166. }
  2167. inline void CParticleCollection::RandomVector( float flMin, float flMax, Vector *pVector )
  2168. {
  2169. // do not call
  2170. RandomVector( m_nRandomQueryCount, flMin, flMax, pVector );
  2171. m_nRandomQueryCount +=3;
  2172. }
  2173. inline void CParticleCollection::RandomVector( const Vector &vecMin, const Vector &vecMax, Vector *pVector )
  2174. {
  2175. // do not call
  2176. RandomVector( m_nRandomQueryCount, vecMin, vecMax, pVector );
  2177. m_nRandomQueryCount +=3;
  2178. }
  2179. inline float CParticleCollection::RandomVectorInUnitSphere( Vector *pVector )
  2180. {
  2181. // do not call
  2182. float flUnitSphere = RandomVectorInUnitSphere( m_nRandomQueryCount, pVector );
  2183. m_nRandomQueryCount +=3;
  2184. return flUnitSphere;
  2185. }
  2186. // get the pointer to an attribute for a given particle. !!speed!! if you find yourself
  2187. // calling this anywhere that matters, you're not handling the simd-ness of the particle system
  2188. // well and will have bad perf.
  2189. inline const float *CParticleCollection::GetFloatAttributePtr( int nAttribute, int nParticleNumber ) const
  2190. {
  2191. Assert( nParticleNumber < m_nAllocatedParticles );
  2192. return m_ParticleAttributes.FloatAttributePtr( nAttribute, nParticleNumber );
  2193. }
  2194. inline int *CParticleCollection::GetIntAttributePtrForWrite( int nAttribute, int nParticleNumber )
  2195. {
  2196. return reinterpret_cast< int* >( GetFloatAttributePtrForWrite( nAttribute, nParticleNumber ) );
  2197. }
  2198. inline const int *CParticleCollection::GetIntAttributePtr( int nAttribute, int nParticleNumber ) const
  2199. {
  2200. return (int*)GetFloatAttributePtr( nAttribute, nParticleNumber );
  2201. }
  2202. inline const fltx4 *CParticleCollection::GetM128AttributePtr( int nAttribute, size_t *pStrideOut ) const
  2203. {
  2204. *(pStrideOut) = m_ParticleAttributes.Stride( nAttribute ) / 4;
  2205. return reinterpret_cast<fltx4 *>( m_ParticleAttributes.Address( nAttribute ) );
  2206. }
  2207. inline const FourInts *CParticleCollection::Get4IAttributePtr( int nAttribute, size_t *pStrideOut ) const
  2208. {
  2209. *(pStrideOut) = m_ParticleAttributes.Stride( nAttribute ) / 4;
  2210. return reinterpret_cast<FourInts *>( m_ParticleAttributes.Address( nAttribute ) );
  2211. }
  2212. inline const int32 *CParticleCollection::GetIntAttributePtr( int nAttribute, size_t *pStrideOut ) const
  2213. {
  2214. *(pStrideOut) = m_ParticleAttributes.Stride( nAttribute );
  2215. return reinterpret_cast<int32 *>( m_ParticleAttributes.Address( nAttribute ) );
  2216. }
  2217. inline const FourVectors *CParticleCollection::Get4VAttributePtr( int nAttribute, size_t *pStrideOut ) const
  2218. {
  2219. *(pStrideOut) = m_ParticleAttributes.Stride( nAttribute ) / 12;
  2220. return reinterpret_cast<const FourVectors *>( m_ParticleAttributes.Address( nAttribute ) );
  2221. }
  2222. inline FourVectors *CParticleCollection::Get4VAttributePtrForWrite( int nAttribute, size_t *pStrideOut )
  2223. {
  2224. *( pStrideOut ) = m_ParticleAttributes.Stride( nAttribute ) / 12;
  2225. return reinterpret_cast<FourVectors *>( m_ParticleAttributes.Address( nAttribute ) );
  2226. }
  2227. inline const FourVectors *CParticleCollection::GetInitial4VAttributePtr( int nAttribute, size_t *pStrideOut ) const
  2228. {
  2229. *(pStrideOut) = m_ParticleInitialAttributes.Stride( nAttribute )/12;
  2230. return reinterpret_cast<FourVectors *>( m_ParticleInitialAttributes.Address( nAttribute ) );
  2231. }
  2232. inline Vector CParticleCollection::GetVectorAttributeValue( int nAttribute, int nParticleNumber ) const
  2233. {
  2234. Assert( nParticleNumber < m_nAllocatedParticles );
  2235. size_t nStride;
  2236. float const *pData = ( float const * ) Get4VAttributePtr( nAttribute, &nStride );
  2237. int nOfs = nParticleNumber / 4;
  2238. int nRemainder = nParticleNumber & 3;
  2239. pData += 12 * nOfs + nRemainder;
  2240. Vector vecRet( pData[0], pData[4], pData[8] );
  2241. return vecRet;
  2242. }
  2243. inline float CParticleCollection::GetFloatAttributeValue( int nAttribute, int nParticleNumber ) const
  2244. {
  2245. Assert( nParticleNumber < m_nAllocatedParticles );
  2246. float const *pData = GetFloatAttributePtr( nAttribute, nParticleNumber );
  2247. return *pData;
  2248. }
  2249. inline float *CParticleCollection::GetFloatAttributePtrForWrite( int nAttribute, int nParticleNumber )
  2250. {
  2251. // NOTE: If you hit this assertion, it means your particle operator isn't returning
  2252. // the appropriate fields in the RequiredAttributesMask call
  2253. Assert( !m_bIsRunningInitializers || ( m_nPerParticleInitializedAttributeMask & (1 << nAttribute) ) );
  2254. Assert( !m_bIsRunningOperators || ( m_nPerParticleUpdatedAttributeMask & (1 << nAttribute) ) );
  2255. Assert( m_ParticleAttributes.Stride( nAttribute ) != 0 );
  2256. Assert( nParticleNumber < m_nAllocatedParticles );
  2257. return m_ParticleAttributes.FloatAttributePtr( nAttribute, nParticleNumber );
  2258. }
  2259. inline fltx4 *CParticleCollection::GetM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut )
  2260. {
  2261. // NOTE: If you hit this assertion, it means your particle operator isn't returning
  2262. // the appropriate fields in the RequiredAttributesMask call
  2263. Assert( !m_bIsRunningInitializers || ( m_nPerParticleInitializedAttributeMask & (1 << nAttribute) ) );
  2264. Assert( !m_bIsRunningOperators || ( m_nPerParticleUpdatedAttributeMask & (1 << nAttribute) ) );
  2265. Assert( m_ParticleAttributes.Stride( nAttribute ) != 0 );
  2266. *( pStrideOut ) = m_ParticleAttributes.Stride( nAttribute ) / 4;
  2267. return reinterpret_cast<fltx4 *>( m_ParticleAttributes.Address( nAttribute ) );
  2268. }
  2269. inline const float *CParticleCollection::GetInitialFloatAttributePtr( int nAttribute, int nParticleNumber ) const
  2270. {
  2271. Assert( nParticleNumber < m_nAllocatedParticles );
  2272. return m_ParticleInitialAttributes.FloatAttributePtr( nAttribute, nParticleNumber );
  2273. }
  2274. inline const fltx4 *CParticleCollection::GetInitialM128AttributePtr( int nAttribute, size_t *pStrideOut ) const
  2275. {
  2276. *( pStrideOut ) = m_ParticleInitialAttributes.Stride( nAttribute ) / 4;
  2277. return reinterpret_cast<fltx4 *>( m_ParticleInitialAttributes.Address( nAttribute ) );
  2278. }
  2279. inline float *CParticleCollection::GetInitialFloatAttributePtrForWrite( int nAttribute, int nParticleNumber )
  2280. {
  2281. Assert( nParticleNumber < m_nAllocatedParticles );
  2282. Assert( m_nPerParticleReadInitialAttributeMask & ( 1 << nAttribute ) );
  2283. return m_ParticleInitialAttributes.FloatAttributePtr( nAttribute, nParticleNumber );
  2284. }
  2285. inline fltx4 *CParticleCollection::GetInitialM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut )
  2286. {
  2287. Assert( m_nPerParticleReadInitialAttributeMask & ( 1 << nAttribute ) );
  2288. *( pStrideOut ) = m_ParticleInitialAttributes.Stride( nAttribute ) / 4;
  2289. return reinterpret_cast<fltx4 *>( m_ParticleInitialAttributes.Address( nAttribute ) );
  2290. }
  2291. // Used to make sure we're accessing valid memory
  2292. inline bool CParticleCollection::IsValidAttributePtr( int nAttribute, const void *pPtr ) const
  2293. {
  2294. if ( pPtr < m_ParticleAttributes.Address( nAttribute ) )
  2295. return false;
  2296. size_t nArraySize = m_ParticleAttributes.Stride( nAttribute ) * m_nAllocatedParticles / 4;
  2297. void *pMaxPtr = m_ParticleAttributes.Address( nAttribute ) + nArraySize;
  2298. return ( pPtr <= pMaxPtr );
  2299. }
  2300. FORCEINLINE void CParticleCollection::KillParticle( int nPidx, unsigned int nKillFlags )
  2301. {
  2302. // add a particle to the sorted kill list. entries must be added in sorted order.
  2303. // within a particle operator, this is safe to call. Outside of one, you have to call
  2304. // the ApplyKillList() method yourself. The storage for the kill list is global between
  2305. // all particle systems, so you can't kill a particle in 2 different CParticleCollections
  2306. // w/o calling ApplyKillList
  2307. Assert( !m_nNumParticlesToKill || ( nPidx > (int)m_pParticleKillList[ m_nNumParticlesToKill - 1 ].nIndex ) );
  2308. // note that it is permissible to kill particles with indices>the number of active
  2309. // particles, in order to faciliate easy sse coding (that said, we only expect the
  2310. // particle index to be at most more than 3 larger than the particle count)
  2311. Assert( nPidx < m_nActiveParticles + 4 );
  2312. COMPILE_TIME_ASSERT( ( sizeof( KillListItem_t ) == 4 ) && ( MAX_PARTICLES_IN_A_SYSTEM < ( 1 << KILL_LIST_INDEX_BITS ) ) );
  2313. Assert( !( nPidx & ~KILL_LIST_INDEX_MASK ) && !( nKillFlags & ~KILL_LIST_FLAGS_MASK ) );
  2314. KillListItem_t killItem = { nPidx, nKillFlags };
  2315. Assert( m_nNumParticlesToKill < MAX_PARTICLES_IN_A_SYSTEM );
  2316. m_pParticleKillList[ m_nNumParticlesToKill++ ] = killItem;
  2317. }
  2318. // initialize this attribute for all active particles
  2319. inline void CParticleCollection::FillAttributeWithConstant( int nAttribute, float fValue )
  2320. {
  2321. size_t stride;
  2322. fltx4 *pAttr = GetM128AttributePtrForWrite( nAttribute, &stride );
  2323. fltx4 fill=ReplicateX4( fValue );
  2324. for( int i = 0; i < m_nPaddedActiveParticles; i++ )
  2325. {
  2326. *(pAttr) = fill;
  2327. pAttr += stride;
  2328. }
  2329. }
  2330. //-----------------------------------------------------------------------------
  2331. // Helper to set vector attribute values
  2332. //-----------------------------------------------------------------------------
  2333. FORCEINLINE void SetVectorAttribute( float *pAttribute, float x, float y, float z )
  2334. {
  2335. pAttribute[0] = x;
  2336. pAttribute[4] = y;
  2337. pAttribute[8] = z;
  2338. }
  2339. FORCEINLINE void SetVectorAttribute( float *pAttribute, const Vector &v )
  2340. {
  2341. pAttribute[0] = v.x;
  2342. pAttribute[4] = v.y;
  2343. pAttribute[8] = v.z;
  2344. }
  2345. FORCEINLINE void SetVectorFromAttribute( Vector &v, const float *pAttribute )
  2346. {
  2347. v.x = pAttribute[0];
  2348. v.y = pAttribute[4];
  2349. v.z = pAttribute[8];
  2350. }
  2351. //-----------------------------------------------------------------------------
  2352. // Computes the sq distance to a particle position
  2353. //-----------------------------------------------------------------------------
  2354. FORCEINLINE float CParticleCollection::ComputeSqrDistanceToParticle( int hParticle, const Vector &vecPosition ) const
  2355. {
  2356. const float *xyz = GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, hParticle );
  2357. Vector vecParticlePosition( xyz[0], xyz[4], xyz[8] );
  2358. return vecParticlePosition.DistToSqr( vecPosition );
  2359. }
  2360. //-----------------------------------------------------------------------------
  2361. // Grows the dist sq range for all particles
  2362. //-----------------------------------------------------------------------------
  2363. FORCEINLINE void CParticleCollection::GrowDistSqrBounds( float flDistSqr )
  2364. {
  2365. if ( m_flLastMinDistSqr > flDistSqr )
  2366. {
  2367. m_flLastMinDistSqr = flDistSqr;
  2368. }
  2369. else if ( m_flLastMaxDistSqr < flDistSqr )
  2370. {
  2371. m_flLastMaxDistSqr = flDistSqr;
  2372. }
  2373. }
  2374. //-----------------------------------------------------------------------------
  2375. // Data associated with children particle systems
  2376. //-----------------------------------------------------------------------------
  2377. struct ParticleChildrenInfo_t
  2378. {
  2379. DmObjectId_t m_Id;
  2380. ParticleSystemHandle_t m_Name;
  2381. bool m_bUseNameBasedLookup;
  2382. float m_flDelay; // How much to delay this system after the parent starts
  2383. bool m_bEndCap; // This child only plays when an effect is stopped with endcap effects.
  2384. };
  2385. //-----------------------------------------------------------------------------
  2386. // A template describing how a particle system will function
  2387. //-----------------------------------------------------------------------------
  2388. class CParticleSystemDefinition
  2389. {
  2390. DECLARE_DMXELEMENT_UNPACK();
  2391. DECLARE_REFERENCED_CLASS( CParticleSystemDefinition );
  2392. public:
  2393. CParticleSystemDefinition( void );
  2394. ~CParticleSystemDefinition( void );
  2395. // Serialization, unserialization
  2396. void Read( CDmxElement *pElement );
  2397. CDmxElement *Write();
  2398. const char *MaterialName() const;
  2399. IMaterial *GetMaterial() const;
  2400. const char *GetName() const;
  2401. const DmObjectId_t& GetId() const;
  2402. // Does the particle system use the power of two frame buffer texture (refraction?)
  2403. bool UsesPowerOfTwoFrameBufferTexture();
  2404. // Does the particle system use the full frame buffer texture (soft particles)
  2405. bool UsesFullFrameBufferTexture();
  2406. // Should we always precache this?
  2407. bool ShouldAlwaysPrecache() const;
  2408. // Should we batch particle collections using this definition up?
  2409. bool ShouldBatch() const;
  2410. // Is the particle system rendered on the viewmodel?
  2411. bool IsViewModelEffect() const;
  2412. bool IsScreenSpaceEffect() const;
  2413. void SetDrawThroughLeafSystem( bool bDraw ) { m_bDrawThroughLeafSystem = bDraw; }
  2414. bool IsDrawnThroughLeafSystem( void ) const { return m_bDrawThroughLeafSystem; }
  2415. // Used to iterate over all particle collections using the same def
  2416. CParticleCollection *FirstCollection();
  2417. // What's the effective cull size + fill cost?
  2418. // Used for early retirement
  2419. float GetCullRadius() const;
  2420. float GetCullFillCost() const;
  2421. int GetCullControlPoint() const;
  2422. const char *GetCullReplacementDefinition() const;
  2423. int GetMaxRecursionDepth() const;
  2424. // Retirement
  2425. bool HasRetirementBeenChecked( int nFrame ) const;
  2426. void MarkRetirementCheck( int nFrame );
  2427. bool HasFallback() const;
  2428. CParticleSystemDefinition *GetFallbackReplacementDefinition() const;
  2429. int GetMinCPULevel() const;
  2430. int GetMinGPULevel() const;
  2431. // Control point read
  2432. void MarkReadsControlPoint( int nPoint );
  2433. bool ReadsControlPoint( int nPoint ) const;
  2434. bool IsNonPositionalControlPoint( int nPoint ) const;
  2435. float GetMaxTailLength() const;
  2436. void SetMaxTailLength( float flMaxTailLength );
  2437. // Sheet symbols (used to avoid string->symbol conversions when effects are created)
  2438. void InvalidateSheetSymbol();
  2439. void CacheSheetSymbol( CUtlSymbol sheetSymbol );
  2440. bool IsSheetSymbolCached() const;
  2441. CUtlSymbol GetSheetSymbol() const;
  2442. private:
  2443. void Precache();
  2444. void Uncache();
  2445. bool IsPrecached() const;
  2446. void UnlinkAllCollections();
  2447. void SetupContextData( );
  2448. void ParseChildren( CDmxElement *pElement );
  2449. void ParseOperators( const char *pszName, ParticleFunctionType_t nFunctionType,
  2450. CDmxElement *pElement, CUtlVector<CParticleOperatorInstance *> &out_list );
  2451. void WriteChildren( CDmxElement *pElement );
  2452. void WriteOperators( CDmxElement *pElement, const char *pOpKeyName,
  2453. const CUtlVector<CParticleOperatorInstance *> &inList );
  2454. CUtlVector<CParticleOperatorInstance *> *GetOperatorList( ParticleFunctionType_t type );
  2455. CParticleOperatorInstance *FindOperatorById( ParticleFunctionType_t type, const DmObjectId_t &id );
  2456. CParticleOperatorInstance *FindOperatorByName( const char *pOperatorName ); // SLOW!
  2457. private:
  2458. int m_nInitialParticles;
  2459. int m_nPerParticleUpdatedAttributeMask;
  2460. int m_nPerParticleInitializedAttributeMask;
  2461. int m_nInitialAttributeReadMask;
  2462. int m_nAttributeReadMask;
  2463. uint64 m_nControlPointReadMask;
  2464. uint64 m_nControlPointNonPositionalMask;
  2465. Vector m_BoundingBoxMin;
  2466. Vector m_BoundingBoxMax;
  2467. CUtlString m_MaterialName;
  2468. CMaterialReference m_Material;
  2469. Vector4D m_vecMaterialModulation;
  2470. CParticleCollection *m_pFirstCollection;
  2471. CUtlString m_CullReplacementName;
  2472. float m_flCullRadius;
  2473. float m_flCullFillCost;
  2474. int m_nCullControlPoint;
  2475. int m_nRetireCheckFrame;
  2476. int m_nMaxRecursionDepth;
  2477. float m_flMaxTailLength;
  2478. // Fallbacks for exceeding maximum number of the same type of system at once.
  2479. CUtlString m_FallbackReplacementName;
  2480. int m_nFallbackMaxCount;
  2481. int m_nFallbackCurrentCount;
  2482. CUtlReference< CParticleSystemDefinition > m_pFallback;
  2483. // Default attribute values
  2484. Color m_ConstantColor;
  2485. Vector m_ConstantNormal;
  2486. float m_flConstantRadius;
  2487. float m_flConstantRotation;
  2488. float m_flConstantRotationSpeed;
  2489. int m_nConstantSequenceNumber;
  2490. int m_nConstantSequenceNumber1;
  2491. int m_nGroupID;
  2492. float m_flMaximumTimeStep;
  2493. float m_flMaximumSimTime; // maximum time to sim before drawing first frame.
  2494. float m_flMinimumSimTime; // minimum time to sim before drawing first frame - prevents all
  2495. // capped particles from drawing at 0 time.
  2496. float m_flMinimumTimeStep; // for simulating at < frame rate
  2497. int m_nMinimumFrames; // number of frames to apply max/min simulation times
  2498. int m_nMinCPULevel; // minimum CPU/GPU levels for a
  2499. int m_nMinGPULevel; // particle system to be allowed to spawn
  2500. // Is the particle system rendered on the viewmodel?
  2501. bool m_bViewModelEffect;
  2502. bool m_bScreenSpaceEffect;
  2503. bool m_bDrawThroughLeafSystem;
  2504. bool m_bSheetSymbolCached;
  2505. CUtlSymbol m_SheetSymbol;
  2506. size_t m_nContextDataSize;
  2507. DmObjectId_t m_Id;
  2508. public:
  2509. float m_flMaxDrawDistance; // distance at which to not draw.
  2510. float m_flNoDrawTimeToGoToSleep; // after not beeing seen for this long, the system will sleep
  2511. int m_nMaxParticles;
  2512. int m_nSkipRenderControlPoint; // if the camera is attached to the
  2513. // object associated with this control
  2514. // point, don't render the system
  2515. int m_nAllowRenderControlPoint; // if the camera is attached to the
  2516. // object associated with this control
  2517. // point, render the system, otherwise, don't
  2518. int m_nAggregationMinAvailableParticles; // only aggregate if their are this many free particles
  2519. float m_flAggregateRadius; // aggregate particles if this system is within radius n
  2520. float m_flStopSimulationAfterTime; // stop ( freeze ) simulation after this time
  2521. CUtlString m_Name;
  2522. CUtlVector<CParticleOperatorInstance *> m_Operators;
  2523. CUtlVector<CParticleOperatorInstance *> m_Renderers;
  2524. CUtlVector<CParticleOperatorInstance *> m_Initializers;
  2525. CUtlVector<CParticleOperatorInstance *> m_Emitters;
  2526. CUtlVector<CParticleOperatorInstance *> m_ForceGenerators;
  2527. CUtlVector<CParticleOperatorInstance *> m_Constraints;
  2528. CUtlVector<ParticleChildrenInfo_t> m_Children;
  2529. CUtlVector<size_t> m_nOperatorsCtxOffsets;
  2530. CUtlVector<size_t> m_nRenderersCtxOffsets;
  2531. CUtlVector<size_t> m_nInitializersCtxOffsets;
  2532. CUtlVector<size_t> m_nEmittersCtxOffsets;
  2533. CUtlVector<size_t> m_nForceGeneratorsCtxOffsets;
  2534. CUtlVector<size_t> m_nConstraintsCtxOffsets;
  2535. #if MEASURE_PARTICLE_PERF
  2536. float m_flTotalSimTime;
  2537. float m_flUncomittedTotalSimTime;
  2538. float m_flMaxMeasuredSimTime;
  2539. float m_flTotalRenderTime;
  2540. float m_flMaxMeasuredRenderTime;
  2541. float m_flUncomittedTotalRenderTime;
  2542. #endif
  2543. uint m_nPerParticleOutlineMaterialVarToken;
  2544. CInterlockedInt m_nNumIntersectionTests; // the number of particle intersectio queries done
  2545. CInterlockedInt m_nNumActualRayTraces; // the total number of ray intersections done.
  2546. int m_nMaximumActiveParticles;
  2547. bool m_bShouldSort;
  2548. bool m_bShouldBatch;
  2549. bool m_bIsPrecached : 1;
  2550. bool m_bAlwaysPrecache : 1;
  2551. friend class CParticleCollection;
  2552. friend class CParticleSystemMgr;
  2553. };
  2554. //-----------------------------------------------------------------------------
  2555. // Inline methods
  2556. //-----------------------------------------------------------------------------
  2557. inline CParticleSystemDefinition::CParticleSystemDefinition( void )
  2558. {
  2559. m_vecMaterialModulation.Init( 1.0f, 1.0f, 1.0f, 1.0f );
  2560. m_SheetSymbol = UTL_INVAL_SYMBOL;
  2561. m_bSheetSymbolCached = false;
  2562. m_nControlPointReadMask = 0;
  2563. m_nControlPointNonPositionalMask = 0;
  2564. m_nInitialAttributeReadMask = 0;
  2565. m_nPerParticleInitializedAttributeMask = 0;
  2566. m_nPerParticleUpdatedAttributeMask = 0;
  2567. m_nAttributeReadMask = 0;
  2568. m_nNumIntersectionTests = 0;
  2569. m_nNumActualRayTraces = 0;
  2570. #if MEASURE_PARTICLE_PERF
  2571. m_flTotalSimTime = 0.0;
  2572. m_flMaxMeasuredSimTime = 0.0;
  2573. m_flMaxMeasuredRenderTime = 0.0f;
  2574. m_flTotalRenderTime = 0.0f;
  2575. m_flUncomittedTotalRenderTime = 0.0f;
  2576. m_flUncomittedTotalSimTime = 0.0f;
  2577. #endif
  2578. m_nMaximumActiveParticles = 0;
  2579. m_bIsPrecached = false;
  2580. m_bAlwaysPrecache = false;
  2581. m_bShouldBatch = false;
  2582. m_bShouldSort = true;
  2583. m_pFirstCollection = NULL;
  2584. m_flCullRadius = 0.0f;
  2585. m_flCullFillCost = 1.0f;
  2586. m_nRetireCheckFrame = 0;
  2587. m_nMaxRecursionDepth = 8;
  2588. m_nFallbackCurrentCount = 0;
  2589. m_bDrawThroughLeafSystem = true;
  2590. m_flMaxTailLength = 0.0f;
  2591. m_flMinimumTimeStep = 0;
  2592. m_nPerParticleOutlineMaterialVarToken = 0;
  2593. }
  2594. inline CParticleSystemDefinition::~CParticleSystemDefinition( void )
  2595. {
  2596. UnlinkAllCollections();
  2597. m_Operators.PurgeAndDeleteElements();
  2598. m_Renderers.PurgeAndDeleteElements();
  2599. m_Initializers.PurgeAndDeleteElements();
  2600. m_Emitters.PurgeAndDeleteElements();
  2601. m_ForceGenerators.PurgeAndDeleteElements();
  2602. m_Constraints.PurgeAndDeleteElements();
  2603. }
  2604. // Used to iterate over all particle collections using the same def
  2605. inline CParticleCollection *CParticleSystemDefinition::FirstCollection()
  2606. {
  2607. return m_pFirstCollection;
  2608. }
  2609. inline float CParticleSystemDefinition::GetCullRadius() const
  2610. {
  2611. return m_flCullRadius;
  2612. }
  2613. inline float CParticleSystemDefinition::GetCullFillCost() const
  2614. {
  2615. return m_flCullFillCost;
  2616. }
  2617. inline const char *CParticleSystemDefinition::GetCullReplacementDefinition() const
  2618. {
  2619. return m_CullReplacementName;
  2620. }
  2621. inline int CParticleSystemDefinition::GetCullControlPoint() const
  2622. {
  2623. return m_nCullControlPoint;
  2624. }
  2625. inline int CParticleSystemDefinition::GetMaxRecursionDepth() const
  2626. {
  2627. return m_nMaxRecursionDepth;
  2628. }
  2629. inline bool CParticleSystemDefinition::HasFallback() const
  2630. {
  2631. return ( m_nFallbackMaxCount > 0 );
  2632. }
  2633. inline int CParticleSystemDefinition::GetMinCPULevel() const
  2634. {
  2635. return m_nMinCPULevel;
  2636. }
  2637. inline int CParticleSystemDefinition::GetMinGPULevel() const
  2638. {
  2639. return m_nMinGPULevel;
  2640. }
  2641. inline void CParticleSystemDefinition::MarkReadsControlPoint( int nPoint )
  2642. {
  2643. m_nControlPointReadMask |= ( 1ULL << nPoint );
  2644. }
  2645. inline bool CParticleSystemDefinition::IsNonPositionalControlPoint( int nPoint ) const
  2646. {
  2647. return ( m_nControlPointNonPositionalMask & ( 1ULL << nPoint ) ) != 0;
  2648. }
  2649. inline bool CParticleSystemDefinition::ReadsControlPoint( int nPoint ) const
  2650. {
  2651. return ( m_nControlPointReadMask & ( 1ULL << nPoint ) ) != 0;
  2652. }
  2653. // Retirement
  2654. inline bool CParticleSystemDefinition::HasRetirementBeenChecked( int nFrame ) const
  2655. {
  2656. return m_nRetireCheckFrame == nFrame;
  2657. }
  2658. inline void CParticleSystemDefinition::MarkRetirementCheck( int nFrame )
  2659. {
  2660. m_nRetireCheckFrame = nFrame;
  2661. }
  2662. inline bool CParticleSystemDefinition::ShouldBatch() const
  2663. {
  2664. return m_bShouldBatch;
  2665. }
  2666. inline bool CParticleSystemDefinition::IsViewModelEffect() const
  2667. {
  2668. return m_bViewModelEffect;
  2669. }
  2670. inline bool CParticleSystemDefinition::IsScreenSpaceEffect() const
  2671. {
  2672. return m_bScreenSpaceEffect;
  2673. }
  2674. inline float CParticleSystemDefinition::GetMaxTailLength() const
  2675. {
  2676. return m_flMaxTailLength;
  2677. }
  2678. inline void CParticleSystemDefinition::SetMaxTailLength( float flMaxTailLength )
  2679. {
  2680. m_flMaxTailLength = flMaxTailLength;
  2681. }
  2682. inline const char *CParticleSystemDefinition::MaterialName() const
  2683. {
  2684. return m_MaterialName;
  2685. }
  2686. inline const DmObjectId_t& CParticleSystemDefinition::GetId() const
  2687. {
  2688. return m_Id;
  2689. }
  2690. inline int CParticleCollection::GetGroupID( void ) const
  2691. {
  2692. return m_pDef->m_nGroupID;
  2693. }
  2694. FORCEINLINE const Vector& CParticleCollection::GetControlPointAtCurrentTime( int nControlPoint ) const
  2695. {
  2696. Assert( !m_pDef || m_pDef->ReadsControlPoint( nControlPoint ) );
  2697. return ControlPoint( nControlPoint ).m_Position;
  2698. }
  2699. FORCEINLINE void CParticleCollection::GetControlPointOrientationAtCurrentTime( int nControlPoint, Vector *pForward, Vector *pRight, Vector *pUp ) const
  2700. {
  2701. Assert( nControlPoint <= GetHighestControlPoint() );
  2702. Assert( !m_pDef || m_pDef->ReadsControlPoint( nControlPoint ) );
  2703. // FIXME: Use quaternion lerp to get control point transform at time
  2704. *pForward = ControlPoint( nControlPoint).m_ForwardVector;
  2705. *pRight = ControlPoint( nControlPoint ).m_RightVector;
  2706. *pUp = ControlPoint( nControlPoint ).m_UpVector;
  2707. }
  2708. FORCEINLINE int CParticleCollection::GetControlPointParent( int nControlPoint ) const
  2709. {
  2710. Assert( nControlPoint <= GetHighestControlPoint() );
  2711. Assert( !m_pDef || m_pDef->ReadsControlPoint( nControlPoint ) );
  2712. return ControlPoint( nControlPoint ).m_nParent;
  2713. }
  2714. FORCEINLINE CParticleSnapshot *CParticleCollection::GetControlPointSnapshot( int nControlPoint ) const
  2715. {
  2716. Assert( nControlPoint <= GetHighestControlPoint() );
  2717. if ( nControlPoint == -1 )
  2718. return NULL;
  2719. return ControlPoint( nControlPoint ).m_pSnapshot;
  2720. }
  2721. #endif // PARTICLES_H