Seaside/SpyCustom/sdk/particlemgr.h
2021-06-16 18:48:15 +03:00

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