#pragma once #include #include #include #include "../munga/time.h" #include "l4d3d.h" #define COLOR_POINT_COUNT 10 #define MAX_PARTICLE_EFFECTS 32 #define EFFECT_GROUPING_EPSILON 1.0f #define L4BASICVERTEX_FVF (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_DIFFUSE | D3DFVF_NORMAL) struct L4BASICVERTEX { float x, y, z; float nx, ny, nz; DWORD color; float u, v; }; union L4COLOR { DWORD argb; struct { unsigned char b; unsigned char g; unsigned char r; unsigned char a; }; }; struct COLOR_POINT { bool active; Scalar time; L4COLOR color; }; struct PARTICLE_EFFECT { int id; struct { float left, top, right, bottom; } textureBounds; bool rotate; float fragSize; float velocity; COLOR_POINT colors[COLOR_POINT_COUNT]; float gravity; float varianceX; float varianceY; float varianceZ; int fragCount; float fragLifetime; float maxRepeat; }; struct INDIE_EFFECT : public PARTICLE_EFFECT { int maxIssue; float releasePeriod; float duration; }; class ParticleEngine; class ParticleEmitter; class Particle { friend class ParticleEngine; public: Particle(PARTICLE_EFFECT *effect); void Execute(Scalar dT); inline bool IsAlive() { return (mEffect && ( mAge < mEffect->fragLifetime)); } inline Particle *Next() { return mNextParticle; } inline Particle *Prev() { return mPrevParticle; } private: float mX, mY, mZ; L4COLOR mColor; D3DXVECTOR3 mVelocity; D3DXVECTOR3 mAcceleration; D3DXMATRIX mTextureTransform; PARTICLE_EFFECT *mEffect; Scalar mAge; Particle *mNextParticle; Particle *mPrevParticle; friend int compare(const Particle *, const Particle *, const D3DXMATRIX *); friend void mergesort(Particle **, Particle **, const D3DXMATRIX *); }; class ParticleEmitter { public: ParticleEmitter(); bool IsActive() { return mActive; } void SetEffect(int effect); void SetEffect(INDIE_EFFECT *effect) { mEffect = effect; } float GetMaxRepeat() { return mEffect->maxRepeat; } void Execute(); void Fire() { mActive = true; } void Start() { mActive = true; mActivated = (Scalar)Now(); } void SetPosition(float x, float y, float z) { mPosition.x = x; mPosition.y = y; mPosition.z = z; } private: PARTICLE_EFFECT *mEffect; bool mActive; Scalar mActivated; D3DXVECTOR3 mPosition; }; class ParticleEngine { friend class ParticleEmitter; public: static void Destroy(); static void Initialize(LPDIRECT3DDEVICE9 device); static void InstallEffect(int effectNumber, PARTICLE_EFFECT effect); static void RenderParticles(const D3DXMATRIX *view_matrix, Scalar timeSlice); private: static void CreateParticle(D3DXVECTOR3 position, PARTICLE_EFFECT *effect); static int BuildParticleVertices(const Particle *p, L4BASICVERTEX *verts, D3DXMATRIX *view_matrix); static void ExecuteParticles(const D3DXMATRIX *view_matrix, Scalar timeSlice); static LPDIRECT3DDEVICE9 mDevice; static PARTICLE_EFFECT mInstalledEffects[]; static LPDIRECT3DTEXTURE9 mParticleTexture; static bool mActiveParticles; static LPDIRECT3DVERTEXBUFFER9 mVertBuffer; static Particle *mParticlesHead; static Particle *mParticlesTail; static long mTotalParticleCount; static long mMaxParticleCount; };