//========= 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 ) = default ;
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