#ifndef PARTICLES_H #define PARTICLES_H #ifdef _WIN32 #pragma once #endif #include "mathlib.h" #include "vector.h" #include "ssemath.h" #include "imaterialsystem.h" #include "dmxelement.h" #include "utlintrusivelist.h" #include "random.h" #include "utlobjectreference.h" #include "UtlStringMap.h" #include "utlmap.h" #include "MaterialSystemUtil.h" #include "trace.h" #include "utlsoacontainer.h" #if defined( CLIENT_DLL ) #include "c_pixel_visibility.h" #endif struct DmxElementUnpackStructure_t; class CParticleSystemDefinition; class CParticleCollection; class CParticleOperatorInstance; class CParticleSystemDictionary; class CUtlBuffer; class IParticleOperatorDefinition; class CSheet; class CMeshBuilder; extern float s_pRandomFloats[]; #define MAX_RANDOM_FLOATS 4096 #define RANDOM_FLOAT_MASK ( MAX_RANDOM_FLOATS - 1 ) #define MAX_PARTICLE_ATTRIBUTES 32 #define DEFPARTICLE_ATTRIBUTE( name, bit ) \ const int PARTICLE_ATTRIBUTE_##name##_MASK = (1 << bit); \ const int PARTICLE_ATTRIBUTE_##name = bit; DEFPARTICLE_ATTRIBUTE(XYZ, 0); DEFPARTICLE_ATTRIBUTE(LIFE_DURATION, 1); DEFPARTICLE_ATTRIBUTE(PREV_XYZ, 2); DEFPARTICLE_ATTRIBUTE(RADIUS, 3); DEFPARTICLE_ATTRIBUTE(ROTATION, 4); DEFPARTICLE_ATTRIBUTE(ROTATION_SPEED, 5); DEFPARTICLE_ATTRIBUTE(TINT_RGB, 6); DEFPARTICLE_ATTRIBUTE(ALPHA, 7); DEFPARTICLE_ATTRIBUTE(CREATION_TIME, 8); DEFPARTICLE_ATTRIBUTE(SEQUENCE_NUMBER, 9); DEFPARTICLE_ATTRIBUTE(TRAIL_LENGTH, 10); DEFPARTICLE_ATTRIBUTE(PARTICLE_ID, 11); DEFPARTICLE_ATTRIBUTE(YAW, 12); DEFPARTICLE_ATTRIBUTE(SEQUENCE_NUMBER1, 13); DEFPARTICLE_ATTRIBUTE(HITBOX_INDEX, 14); DEFPARTICLE_ATTRIBUTE(HITBOX_RELATIVE_XYZ, 15); DEFPARTICLE_ATTRIBUTE(ALPHA2, 16); DEFPARTICLE_ATTRIBUTE(TRACE_P0, 17); DEFPARTICLE_ATTRIBUTE(TRACE_P1, 18); DEFPARTICLE_ATTRIBUTE(TRACE_HIT_T, 19); DEFPARTICLE_ATTRIBUTE(TRACE_HIT_NORMAL, 20); #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 #define MEASURE_PARTICLE_PERF 0 enum ParticleFunctionType_t { FUNCTION_RENDERER = 0, FUNCTION_OPERATOR, FUNCTION_INITIALIZER, FUNCTION_EMITTER, FUNCTION_CHILDREN, 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; } }; #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; 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; } 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, ModelHitBoxInfo_t* pHitBoxOutputBuffer) { 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) { } }; typedef int ParticleSystemHandle_t; class CParticleSystemMgr { public: CParticleSystemMgr(); ~CParticleSystemMgr(); bool Init(IParticleSystemQuery* pQuery); void AddBuiltinSimulationOperators(void); void AddBuiltinRenderingOperators(void); void AddParticleOperator(ParticleFunctionType_t nOpType, IParticleOperatorDefinition* pOpFactory); 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(); bool WriteParticleConfigFile(const char* pParticleSystemName, CUtlBuffer& buf, bool bPreventNameBasedLookup = false); bool WriteParticleConfigFile(const DmObjectId_t& id, CUtlBuffer& buf, bool bPreventNameBasedLookup = false); CParticleCollection* CreateParticleCollection(const char* pParticleSystemName, float flDelay = 0.0f, int nRandomSeed = 0); CParticleCollection* CreateParticleCollection(const DmObjectId_t& id, float flDelay = 0.0f, int nRandomSeed = 0); bool IsParticleSystemDefined(const char* pParticleSystemName); bool IsParticleSystemDefined(const DmObjectId_t& id); ParticleSystemHandle_t GetParticleSystemIndex(const char* pParticleSystemName); const char* GetParticleSystemNameFromIndex(ParticleSystemHandle_t iIndex); int GetParticleSystemCount(void); CUtlVector< IParticleOperatorDefinition*>& GetAvailableParticleOperatorList(ParticleFunctionType_t nWhichList); const DmxElementUnpackStructure_t* GetParticleSystemDefinitionUnpackStructure(); void ShouldLoadSheets(bool bLoadSheets); CSheet* FindOrLoadSheet(char const* pszFname, ITexture* pTexture); CSheet* FindOrLoadSheet(IMaterial* pMaterial); void FlushAllSheets(void); void ResetRenderCache(void); void AddToRenderCache(CParticleCollection* pParticles); void DrawRenderCache(bool bShadowDepth); IParticleSystemQuery* Query(void) { return m_pQuery; } const char* GetParticleFieldName(int nParticleField) const; CParticleSystemDefinition* FindParticleSystem(const char* pName); CParticleSystemDefinition* FindParticleSystem(const DmObjectId_t& id); void CommitProfileInformation(bool bCommit); void DumpProfileInformation(void); void PrecacheParticleSystem(const char* pName); void UncacheAllParticleSystems(); void SetLastSimulationTime(float flTime); float GetLastSimulationTime() const; int Debug_GetTotalParticleCount() const; bool Debug_FrameWarningNeededTestAndReset(); float ParticleThrottleScaling() const; bool ParticleThrottleRandomEnable() const; 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; }; bool ReadParticleDefinitions(CUtlBuffer& buf, const char* pFileName, bool bPrecache, bool bDecommitTempMemory); void AddParticleSystem(CDmxElement* pParticleSystem); CDmxElement* CreateParticleDmxElement(const DmObjectId_t& id); CDmxElement* CreateParticleDmxElement(const char* pParticleSystemName); bool WriteParticleConfigFile(CDmxElement* pParticleSystem, CUtlBuffer& buf, bool bPreventNameBasedLookup); void BuildBatchList(int iRenderCache, IMatRenderContext* pRenderContext, CUtlVector< Batch_t >& batches); CUtlVector m_ParticleOperators[PARTICLE_FUNCTION_COUNT]; CParticleSystemDictionary* m_pParticleSystemDictionary; typedef CUtlStringMap< CSheet* > SheetsCache_t; SheetsCache_t m_SheetList; void AttachKillList(CParticleCollection* pParticles); void DetachKillList(CParticleCollection* pParticles); 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; enum ParticleOperatorId_t { OPERATOR_GENERIC = -2, OPERATOR_SINGLETON = -1, OPERATOR_PI_POSITION, OPERATOR_PI_RADIUS, OPERATOR_PI_ALPHA, OPERATOR_PI_TINT_RGB, OPERATOR_PI_ROTATION, OPERATOR_PI_YAW, OPERATOR_ID_COUNT, }; class IParticleOperatorDefinition { public: virtual const char* GetName() const = 0; virtual CParticleOperatorInstance* CreateInstance(const DmObjectId_t& id) 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 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 }; class CParticleOperatorInstance { public: 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); 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; } virtual uint32 GetReadInitialAttributes(void) const { return 0; } virtual void Operate(CParticleCollection* pParticles, float flOpStrength, void* pContext) const { } 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 { } virtual int GetParticlesToRender(CParticleCollection* pParticles, void* pContext, int nFirstParticle, int nRemainingVertices, int nRemainingIndices, int* pVertsUsed, int* pIndicesUsed) const { *pVertsUsed = 0; *pIndicesUsed = 0; return 0; } virtual uint32 Emit(CParticleCollection* pParticles, float flOpCurStrength, void* pContext) const { return 0; } 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) {} virtual void InitParticleSystem(CParticleCollection* pParticles, void* pContext) const { } virtual void AddForces(FourVectors* AccumulatedForces, CParticleCollection* pParticles, int nBlocks, float flCurStrength, void* pContext) const { } virtual void SetupConstraintPerFrameData(CParticleCollection* pParticles, void* pContext) const { } virtual bool EnforceConstraint(int nStartBlock, int nNumBlocks, CParticleCollection* pParticles, void* pContext, int nNumValidParticlesInLastChunk) const { return false; } virtual bool IsFinalConstraint(void) const { return false; } virtual bool InitMultipleOverride() { return false; } virtual bool IsScrubSafe() { return false; } virtual void InitNewParticlesScalar(CParticleCollection* pParticles, int nFirstParticle, int n_particles, int attribute_write_mask, void* pContext) const { } virtual void InitNewParticlesBlock(CParticleCollection* pParticles, int start_block, int n_blocks, int attribute_write_mask, void* pContext) const { InitNewParticlesScalar(pParticles, 4 * start_block, 4 * n_blocks, attribute_write_mask, pContext); } void InitNewParticles(CParticleCollection* pParticles, int nFirstParticle, int n_particles, int attribute_write_mask, void* pContext) const; virtual bool MayCreateMoreParticles(CParticleCollection* pParticles, void* pContext) const { return false; } const IParticleOperatorDefinition* GetDefinition() { return m_pDef; } virtual bool ShouldRunBeforeEmitters(void) const { return false; } virtual bool RequiresOrderInvariance(void) const { return false; } virtual void SkipToTime(float flTime, CParticleCollection* pParticles, void* pContext) const {} const DmObjectId_t& GetId() { return m_Id; } virtual void Render(CParticleCollection* pParticles) const {} int RandomInt(int nMin, int nMax) { Assert(0); return 0; } float RandomFloat(float flMinVal = 0.0f, float flMaxVal = 1.0f) { Assert(0); return 0.0f; } float RandomFloatExp(float flMinVal = 0.0f, float flMaxVal = 1.0f, float flExponent = 1.0f) { Assert(0); return 0.0f; } float m_flOpStartFadeInTime; float m_flOpEndFadeInTime; float m_flOpStartFadeOutTime; float m_flOpEndFadeOutTime; float m_flOpFadeOscillatePeriod; virtual ~CParticleOperatorInstance(void) { } protected: 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 friend class CParticleOperatorDefinition; }; class CParticleRenderOperatorInstance : public CParticleOperatorInstance { public: CParticleVisibilityInputs VisibilityInputs; }; 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; } 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 ) #define REGISTER_PARTICLE_OPERATOR( _type, _className ) \ g_pParticleSystemMgr->AddParticleOperator( _type, &s_##_className##Factory ) enum { PCFLAGS_FIRST_FRAME = 0x1, PCFLAGS_PREV_CONTROL_POINTS_INITIALIZED = 0x2, }; #define DEBUG_PARTICLE_SORT 0 struct ParticleRenderData_t { float m_flSortKey; int m_nIndex; float m_flRadius; #if VALVE_LITTLE_ENDIAN uint8 m_nAlpha; uint8 m_nAlphaPad[3]; #else uint8 m_nAlphaPad[3]; uint8 m_nAlpha; #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; 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; Vector m_ForwardVector; Vector m_UpVector; Vector m_RightVector; void* m_pObject; int m_nParent; }; 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 class CParticleCollection { public: ~CParticleCollection(void); void Restart(); 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); 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); void SkipToTime(float t); void Render(IMatRenderContext* pRenderContext, bool bTranslucentOnly = false, void* pCameraObject = NULL); bool IsValid(void) const; const char* GetName() const; bool IsFinished(void); 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; 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; bool HasMoved() const; bool ReadsControlPoint(int nPoint) const; 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); 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); fltx4 RandomFloat(const FourInts& ParticleID, int nRandomSampleOffset); int OperatorRandomSampleOffset() const; void GetBounds(Vector* pMin, Vector* pMax); void VisualizeOperator(const DmObjectId_t* pOpId = NULL); bool UsesPowerOfTwoFrameBufferTexture(bool bThisFrame) const; bool UsesFullFrameBufferTexture(bool bThisFrame) const; bool IsTranslucent() const; bool IsTwoPass() const; bool IsBatchable() const; 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); const ParticleRenderData_t* GetRenderList(IMatRenderContext* pRenderContext, bool bSorted, int* pNparticles, CParticleVisibilityData* pVisibilityData); void CalculatePathValues(CPathParameters const& PathIn, float flTimeStamp, Vector* pStartPnt, Vector* pMidPnt, Vector* pEndPnt ); int GetGroupID() const; void InitializeNewParticles(int nFirstParticle, int nParticleCount, uint32 nInittedMask); void UpdateHitBoxInfo(int nControlPointNumber); void UnlinkFromDefList(); CParticleCollection* GetNextCollectionUsingSameDef() { return m_pNextDef; } CUtlReference< CSheet > m_Sheet; protected: CParticleCollection(); bool Init(const char* pParticleSystemName); bool Init(CParticleSystemDefinition* pDef); 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); void FillAttributeWithConstant(int nAttribute, float fValue); void UpdatePrevControlPoints(float dt); float* GetConstantAttributeMemory(int nAttribute); void SwapAdjacentParticles(int hParticle); void UnlinkParticle(int hParticle); void InsertParticleBefore(int hParticle, int hBefore); void MoveParticle(int nInitialIndex, int nNewIndex); float ComputeSqrDistanceToParticle(int hParticle, const Vector& vecPosition) const; void GrowDistSqrBounds(float flDistSqr); void SimulateFirstFrame(); bool SystemContainsParticlesWithBoolSet(bool CParticleCollection::* pField) const; bool ContainsOpaqueCollections(); bool ComputeUsesPowerOfTwoFrameBufferTexture(); bool ComputeUsesFullFrameBufferTexture(); bool ComputeIsTranslucent(); bool ComputeIsTwoPass(); bool ComputeIsBatchable(); bool ComputeRequiresOrderInvariance(); void LabelTextureUsage(void); void LinkIntoDefList(); public: fltx4 m_fl4CurTime; int m_nPaddedActiveParticles; float m_flCurTime; int m_nActiveParticles; float m_flDt; float m_flPreviousDt; float m_flNextSleepTime; 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; CParticleControlPoint m_ControlPoints[MAX_PARTICLE_CONTROL_POINTS]; CModelHitBoxesInfo m_ControlPointHitBoxes[MAX_PARTICLE_CONTROL_POINTS]; uint8* m_pOperatorContextData; CParticleCollection* m_pNext; CParticleCollection* m_pPrev; struct CWorldCollideContextData* m_pCollisionCacheData[NUM_COLLISION_CACHE_MODES]; CParticleCollection* m_pParent; CUtlIntrusiveDList m_Children; 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: bool m_bBoundsValid; Vector m_MinBounds; Vector m_MaxBounds; int m_nHighestCP; private: unsigned char* m_pParticleMemory; unsigned char* m_pParticleInitialMemory; unsigned char* m_pConstantMemory; int m_nPerParticleInitializedAttributeMask; int m_nPerParticleUpdatedAttributeMask; int m_nPerParticleReadInitialAttributeMask; 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; int m_nParticleFlags; bool m_bIsScrubbable : 1; bool m_bIsRunningInitializers : 1; bool m_bIsRunningOperators : 1; bool m_bIsTranslucent : 1; bool m_bIsTwoPass : 1; bool m_bAnyUsesPowerOfTwoFrameBufferTexture : 1; bool m_bAnyUsesFullFrameBufferTexture : 1; bool m_bIsBatchable : 1; bool m_bUsesPowerOfTwoFrameBufferTexture; bool m_bUsesFullFrameBufferTexture; int m_nDrawnFrames; int m_nSimulatedFrames; Vector m_Center; int m_nUniqueParticleId; 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; int m_nNumParticlesToKill; int* m_pParticleKillList; CParticleCollection* m_pNextDef; CParticleCollection* m_pPrevDef; void LoanKillListTo(CParticleCollection* pBorrower) const; bool HasAttachedKillList(void) const; CParticleOperatorInstance* m_pRenderOp; friend class CParticleSystemMgr; friend class CParticleOperatorInstance; }; class CM128InitialAttributeIterator : public CStridedConstPtr { public: FORCEINLINE CM128InitialAttributeIterator(int nAttribute, CParticleCollection* pParticles) { m_pData = pParticles->GetInitialM128AttributePtr(nAttribute, &m_nStride); } }; class CM128AttributeIterator : public CStridedConstPtr { public: FORCEINLINE CM128AttributeIterator(int nAttribute, CParticleCollection* pParticles) { m_pData = pParticles->GetM128AttributePtr(nAttribute, &m_nStride); } }; class C4IAttributeIterator : public CStridedConstPtr { public: FORCEINLINE C4IAttributeIterator(int nAttribute, CParticleCollection* pParticles) { m_pData = pParticles->Get4IAttributePtr(nAttribute, &m_nStride); } }; class CM128AttributeWriteIterator : public CStridedPtr { 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 { public: FORCEINLINE C4VAttributeIterator(int nAttribute, CParticleCollection* pParticles) { m_pData = pParticles->Get4VAttributePtr(nAttribute, &m_nStride); } }; class C4VInitialAttributeIterator : public CStridedConstPtr { public: FORCEINLINE C4VInitialAttributeIterator(int nAttribute, CParticleCollection* pParticles) { m_pData = pParticles->GetInitial4VAttributePtr(nAttribute, &m_nStride); } }; class C4VAttributeWriteIterator : public CStridedPtr { public: FORCEINLINE C4VAttributeWriteIterator(int nAttribute, CParticleCollection* pParticles) { m_pData = pParticles->Get4VAttributePtrForWrite(nAttribute, &m_nStride); } }; 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) { 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)); 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; 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 (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); } } inline float* CParticleCollection::GetConstantAttributeMemory(int nAttribute) { return m_pConstantAttributes + 3 * 4 * nAttribute; } inline int CParticleCollection::OperatorRandomSampleOffset() const { return m_nOperatorRandomSampleOffset; } inline int CParticleCollection::RandomInt(int nRandomSampleId, int nMin, int nMax) { 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) { 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) { 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) { 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) { 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); } inline int CParticleCollection::RandomInt(int nMin, int nMax) { return RandomInt(m_nRandomQueryCount++, nMin, nMax); } inline float CParticleCollection::RandomFloat(float flMin, float flMax) { return RandomFloat(m_nRandomQueryCount++, flMin, flMax); } inline float CParticleCollection::RandomFloatExp(float flMin, float flMax, float flExponent) { return RandomFloatExp(m_nRandomQueryCount++, flMin, flMax, flExponent); } inline void CParticleCollection::RandomVector(float flMin, float flMax, Vector* pVector) { RandomVector(m_nRandomQueryCount++, flMin, flMax, pVector); } inline void CParticleCollection::RandomVector(const Vector& vecMin, const Vector& vecMax, Vector* pVector) { RandomVector(m_nRandomQueryCount++, vecMin, vecMax, pVector); } inline float CParticleCollection::RandomVectorInUnitSphere(Vector* pVector) { return RandomVectorInUnitSphere(m_nRandomQueryCount++, pVector); } 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(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(m_pParticleAttributes[nAttribute]); } inline const FourInts* CParticleCollection::Get4IAttributePtr(int nAttribute, size_t* pStrideOut) const { *(pStrideOut) = m_nParticleFloatStrides[nAttribute] / 4; return reinterpret_cast(m_pParticleAttributes[nAttribute]); } inline const int32* CParticleCollection::GetIntAttributePtr(int nAttribute, size_t* pStrideOut) const { *(pStrideOut) = m_nParticleFloatStrides[nAttribute]; return reinterpret_cast(m_pParticleAttributes[nAttribute]); } inline const FourVectors* CParticleCollection::Get4VAttributePtr(int nAttribute, size_t* pStrideOut) const { *(pStrideOut) = m_nParticleFloatStrides[nAttribute] / 12; return reinterpret_cast(m_pParticleAttributes[nAttribute]); } inline FourVectors* CParticleCollection::Get4VAttributePtrForWrite(int nAttribute, size_t* pStrideOut) { *(pStrideOut) = m_nParticleFloatStrides[nAttribute] / 12; return reinterpret_cast(m_pParticleAttributes[nAttribute]); } inline const FourVectors* CParticleCollection::GetInitial4VAttributePtr(int nAttribute, size_t* pStrideOut) const { *(pStrideOut) = m_nParticleInitialFloatStrides[nAttribute] / 12; return reinterpret_cast(m_pParticleInitialAttributes[nAttribute]); } inline float* CParticleCollection::GetFloatAttributePtrForWrite(int nAttribute, int nParticleNumber) { 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) { 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(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(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(m_pParticleInitialAttributes[nAttribute]); } 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) { Assert(nPidx < m_nActiveParticles + 4); Assert(m_nNumParticlesToKill < MAX_PARTICLES_IN_A_SYSTEM); m_pParticleKillList[m_nNumParticlesToKill++] = nPidx; } 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; } } 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]; } 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); } FORCEINLINE void CParticleCollection::GrowDistSqrBounds(float flDistSqr) { if (m_flLastMinDistSqr > flDistSqr) { m_flLastMinDistSqr = flDistSqr; } else if (m_flLastMaxDistSqr < flDistSqr) { m_flLastMaxDistSqr = flDistSqr; } } struct ParticleChildrenInfo_t { DmObjectId_t m_Id; CUtlString m_Name; bool m_bUseNameBasedLookup; float m_flDelay; }; class CParticleSystemDefinition { DECLARE_DMXELEMENT_UNPACK(); DECLARE_REFERENCED_CLASS(CParticleSystemDefinition); public: CParticleSystemDefinition(void); ~CParticleSystemDefinition(void); void Read(CDmxElement* pElement); CDmxElement* Write(); const char* MaterialName() const; IMaterial* GetMaterial() const; const char* GetName() const; const DmObjectId_t& GetId() const; bool UsesPowerOfTwoFrameBufferTexture(); bool UsesFullFrameBufferTexture(); bool ShouldAlwaysPrecache() const; bool ShouldBatch() const; bool IsViewModelEffect() const; CParticleCollection* FirstCollection(); float GetCullRadius() const; float GetCullFillCost() const; int GetCullControlPoint() const; const char* GetCullReplacementDefinition() const; bool HasRetirementBeenChecked(int nFrame) const; void MarkRetirementCheck(int nFrame); 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& out_list); void WriteChildren(CDmxElement* pElement); void WriteOperators(CDmxElement* pElement, const char* pOpKeyName, const CUtlVector& inList); CUtlVector* 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; 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; float m_flMinimumSimTime; int m_nMinimumFrames; bool m_bViewModelEffect; size_t m_nContextDataSize; DmObjectId_t m_Id; public: float m_flMaxDrawDistance; float m_flNoDrawTimeToGoToSleep; int m_nMaxParticles; int m_nSkipRenderControlPoint; CUtlString m_Name; CUtlVector m_Operators; CUtlVector m_Renderers; CUtlVector m_Initializers; CUtlVector m_Emitters; CUtlVector m_ForceGenerators; CUtlVector m_Constraints; CUtlVector m_Children; CUtlVector m_nOperatorsCtxOffsets; CUtlVector m_nRenderersCtxOffsets; CUtlVector m_nInitializersCtxOffsets; CUtlVector m_nEmittersCtxOffsets; CUtlVector m_nForceGeneratorsCtxOffsets; CUtlVector m_nConstraintsCtxOffsets; 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 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(); } 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; } 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)); *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