diff --git a/src/graphics/render/Emitter.cpp b/src/graphics/render/Emitter.cpp index 58f9c809..ae2cdc48 100644 --- a/src/graphics/render/Emitter.cpp +++ b/src/graphics/render/Emitter.cpp @@ -15,7 +15,8 @@ Emitter::Emitter( prototype(std::move(prototype)), texture(texture), spawnInterval(spawnInterval), - count(count) { + count(count), + behaviour() { this->prototype.emitter = this; } @@ -37,6 +38,7 @@ void Emitter::update(float delta, std::vector& particles) { while (count && timer > spawnInterval) { // spawn particle Particle particle = prototype; + particle.emitter = this; particle.position = position; particle.velocity += glm::ballRand(1.0f) * explosion; particles.push_back(std::move(particle)); diff --git a/src/graphics/render/Emitter.hpp b/src/graphics/render/Emitter.hpp index 6a1dc06c..9f6940a4 100644 --- a/src/graphics/render/Emitter.hpp +++ b/src/graphics/render/Emitter.hpp @@ -26,6 +26,11 @@ struct Particle { class Texture; +struct ParticleBehaviour { + bool collision = true; + glm::vec3 gravity {0.0f, -16.0f, 0.0f}; +}; + class Emitter { /// @brief Static position or entity std::variant origin; @@ -42,8 +47,10 @@ class Emitter { /// to spawn on update. May be innacurate. float timer = 0.0f; /// @brief Random velocity magnitude applying to spawned particles - glm::vec3 explosion {1.0f}; + glm::vec3 explosion {8.0f}; public: + ParticleBehaviour behaviour; + Emitter( std::variant origin, Particle prototype, @@ -52,6 +59,8 @@ public: int count ); + explicit Emitter(const Emitter&) = delete; + /// @return Emitter particles texture const Texture* getTexture() const; diff --git a/src/graphics/render/ParticlesRenderer.cpp b/src/graphics/render/ParticlesRenderer.cpp index 065eebb3..913deb23 100644 --- a/src/graphics/render/ParticlesRenderer.cpp +++ b/src/graphics/render/ParticlesRenderer.cpp @@ -6,22 +6,38 @@ #include "graphics/core/Texture.hpp" #include "graphics/render/MainBatch.hpp" #include "window/Camera.hpp" +#include "world/Level.hpp" +#include "voxels/Chunks.hpp" size_t ParticlesRenderer::visibleParticles = 0; size_t ParticlesRenderer::aliveEmitters = 0; -ParticlesRenderer::ParticlesRenderer(const Assets& assets) - : batch(std::make_unique(1024)) { +ParticlesRenderer::ParticlesRenderer(const Assets& assets, const Level& level) + : batch(std::make_unique(1024)), level(level) { - auto region = util::get_texture_region(assets, "blocks:grass_side", ""); - Emitter emitter(glm::vec3(0, 100, 0), Particle { + auto region = util::get_texture_region(assets, "blocks:bazalt", ""); + emitters.push_back(std::make_unique(glm::vec3(0, 100, 0), Particle { nullptr, glm::vec3(), glm::vec3(), 5.0f, region.region - },region.texture, 0.001f, 1000); - emitters.push_back(std::make_unique(emitter)); + },region.texture, 0.002f, -1)); } ParticlesRenderer::~ParticlesRenderer() = default; +static inline void update_particle( + Particle& particle, float delta, const Chunks& chunks +) { + const auto& behave = particle.emitter->behaviour; + auto& pos = particle.position; + auto& vel = particle.velocity; + + vel += delta * behave.gravity; + if (behave.collision && chunks.isObstacleAt(pos + vel * delta)) { + vel *= 0.0f; + } + pos += vel * delta; + particle.lifetime -= delta; +} + void ParticlesRenderer::renderParticles(const Camera& camera, float delta) { const auto& right = camera.right; const auto& up = camera.up; @@ -41,7 +57,7 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) { while (iter != vec.end()) { auto& particle = *iter; - particle.position += particle.velocity * delta; + update_particle(particle, delta, *level.chunks); batch->quad( particle.position, @@ -52,8 +68,6 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) { glm::vec3(1.0f), particle.region ); - - particle.lifetime -= delta; if (particle.lifetime <= 0.0f) { iter = vec.erase(iter); } else { diff --git a/src/graphics/render/ParticlesRenderer.hpp b/src/graphics/render/ParticlesRenderer.hpp index 0ca55123..6d1bbb94 100644 --- a/src/graphics/render/ParticlesRenderer.hpp +++ b/src/graphics/render/ParticlesRenderer.hpp @@ -10,15 +10,17 @@ class Texture; class Assets; class Camera; class MainBatch; +class Level; class ParticlesRenderer { + const Level& level; std::unordered_map> particles; std::vector> emitters; std::unique_ptr batch; void renderParticles(const Camera& camera, float delta); public: - ParticlesRenderer(const Assets& assets); + ParticlesRenderer(const Assets& assets, const Level& level); ~ParticlesRenderer(); void render(const Camera& camera, float delta); diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index c1e85451..ef579d7c 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -62,8 +62,9 @@ WorldRenderer::WorldRenderer( level->chunks.get(), &engine->getSettings() )), - particles(std::make_unique(*engine->getAssets())) { - + particles(std::make_unique( + *engine->getAssets(), *frontend->getLevel() + )) { renderer = std::make_unique( level, frontend->getContentGfxCache(), &engine->getSettings() ); diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index dbd2e17e..70c73140 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -61,10 +61,10 @@ voxel* Chunks::get(int32_t x, int32_t y, int32_t z) const { return &chunk->voxels[(y * CHUNK_D + lz) * CHUNK_W + lx]; } -const AABB* Chunks::isObstacleAt(float x, float y, float z) { - int ix = floor(x); - int iy = floor(y); - int iz = floor(z); +const AABB* Chunks::isObstacleAt(float x, float y, float z) const { + int ix = std::floor(x); + int iy = std::floor(y); + int iz = std::floor(z); voxel* v = get(ix, iy, iz); if (v == nullptr) { if (iy >= CHUNK_H) { @@ -172,8 +172,9 @@ Chunk* Chunks::getChunk(int x, int z) { } glm::ivec3 Chunks::seekOrigin( - glm::ivec3 pos, const Block& def, blockstate state -) { + const glm::ivec3& srcpos, const Block& def, blockstate state +) const { + auto pos = srcpos; const auto& rotation = def.rotations.variants[state.rotation]; auto segment = state.segment; while (true) { diff --git a/src/voxels/Chunks.hpp b/src/voxels/Chunks.hpp index 6e73193a..a1131f1b 100644 --- a/src/voxels/Chunks.hpp +++ b/src/voxels/Chunks.hpp @@ -69,7 +69,9 @@ public: /// @param def segment block definition /// @param state segment block state /// @return origin block position or `pos` if block is not extended - glm::ivec3 seekOrigin(glm::ivec3 pos, const Block& def, blockstate state); + glm::ivec3 seekOrigin( + const glm::ivec3& pos, const Block& def, blockstate state + ) const; /// @brief Check if required zone is replaceable /// @param def definition of the block that requires a replaceable zone @@ -97,7 +99,12 @@ public: glm::vec3 rayCastToObstacle(glm::vec3 start, glm::vec3 dir, float maxDist); - const AABB* isObstacleAt(float x, float y, float z); + const AABB* isObstacleAt(float x, float y, float z) const; + + const AABB* isObstacleAt(const glm::vec3& pos) const { + return isObstacleAt(pos.x, pos.y, pos.z); + } + bool isSolidBlock(int32_t x, int32_t y, int32_t z); bool isReplaceableBlock(int32_t x, int32_t y, int32_t z); bool isObstacleBlock(int32_t x, int32_t y, int32_t z);