aboutsummaryrefslogtreecommitdiff
path: root/sp/src/public/particles/particles.h
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /sp/src/public/particles/particles.h
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'sp/src/public/particles/particles.h')
-rw-r--r--sp/src/public/particles/particles.h2245
1 files changed, 2245 insertions, 0 deletions
diff --git a/sp/src/public/particles/particles.h b/sp/src/public/particles/particles.h
new file mode 100644
index 00000000..7ecac997
--- /dev/null
+++ b/sp/src/public/particles/particles.h
@@ -0,0 +1,2245 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: particle system definitions
+//
+//===========================================================================//
+
+#ifndef PARTICLES_H
+#define PARTICLES_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "mathlib/mathlib.h"
+#include "mathlib/vector.h"
+#include "mathlib/ssemath.h"
+#include "materialsystem/imaterialsystem.h"
+#include "dmxloader/dmxelement.h"
+#include "tier1/utlintrusivelist.h"
+#include "vstdlib/random.h"
+#include "tier1/utlobjectreference.h"
+#include "tier1/UtlStringMap.h"
+#include "tier1/utlmap.h"
+#include "materialsystem/MaterialSystemUtil.h"
+#include "trace.h"
+#include "tier1/utlsoacontainer.h"
+
+#if defined( CLIENT_DLL )
+#include "c_pixel_visibility.h"
+#endif
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+struct DmxElementUnpackStructure_t;
+class CParticleSystemDefinition;
+class CParticleCollection;
+class CParticleOperatorInstance;
+class CParticleSystemDictionary;
+class CUtlBuffer;
+class IParticleOperatorDefinition;
+class CSheet;
+class CMeshBuilder;
+extern float s_pRandomFloats[];
+
+
+//-----------------------------------------------------------------------------
+// Random numbers
+//-----------------------------------------------------------------------------
+#define MAX_RANDOM_FLOATS 4096
+#define RANDOM_FLOAT_MASK ( MAX_RANDOM_FLOATS - 1 )
+
+
+//-----------------------------------------------------------------------------
+// Particle attributes
+//-----------------------------------------------------------------------------
+#define MAX_PARTICLE_ATTRIBUTES 32
+
+#define DEFPARTICLE_ATTRIBUTE( name, bit ) \
+ const int PARTICLE_ATTRIBUTE_##name##_MASK = (1 << bit); \
+ const int PARTICLE_ATTRIBUTE_##name = bit;
+
+// required
+DEFPARTICLE_ATTRIBUTE( XYZ, 0 );
+
+// particle lifetime (duration) of particle as a float.
+DEFPARTICLE_ATTRIBUTE( LIFE_DURATION, 1 );
+
+// prev coordinates for verlet integration
+DEFPARTICLE_ATTRIBUTE( PREV_XYZ, 2 );
+
+// radius of particle
+DEFPARTICLE_ATTRIBUTE( RADIUS, 3 );
+
+// rotation angle of particle
+DEFPARTICLE_ATTRIBUTE( ROTATION, 4 );
+
+// rotation speed of particle
+DEFPARTICLE_ATTRIBUTE( ROTATION_SPEED, 5 );
+
+// tint of particle
+DEFPARTICLE_ATTRIBUTE( TINT_RGB, 6 );
+
+// alpha tint of particle
+DEFPARTICLE_ATTRIBUTE( ALPHA, 7 );
+
+// creation time stamp (relative to particle system creation)
+DEFPARTICLE_ATTRIBUTE( CREATION_TIME, 8 );
+
+// sequnece # (which animation sequence number this particle uses )
+DEFPARTICLE_ATTRIBUTE( SEQUENCE_NUMBER, 9 );
+
+// length of the trail
+DEFPARTICLE_ATTRIBUTE( TRAIL_LENGTH, 10 );
+
+// unique particle identifier
+DEFPARTICLE_ATTRIBUTE( PARTICLE_ID, 11 );
+
+// unique rotation around up vector
+DEFPARTICLE_ATTRIBUTE( YAW, 12 );
+
+// second sequnece # (which animation sequence number this particle uses )
+DEFPARTICLE_ATTRIBUTE( SEQUENCE_NUMBER1, 13 );
+
+// hit box index
+DEFPARTICLE_ATTRIBUTE( HITBOX_INDEX, 14 );
+
+DEFPARTICLE_ATTRIBUTE( HITBOX_RELATIVE_XYZ, 15 );
+
+DEFPARTICLE_ATTRIBUTE( ALPHA2, 16 );
+
+// particle trace caching fields
+DEFPARTICLE_ATTRIBUTE( TRACE_P0, 17 ); // start pnt of trace
+DEFPARTICLE_ATTRIBUTE( TRACE_P1, 18 ); // end pnt of trace
+DEFPARTICLE_ATTRIBUTE( TRACE_HIT_T, 19 ); // 0..1 if hit
+DEFPARTICLE_ATTRIBUTE( TRACE_HIT_NORMAL, 20 ); // 0 0 0 if no hit
+
+
+#define MAX_PARTICLE_CONTROL_POINTS 64
+
+#define ATTRIBUTES_WHICH_ARE_VEC3S_MASK ( PARTICLE_ATTRIBUTE_TRACE_P0_MASK | PARTICLE_ATTRIBUTE_TRACE_P1_MASK | \
+ PARTICLE_ATTRIBUTE_TRACE_HIT_NORMAL | PARTICLE_ATTRIBUTE_XYZ_MASK | \
+ PARTICLE_ATTRIBUTE_PREV_XYZ_MASK | PARTICLE_ATTRIBUTE_TINT_RGB_MASK | \
+ PARTICLE_ATTRIBUTE_HITBOX_RELATIVE_XYZ_MASK )
+#define ATTRIBUTES_WHICH_ARE_0_TO_1 (PARTICLE_ATTRIBUTE_ALPHA_MASK | PARTICLE_ATTRIBUTE_ALPHA2_MASK)
+#define ATTRIBUTES_WHICH_ARE_ANGLES (PARTICLE_ATTRIBUTE_ROTATION_MASK | PARTICLE_ATTRIBUTE_YAW_MASK )
+#define ATTRIBUTES_WHICH_ARE_INTS (PARTICLE_ATTRIBUTE_PARTICLE_ID_MASK | PARTICLE_ATTRIBUTE_HITBOX_INDEX_MASK )
+
+#if defined( _X360 )
+#define MAX_PARTICLES_IN_A_SYSTEM 2000
+#else
+#define MAX_PARTICLES_IN_A_SYSTEM 5000
+#endif
+
+// Set this to 1 or 0 to enable or disable particle profiling.
+// Note that this profiling is expensive on Linux, and some anti-virus
+// products can make this *extremely* expensive on Windows.
+#define MEASURE_PARTICLE_PERF 0
+
+
+//-----------------------------------------------------------------------------
+// Particle function types
+//-----------------------------------------------------------------------------
+enum ParticleFunctionType_t
+{
+ FUNCTION_RENDERER = 0,
+ FUNCTION_OPERATOR,
+ FUNCTION_INITIALIZER,
+ FUNCTION_EMITTER,
+ FUNCTION_CHILDREN, // NOTE: This one is a fake function type, only here to help eliminate a ton of duplicated code in the editor
+ FUNCTION_FORCEGENERATOR,
+ FUNCTION_CONSTRAINT,
+ PARTICLE_FUNCTION_COUNT
+};
+
+struct CParticleVisibilityInputs
+{
+ float m_flInputMin;
+ float m_flInputMax;
+ float m_flAlphaScaleMin;
+ float m_flAlphaScaleMax;
+ float m_flRadiusScaleMin;
+ float m_flRadiusScaleMax;
+ float m_flProxyRadius;
+ float m_flBBoxScale;
+ bool m_bUseBBox;
+ int m_nCPin;
+};
+
+struct ModelHitBoxInfo_t
+{
+ Vector m_vecBoxMins;
+ Vector m_vecBoxMaxes;
+ matrix3x4_t m_Transform;
+};
+
+class CModelHitBoxesInfo
+{
+public:
+ float m_flLastUpdateTime;
+ float m_flPrevLastUpdateTime;
+ int m_nNumHitBoxes;
+ int m_nNumPrevHitBoxes;
+ ModelHitBoxInfo_t *m_pHitBoxes;
+ ModelHitBoxInfo_t *m_pPrevBoxes;
+
+ bool CurAndPrevValid( void ) const
+ {
+ return ( m_nNumHitBoxes && ( m_nNumPrevHitBoxes == m_nNumHitBoxes ) );
+ }
+
+ CModelHitBoxesInfo( void )
+ {
+ m_flLastUpdateTime = -1;
+ m_nNumHitBoxes = 0;
+ m_nNumPrevHitBoxes = 0;
+ m_pHitBoxes = NULL;
+ m_pPrevBoxes = NULL;
+ }
+
+ ~CModelHitBoxesInfo( void )
+ {
+ if ( m_pHitBoxes )
+ delete[] m_pHitBoxes;
+ if ( m_pPrevBoxes )
+ delete[] m_pPrevBoxes;
+ }
+
+};
+
+
+
+
+//-----------------------------------------------------------------------------
+// Interface to allow the particle system to call back into the client
+//-----------------------------------------------------------------------------
+
+#define PARTICLE_SYSTEM_QUERY_INTERFACE_VERSION "VParticleSystemQuery001"
+
+class IParticleSystemQuery : public IAppSystem
+{
+public:
+ virtual void GetLightingAtPoint( const Vector& vecOrigin, Color &tint ) = 0;
+ virtual void TraceLine( const Vector& vecAbsStart,
+ const Vector& vecAbsEnd, unsigned int mask,
+ const class IHandleEntity *ignore,
+ int collisionGroup,
+ CBaseTrace *ptr ) = 0;
+
+ // given a possible spawn point, tries to movie it to be on or in the source object. returns
+ // true if it succeeded
+ virtual bool MovePointInsideControllingObject( CParticleCollection *pParticles,
+ void *pObject,
+ Vector *pPnt )
+ {
+ return true;
+ }
+
+ virtual bool IsPointInControllingObjectHitBox(
+ CParticleCollection *pParticles,
+ int nControlPointNumber, Vector vecPos, bool bBBoxOnly = false )
+ {
+ return true;
+ }
+
+ virtual int GetCollisionGroupFromName( const char *pszCollisionGroupName )
+ {
+ return 0; // == COLLISION_GROUP_NONE
+ }
+
+ virtual void GetRandomPointsOnControllingObjectHitBox(
+ CParticleCollection *pParticles,
+ int nControlPointNumber,
+ int nNumPtsOut,
+ float flBBoxScale,
+ int nNumTrysToGetAPointInsideTheModel,
+ Vector *pPntsOut,
+ Vector vecDirectionBias,
+ Vector *pHitBoxRelativeCoordOut = NULL,
+ int *pHitBoxIndexOut = NULL ) = 0;
+
+
+ virtual int GetControllingObjectHitBoxInfo(
+ CParticleCollection *pParticles,
+ int nControlPointNumber,
+ int nBufSize, // # of output slots available
+ ModelHitBoxInfo_t *pHitBoxOutputBuffer )
+ {
+ // returns number of hit boxes output
+ return 0;
+ }
+
+ virtual Vector GetLocalPlayerPos( void )
+ {
+ return vec3_origin;
+ }
+
+ virtual void GetLocalPlayerEyeVectors( Vector *pForward, Vector *pRight = NULL, Vector *pUp = NULL )
+ {
+ *pForward = vec3_origin;
+ *pRight = vec3_origin;
+ *pUp = vec3_origin;
+ }
+
+ virtual float GetPixelVisibility( int *pQueryHandle, const Vector &vecOrigin, float flScale ) = 0;
+
+ virtual void SetUpLightingEnvironment( const Vector& pos )
+ {
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+//
+// Particle system manager. Using a class because tools need it that way
+// so the SFM and PET tools can share managers despite being linked to
+// separate particle system .libs
+//
+//-----------------------------------------------------------------------------
+typedef int ParticleSystemHandle_t;
+
+class CParticleSystemMgr
+{
+public:
+ // Constructor, destructor
+ CParticleSystemMgr();
+ ~CParticleSystemMgr();
+
+ // Initialize the particle system
+ bool Init( IParticleSystemQuery *pQuery );
+
+ // 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
+ // the server can omit the code needed for rendering/simulation, if desired.
+ void AddBuiltinSimulationOperators( void );
+ void AddBuiltinRenderingOperators( void );
+
+
+
+ // Registration of known operators
+ void AddParticleOperator( ParticleFunctionType_t nOpType, IParticleOperatorDefinition *pOpFactory );
+
+ // Read a particle config file, add it to the list of particle configs
+ bool ReadParticleConfigFile( const char *pFileName, bool bPrecache, bool bDecommitTempMemory = true );
+ bool ReadParticleConfigFile( CUtlBuffer &buf, bool bPrecache, bool bDecommitTempMemory = true, const char *pFileName = NULL );
+ void DecommitTempMemory();
+
+ // For recording, write a specific particle system to a CUtlBuffer in DMX format
+ bool WriteParticleConfigFile( const char *pParticleSystemName, CUtlBuffer &buf, bool bPreventNameBasedLookup = false );
+ bool WriteParticleConfigFile( const DmObjectId_t& id, CUtlBuffer &buf, bool bPreventNameBasedLookup = false );
+
+ // create a particle system by name. returns null if one of that name does not exist
+ CParticleCollection *CreateParticleCollection( const char *pParticleSystemName, float flDelay = 0.0f, int nRandomSeed = 0 );
+
+ // create a particle system given a particle system id
+ CParticleCollection *CreateParticleCollection( const DmObjectId_t &id, float flDelay = 0.0f, int nRandomSeed = 0 );
+
+ // Is a particular particle system defined?
+ bool IsParticleSystemDefined( const char *pParticleSystemName );
+ bool IsParticleSystemDefined( const DmObjectId_t &id );
+
+ // Returns the index of the specified particle system.
+ ParticleSystemHandle_t GetParticleSystemIndex( const char *pParticleSystemName );
+
+ // Returns the name of the specified particle system.
+ const char *GetParticleSystemNameFromIndex( ParticleSystemHandle_t iIndex );
+
+ // Return the number of particle systems in our dictionary
+ int GetParticleSystemCount( void );
+
+ // call to get available particle operator definitions
+ // NOTE: FUNCTION_CHILDREN will return a faked one, for ease of writing the editor
+ CUtlVector< IParticleOperatorDefinition *> &GetAvailableParticleOperatorList( ParticleFunctionType_t nWhichList );
+
+ // Returns the unpack structure for a particle system definition
+ const DmxElementUnpackStructure_t *GetParticleSystemDefinitionUnpackStructure();
+
+ // Particle sheet management
+ void ShouldLoadSheets( bool bLoadSheets );
+ CSheet *FindOrLoadSheet( char const *pszFname, ITexture *pTexture );
+ CSheet *FindOrLoadSheet( IMaterial *pMaterial );
+ void FlushAllSheets( void );
+
+
+ // Render cache used to render opaque particle collections
+ void ResetRenderCache( void );
+ void AddToRenderCache( CParticleCollection *pParticles );
+ void DrawRenderCache( bool bShadowDepth );
+
+ IParticleSystemQuery *Query( void ) { return m_pQuery; }
+
+ // return the particle field name
+ const char* GetParticleFieldName( int nParticleField ) const;
+
+ // WARNING: the pointer returned by this function may be invalidated
+ // *at any time* by the editor, so do not ever cache it.
+ CParticleSystemDefinition* FindParticleSystem( const char *pName );
+ CParticleSystemDefinition* FindParticleSystem( const DmObjectId_t& id );
+
+ void CommitProfileInformation( bool bCommit ); // call after simulation, if you want
+ // sim time recorded. if oyu pass
+ // flase, info will be thrown away and
+ // uncomitted time reset. Having this
+ // function lets you only record
+ // profile data for slow frames if
+ // desired.
+
+
+ void DumpProfileInformation( void ); // write particle_profile.csv
+
+ // Cache/uncache materials used by particle systems
+ void PrecacheParticleSystem( const char *pName );
+ void UncacheAllParticleSystems();
+
+ // Sets the last simulation time, used for particle system sleeping logic
+ void SetLastSimulationTime( float flTime );
+ float GetLastSimulationTime() const;
+
+ int Debug_GetTotalParticleCount() const;
+ bool Debug_FrameWarningNeededTestAndReset();
+ float ParticleThrottleScaling() const; // Returns 1.0 = not restricted, 0.0 = fully restricted (i.e. don't draw!)
+ bool ParticleThrottleRandomEnable() const; // Retruns a randomish bool to say if you should draw this particle.
+
+ void TallyParticlesRendered( int nVertexCount, int nIndexCount = 0 );
+
+private:
+ struct RenderCache_t
+ {
+ IMaterial *m_pMaterial;
+ CUtlVector< CParticleCollection * > m_ParticleCollections;
+ };
+
+ struct BatchStep_t
+ {
+ CParticleCollection *m_pParticles;
+ CParticleOperatorInstance *m_pRenderer;
+ void *m_pContext;
+ int m_nFirstParticle;
+ int m_nParticleCount;
+ int m_nVertCount;
+ };
+
+ struct Batch_t
+ {
+ int m_nVertCount;
+ int m_nIndexCount;
+ CUtlVector< BatchStep_t > m_BatchStep;
+ };
+
+ // Unserialization-related methods
+ bool ReadParticleDefinitions( CUtlBuffer &buf, const char *pFileName, bool bPrecache, bool bDecommitTempMemory );
+ void AddParticleSystem( CDmxElement *pParticleSystem );
+
+ // Serialization-related methods
+ CDmxElement *CreateParticleDmxElement( const DmObjectId_t &id );
+ CDmxElement *CreateParticleDmxElement( const char *pParticleSystemName );
+
+ bool WriteParticleConfigFile( CDmxElement *pParticleSystem, CUtlBuffer &buf, bool bPreventNameBasedLookup );
+
+ // Builds a list of batches to render
+ void BuildBatchList( int iRenderCache, IMatRenderContext *pRenderContext, CUtlVector< Batch_t >& batches );
+
+ // Known operators
+ CUtlVector<IParticleOperatorDefinition *> m_ParticleOperators[PARTICLE_FUNCTION_COUNT];
+
+ // Particle system dictionary
+ CParticleSystemDictionary *m_pParticleSystemDictionary;
+
+ // typedef CUtlMap< ITexture *, CSheet* > SheetsCache;
+ typedef CUtlStringMap< CSheet* > SheetsCache_t;
+ SheetsCache_t m_SheetList;
+
+ // attaching and dtaching killlists. when simulating, a particle system gets a kill list. after
+ // simulating, the memory for that will be used for the next particle system. This matters for
+ // threaded particles, because we don't want to share the same kill list between simultaneously
+ // simulating particle systems.
+ void AttachKillList( CParticleCollection *pParticles);
+ void DetachKillList( CParticleCollection *pParticles);
+
+ // For visualization (currently can only visualize one operator at a time)
+ CParticleCollection *m_pVisualizedParticles;
+ DmObjectId_t m_VisualizedOperatorId;
+ IParticleSystemQuery *m_pQuery;
+ CUtlVector< RenderCache_t > m_RenderCache;
+ IMaterial *m_pShadowDepthMaterial;
+ float m_flLastSimulationTime;
+
+ bool m_bDidInit;
+ bool m_bUsingDefaultQuery;
+ bool m_bShouldLoadSheets;
+
+ int m_nNumFramesMeasured;
+
+ enum { c_nNumFramesTracked = 10 };
+ int m_nParticleVertexCountHistory[c_nNumFramesTracked];
+ float m_fParticleCountScaling;
+ int m_nParticleIndexCount;
+ int m_nParticleVertexCount;
+ bool m_bFrameWarningNeeded;
+
+ friend class CParticleSystemDefinition;
+ friend class CParticleCollection;
+};
+
+extern CParticleSystemMgr *g_pParticleSystemMgr;
+
+
+//-----------------------------------------------------------------------------
+// A particle system can only have 1 operator using a particular ID
+//-----------------------------------------------------------------------------
+enum ParticleOperatorId_t
+{
+ // Generic IDs
+ OPERATOR_GENERIC = -2, // Can have as many of these as you want
+ OPERATOR_SINGLETON = -1, // Can only have 1 operator with the same name as this one
+
+ // Renderer operator IDs
+
+ // Operator IDs
+
+ // Initializer operator IDs
+ OPERATOR_PI_POSITION, // Particle initializer: position (can only have 1 position setter)
+ OPERATOR_PI_RADIUS,
+ OPERATOR_PI_ALPHA,
+ OPERATOR_PI_TINT_RGB,
+ OPERATOR_PI_ROTATION,
+ OPERATOR_PI_YAW,
+
+ // Emitter IDs
+
+ OPERATOR_ID_COUNT,
+};
+
+
+//-----------------------------------------------------------------------------
+// Class factory for particle operators
+//-----------------------------------------------------------------------------
+class IParticleOperatorDefinition
+{
+public:
+ virtual const char *GetName() const = 0;
+ virtual CParticleOperatorInstance *CreateInstance( const DmObjectId_t &id ) const = 0;
+// virtual void DestroyInstance( CParticleOperatorInstance *pInstance ) const = 0;
+ virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const = 0;
+ virtual ParticleOperatorId_t GetId() const = 0;
+ virtual bool IsObsolete() const = 0;
+ virtual size_t GetClassSize() const = 0;
+
+#if MEASURE_PARTICLE_PERF
+ // performance monitoring
+ float m_flMaxExecutionTime;
+ float m_flTotalExecutionTime;
+ float m_flUncomittedTime;
+
+ FORCEINLINE void RecordExecutionTime( float flETime )
+ {
+ m_flUncomittedTime += flETime;
+ m_flMaxExecutionTime = MAX( m_flMaxExecutionTime, flETime );
+ }
+
+ FORCEINLINE float TotalRecordedExecutionTime( void ) const
+ {
+ return m_flTotalExecutionTime;
+ }
+
+ FORCEINLINE float MaximumRecordedExecutionTime( void ) const
+ {
+ return m_flMaxExecutionTime;
+ }
+#endif
+};
+
+
+//-----------------------------------------------------------------------------
+// Particle operators
+//-----------------------------------------------------------------------------
+class CParticleOperatorInstance
+{
+public:
+ // custom allocators so we can be simd aligned
+ void *operator new( size_t nSize );
+ void* operator new( size_t size, int nBlockUse, const char *pFileName, int nLine );
+ void operator delete( void *pData );
+ void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine );
+
+ // unpack structure will be applied by creator. add extra initialization needed here
+ virtual void InitParams( CParticleSystemDefinition *pDef, CDmxElement *pElement )
+ {
+ }
+
+ virtual size_t GetRequiredContextBytes( ) const
+ {
+ return 0;
+ }
+
+ virtual void InitializeContextData( CParticleCollection *pParticles, void *pContext ) const
+ {
+ }
+
+ virtual uint32 GetWrittenAttributes( void ) const = 0;
+ virtual uint32 GetReadAttributes( void ) const = 0;
+ virtual uint64 GetReadControlPointMask() const
+ {
+ return 0;
+ }
+
+ // Used when an operator needs to read the attributes of a particle at spawn time
+ virtual uint32 GetReadInitialAttributes( void ) const
+ {
+ return 0;
+ }
+
+ // a particle simulator does this
+ virtual void Operate( CParticleCollection *pParticles, float flOpStrength, void *pContext ) const
+ {
+ }
+
+ // a renderer overrides this
+ virtual void Render( IMatRenderContext *pRenderContext,
+ CParticleCollection *pParticles, void *pContext ) const
+ {
+ }
+
+ virtual bool IsBatchable() const
+ {
+ return true;
+ }
+
+ virtual void RenderUnsorted( CParticleCollection *pParticles, void *pContext, IMatRenderContext *pRenderContext, CMeshBuilder &meshBuilder, int nVertexOffset, int nFirstParticle, int nParticleCount ) const
+ {
+ }
+
+ // Returns the number of verts + indices to render
+ virtual int GetParticlesToRender( CParticleCollection *pParticles, void *pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int *pVertsUsed, int *pIndicesUsed ) const
+ {
+ *pVertsUsed = 0;
+ *pIndicesUsed = 0;
+ return 0;
+ }
+
+
+ // emitters over-ride this. Return a mask of what fields you initted
+ virtual uint32 Emit( CParticleCollection *pParticles, float flOpCurStrength,
+ void *pContext ) const
+ {
+ return 0;
+ }
+
+ // emitters over-ride this.
+ virtual void StopEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly = false ) const
+ {
+ }
+ virtual void StartEmission( CParticleCollection *pParticles, void *pContext, bool bInfiniteOnly = false ) const
+ {
+ }
+ virtual void Restart( CParticleCollection *pParticles, void *pContext ) {}
+
+ // initters over-ride this
+ virtual void InitParticleSystem( CParticleCollection *pParticles, void *pContext ) const
+ {
+ }
+
+
+ // a force generator does this. It accumulates in the force array
+ virtual void AddForces( FourVectors *AccumulatedForces,
+ CParticleCollection *pParticles,
+ int nBlocks,
+ float flCurStrength,
+ void *pContext ) const
+ {
+ }
+
+
+ // this is called for each constarint every frame. It can set up data like nearby world traces,
+ // etc
+ virtual void SetupConstraintPerFrameData( CParticleCollection *pParticles,
+ void *pContext ) const
+ {
+ }
+
+
+ // a constraint overrides this. It shold return a true if it did anything
+ virtual bool EnforceConstraint( int nStartBlock,
+ int nNumBlocks,
+ CParticleCollection *pParticles,
+ void *pContext,
+ int nNumValidParticlesInLastChunk ) const
+ {
+ return false;
+ }
+
+ // should the constraint be run only once after all other constraints?
+ virtual bool IsFinalConstaint( void ) const
+ {
+ return false;
+ }
+
+ // determines if a mask needs to be initialized multiple times.
+ virtual bool InitMultipleOverride()
+ {
+ return false;
+ }
+
+
+ // Indicates if this initializer is scrub-safe (initializers don't use random numbers, for example)
+ virtual bool IsScrubSafe()
+ {
+ return false;
+ }
+
+ // particle-initters over-ride this
+ virtual void InitNewParticlesScalar( CParticleCollection *pParticles, int nFirstParticle, int n_particles, int attribute_write_mask, void *pContext ) const
+ {
+ }
+
+ // 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.
+ virtual void InitNewParticlesBlock( CParticleCollection *pParticles, int start_block, int n_blocks, int attribute_write_mask, void *pContext ) const
+ {
+ // default behaviour is to call the scalar one 4x times
+ InitNewParticlesScalar( pParticles, 4*start_block, 4*n_blocks, attribute_write_mask, pContext );
+ }
+
+ // splits particle initialization up into scalar and block sections, callingt he right code
+ void InitNewParticles( CParticleCollection *pParticles, int nFirstParticle, int n_particles, int attribute_write_mask , void *pContext) const;
+
+
+ // this function is queried to determine if a particle system is over and doen with. A particle
+ // system is done with when it has noparticles and no operators intend to create any more
+ virtual bool MayCreateMoreParticles( CParticleCollection *pParticles, void *pContext ) const
+ {
+ return false;
+ }
+
+ // Returns the operator definition that spawned this operator
+ const IParticleOperatorDefinition *GetDefinition()
+ {
+ return m_pDef;
+ }
+
+ virtual bool ShouldRunBeforeEmitters( void ) const
+ {
+ return false;
+ }
+
+ // Called when the SFM wants to skip forward in time
+ virtual void SkipToTime( float flTime, CParticleCollection *pParticles, void *pContext ) const {}
+
+ // Returns a unique ID for this definition
+ const DmObjectId_t& GetId() { return m_Id; }
+
+ // Used for editing + debugging to visualize the operator in 3D
+ virtual void Render( CParticleCollection *pParticles ) const {}
+
+ // Used as a debugging mechanism to prevent bogus calls to RandomInt or RandomFloat inside operators
+ // Use CParticleCollection::RandomInt/RandomFloat instead
+ int RandomInt( int nMin, int nMax )
+ {
+ // NOTE: Use CParticleCollection::RandomInt!
+ Assert(0);
+ return 0;
+ }
+
+ float RandomFloat( float flMinVal = 0.0f, float flMaxVal = 1.0f )
+ {
+ // NOTE: Use CParticleCollection::RandomFloat!
+ Assert(0);
+ return 0.0f;
+ }
+
+ float RandomFloatExp( float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f )
+ {
+ // NOTE: Use CParticleCollection::RandomFloatExp!
+ Assert(0);
+ return 0.0f;
+ }
+
+ float m_flOpStartFadeInTime;
+ float m_flOpEndFadeInTime;
+ float m_flOpStartFadeOutTime;
+ float m_flOpEndFadeOutTime;
+ float m_flOpFadeOscillatePeriod;
+
+ virtual ~CParticleOperatorInstance( void )
+ {
+ // so that sheet references, etc can be cleaned up
+ }
+
+protected:
+ // utility function for initting a scalar attribute to a random range in an sse fashion
+ void InitScalarAttributeRandomRangeBlock( int nAttributeId, float fMinValue, float fMaxValue,
+ CParticleCollection *pParticles, int nStartBlock, int nBlockCount ) const;
+ void InitScalarAttributeRandomRangeExpBlock( int nAttributeId, float fMinValue, float fMaxValue, float fExp,
+ CParticleCollection *pParticles, int nStartBlock, int nBlockCount ) const;
+ void AddScalarAttributeRandomRangeBlock( int nAttributeId, float fMinValue, float fMaxValue, float fExp,
+ CParticleCollection *pParticles, int nStartBlock, int nBlockCount, bool bRandomlyInvert ) const;
+
+private:
+ friend class CParticleCollection;
+
+ const IParticleOperatorDefinition *m_pDef;
+ void SetDefinition( const IParticleOperatorDefinition * pDef, const DmObjectId_t &id )
+ {
+ m_pDef = pDef;
+ CopyUniqueId( id, &m_Id );
+ }
+
+ DmObjectId_t m_Id;
+
+ template <typename T> friend class CParticleOperatorDefinition;
+};
+
+class CParticleRenderOperatorInstance : public CParticleOperatorInstance
+{
+public:
+
+ CParticleVisibilityInputs VisibilityInputs;
+};
+
+//-----------------------------------------------------------------------------
+// Helper macro for creating particle operator factories
+//-----------------------------------------------------------------------------
+template < class T >
+class CParticleOperatorDefinition : public IParticleOperatorDefinition
+{
+public:
+ CParticleOperatorDefinition( const char *pFactoryName, ParticleOperatorId_t id, bool bIsObsolete ) : m_pFactoryName( pFactoryName ), m_Id( id )
+ {
+#if MEASURE_PARTICLE_PERF
+ m_flTotalExecutionTime = 0.0f;
+ m_flMaxExecutionTime = 0.0f;
+ m_flUncomittedTime = 0.0f;
+#endif
+ m_bIsObsolete = bIsObsolete;
+ }
+
+ virtual const char *GetName() const
+ {
+ return m_pFactoryName;
+ }
+
+ virtual ParticleOperatorId_t GetId() const
+ {
+ return m_Id;
+ }
+
+ virtual CParticleOperatorInstance *CreateInstance( const DmObjectId_t &id ) const
+ {
+ CParticleOperatorInstance *pOp = new T;
+ pOp->SetDefinition( this, id );
+ return pOp;
+ }
+
+ virtual const DmxElementUnpackStructure_t* GetUnpackStructure() const
+ {
+ return m_pUnpackParams;
+ }
+
+ // Editor won't display obsolete operators
+ virtual bool IsObsolete() const
+ {
+ return m_bIsObsolete;
+ }
+
+ virtual size_t GetClassSize() const
+ {
+ return sizeof( T );
+ }
+
+private:
+ const char *m_pFactoryName;
+ ParticleOperatorId_t m_Id;
+ bool m_bIsObsolete;
+ static DmxElementUnpackStructure_t *m_pUnpackParams;
+};
+
+#define DECLARE_PARTICLE_OPERATOR( _className ) \
+ DECLARE_DMXELEMENT_UNPACK() \
+ friend class CParticleOperatorDefinition<_className >
+
+#define DEFINE_PARTICLE_OPERATOR( _className, _operatorName, _id ) \
+ static CParticleOperatorDefinition<_className> s_##_className##Factory( _operatorName, _id, false )
+
+#define DEFINE_PARTICLE_OPERATOR_OBSOLETE( _className, _operatorName, _id ) \
+ static CParticleOperatorDefinition<_className> s_##_className##Factory( _operatorName, _id, true )
+
+#define BEGIN_PARTICLE_OPERATOR_UNPACK( _className ) \
+ BEGIN_DMXELEMENT_UNPACK( _className ) \
+ DMXELEMENT_UNPACK_FIELD( "operator start fadein","0", float, m_flOpStartFadeInTime ) \
+ DMXELEMENT_UNPACK_FIELD( "operator end fadein","0", float, m_flOpEndFadeInTime ) \
+ DMXELEMENT_UNPACK_FIELD( "operator start fadeout","0", float, m_flOpStartFadeOutTime ) \
+ DMXELEMENT_UNPACK_FIELD( "operator end fadeout","0", float, m_flOpEndFadeOutTime ) \
+ DMXELEMENT_UNPACK_FIELD( "operator fade oscillate","0", float, m_flOpFadeOscillatePeriod )
+
+#define END_PARTICLE_OPERATOR_UNPACK( _className ) \
+ END_DMXELEMENT_UNPACK_TEMPLATE( _className, CParticleOperatorDefinition<_className>::m_pUnpackParams )
+
+#define BEGIN_PARTICLE_RENDER_OPERATOR_UNPACK( _className ) \
+ BEGIN_PARTICLE_OPERATOR_UNPACK( _className ) \
+ DMXELEMENT_UNPACK_FIELD( "Visibility Proxy Input Control Point Number", "-1", int, VisibilityInputs.m_nCPin ) \
+ DMXELEMENT_UNPACK_FIELD( "Visibility Proxy Radius", "1.0", float, VisibilityInputs.m_flProxyRadius ) \
+ DMXELEMENT_UNPACK_FIELD( "Visibility input minimum","0", float, VisibilityInputs.m_flInputMin ) \
+ DMXELEMENT_UNPACK_FIELD( "Visibility input maximum","1", float, VisibilityInputs.m_flInputMax ) \
+ DMXELEMENT_UNPACK_FIELD( "Visibility Alpha Scale minimum","0", float, VisibilityInputs.m_flAlphaScaleMin ) \
+ DMXELEMENT_UNPACK_FIELD( "Visibility Alpha Scale maximum","1", float, VisibilityInputs.m_flAlphaScaleMax ) \
+ DMXELEMENT_UNPACK_FIELD( "Visibility Radius Scale minimum","1", float, VisibilityInputs.m_flRadiusScaleMin ) \
+ DMXELEMENT_UNPACK_FIELD( "Visibility Radius Scale maximum","1", float, VisibilityInputs.m_flRadiusScaleMax )
+// DMXELEMENT_UNPACK_FIELD( "Visibility Use Bounding Box for Proxy", "0", bool, VisibilityInputs.m_bUseBBox )
+// DMXELEMENT_UNPACK_FIELD( "Visibility Bounding Box Scale", "1.0", float, VisibilityInputs.m_flBBoxScale )
+
+#define REGISTER_PARTICLE_OPERATOR( _type, _className ) \
+ g_pParticleSystemMgr->AddParticleOperator( _type, &s_##_className##Factory )
+
+
+// need to think about particle constraints in terms of segregating affected particles so as to
+// run multi-pass constraints on only a subset
+
+
+//-----------------------------------------------------------------------------
+// flags for particle systems
+//-----------------------------------------------------------------------------
+enum
+{
+ PCFLAGS_FIRST_FRAME = 0x1,
+ PCFLAGS_PREV_CONTROL_POINTS_INITIALIZED = 0x2,
+};
+
+
+
+#define DEBUG_PARTICLE_SORT 0
+
+// sorting functionality for rendering. Call GetRenderList( bool bSorted ) to get the list of
+// particles to render (sorted or not, including children).
+// **do not casually change this structure**. The sorting code treats it interchangably as an SOA
+// and accesses it using sse. Any changes to this struct need the sort code updated.**
+struct ParticleRenderData_t
+{
+ float m_flSortKey; // what we sort by
+ int m_nIndex; // index or fudged index (for child particles)
+ float m_flRadius; // effective radius, using visibility
+#if VALVE_LITTLE_ENDIAN
+ uint8 m_nAlpha; // effective alpha, combining alpha and alpha2 and vis. 0 - 255
+ uint8 m_nAlphaPad[3]; // this will be written to
+#else
+ uint8 m_nAlphaPad[3]; // this will be written to
+ uint8 m_nAlpha; // effective alpha, combining alpha and alpha2 and vis. 0 - 255
+#endif
+};
+
+struct ExtendedParticleRenderData_t : ParticleRenderData_t
+{
+ float m_flX;
+ float m_flY;
+ float m_flZ;
+ float m_flPad;
+};
+
+
+typedef struct ALIGN16 _FourInts
+{
+ int32 m_nValue[4];
+} ALIGN16_POST FourInts;
+
+
+
+// structure describing the parameter block used by operators which use the path between two points to
+// control particles.
+struct CPathParameters
+{
+ int m_nStartControlPointNumber;
+ int m_nEndControlPointNumber;
+ int m_nBulgeControl;
+ float m_flBulge;
+ float m_flMidPoint;
+
+ void ClampControlPointIndices( void )
+ {
+ m_nStartControlPointNumber = MAX(0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nStartControlPointNumber ) );
+ m_nEndControlPointNumber = MAX(0, MIN( MAX_PARTICLE_CONTROL_POINTS-1, m_nEndControlPointNumber ) );
+ }
+};
+
+struct CParticleVisibilityData
+{
+ float m_flAlphaVisibility;
+ float m_flRadiusVisibility;
+ bool m_bUseVisibility;
+};
+
+struct CParticleControlPoint
+{
+ Vector m_Position;
+ Vector m_PrevPosition;
+
+ // orientation
+ Vector m_ForwardVector;
+ Vector m_UpVector;
+ Vector m_RightVector;
+
+ // reference to entity or whatever this control point comes from
+ void *m_pObject;
+
+ // parent for hierarchies
+ int m_nParent;
+};
+
+
+// struct for simd xform to transform a point from an identitiy coordinate system to that of the control point
+struct CParticleSIMDTransformation
+{
+ FourVectors m_v4Origin;
+ FourVectors m_v4Fwd;
+ FourVectors m_v4Up;
+ FourVectors m_v4Right;
+
+
+ FORCEINLINE void VectorRotate( FourVectors &InPnt )
+ {
+ fltx4 fl4OutX = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.x ), MulSIMD( InPnt.z, m_v4Up.x ) ), MulSIMD( InPnt.y, m_v4Right.x ) );
+ fltx4 fl4OutY = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.y ), MulSIMD( InPnt.z, m_v4Up.y ) ), MulSIMD( InPnt.y, m_v4Right.y ) );
+ InPnt.z = SubSIMD( AddSIMD( MulSIMD( InPnt.x, m_v4Fwd.z ), MulSIMD( InPnt.z, m_v4Up.z ) ), MulSIMD( InPnt.y, m_v4Right.z ) );
+ InPnt.x = fl4OutX;
+ InPnt.y = fl4OutY;
+ }
+
+ FORCEINLINE void VectorTransform( FourVectors &InPnt )
+ {
+ VectorRotate( InPnt );
+ InPnt.x = AddSIMD( InPnt.x, m_v4Origin.x );
+ InPnt.y = AddSIMD( InPnt.y, m_v4Origin.y );
+ InPnt.z = AddSIMD( InPnt.z, m_v4Origin.z );
+ }
+};
+
+#define NUM_COLLISION_CACHE_MODES 4
+
+//-----------------------------------------------------------------------------
+//
+// CParticleCollection
+//
+//-----------------------------------------------------------------------------
+class CParticleCollection
+{
+public:
+ ~CParticleCollection( void );
+
+ // Restarts the particle collection, stopping all non-continuous emitters
+ void Restart();
+
+ // compute bounds from particle list
+ void RecomputeBounds( void );
+
+ void SetControlPoint( int nWhichPoint, const Vector &v );
+ void SetControlPointObject( int nWhichPoint, void *pObject );
+
+ void SetControlPointOrientation( int nWhichPoint, const Vector &forward,
+ const Vector &right, const Vector &up );
+ void SetControlPointOrientation( int nWhichPoint, const Quaternion &q );
+ void SetControlPointForwardVector( int nWhichPoint, const Vector &v );
+ void SetControlPointUpVector( int nWhichPoint, const Vector &v );
+ void SetControlPointRightVector( int nWhichPoint, const Vector &v );
+ void SetControlPointParent( int nWhichPoint, int n );
+
+ // get the pointer to an attribute for a given particle.
+ // !!speed!! if you find yourself calling this anywhere that matters,
+ // you're not handling the simd-ness of the particle system well
+ // and will have bad perf.
+ const float *GetFloatAttributePtr( int nAttribute, int nParticleNumber ) const;
+ const int *GetIntAttributePtr( int nAttribute, int nParticleNumber ) const;
+ const fltx4 *GetM128AttributePtr( int nAttribute, size_t *pStrideOut ) const;
+ const FourVectors *Get4VAttributePtr( int nAttribute, size_t *pStrideOut ) const;
+ const FourInts *Get4IAttributePtr( int nAttribute, size_t *pStrideOut ) const;
+ const int *GetIntAttributePtr( int nAttribute, size_t *pStrideOut ) const;
+
+
+ int *GetIntAttributePtrForWrite( int nAttribute, int nParticleNumber );
+
+ float *GetFloatAttributePtrForWrite( int nAttribute, int nParticleNumber );
+ fltx4 *GetM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut );
+ FourVectors *Get4VAttributePtrForWrite( int nAttribute, size_t *pStrideOut );
+
+ const float *GetInitialFloatAttributePtr( int nAttribute, int nParticleNumber ) const;
+ const fltx4 *GetInitialM128AttributePtr( int nAttribute, size_t *pStrideOut ) const;
+ const FourVectors *GetInitial4VAttributePtr( int nAttribute, size_t *pStrideOut ) const;
+ float *GetInitialFloatAttributePtrForWrite( int nAttribute, int nParticleNumber );
+ fltx4 *GetInitialM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut );
+
+ void Simulate( float dt );
+ void SkipToTime( float t );
+
+ // the camera objetc may be compared for equality against control point objects
+ void Render( IMatRenderContext *pRenderContext, bool bTranslucentOnly = false, void *pCameraObject = NULL );
+
+ bool IsValid( void ) const;
+ const char *GetName() const;
+
+ // IsFinished returns true when a system has no particles and won't be creating any more
+ bool IsFinished( void );
+
+ // Used to make sure we're accessing valid memory
+ bool IsValidAttributePtr( int nAttribute, const void *pPtr ) const;
+
+ void SwapPosAndPrevPos( void );
+
+ void SetNActiveParticles( int nCount );
+ void KillParticle(int nPidx);
+
+ void StopEmission( bool bInfiniteOnly = false, bool bRemoveAllParticles = false, bool bWakeOnStop = false );
+ void StartEmission( bool bInfiniteOnly = false );
+ void SetDormant( bool bDormant );
+
+ const Vector& GetControlPointAtCurrentTime( int nControlPoint ) const;
+ void GetControlPointOrientationAtCurrentTime( int nControlPoint, Vector *pForward, Vector *pRight, Vector *pUp ) const;
+ void GetControlPointTransformAtCurrentTime( int nControlPoint, matrix3x4_t *pMat );
+ void GetControlPointTransformAtCurrentTime( int nControlPoint, VMatrix *pMat );
+ int GetControlPointParent( int nControlPoint ) const;
+
+ // Used to retrieve the position of a control point
+ // somewhere between m_fCurTime and m_fCurTime - m_fPreviousDT
+ void GetControlPointAtTime( int nControlPoint, float flTime, Vector *pControlPoint );
+ void GetControlPointAtPrevTime( int nControlPoint, Vector *pControlPoint );
+ void GetControlPointOrientationAtTime( int nControlPoint, float flTime, Vector *pForward, Vector *pRight, Vector *pUp );
+ void GetControlPointTransformAtTime( int nControlPoint, float flTime, matrix3x4_t *pMat );
+ void GetControlPointTransformAtTime( int nControlPoint, float flTime, VMatrix *pMat );
+ void GetControlPointTransformAtTime( int nControlPoint, float flTime, CParticleSIMDTransformation *pXForm );
+ int GetHighestControlPoint( void ) const;
+
+ // Control point accessed:
+ // NOTE: Unlike the definition's version of these methods,
+ // these OR-in the masks of their children.
+ bool ReadsControlPoint( int nPoint ) const;
+
+ // Used by particle systems to generate random numbers. Do not call these methods - use sse
+ // code
+ int RandomInt( int nMin, int nMax );
+ float RandomFloat( float flMin, float flMax );
+ float RandomFloatExp( float flMin, float flMax, float flExponent );
+ void RandomVector( float flMin, float flMax, Vector *pVector );
+ void RandomVector( const Vector &vecMin, const Vector &vecMax, Vector *pVector );
+ float RandomVectorInUnitSphere( Vector *pVector ); // Returns the length sqr of the vector
+
+ // NOTE: These versions will produce the *same random numbers* if you give it the same random
+ // sample id. do not use these methods.
+ int RandomInt( int nRandomSampleId, int nMin, int nMax );
+ float RandomFloat( int nRandomSampleId, float flMin, float flMax );
+ float RandomFloatExp( int nRandomSampleId, float flMin, float flMax, float flExponent );
+ void RandomVector( int nRandomSampleId, float flMin, float flMax, Vector *pVector );
+ void RandomVector( int nRandomSampleId, const Vector &vecMin, const Vector &vecMax, Vector *pVector );
+ float RandomVectorInUnitSphere( int nRandomSampleId, Vector *pVector ); // Returns the length sqr of the vector
+
+ fltx4 RandomFloat( const FourInts &ParticleID, int nRandomSampleOffset );
+
+
+ // Random number offset (for use in getting Random #s in operators)
+ int OperatorRandomSampleOffset() const;
+
+ // Returns the render bounds
+ void GetBounds( Vector *pMin, Vector *pMax );
+
+ // Visualize operators (for editing/debugging)
+ void VisualizeOperator( const DmObjectId_t *pOpId = NULL );
+
+ // Does the particle system use the power of two frame buffer texture (refraction?)
+ bool UsesPowerOfTwoFrameBufferTexture( bool bThisFrame ) const;
+
+ // Does the particle system use the full frame buffer texture (soft particles)
+ bool UsesFullFrameBufferTexture( bool bThisFrame ) const;
+
+ // Is the particle system translucent?
+ bool IsTranslucent() const;
+
+ // Is the particle system two-pass?
+ bool IsTwoPass() const;
+
+ // Is the particle system batchable?
+ bool IsBatchable() const;
+
+ // Renderer iteration
+ int GetRendererCount() const;
+ CParticleOperatorInstance *GetRenderer( int i );
+ void *GetRendererContext( int i );
+
+
+ bool CheckIfOperatorShouldRun( CParticleOperatorInstance const * op, float *pflCurStrength = NULL );
+
+ Vector TransformAxis( const Vector &SrcAxis, bool bLocalSpace, int nControlPointNumber = 0);
+
+ // return backwards-sorted particle list. use --addressing
+ const ParticleRenderData_t *GetRenderList( IMatRenderContext *pRenderContext, bool bSorted, int *pNparticles, CParticleVisibilityData *pVisibilityData );
+
+ // calculate the points of a curve for a path
+ void CalculatePathValues( CPathParameters const &PathIn,
+ float flTimeStamp,
+ Vector *pStartPnt,
+ Vector *pMidPnt,
+ Vector *pEndPnt
+ );
+
+ int GetGroupID() const;
+
+ void InitializeNewParticles( int nFirstParticle, int nParticleCount, uint32 nInittedMask );
+
+ // update hit boxes for control point if not updated yet for this sim step
+ void UpdateHitBoxInfo( int nControlPointNumber );
+
+ // Used by particle system definitions to manage particle collection lists
+ void UnlinkFromDefList( );
+
+ CParticleCollection *GetNextCollectionUsingSameDef() { return m_pNextDef; }
+
+ CUtlReference< CSheet > m_Sheet;
+
+
+
+protected:
+ CParticleCollection( );
+
+ // Used by client code
+ bool Init( const char *pParticleSystemName );
+ bool Init( CParticleSystemDefinition *pDef );
+
+ // Bloat the bounding box by bounds around the control point
+ void BloatBoundsUsingControlPoint();
+
+private:
+ void GenerateSortedIndexList( Vector vecCameraPos, CParticleVisibilityData *pVisibilityData, bool bSorted );
+
+ void Init( CParticleSystemDefinition *pDef, float flDelay, int nRandomSeed );
+ void InitStorage( CParticleSystemDefinition *pDef );
+ void InitParticleCreationTime( int nFirstParticle, int nNumToInit );
+ void CopyInitialAttributeValues( int nStartParticle, int nNumParticles );
+ void ApplyKillList( void );
+ void SetAttributeToConstant( int nAttribute, float fValue );
+ void SetAttributeToConstant( int nAttribute, float fValueX, float fValueY, float fValueZ );
+ void InitParticleAttributes( int nStartParticle, int nNumParticles, int nAttrsLeftToInit );
+
+ // initialize this attribute for all active particles
+ void FillAttributeWithConstant( int nAttribute, float fValue );
+
+ // Updates the previous control points
+ void UpdatePrevControlPoints( float dt );
+
+ // Returns the memory for a particular constant attribute
+ float *GetConstantAttributeMemory( int nAttribute );
+
+ // Swaps two particles in the particle list
+ void SwapAdjacentParticles( int hParticle );
+
+ // Unlinks a particle from the list
+ void UnlinkParticle( int hParticle );
+
+ // Inserts a particle before another particle in the list
+ void InsertParticleBefore( int hParticle, int hBefore );
+
+ // Move a particle from one index to another
+ void MoveParticle( int nInitialIndex, int nNewIndex );
+
+ // Computes the sq distance to a particle position
+ float ComputeSqrDistanceToParticle( int hParticle, const Vector &vecPosition ) const;
+
+ // Grows the dist sq range for all particles
+ void GrowDistSqrBounds( float flDistSqr );
+
+ // Simulates the first frame
+ void SimulateFirstFrame( );
+
+ bool SystemContainsParticlesWithBoolSet( bool CParticleCollection::*pField ) const;
+ // Does the particle collection contain opaque particle systems
+ bool ContainsOpaqueCollections();
+ bool ComputeUsesPowerOfTwoFrameBufferTexture();
+ bool ComputeUsesFullFrameBufferTexture();
+ bool ComputeIsTranslucent();
+ bool ComputeIsTwoPass();
+ bool ComputeIsBatchable();
+
+ void LabelTextureUsage( void );
+
+ void LinkIntoDefList( );
+
+public:
+ fltx4 m_fl4CurTime; // accumulated time
+
+ int m_nPaddedActiveParticles; // # of groups of 4 particles
+ float m_flCurTime; // accumulated time
+
+ int m_nActiveParticles; // # of active particles
+ float m_flDt;
+ float m_flPreviousDt;
+ float m_flNextSleepTime; // time to go to sleep if not drawn
+
+ CUtlReference< CParticleSystemDefinition > m_pDef;
+ int m_nAllocatedParticles;
+ int m_nMaxAllowedParticles;
+ bool m_bDormant;
+ bool m_bEmissionStopped;
+
+ int m_LocalLightingCP;
+ Color m_LocalLighting;
+
+ // control point data. Don't set these directly, or they won't propagate down to children
+ // particle control points can act as emitter centers, repulsions points, etc. what they are
+ // used for depends on what operators and parameters your system has.
+ CParticleControlPoint m_ControlPoints[MAX_PARTICLE_CONTROL_POINTS];
+
+ CModelHitBoxesInfo m_ControlPointHitBoxes[MAX_PARTICLE_CONTROL_POINTS];
+
+ // public so people can call methods
+ uint8 *m_pOperatorContextData;
+ CParticleCollection *m_pNext; // for linking children together
+ CParticleCollection *m_pPrev; // for linking children together
+
+ struct CWorldCollideContextData *m_pCollisionCacheData[NUM_COLLISION_CACHE_MODES]; // children can share collision caches w/ parent
+ CParticleCollection *m_pParent;
+
+ CUtlIntrusiveDList<CParticleCollection> m_Children; // list for all child particle systems
+
+ void *operator new(size_t nSize);
+ void *operator new( size_t size, int nBlockUse, const char *pFileName, int nLine );
+ void operator delete(void *pData);
+ void operator delete( void* p, int nBlockUse, const char *pFileName, int nLine );
+
+
+protected:
+ // current bounds for the particle system
+ bool m_bBoundsValid;
+ Vector m_MinBounds;
+ Vector m_MaxBounds;
+ int m_nHighestCP; //Highest CP set externally. Needs to assert if a system calls to an unassigned CP.
+
+private:
+
+
+ unsigned char *m_pParticleMemory; // fixed size at initialization. Must be aligned for SSE
+ unsigned char *m_pParticleInitialMemory; // fixed size at initialization. Must be aligned for SSE
+ unsigned char *m_pConstantMemory;
+
+ int m_nPerParticleInitializedAttributeMask;
+ int m_nPerParticleUpdatedAttributeMask;
+ int m_nPerParticleReadInitialAttributeMask; // What fields do operators want to see initial attribute values for?
+ float *m_pParticleAttributes[MAX_PARTICLE_ATTRIBUTES];
+ float *m_pParticleInitialAttributes[MAX_PARTICLE_ATTRIBUTES];
+ size_t m_nParticleFloatStrides[MAX_PARTICLE_ATTRIBUTES];
+ size_t m_nParticleInitialFloatStrides[MAX_PARTICLE_ATTRIBUTES];
+
+ float *m_pConstantAttributes;
+
+ uint64 m_nControlPointReadMask; // Mask indicating which control points have been accessed
+ int m_nParticleFlags; // PCFLAGS_xxx
+ bool m_bIsScrubbable : 1;
+ bool m_bIsRunningInitializers : 1;
+ bool m_bIsRunningOperators : 1;
+ bool m_bIsTranslucent : 1;
+ bool m_bIsTwoPass : 1;
+ bool m_bAnyUsesPowerOfTwoFrameBufferTexture : 1; // whether or not we or any children use this
+ bool m_bAnyUsesFullFrameBufferTexture : 1;
+ bool m_bIsBatchable : 1;
+
+ bool m_bUsesPowerOfTwoFrameBufferTexture; // whether or not we use this, _not_ our children
+ bool m_bUsesFullFrameBufferTexture;
+
+ // How many frames have we drawn?
+ int m_nDrawnFrames;
+
+ Vector m_Center; // average of particle centers
+
+ // Used to assign unique ids to each particle
+ int m_nUniqueParticleId;
+
+ // Used to generate random numbers
+ int m_nRandomQueryCount;
+ int m_nRandomSeed;
+ int m_nOperatorRandomSampleOffset;
+
+ float m_flMinDistSqr;
+ float m_flMaxDistSqr;
+ float m_flOOMaxDistSqr;
+ Vector m_vecLastCameraPos;
+ float m_flLastMinDistSqr;
+ float m_flLastMaxDistSqr;
+
+ // Particle collection kill list. set up by particle system mgr
+ int m_nNumParticlesToKill;
+ int *m_pParticleKillList;
+
+ // Used to build a list of all particle collections that have the same particle def
+ CParticleCollection *m_pNextDef;
+ CParticleCollection *m_pPrevDef;
+
+ void LoanKillListTo( CParticleCollection *pBorrower ) const;
+ bool HasAttachedKillList( void ) const;
+
+
+ // For debugging
+ CParticleOperatorInstance *m_pRenderOp;
+ friend class CParticleSystemMgr;
+ friend class CParticleOperatorInstance;
+};
+
+
+
+class CM128InitialAttributeIterator : public CStridedConstPtr<fltx4>
+{
+public:
+ FORCEINLINE CM128InitialAttributeIterator( int nAttribute, CParticleCollection *pParticles )
+ {
+ m_pData = pParticles->GetInitialM128AttributePtr( nAttribute, &m_nStride );
+ }
+};
+
+
+class CM128AttributeIterator : public CStridedConstPtr<fltx4>
+{
+public:
+ FORCEINLINE CM128AttributeIterator( int nAttribute, CParticleCollection *pParticles )
+ {
+ m_pData = pParticles->GetM128AttributePtr( nAttribute, &m_nStride );
+ }
+};
+
+class C4IAttributeIterator : public CStridedConstPtr<FourInts>
+{
+public:
+ FORCEINLINE C4IAttributeIterator( int nAttribute, CParticleCollection *pParticles )
+ {
+ m_pData = pParticles->Get4IAttributePtr( nAttribute, &m_nStride );
+ }
+};
+
+class CM128AttributeWriteIterator : public CStridedPtr<fltx4>
+{
+public:
+ FORCEINLINE CM128AttributeWriteIterator( void )
+ {
+ }
+ FORCEINLINE void Init ( int nAttribute, CParticleCollection *pParticles )
+ {
+ m_pData = pParticles->GetM128AttributePtrForWrite( nAttribute, &m_nStride );
+ }
+ FORCEINLINE CM128AttributeWriteIterator( int nAttribute, CParticleCollection *pParticles )
+ {
+ Init( nAttribute, pParticles );
+ }
+};
+
+class C4VAttributeIterator : public CStridedConstPtr<FourVectors>
+{
+public:
+ FORCEINLINE C4VAttributeIterator( int nAttribute, CParticleCollection *pParticles )
+ {
+ m_pData = pParticles->Get4VAttributePtr( nAttribute, &m_nStride );
+ }
+};
+
+class C4VInitialAttributeIterator : public CStridedConstPtr<FourVectors>
+{
+public:
+ FORCEINLINE C4VInitialAttributeIterator( int nAttribute, CParticleCollection *pParticles )
+ {
+ m_pData = pParticles->GetInitial4VAttributePtr( nAttribute, &m_nStride );
+ }
+};
+
+class C4VAttributeWriteIterator : public CStridedPtr<FourVectors>
+{
+public:
+ FORCEINLINE C4VAttributeWriteIterator( int nAttribute, CParticleCollection *pParticles )
+ {
+ m_pData = pParticles->Get4VAttributePtrForWrite( nAttribute, &m_nStride );
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// Inline methods of CParticleCollection
+//-----------------------------------------------------------------------------
+
+inline bool CParticleCollection::HasAttachedKillList( void ) const
+{
+ return m_pParticleKillList != NULL;
+}
+
+inline bool CParticleCollection::ReadsControlPoint( int nPoint ) const
+{
+ return ( m_nControlPointReadMask & ( 1ULL << nPoint ) ) != 0;
+}
+
+inline void CParticleCollection::SetNActiveParticles( int nCount )
+{
+ Assert( nCount <= m_nMaxAllowedParticles );
+ m_nActiveParticles = nCount;
+ m_nPaddedActiveParticles = ( nCount+3 )/4;
+}
+
+inline void CParticleCollection::SwapPosAndPrevPos( void )
+{
+ // strides better be the same!
+ Assert( m_nParticleFloatStrides[PARTICLE_ATTRIBUTE_XYZ] == m_nParticleFloatStrides[ PARTICLE_ATTRIBUTE_PREV_XYZ ] );
+ V_swap( m_pParticleAttributes[ PARTICLE_ATTRIBUTE_XYZ ], m_pParticleAttributes[ PARTICLE_ATTRIBUTE_PREV_XYZ ] );
+}
+
+inline void CParticleCollection::LoanKillListTo( CParticleCollection *pBorrower ) const
+{
+ Assert(! pBorrower->m_pParticleKillList );
+ pBorrower->m_nNumParticlesToKill = 0;
+ pBorrower->m_pParticleKillList = m_pParticleKillList;
+}
+
+inline void CParticleCollection::SetAttributeToConstant( int nAttribute, float fValue )
+{
+ float *fconst = m_pConstantAttributes + 4*3*nAttribute;
+ fconst[0] = fconst[1] = fconst[2] = fconst[3] = fValue;
+}
+
+inline void CParticleCollection::SetAttributeToConstant( int nAttribute, float fValueX, float fValueY, float fValueZ )
+{
+ float *fconst = m_pConstantAttributes + 4*3*nAttribute;
+ fconst[0] = fconst[1] = fconst[2] = fconst[3] = fValueX;
+ fconst[4] = fconst[5] = fconst[6] = fconst[7] = fValueY;
+ fconst[8] = fconst[9] = fconst[10] = fconst[11] = fValueZ;
+}
+
+inline void CParticleCollection::SetControlPoint( int nWhichPoint, const Vector &v )
+{
+ Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
+ m_nHighestCP = MAX( m_nHighestCP, nWhichPoint );
+ m_ControlPoints[ nWhichPoint ].m_Position = v;
+ for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
+ {
+ i->SetControlPoint( nWhichPoint, v );
+ }
+}
+
+inline void CParticleCollection::SetControlPointObject( int nWhichPoint, void *pObject )
+{
+ Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
+ m_ControlPoints[ nWhichPoint ].m_pObject = pObject;
+ for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
+ {
+ i->SetControlPointObject( nWhichPoint, pObject );
+ }
+}
+
+inline void CParticleCollection::SetControlPointOrientation( int nWhichPoint, const Vector &forward,
+ const Vector &right, const Vector &up )
+{
+ Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
+
+ // check perpendicular
+ if ( fabs( DotProduct( forward, up ) ) <= 0.1f
+ && fabs( DotProduct( forward, right ) ) <= 0.1f
+ && fabs( DotProduct( right, up ) ) <= 0.1f )
+ {
+ m_ControlPoints[ nWhichPoint ].m_ForwardVector = forward;
+ m_ControlPoints[ nWhichPoint ].m_UpVector = up;
+ m_ControlPoints[ nWhichPoint ].m_RightVector = right;
+
+ // make sure all children are finished
+ for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
+ {
+ i->SetControlPointOrientation( nWhichPoint, forward, right, up );
+ }
+ }
+ else
+ {
+ Warning( "Attempt to set particle collection %s to invalid orientation matrix\n", GetName() );
+ }
+}
+
+inline Vector CParticleCollection::TransformAxis( const Vector &SrcAxis, bool bLocalSpace,
+ int nControlPointNumber)
+{
+ if ( bLocalSpace )
+ {
+ return // mxmul
+ ( SrcAxis.x*m_ControlPoints[nControlPointNumber].m_RightVector )+
+ ( SrcAxis.y*m_ControlPoints[nControlPointNumber].m_ForwardVector )+
+ ( SrcAxis.z*m_ControlPoints[nControlPointNumber].m_UpVector );
+ }
+ else
+ return SrcAxis;
+}
+
+
+inline void CParticleCollection::SetControlPointOrientation( int nWhichPoint, const Quaternion &q )
+{
+ matrix3x4_t mat;
+ Vector vecForward, vecUp, vecRight;
+ QuaternionMatrix( q, mat );
+ MatrixVectors( mat, &vecForward, &vecRight, &vecUp );
+ SetControlPointOrientation( nWhichPoint, vecForward, vecRight, vecUp );
+}
+
+inline void CParticleCollection::SetControlPointForwardVector( int nWhichPoint, const Vector &v)
+{
+ Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
+ m_ControlPoints[ nWhichPoint ].m_ForwardVector = v;
+ for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
+ {
+ i->SetControlPointForwardVector( nWhichPoint, v );
+ }
+}
+
+inline void CParticleCollection::SetControlPointUpVector( int nWhichPoint, const Vector &v)
+{
+ Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
+ m_ControlPoints[ nWhichPoint ].m_UpVector = v;
+ for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
+ {
+ i->SetControlPointUpVector( nWhichPoint, v );
+ }
+}
+
+inline void CParticleCollection::SetControlPointRightVector( int nWhichPoint, const Vector &v)
+{
+ Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
+ m_ControlPoints[ nWhichPoint ].m_RightVector = v;
+ for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
+ {
+ i->SetControlPointRightVector( nWhichPoint, v );
+ }
+}
+
+inline void CParticleCollection::SetControlPointParent( int nWhichPoint, int n )
+{
+ Assert( ( nWhichPoint >= 0) && ( nWhichPoint < MAX_PARTICLE_CONTROL_POINTS ) );
+ m_ControlPoints[ nWhichPoint ].m_nParent = n;
+ for( CParticleCollection *i = m_Children.m_pHead; i; i=i->m_pNext )
+ {
+ i->SetControlPointParent( nWhichPoint, n );
+ }
+}
+
+
+// Returns the memory for a particular constant attribute
+inline float *CParticleCollection::GetConstantAttributeMemory( int nAttribute )
+{
+ return m_pConstantAttributes + 3 * 4 * nAttribute;
+}
+
+// Random number offset (for use in getting Random #s in operators)
+inline int CParticleCollection::OperatorRandomSampleOffset() const
+{
+ return m_nOperatorRandomSampleOffset;
+}
+
+// Used by particle systems to generate random numbers
+inline int CParticleCollection::RandomInt( int nRandomSampleId, int nMin, int nMax )
+{
+ // do not call
+ float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ];
+ flRand *= ( nMax + 1 - nMin );
+ int nRand = (int)flRand + nMin;
+ return nRand;
+}
+
+inline float CParticleCollection::RandomFloat( int nRandomSampleId, float flMin, float flMax )
+{
+ // do not call
+ float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ];
+ flRand *= ( flMax - flMin );
+ flRand += flMin;
+ return flRand;
+}
+
+inline fltx4 CParticleCollection::RandomFloat( const FourInts &ParticleID, int nRandomSampleOffset )
+{
+ fltx4 Retval;
+ int nOfs=m_nRandomSeed+nRandomSampleOffset;
+ SubFloat( Retval, 0 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[0] ) & RANDOM_FLOAT_MASK ];
+ SubFloat( Retval, 1 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[1] ) & RANDOM_FLOAT_MASK ];
+ SubFloat( Retval, 2 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[2] ) & RANDOM_FLOAT_MASK ];
+ SubFloat( Retval, 3 ) = s_pRandomFloats[ ( nOfs + ParticleID.m_nValue[3] ) & RANDOM_FLOAT_MASK ];
+ return Retval;
+}
+
+
+inline float CParticleCollection::RandomFloatExp( int nRandomSampleId, float flMin, float flMax, float flExponent )
+{
+ // do not call
+ float flRand = s_pRandomFloats[ ( m_nRandomSeed + nRandomSampleId ) & RANDOM_FLOAT_MASK ];
+ flRand = powf( flRand, flExponent );
+ flRand *= ( flMax - flMin );
+ flRand += flMin;
+ return flRand;
+}
+
+inline void CParticleCollection::RandomVector( int nRandomSampleId, float flMin, float flMax, Vector *pVector )
+{
+ // do not call
+ float flDelta = flMax - flMin;
+ int nBaseId = m_nRandomSeed + nRandomSampleId;
+
+ pVector->x = s_pRandomFloats[ nBaseId & RANDOM_FLOAT_MASK ];
+ pVector->x *= flDelta;
+ pVector->x += flMin;
+
+ pVector->y = s_pRandomFloats[ ( nBaseId + 1 ) & RANDOM_FLOAT_MASK ];
+ pVector->y *= flDelta;
+ pVector->y += flMin;
+
+ pVector->z = s_pRandomFloats[ ( nBaseId + 2 ) & RANDOM_FLOAT_MASK ];
+ pVector->z *= flDelta;
+ pVector->z += flMin;
+}
+
+inline void CParticleCollection::RandomVector( int nRandomSampleId, const Vector &vecMin, const Vector &vecMax, Vector *pVector )
+{
+ // do not call
+ int nBaseId = m_nRandomSeed + nRandomSampleId;
+ pVector->x = RandomFloat( nBaseId, vecMin.x, vecMax.x );
+ pVector->y = RandomFloat( nBaseId + 1, vecMin.y, vecMax.y );
+ pVector->z = RandomFloat( nBaseId + 2, vecMin.z, vecMax.z );
+}
+
+// Used by particle systems to generate random numbers
+inline int CParticleCollection::RandomInt( int nMin, int nMax )
+{
+ // do not call
+ return RandomInt( m_nRandomQueryCount++, nMin, nMax );
+}
+
+inline float CParticleCollection::RandomFloat( float flMin, float flMax )
+{
+ // do not call
+ return RandomFloat( m_nRandomQueryCount++, flMin, flMax );
+}
+
+inline float CParticleCollection::RandomFloatExp( float flMin, float flMax, float flExponent )
+{
+ // do not call
+ return RandomFloatExp( m_nRandomQueryCount++, flMin, flMax, flExponent );
+}
+
+inline void CParticleCollection::RandomVector( float flMin, float flMax, Vector *pVector )
+{
+ // do not call
+ RandomVector( m_nRandomQueryCount++, flMin, flMax, pVector );
+}
+
+inline void CParticleCollection::RandomVector( const Vector &vecMin, const Vector &vecMax, Vector *pVector )
+{
+ // do not call
+ RandomVector( m_nRandomQueryCount++, vecMin, vecMax, pVector );
+}
+
+inline float CParticleCollection::RandomVectorInUnitSphere( Vector *pVector )
+{
+ // do not call
+ return RandomVectorInUnitSphere( m_nRandomQueryCount++, pVector );
+}
+
+
+// get the pointer to an attribute for a given particle. !!speed!! if you find yourself
+// calling this anywhere that matters, you're not handling the simd-ness of the particle system
+// well and will have bad perf.
+inline const float *CParticleCollection::GetFloatAttributePtr( int nAttribute, int nParticleNumber ) const
+{
+ Assert( nParticleNumber < m_nAllocatedParticles );
+ int block_ofs = nParticleNumber/4;
+ return m_pParticleAttributes[ nAttribute ] +
+ m_nParticleFloatStrides[ nAttribute ] * block_ofs +
+ ( nParticleNumber & 3 );
+}
+
+inline int *CParticleCollection::GetIntAttributePtrForWrite( int nAttribute, int nParticleNumber )
+{
+ return reinterpret_cast< int* >( GetFloatAttributePtrForWrite( nAttribute, nParticleNumber ) );
+}
+
+inline const int *CParticleCollection::GetIntAttributePtr( int nAttribute, int nParticleNumber ) const
+{
+ return (int*)GetFloatAttributePtr( nAttribute, nParticleNumber );
+}
+
+inline const fltx4 *CParticleCollection::GetM128AttributePtr( int nAttribute, size_t *pStrideOut ) const
+{
+ *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/4;
+ return reinterpret_cast<fltx4 *>( m_pParticleAttributes[ nAttribute ] );
+}
+
+inline const FourInts *CParticleCollection::Get4IAttributePtr( int nAttribute, size_t *pStrideOut ) const
+{
+ *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/4;
+ return reinterpret_cast<FourInts *>( m_pParticleAttributes[ nAttribute ] );
+}
+
+inline const int32 *CParticleCollection::GetIntAttributePtr( int nAttribute, size_t *pStrideOut ) const
+{
+ *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ];
+ return reinterpret_cast<int32 *>( m_pParticleAttributes[ nAttribute ] );
+}
+
+inline const FourVectors *CParticleCollection::Get4VAttributePtr( int nAttribute, size_t *pStrideOut ) const
+{
+ *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/12;
+ return reinterpret_cast<const FourVectors *>( m_pParticleAttributes[ nAttribute ] );
+}
+
+inline FourVectors *CParticleCollection::Get4VAttributePtrForWrite( int nAttribute, size_t *pStrideOut )
+{
+ *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/12;
+ return reinterpret_cast<FourVectors *>( m_pParticleAttributes[ nAttribute ] );
+}
+
+inline const FourVectors *CParticleCollection::GetInitial4VAttributePtr( int nAttribute, size_t *pStrideOut ) const
+{
+ *(pStrideOut) = m_nParticleInitialFloatStrides[ nAttribute ]/12;
+ return reinterpret_cast<FourVectors *>( m_pParticleInitialAttributes[ nAttribute ] );
+}
+
+inline float *CParticleCollection::GetFloatAttributePtrForWrite( int nAttribute, int nParticleNumber )
+{
+ // NOTE: If you hit this assertion, it means your particle operator isn't returning
+ // the appropriate fields in the RequiredAttributesMask call
+ Assert( !m_bIsRunningInitializers || ( m_nPerParticleInitializedAttributeMask & (1 << nAttribute) ) );
+ Assert( !m_bIsRunningOperators || ( m_nPerParticleUpdatedAttributeMask & (1 << nAttribute) ) );
+
+ Assert( m_nParticleFloatStrides[nAttribute] != 0 );
+
+ Assert( nParticleNumber < m_nAllocatedParticles );
+ int block_ofs = nParticleNumber/4;
+ return m_pParticleAttributes[ nAttribute ] +
+ m_nParticleFloatStrides[ nAttribute ] * block_ofs +
+ ( nParticleNumber & 3 );
+}
+
+inline fltx4 *CParticleCollection::GetM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut )
+{
+ // NOTE: If you hit this assertion, it means your particle operator isn't returning
+ // the appropriate fields in the RequiredAttributesMask call
+ Assert( !m_bIsRunningInitializers || ( m_nPerParticleInitializedAttributeMask & (1 << nAttribute) ) );
+ Assert( !m_bIsRunningOperators || ( m_nPerParticleUpdatedAttributeMask & (1 << nAttribute) ) );
+ Assert( m_nParticleFloatStrides[nAttribute] != 0 );
+
+ *(pStrideOut) = m_nParticleFloatStrides[ nAttribute ]/4;
+ return reinterpret_cast<fltx4 *>( m_pParticleAttributes[ nAttribute ] );
+}
+
+inline const float *CParticleCollection::GetInitialFloatAttributePtr( int nAttribute, int nParticleNumber ) const
+{
+ Assert( nParticleNumber < m_nAllocatedParticles );
+ int block_ofs = nParticleNumber / 4;
+ return m_pParticleInitialAttributes[ nAttribute ] + m_nParticleInitialFloatStrides[ nAttribute ] * block_ofs + ( nParticleNumber & 3 );
+}
+
+inline const fltx4 *CParticleCollection::GetInitialM128AttributePtr( int nAttribute, size_t *pStrideOut ) const
+{
+ *(pStrideOut) = m_nParticleInitialFloatStrides[ nAttribute ]/4;
+ return reinterpret_cast<fltx4 *>( m_pParticleInitialAttributes[ nAttribute ] );
+}
+
+inline float *CParticleCollection::GetInitialFloatAttributePtrForWrite( int nAttribute, int nParticleNumber )
+{
+ Assert( nParticleNumber < m_nAllocatedParticles );
+ Assert( m_nPerParticleReadInitialAttributeMask & ( 1 << nAttribute ) );
+ int block_ofs = nParticleNumber / 4;
+ return m_pParticleInitialAttributes[ nAttribute ] + m_nParticleInitialFloatStrides[ nAttribute ] * block_ofs + ( nParticleNumber & 3 );
+}
+
+inline fltx4 *CParticleCollection::GetInitialM128AttributePtrForWrite( int nAttribute, size_t *pStrideOut )
+{
+ Assert( m_nPerParticleReadInitialAttributeMask & ( 1 << nAttribute ) );
+ *(pStrideOut) = m_nParticleInitialFloatStrides[ nAttribute ] / 4;
+ return reinterpret_cast<fltx4 *>( m_pParticleInitialAttributes[ nAttribute ] );
+}
+
+// Used to make sure we're accessing valid memory
+inline bool CParticleCollection::IsValidAttributePtr( int nAttribute, const void *pPtr ) const
+{
+ if ( pPtr < m_pParticleAttributes[nAttribute] )
+ return false;
+
+ size_t nArraySize = m_nParticleFloatStrides[nAttribute] * m_nAllocatedParticles / 4;
+ void *pMaxPtr = m_pParticleAttributes[nAttribute] + nArraySize;
+ return ( pPtr <= pMaxPtr );
+}
+
+
+FORCEINLINE void CParticleCollection::KillParticle( int nPidx )
+{
+ // add a particle to the sorted kill list. entries must be added in sorted order.
+ // within a particle operator, this is safe to call. Outside of one, you have to call
+ // the ApplyKillList() method yourself. The storage for the kill list is global between
+ // all particle systems, so you can't kill a particle in 2 different CParticleCollections
+ // w/o calling ApplyKillList
+
+ // That said, we only expect the particle index to be at most more than 3 larger than the
+ // particle count
+ Assert( nPidx < m_nActiveParticles + 4 );
+
+ // note that it is permissible to kill particles with indices>the number of active
+ // particles, in order to faciliate easy sse coding
+ Assert( m_nNumParticlesToKill < MAX_PARTICLES_IN_A_SYSTEM );
+ m_pParticleKillList[ m_nNumParticlesToKill++ ] = nPidx;
+}
+
+// initialize this attribute for all active particles
+inline void CParticleCollection::FillAttributeWithConstant( int nAttribute, float fValue )
+{
+ size_t stride;
+ fltx4 *pAttr = GetM128AttributePtrForWrite( nAttribute, &stride );
+ fltx4 fill=ReplicateX4( fValue );
+ for( int i = 0; i < m_nPaddedActiveParticles; i++ )
+ {
+ *(pAttr) = fill;
+ pAttr += stride;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Helper to set vector attribute values
+//-----------------------------------------------------------------------------
+FORCEINLINE void SetVectorAttribute( float *pAttribute, float x, float y, float z )
+{
+ pAttribute[0] = x;
+ pAttribute[4] = y;
+ pAttribute[8] = z;
+}
+
+FORCEINLINE void SetVectorAttribute( float *pAttribute, const Vector &v )
+{
+ pAttribute[0] = v.x;
+ pAttribute[4] = v.y;
+ pAttribute[8] = v.z;
+}
+
+FORCEINLINE void SetVectorFromAttribute( Vector &v, const float *pAttribute )
+{
+ v.x = pAttribute[0];
+ v.y = pAttribute[4];
+ v.z = pAttribute[8];
+}
+
+
+//-----------------------------------------------------------------------------
+// Computes the sq distance to a particle position
+//-----------------------------------------------------------------------------
+FORCEINLINE float CParticleCollection::ComputeSqrDistanceToParticle( int hParticle, const Vector &vecPosition ) const
+{
+ const float *xyz = GetFloatAttributePtr( PARTICLE_ATTRIBUTE_XYZ, hParticle );
+ Vector vecParticlePosition( xyz[0], xyz[4], xyz[8] );
+ return vecParticlePosition.DistToSqr( vecPosition );
+}
+
+
+//-----------------------------------------------------------------------------
+// Grows the dist sq range for all particles
+//-----------------------------------------------------------------------------
+FORCEINLINE void CParticleCollection::GrowDistSqrBounds( float flDistSqr )
+{
+ if ( m_flLastMinDistSqr > flDistSqr )
+ {
+ m_flLastMinDistSqr = flDistSqr;
+ }
+ else if ( m_flLastMaxDistSqr < flDistSqr )
+ {
+ m_flLastMaxDistSqr = flDistSqr;
+ }
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Data associated with children particle systems
+//-----------------------------------------------------------------------------
+struct ParticleChildrenInfo_t
+{
+ DmObjectId_t m_Id;
+ CUtlString m_Name;
+ bool m_bUseNameBasedLookup;
+ float m_flDelay; // How much to delay this system after the parent starts
+};
+
+
+//-----------------------------------------------------------------------------
+// A template describing how a particle system will function
+//-----------------------------------------------------------------------------
+class CParticleSystemDefinition
+{
+ DECLARE_DMXELEMENT_UNPACK();
+ DECLARE_REFERENCED_CLASS( CParticleSystemDefinition );
+
+
+public:
+ CParticleSystemDefinition( void );
+ ~CParticleSystemDefinition( void );
+
+ // Serialization, unserialization
+ void Read( CDmxElement *pElement );
+ CDmxElement *Write();
+
+ const char *MaterialName() const;
+ IMaterial *GetMaterial() const;
+ const char *GetName() const;
+ const DmObjectId_t& GetId() const;
+
+ // Does the particle system use the power of two frame buffer texture (refraction?)
+ bool UsesPowerOfTwoFrameBufferTexture();
+
+ // Does the particle system use the full frame buffer texture (soft particles)
+ bool UsesFullFrameBufferTexture();
+
+ // Should we always precache this?
+ bool ShouldAlwaysPrecache() const;
+
+ // Should we batch particle collections using this definition up?
+ bool ShouldBatch() const;
+
+ // Is the particle system rendered on the viewmodel?
+ bool IsViewModelEffect() const;
+
+ // Used to iterate over all particle collections using the same def
+ CParticleCollection *FirstCollection();
+
+ // What's the effective cull size + fill cost?
+ // Used for early retirement
+ float GetCullRadius() const;
+ float GetCullFillCost() const;
+ int GetCullControlPoint() const;
+ const char *GetCullReplacementDefinition() const;
+
+ // Retirement
+ bool HasRetirementBeenChecked( int nFrame ) const;
+ void MarkRetirementCheck( int nFrame );
+
+ // Control point read
+ void MarkReadsControlPoint( int nPoint );
+ bool ReadsControlPoint( int nPoint ) const;
+
+private:
+ void Precache();
+ void Uncache();
+ bool IsPrecached() const;
+
+ void UnlinkAllCollections();
+
+ void SetupContextData( );
+ void ParseChildren( CDmxElement *pElement );
+ void ParseOperators( const char *pszName, ParticleFunctionType_t nFunctionType,
+ CDmxElement *pElement, CUtlVector<CParticleOperatorInstance *> &out_list );
+ void WriteChildren( CDmxElement *pElement );
+ void WriteOperators( CDmxElement *pElement, const char *pOpKeyName,
+ const CUtlVector<CParticleOperatorInstance *> &inList );
+ CUtlVector<CParticleOperatorInstance *> *GetOperatorList( ParticleFunctionType_t type );
+ CParticleOperatorInstance *FindOperatorById( ParticleFunctionType_t type, const DmObjectId_t &id );
+
+private:
+ int m_nInitialParticles;
+ int m_nPerParticleUpdatedAttributeMask;
+ int m_nPerParticleInitializedAttributeMask;
+ int m_nInitialAttributeReadMask;
+ int m_nAttributeReadMask;
+ uint64 m_nControlPointReadMask;
+ Vector m_BoundingBoxMin;
+ Vector m_BoundingBoxMax;
+ char m_pszMaterialName[MAX_PATH];
+ CMaterialReference m_Material;
+ CParticleCollection *m_pFirstCollection;
+ char m_pszCullReplacementName[128];
+ float m_flCullRadius;
+ float m_flCullFillCost;
+ int m_nCullControlPoint;
+ int m_nRetireCheckFrame;
+
+ // Default attribute values
+ Color m_ConstantColor;
+ float m_flConstantRadius;
+ float m_flConstantRotation;
+ float m_flConstantRotationSpeed;
+ int m_nConstantSequenceNumber;
+ int m_nConstantSequenceNumber1;
+ int m_nGroupID;
+ float m_flMaximumTimeStep;
+ float m_flMaximumSimTime; // maximum time to sim before drawing first frame.
+ float m_flMinimumSimTime; // minimum time to sim before drawing first frame - prevents all
+ // capped particles from drawing at 0 time.
+
+ int m_nMinimumFrames; // number of frames to apply max/min simulation times
+
+
+ // Is the particle system rendered on the viewmodel?
+ bool m_bViewModelEffect;
+
+
+ size_t m_nContextDataSize;
+ DmObjectId_t m_Id;
+
+public:
+ float m_flMaxDrawDistance; // distance at which to not draw.
+ float m_flNoDrawTimeToGoToSleep; // after not beeing seen for this long, the system will sleep
+
+ int m_nMaxParticles;
+ int m_nSkipRenderControlPoint; // if the camera is attached to the
+ // object associated with this control
+ // point, don't render the system
+
+ CUtlString m_Name;
+
+ CUtlVector<CParticleOperatorInstance *> m_Operators;
+ CUtlVector<CParticleOperatorInstance *> m_Renderers;
+ CUtlVector<CParticleOperatorInstance *> m_Initializers;
+ CUtlVector<CParticleOperatorInstance *> m_Emitters;
+ CUtlVector<CParticleOperatorInstance *> m_ForceGenerators;
+ CUtlVector<CParticleOperatorInstance *> m_Constraints;
+ CUtlVector<ParticleChildrenInfo_t> m_Children;
+
+ CUtlVector<size_t> m_nOperatorsCtxOffsets;
+ CUtlVector<size_t> m_nRenderersCtxOffsets;
+ CUtlVector<size_t> m_nInitializersCtxOffsets;
+ CUtlVector<size_t> m_nEmittersCtxOffsets;
+ CUtlVector<size_t> m_nForceGeneratorsCtxOffsets;
+ CUtlVector<size_t> m_nConstraintsCtxOffsets;
+
+ // profiling information
+ float m_flTotalSimTime;
+ float m_flUncomittedTotalSimTime;
+ float m_flMaxMeasuredSimTime;
+ int m_nMaximumActiveParticles;
+ bool m_bShouldSort;
+ bool m_bShouldBatch;
+ bool m_bIsPrecached : 1;
+ bool m_bAlwaysPrecache : 1;
+
+ friend class CParticleCollection;
+ friend class CParticleSystemMgr;
+};
+
+
+//-----------------------------------------------------------------------------
+// Inline methods
+//-----------------------------------------------------------------------------
+inline CParticleSystemDefinition::CParticleSystemDefinition( void )
+{
+ m_nControlPointReadMask = 0;
+ m_nInitialAttributeReadMask = 0;
+ m_nPerParticleInitializedAttributeMask = 0;
+ m_nPerParticleUpdatedAttributeMask = 0;
+ m_nAttributeReadMask = 0;
+ m_flTotalSimTime = 0.0;
+ m_flMaxMeasuredSimTime = 0.0;
+ m_nMaximumActiveParticles = 0;
+ m_bIsPrecached = false;
+ m_bAlwaysPrecache = false;
+ m_bShouldBatch = false;
+ m_bShouldSort = true;
+ m_pFirstCollection = NULL;
+ m_flCullRadius = 0.0f;
+ m_flCullFillCost = 1.0f;
+ m_nRetireCheckFrame = 0;
+}
+
+inline CParticleSystemDefinition::~CParticleSystemDefinition( void )
+{
+ UnlinkAllCollections();
+ m_Operators.PurgeAndDeleteElements();
+ m_Renderers.PurgeAndDeleteElements();
+ m_Initializers.PurgeAndDeleteElements();
+ m_Emitters.PurgeAndDeleteElements();
+ m_ForceGenerators.PurgeAndDeleteElements();
+ m_Constraints.PurgeAndDeleteElements();
+}
+
+// Used to iterate over all particle collections using the same def
+inline CParticleCollection *CParticleSystemDefinition::FirstCollection()
+{
+ return m_pFirstCollection;
+}
+
+inline float CParticleSystemDefinition::GetCullRadius() const
+{
+ return m_flCullRadius;
+}
+
+inline float CParticleSystemDefinition::GetCullFillCost() const
+{
+ return m_flCullFillCost;
+}
+
+inline const char *CParticleSystemDefinition::GetCullReplacementDefinition() const
+{
+ return m_pszCullReplacementName;
+}
+
+inline int CParticleSystemDefinition::GetCullControlPoint() const
+{
+ return m_nCullControlPoint;
+}
+
+inline void CParticleSystemDefinition::MarkReadsControlPoint( int nPoint )
+{
+ m_nControlPointReadMask |= ( 1ULL << nPoint );
+}
+
+inline bool CParticleSystemDefinition::ReadsControlPoint( int nPoint ) const
+{
+ return ( m_nControlPointReadMask & ( 1ULL << nPoint ) ) != 0;
+}
+
+// Retirement
+inline bool CParticleSystemDefinition::HasRetirementBeenChecked( int nFrame ) const
+{
+ return m_nRetireCheckFrame == nFrame;
+}
+
+inline void CParticleSystemDefinition::MarkRetirementCheck( int nFrame )
+{
+ m_nRetireCheckFrame = nFrame;
+}
+
+inline bool CParticleSystemDefinition::ShouldBatch() const
+{
+ return m_bShouldBatch;
+}
+
+inline bool CParticleSystemDefinition::IsViewModelEffect() const
+{
+ return m_bViewModelEffect;
+}
+
+inline const char *CParticleSystemDefinition::MaterialName() const
+{
+ return m_pszMaterialName;
+}
+
+inline const DmObjectId_t& CParticleSystemDefinition::GetId() const
+{
+ return m_Id;
+}
+
+inline int CParticleCollection::GetGroupID( void ) const
+{
+ return m_pDef->m_nGroupID;
+}
+
+FORCEINLINE const Vector& CParticleCollection::GetControlPointAtCurrentTime( int nControlPoint ) const
+{
+ Assert( nControlPoint <= GetHighestControlPoint() );
+ Assert( m_pDef->ReadsControlPoint( nControlPoint ) );
+ return m_ControlPoints[nControlPoint].m_Position;
+}
+
+FORCEINLINE void CParticleCollection::GetControlPointOrientationAtCurrentTime( int nControlPoint, Vector *pForward, Vector *pRight, Vector *pUp ) const
+{
+ Assert( nControlPoint <= GetHighestControlPoint() );
+ Assert( m_pDef->ReadsControlPoint( nControlPoint ) );
+
+ // FIXME: Use quaternion lerp to get control point transform at time
+ *pForward = m_ControlPoints[nControlPoint].m_ForwardVector;
+ *pRight = m_ControlPoints[nControlPoint].m_RightVector;
+ *pUp = m_ControlPoints[nControlPoint].m_UpVector;
+}
+
+FORCEINLINE int CParticleCollection::GetControlPointParent( int nControlPoint ) const
+{
+ Assert( nControlPoint <= GetHighestControlPoint() );
+ Assert( m_pDef->ReadsControlPoint( nControlPoint ) );
+ return m_ControlPoints[nControlPoint].m_nParent;
+}
+
+FORCEINLINE bool CParticleCollection::IsValid( void ) const
+{
+ return ( m_pDef != NULL && m_pDef->GetMaterial() );
+}
+
+
+#endif // PARTICLES_H