mirror of
https://github.com/0TheSpy/Seaside.git
synced 2025-01-07 10:03:29 +08:00
618 lines
16 KiB
C++
618 lines
16 KiB
C++
|
|
#ifndef PARTICLEMGR_H
|
|
#define PARTICLEMGR_H
|
|
|
|
#ifdef _WIN32
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "imaterial.h"
|
|
#include "imaterialsystem.h"
|
|
#include "vector.h"
|
|
#include "vmatrix.h"
|
|
#include "Mathlib.h"
|
|
#include "iclientrenderable.h"
|
|
#include "clientleafsystem.h"
|
|
#include "fasttimer.h"
|
|
#include "utllinkedlist.h"
|
|
#include "UtlDict.h"
|
|
#ifdef WIN32
|
|
#include <typeinfo>
|
|
#else
|
|
#include <typeinfo>
|
|
#endif
|
|
#include "utlintrusivelist.h"
|
|
#include "utlobjectreference.h"
|
|
#include "utlstring.h"
|
|
|
|
|
|
class IParticleEffect;
|
|
class IClientParticleListener;
|
|
struct Particle;
|
|
class ParticleDraw;
|
|
class CMeshBuilder;
|
|
class CUtlMemoryPool;
|
|
class CEffectMaterial;
|
|
class CParticleSimulateIterator;
|
|
class CParticleRenderIterator;
|
|
class IThreadPool;
|
|
class CParticleSystemDefinition;
|
|
class CParticleMgr;
|
|
class CNewParticleEffect;
|
|
class CParticleCollection;
|
|
|
|
#define INVALID_MATERIAL_HANDLE NULL
|
|
|
|
|
|
|
|
class CParticleSubTexture;
|
|
class CParticleSubTextureGroup;
|
|
|
|
|
|
struct Particle
|
|
{
|
|
Particle* m_pPrev, * m_pNext;
|
|
|
|
CParticleSubTexture* m_pSubTexture;
|
|
|
|
Vector m_Pos;
|
|
};
|
|
|
|
|
|
typedef CParticleSubTexture* PMaterialHandle;
|
|
|
|
class CEffectMaterial
|
|
{
|
|
public:
|
|
CEffectMaterial();
|
|
|
|
public:
|
|
CParticleSubTextureGroup* m_pGroup;
|
|
|
|
Particle m_Particles;
|
|
CEffectMaterial* m_pHashedNext;
|
|
};
|
|
|
|
|
|
class CParticleSubTextureGroup
|
|
{
|
|
public:
|
|
CParticleSubTextureGroup();
|
|
~CParticleSubTextureGroup();
|
|
|
|
IMaterial* m_pPageMaterial;
|
|
};
|
|
|
|
class CParticleSubTexture
|
|
{
|
|
public:
|
|
CParticleSubTexture();
|
|
|
|
float m_tCoordMins[2];
|
|
float m_tCoordMaxs[2];
|
|
|
|
CParticleSubTextureGroup* m_pGroup;
|
|
CParticleSubTextureGroup m_DefaultGroup;
|
|
#ifdef _DEBUG
|
|
char* m_szDebugName;
|
|
#endif
|
|
|
|
IMaterial* m_pMaterial;
|
|
};
|
|
|
|
|
|
abstract_class IParticleEffect
|
|
{
|
|
public:
|
|
|
|
virtual ~IParticleEffect() {}
|
|
|
|
virtual void Update(float fTimeDelta) {}
|
|
|
|
virtual void StartRender(VMatrix & effectMatrix) {}
|
|
|
|
virtual bool ShouldSimulate() const = 0;
|
|
virtual void SetShouldSimulate(bool bSim) = 0;
|
|
virtual void SimulateParticles(CParticleSimulateIterator* pIterator) = 0;
|
|
|
|
virtual void RenderParticles(CParticleRenderIterator* pIterator) = 0;
|
|
|
|
virtual void NotifyRemove() {}
|
|
|
|
virtual void NotifyDestroyParticle(Particle* pParticle) {}
|
|
|
|
virtual const Vector& GetSortOrigin() = 0;
|
|
|
|
virtual const Vector* GetParticlePosition(Particle* pParticle) { return &pParticle->m_Pos; }
|
|
|
|
virtual const char* GetEffectName() { return "???"; }
|
|
};
|
|
|
|
#define REGISTER_EFFECT( effect ) \
|
|
IParticleEffect* effect##_Factory() \
|
|
{ \
|
|
return new effect; \
|
|
} \
|
|
struct effect##_RegistrationHelper \
|
|
{ \
|
|
effect##_RegistrationHelper() \
|
|
{ \
|
|
ParticleMgr()->RegisterEffect( typeid( effect ).name(), effect##_Factory ); \
|
|
} \
|
|
}; \
|
|
static effect##_RegistrationHelper g_##effect##_RegistrationHelper
|
|
|
|
#define REGISTER_EFFECT_USING_CREATE( effect ) \
|
|
IParticleEffect* effect##_Factory() \
|
|
{ \
|
|
return effect::Create( #effect ).GetObject(); \
|
|
} \
|
|
struct effect##_RegistrationHelper \
|
|
{ \
|
|
effect##_RegistrationHelper() \
|
|
{ \
|
|
ParticleMgr()->RegisterEffect( typeid( effect ).name(), effect##_Factory ); \
|
|
} \
|
|
}; \
|
|
static effect##_RegistrationHelper g_##effect##_RegistrationHelper
|
|
|
|
|
|
class CParticleEffectBinding : public CDefaultClientRenderable
|
|
{
|
|
friend class CParticleMgr;
|
|
friend class CParticleSimulateIterator;
|
|
friend class CNewParticleEffect;
|
|
|
|
public:
|
|
CParticleEffectBinding();
|
|
~CParticleEffectBinding();
|
|
|
|
|
|
public:
|
|
|
|
void SimulateParticles(float flTimeDelta);
|
|
|
|
PMaterialHandle FindOrAddMaterial(const char* pMaterialName);
|
|
|
|
Particle* AddParticle(int sizeInBytes, PMaterialHandle pMaterial);
|
|
|
|
void SetBBox(const Vector& bbMin, const Vector& bbMax, bool bDisableAutoUpdate = true);
|
|
void GetWorldspaceBounds(Vector* pMins, Vector* pMaxs);
|
|
|
|
const matrix3x4_t& GetLocalSpaceTransform() const;
|
|
void SetLocalSpaceTransform(const matrix3x4_t& transform);
|
|
|
|
bool EnlargeBBoxToContain(const Vector& pt);
|
|
|
|
void SetDrawThruLeafSystem(int bDraw);
|
|
|
|
void SetDrawBeforeViewModel(int bDraw);
|
|
|
|
int GetRemoveFlag() { return GetFlag(FLAGS_REMOVE); }
|
|
void SetRemoveFlag() { SetFlag(FLAGS_REMOVE, 1); }
|
|
|
|
int GetAlwaysSimulate() { return GetFlag(FLAGS_ALWAYSSIMULATE); }
|
|
void SetAlwaysSimulate(int bAlwaysSimulate) { SetFlag(FLAGS_ALWAYSSIMULATE, bAlwaysSimulate); }
|
|
|
|
void SetIsNewParticleSystem(void) { SetFlag(FLAGS_NEW_PARTICLE_SYSTEM, 1); }
|
|
int WasDrawnPrevFrame() { return GetFlag(FLAGS_DRAWN_PREVFRAME); }
|
|
void SetWasDrawnPrevFrame(int bWasDrawnPrevFrame) { SetFlag(FLAGS_DRAWN_PREVFRAME, bWasDrawnPrevFrame); }
|
|
|
|
int IsEffectCameraSpace() { return GetFlag(FLAGS_CAMERASPACE); }
|
|
void SetEffectCameraSpace(int bCameraSpace) { SetFlag(FLAGS_CAMERASPACE, bCameraSpace); }
|
|
|
|
int GetAutoApplyLocalTransform() const { return GetFlag(FLAGS_AUTOAPPLYLOCALTRANSFORM); }
|
|
void SetAutoApplyLocalTransform(int b) { SetFlag(FLAGS_AUTOAPPLYLOCALTRANSFORM, b); }
|
|
|
|
int GetAutoUpdateBBox() { return GetFlag(FLAGS_AUTOUPDATEBBOX); }
|
|
void SetAutoUpdateBBox(int bAutoUpdate) { SetFlag(FLAGS_AUTOUPDATEBBOX, bAutoUpdate); }
|
|
|
|
int GetNumActiveParticles();
|
|
|
|
void SetParticleCullRadius(float flMaxParticleRadius);
|
|
|
|
int GetActiveParticleList(int nCount, Particle** ppParticleList);
|
|
|
|
void DetectChanges();
|
|
|
|
private:
|
|
void SetFlag(int flag, int bOn) { if (bOn) m_Flags |= flag; else m_Flags &= ~flag; }
|
|
int GetFlag(int flag) const { return m_Flags & flag; }
|
|
|
|
void Init(CParticleMgr* pMgr, IParticleEffect* pSim);
|
|
void Term();
|
|
|
|
void RemoveParticle(Particle* pParticle);
|
|
|
|
void StartDrawMaterialParticles(
|
|
CEffectMaterial* pMaterial,
|
|
float flTimeDelta,
|
|
IMesh*& pMesh,
|
|
CMeshBuilder& builder,
|
|
ParticleDraw& particleDraw,
|
|
bool bWireframe);
|
|
|
|
int DrawMaterialParticles(
|
|
bool bBucketSort,
|
|
CEffectMaterial* pMaterial,
|
|
float flTimeDelta,
|
|
bool bWireframe
|
|
);
|
|
|
|
void GrowBBoxFromParticlePositions(CEffectMaterial* pMaterial, bool& bboxSet, Vector& bbMin, Vector& bbMax);
|
|
|
|
void RenderStart(VMatrix& mTempModel, VMatrix& mTempView);
|
|
void RenderEnd(VMatrix& mModel, VMatrix& mView);
|
|
|
|
void BBoxCalcStart(Vector& bbMin, Vector& bbMax);
|
|
void BBoxCalcEnd(bool bboxSet, Vector& bbMin, Vector& bbMax);
|
|
|
|
void DoBucketSort(
|
|
CEffectMaterial* pMaterial,
|
|
float* zCoords,
|
|
int nZCoords,
|
|
float minZ,
|
|
float maxZ);
|
|
|
|
int GetRemovalInProgressFlag() { return GetFlag(FLAGS_REMOVALINPROGRESS); }
|
|
void SetRemovalInProgressFlag() { SetFlag(FLAGS_REMOVALINPROGRESS, 1); }
|
|
|
|
int GetNeedsBBoxUpdate() { return GetFlag(FLAGS_NEEDS_BBOX_UPDATE); }
|
|
void SetNeedsBBoxUpdate(int bFirstUpdate) { SetFlag(FLAGS_NEEDS_BBOX_UPDATE, bFirstUpdate); }
|
|
|
|
int GetFirstFrameFlag() { return GetFlag(FLAGS_FIRST_FRAME); }
|
|
void SetFirstFrameFlag(int bFirstUpdate) { SetFlag(FLAGS_FIRST_FRAME, bFirstUpdate); }
|
|
|
|
int WasDrawn() { return GetFlag(FLAGS_DRAWN); }
|
|
void SetDrawn(int bDrawn) { SetFlag(FLAGS_DRAWN, bDrawn); }
|
|
|
|
bool RecalculateBoundingBox();
|
|
|
|
CEffectMaterial* GetEffectMaterial(CParticleSubTexture* pSubTexture);
|
|
|
|
public:
|
|
|
|
virtual const Vector& GetRenderOrigin(void);
|
|
virtual const QAngle& GetRenderAngles(void);
|
|
virtual const matrix3x4_t& RenderableToWorldTransform();
|
|
virtual void GetRenderBounds(Vector& mins, Vector& maxs);
|
|
virtual bool ShouldDraw(void);
|
|
virtual int DrawModel(int flags, const RenderableInstance_t& instance);
|
|
|
|
private:
|
|
enum
|
|
{
|
|
FLAGS_REMOVE = (1 << 0),
|
|
FLAGS_REMOVALINPROGRESS = (1 << 1),
|
|
FLAGS_NEEDS_BBOX_UPDATE = (1 << 2),
|
|
FLAGS_AUTOUPDATEBBOX = (1 << 3),
|
|
FLAGS_ALWAYSSIMULATE = (1 << 4),
|
|
FLAGS_DRAWN = (1 << 5),
|
|
FLAGS_DRAWN_PREVFRAME = (1 << 6),
|
|
FLAGS_CAMERASPACE = (1 << 7),
|
|
FLAGS_DRAW_THRU_LEAF_SYSTEM = (1 << 8),
|
|
FLAGS_DRAW_BEFORE_VIEW_MODEL = (1 << 9),
|
|
FLAGS_AUTOAPPLYLOCALTRANSFORM = (1 << 10),
|
|
FLAGS_FIRST_FRAME = (1 << 11),
|
|
FLAGS_NEW_PARTICLE_SYSTEM = (1 << 12)
|
|
};
|
|
|
|
|
|
VMatrix m_LocalSpaceTransform;
|
|
bool m_bLocalSpaceTransformIdentity;
|
|
|
|
Vector m_Min;
|
|
Vector m_Max;
|
|
|
|
Vector m_LastMin;
|
|
Vector m_LastMax;
|
|
|
|
float m_flParticleCullRadius;
|
|
|
|
unsigned short m_nActiveParticles;
|
|
|
|
unsigned short m_FrameCode;
|
|
|
|
unsigned short m_ListIndex;
|
|
|
|
IParticleEffect* m_pSim;
|
|
CParticleMgr* m_pParticleMgr;
|
|
|
|
int m_Flags;
|
|
|
|
enum { EFFECT_MATERIAL_HASH_SIZE = 8 };
|
|
CEffectMaterial* m_EffectMaterialHash[EFFECT_MATERIAL_HASH_SIZE];
|
|
|
|
#ifdef INFESTED_PARTICLES
|
|
public:
|
|
#endif
|
|
CUtlLinkedList<CEffectMaterial*, unsigned short> m_Materials;
|
|
|
|
unsigned short m_UpdateBBoxCounter;
|
|
};
|
|
|
|
|
|
class CParticleLightInfo
|
|
{
|
|
public:
|
|
Vector m_vPos;
|
|
Vector m_vColor;
|
|
float m_flIntensity;
|
|
};
|
|
|
|
typedef IParticleEffect* (*CreateParticleEffectFN)();
|
|
|
|
enum
|
|
{
|
|
TOOLPARTICLESYSTEMID_INVALID = -1,
|
|
};
|
|
|
|
|
|
class CParticleCollection;
|
|
|
|
class CNonDrawingParticleSystem
|
|
{
|
|
public:
|
|
CNonDrawingParticleSystem* m_pNext;
|
|
CNonDrawingParticleSystem* m_pPrev;
|
|
CParticleCollection* m_pSystem;
|
|
|
|
FORCEINLINE CParticleCollection* operator()(void) const
|
|
{
|
|
return m_pSystem;
|
|
}
|
|
|
|
FORCEINLINE CParticleCollection* Get(void) const
|
|
{
|
|
return m_pSystem;
|
|
}
|
|
|
|
~CNonDrawingParticleSystem(void);
|
|
};
|
|
|
|
|
|
|
|
|
|
class CClientTools;
|
|
|
|
class CParticleMgr
|
|
{
|
|
friend class CParticleEffectBinding;
|
|
friend class CParticleCollection;
|
|
friend class CNonDrawingParticleSystem;
|
|
friend class CClientTools;
|
|
|
|
public:
|
|
|
|
CParticleMgr();
|
|
virtual ~CParticleMgr();
|
|
|
|
bool Init(unsigned long nPreallocatedParticles, IMaterialSystem* pMaterial);
|
|
|
|
void Term();
|
|
|
|
void LevelInit();
|
|
|
|
void RegisterEffect(const char* pEffectType, CreateParticleEffectFN func);
|
|
IParticleEffect* CreateEffect(const char* pEffectType);
|
|
|
|
bool AddEffect(CParticleEffectBinding* pEffect, IParticleEffect* pSim);
|
|
void RemoveEffect(CParticleEffectBinding* pEffect);
|
|
|
|
void AddEffect(CNewParticleEffect* pEffect);
|
|
void RemoveEffect(CNewParticleEffect* pEffect);
|
|
|
|
void RemoveAllEffects();
|
|
|
|
void IncrementFrameCode();
|
|
|
|
void Simulate(float fTimeDelta);
|
|
|
|
void PostRender();
|
|
|
|
void DrawBeforeViewModelEffects();
|
|
|
|
VMatrix& GetModelView();
|
|
|
|
Particle* AllocParticle(int size);
|
|
void FreeParticle(Particle*);
|
|
|
|
PMaterialHandle GetPMaterial(const char* pMaterialName);
|
|
IMaterial* PMaterialToIMaterial(PMaterialHandle hMaterial);
|
|
|
|
void RepairPMaterial(PMaterialHandle hMaterial);
|
|
|
|
void GetDirectionalLightInfo(CParticleLightInfo& info) const;
|
|
void SetDirectionalLightInfo(const CParticleLightInfo& info);
|
|
|
|
void SpewInfo(bool bDetail);
|
|
|
|
void AddEffectListener(IClientParticleListener* pListener);
|
|
void RemoveEffectListener(IClientParticleListener* pListener);
|
|
|
|
int AllocateToolParticleEffectId();
|
|
|
|
void RemoveAllNewEffects();
|
|
|
|
CNewParticleEffect* FirstNewEffect();
|
|
CNewParticleEffect* NextNewEffect(CNewParticleEffect* pEffect);
|
|
|
|
void RenderParticleSystems(bool bEnable);
|
|
bool ShouldRenderParticleSystems() const;
|
|
|
|
void RemoveOldParticleEffects(float flTime);
|
|
int GetNumParticles() const { return m_nCurrentParticlesAllocated; }
|
|
|
|
|
|
CNonDrawingParticleSystem* CreateNonDrawingEffect(const char* pEffectName);
|
|
|
|
private:
|
|
struct RetireInfo_t
|
|
{
|
|
CParticleCollection* m_pCollection;
|
|
float m_flScreenArea;
|
|
bool m_bFirstFrame;
|
|
};
|
|
|
|
void UpdateAllEffects(float flTimeDelta);
|
|
|
|
void UpdateNewEffects(float flTimeDelta);
|
|
|
|
void SpewActiveParticleSystems();
|
|
|
|
CParticleSubTextureGroup* FindOrAddSubTextureGroup(IMaterial* pPageMaterial);
|
|
|
|
int ComputeParticleDefScreenArea(int nInfoCount, RetireInfo_t* pInfo, float* pTotalArea, CParticleSystemDefinition* pDef,
|
|
const CViewSetup& view, const VMatrix& worldToPixels, float flFocalDist);
|
|
|
|
bool RetireParticleCollections(CParticleSystemDefinition* pDef, int nCount, RetireInfo_t* pInfo, float flScreenArea, float flMaxTotalArea);
|
|
void BuildParticleSimList(CUtlVector< CNewParticleEffect* >& list);
|
|
bool EarlyRetireParticleSystems(int nCount, CNewParticleEffect** ppEffects);
|
|
static int RetireSort(const void* p1, const void* p2);
|
|
|
|
private:
|
|
|
|
int m_nCurrentParticlesAllocated;
|
|
|
|
CParticleLightInfo m_DirectionalLight;
|
|
|
|
unsigned short m_FrameCode;
|
|
|
|
bool m_bUpdatingEffects;
|
|
bool m_bRenderParticleEffects;
|
|
|
|
CUtlLinkedList<CParticleEffectBinding*, unsigned short> m_Effects;
|
|
|
|
CUtlIntrusiveDList< CNewParticleEffect > m_NewEffects;
|
|
CUtlIntrusiveDList< CNonDrawingParticleSystem > m_NonDrawingParticleSystems;
|
|
|
|
|
|
|
|
CUtlVector< IClientParticleListener*> m_effectListeners;
|
|
|
|
IMaterialSystem* m_pMaterialSystem;
|
|
|
|
VMatrix m_mModelView;
|
|
|
|
CUtlVector<CParticleSubTextureGroup*> m_SubTextureGroups;
|
|
CUtlDict<CParticleSubTexture*, unsigned short> m_SubTextures;
|
|
CParticleSubTexture m_DefaultInvalidSubTexture;
|
|
|
|
CUtlMap< const char*, CreateParticleEffectFN > m_effectFactories;
|
|
|
|
int m_nToolParticleEffectId;
|
|
|
|
IThreadPool* m_pThreadPool[2];
|
|
};
|
|
|
|
inline int CParticleMgr::AllocateToolParticleEffectId()
|
|
{
|
|
return m_nToolParticleEffectId++;
|
|
}
|
|
|
|
class IClientParticleListener
|
|
{
|
|
public:
|
|
virtual void OnParticleEffectAdded(IParticleEffect* pEffect) = 0;
|
|
virtual void OnParticleEffectRemoved(IParticleEffect* pEffect) = 0;
|
|
};
|
|
|
|
|
|
|
|
float Helper_GetTime();
|
|
float Helper_GetFrameTime();
|
|
float Helper_RandomFloat(float minVal, float maxVal);
|
|
int Helper_RandomInt(int minVal, int maxVal);
|
|
|
|
|
|
|
|
inline VMatrix& CParticleMgr::GetModelView()
|
|
{
|
|
return m_mModelView;
|
|
}
|
|
|
|
|
|
|
|
inline const matrix3x4_t& CParticleEffectBinding::GetLocalSpaceTransform() const
|
|
{
|
|
return m_LocalSpaceTransform.As3x4();
|
|
}
|
|
|
|
|
|
|
|
CParticleMgr* ParticleMgr();
|
|
|
|
|
|
|
|
|
|
struct StandardParticle_t : public Particle
|
|
{
|
|
void SetColor(float r, float g, float b);
|
|
void SetAlpha(float a);
|
|
|
|
Vector m_Velocity;
|
|
|
|
float m_Lifetime;
|
|
|
|
unsigned char m_EffectData;
|
|
unsigned short m_EffectDataWord;
|
|
|
|
unsigned char m_Color[4];
|
|
};
|
|
|
|
|
|
inline void TransformParticle(const VMatrix& vMat, const Vector& vIn, Vector& vOut)
|
|
{
|
|
vOut.x = vMat.m[0][0] * vIn.x + vMat.m[0][1] * vIn.y + vMat.m[0][2] * vIn.z + vMat.m[0][3];
|
|
vOut.y = vMat.m[1][0] * vIn.x + vMat.m[1][1] * vIn.y + vMat.m[1][2] * vIn.z + vMat.m[1][3];
|
|
vOut.z = vMat.m[2][0] * vIn.x + vMat.m[2][1] * vIn.y + vMat.m[2][2] * vIn.z + vMat.m[2][3];
|
|
}
|
|
|
|
|
|
inline void StandardParticle_t::SetColor(float r, float g, float b)
|
|
{
|
|
m_Color[0] = (unsigned char)(r * 255.9f);
|
|
m_Color[1] = (unsigned char)(g * 255.9f);
|
|
m_Color[2] = (unsigned char)(b * 255.9f);
|
|
}
|
|
|
|
inline void StandardParticle_t::SetAlpha(float a)
|
|
{
|
|
m_Color[3] = (unsigned char)(a * 255.9f);
|
|
}
|
|
|
|
|
|
|
|
inline void UnlinkParticle(Particle* pParticle)
|
|
{
|
|
pParticle->m_pPrev->m_pNext = pParticle->m_pNext;
|
|
pParticle->m_pNext->m_pPrev = pParticle->m_pPrev;
|
|
}
|
|
|
|
inline void InsertParticleBefore(Particle* pInsert, Particle* pNext)
|
|
{
|
|
pInsert->m_pNext = pNext;
|
|
pInsert->m_pPrev = pNext->m_pPrev;
|
|
pInsert->m_pNext->m_pPrev = pInsert->m_pPrev->m_pNext = pInsert;
|
|
}
|
|
|
|
inline void InsertParticleAfter(Particle* pInsert, Particle* pPrev)
|
|
{
|
|
pInsert->m_pPrev = pPrev;
|
|
pInsert->m_pNext = pPrev->m_pNext;
|
|
|
|
pInsert->m_pNext->m_pPrev = pInsert->m_pPrev->m_pNext = pInsert;
|
|
}
|
|
|
|
inline void SwapParticles(Particle* pPrev, Particle* pCur)
|
|
{
|
|
UnlinkParticle(pCur);
|
|
InsertParticleBefore(pCur, pPrev);
|
|
}
|
|
|
|
|
|
#include "particle_iterators.h"
|
|
|
|
|
|
#endif
|