#pragma once #include "hd2d/GL.h" #include #include #include namespace hd2d { struct PointLight; // High-resolution (non pixel-art) particles: ambient fields (fireflies, dust), // fire emitters (flames, embers, smoke, glow + flickering light) and bursts. class ParticleSystem { public: // Must match the kind ids in particles.vert / particles.frag. enum class Kind : int { Firefly = 0, // blinking emissive glow, wanders near the ground Mote = 1, // dust speck only visible where sunlight hits it (god rays) Spark = 2, // ballistic burst particle (footstep dust, rain splashes, ...) Flame = 3, // additive tongue of fire, eroded by noise as it ages Ember = 4, // tiny hot spark drifting up on turbulent air Smoke = 5, // alpha-blended puff rising above a fire Glow = 6, // large soft halo around a fire (one per emitter per frame) }; struct Field { // region that keeps a constant population of ambient particles Kind kind; glm::vec3 min, max; int count; }; struct Fire { glm::vec3 pos; // base of the flames float scale = 1.0f; // overall size / intensity float flameAccum = 0.0f, emberAccum = 0.0f, smokeAccum = 0.0f; float flicker = 1.0f; // current light flicker multiplier float phase = 0.0f; }; ~ParticleSystem(); void addField(Kind kind, glm::vec3 min, glm::vec3 max, int count); int addFire(glm::vec3 pos, float scale = 1.0f); void burst(glm::vec3 pos, int count, glm::vec3 color, float speed, float size, float life); void update(float dt, float time); void draw() const; // Appends fire lights first, then up to `maxFireflies` firefly lights. void collectLights(std::vector& out, int maxFireflies) const; const std::vector& fires() const { return fires_; } glm::vec3 fireflyColor{2.6f, 3.2f, 0.9f}; glm::vec3 moteColor{1.0f, 0.95f, 0.8f}; float fireflyLightRadius = 2.2f; glm::vec3 fireLightColor{4.0f, 1.75f, 0.55f}; float fireLightRadius = 7.0f; glm::vec3 wind{0.0f}; // world-space drift applied to smoke and embers float ambientFade = 1.0f; // scales fireflies + motes (Weather lowers it in rain / mist) float fireflyGlow = 1.0f; // firefly brightness + light (WeatherLook::fireflyGlow, raised at night) private: struct Particle { glm::vec3 pos, vel; glm::vec3 color; float size, age, life, phase; Kind kind; int field; // ambient field index, or -1 int fire; // owning fire, or -1 }; struct GpuParticle { glm::vec4 posSize; glm::vec4 color; // rgb, a = alpha glm::vec4 params; // x = kind, y = age / life, z = random seed }; void spawnInField(Particle& p, int fieldIndex, bool randomAge); void spawnFire(const Fire& f, int fireIndex, Kind kind); std::vector fields_; std::vector fires_; std::vector particles_; std::vector gpu_; std::mt19937 rng_{1337}; GLuint vao_ = 0, vbo_ = 0; size_t capacity_ = 0; }; } // namespace hd2d