You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2264 lines
75 KiB
2264 lines
75 KiB
//========= 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_flCameraBias; |
|
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 IsFinalConstraint( 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; |
|
} |
|
|
|
// Does this operator require that particles remain in the order they were emitted? |
|
virtual bool RequiresOrderInvariance( 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 Camera Depth Bias", "0", float, VisibilityInputs.m_flCameraBias ) |
|
|
|
// 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; |
|
float m_flCameraBias; |
|
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, bool updateBboxOnly = false ); |
|
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 ) const; |
|
void GetControlPointAtPrevTime( int nControlPoint, Vector *pControlPoint ) const; |
|
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; |
|
|
|
// Has this particle moved recently (since the last simulation?) |
|
bool HasMoved() 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(); |
|
bool ComputeRequiresOrderInvariance(); |
|
|
|
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; |
|
bool m_bRequiresOrderInvariance; |
|
|
|
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; |
|
int m_nSimulatedFrames; |
|
|
|
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 |
|
if ( !HushAsserts() ) |
|
{ |
|
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
|
|
|