diff --git a/src/graphics/render/Emitter.cpp b/src/graphics/render/Emitter.cpp index 96bcb96d..046d6486 100644 --- a/src/graphics/render/Emitter.cpp +++ b/src/graphics/render/Emitter.cpp @@ -58,6 +58,9 @@ void Emitter::update( } else if (auto entityId = std::get_if(&origin)) { if (auto entity = level.entities->get(*entityId)) { position = entity->getTransform().pos; + } else { + stop(); + return; } } const float maxDistance = preset.maxDistance; @@ -102,6 +105,10 @@ void Emitter::update( } } +void Emitter::stop() { + count = 0; +} + bool Emitter::isDead() const { return count == 0; } diff --git a/src/graphics/render/Emitter.hpp b/src/graphics/render/Emitter.hpp index 749c82fd..24867edd 100644 --- a/src/graphics/render/Emitter.hpp +++ b/src/graphics/render/Emitter.hpp @@ -75,7 +75,10 @@ public: const glm::vec3& cameraPosition, std::vector& particles ); - + + /// @brief Set remaining particles count to 0 + void stop(); + /// @return true if the emitter has spawned all particles bool isDead() const; }; diff --git a/src/graphics/render/ParticlesRenderer.cpp b/src/graphics/render/ParticlesRenderer.cpp index ab099058..a15e75a8 100644 --- a/src/graphics/render/ParticlesRenderer.cpp +++ b/src/graphics/render/ParticlesRenderer.cpp @@ -1,6 +1,7 @@ #include "ParticlesRenderer.hpp" #include "assets/Assets.hpp" +#include "assets/assets_util.hpp" #include "graphics/core/Shader.hpp" #include "graphics/core/Texture.hpp" #include "graphics/render/MainBatch.hpp" @@ -17,6 +18,7 @@ ParticlesRenderer::ParticlesRenderer( ) : batch(std::make_unique(1024)), level(level), + assets(assets), settings(settings) {} ParticlesRenderer::~ParticlesRenderer() = default; @@ -59,6 +61,23 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) { auto& particle = *iter; auto& preset = particle.emitter->preset; + if (!preset.frames.empty()) { + float time = preset.lifetime - particle.lifetime; + int framesCount = preset.frames.size(); + int frameid = time / preset.lifetime * framesCount; + int frameid2 = glm::min( + (time + delta) / preset.lifetime * framesCount, + framesCount - 1.0f + ); + if (frameid2 != frameid) { + auto tregion = util::get_texture_region( + assets, preset.frames.at(frameid2), "" + ); + if (tregion.texture == texture) { + particle.region = tregion.region; + } + } + } update_particle(particle, delta, chunks); glm::vec4 light(1, 1, 1, 0); diff --git a/src/graphics/render/ParticlesRenderer.hpp b/src/graphics/render/ParticlesRenderer.hpp index 6986db05..27877959 100644 --- a/src/graphics/render/ParticlesRenderer.hpp +++ b/src/graphics/render/ParticlesRenderer.hpp @@ -15,6 +15,7 @@ struct GraphicsSettings; class ParticlesRenderer { const Level& level; + const Assets& assets; const GraphicsSettings* settings; std::unordered_map> particles; std::vector> emitters; diff --git a/src/presets/ParticlesPreset.cpp b/src/presets/ParticlesPreset.cpp index 7d9f86ab..f832507d 100644 --- a/src/presets/ParticlesPreset.cpp +++ b/src/presets/ParticlesPreset.cpp @@ -36,6 +36,12 @@ dv::value ParticlesPreset::serialize() const { root["spawn_spread"] = dv::to_value(size); root["spawn_shape"] = to_string(spawnShape); root["random_sub_uv"] = randomSubUV; + if (!frames.empty()) { + auto& arr = root.list("animation"); + for (const auto& frame : frames) { + arr.add(frame); + } + } return root; } @@ -63,4 +69,13 @@ void ParticlesPreset::deserialize(const dv::value& src) { if (src.has("spawn_shape")) { spawnShape = ParticleSpawnShape_from(src["spawn_shape"].asString()); } + if (src.has("frames")) { + for (const auto& frame : src["frames"]) { + frames.push_back(frame.asString()); + } + if (!frames.empty()) { + texture = frames.at(0); + randomSubUV = 1.0f; + } + } } diff --git a/src/presets/ParticlesPreset.hpp b/src/presets/ParticlesPreset.hpp index 38fc1214..fcaddb3f 100644 --- a/src/presets/ParticlesPreset.hpp +++ b/src/presets/ParticlesPreset.hpp @@ -48,6 +48,8 @@ struct ParticlesPreset : public Serializable { std::string texture = ""; /// @brief Size of random sub-uv region float randomSubUV = 1.0f; + /// @brief Animation frames + std::vector frames {}; dv::value serialize() const override; void deserialize(const dv::value& src) override;