From c8187c5f25592fcb7940106ac72619a6c5bd3448 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 3 Nov 2024 16:01:07 +0300 Subject: [PATCH] add particles.emit(...) (WIP) --- res/content/base/scripts/world.lua | 8 ++++ src/frontend/screens/LevelScreen.cpp | 2 +- src/graphics/render/Emitter.cpp | 16 +++---- src/graphics/render/Emitter.hpp | 17 +++---- src/graphics/render/ParticlesRenderer.cpp | 24 ++++------ src/graphics/render/ParticlesRenderer.hpp | 2 + src/graphics/render/WorldRenderer.cpp | 5 +++ src/graphics/render/WorldRenderer.hpp | 5 ++- src/logic/scripting/lua/libs/api_lua.hpp | 1 + src/logic/scripting/lua/libs/libparticles.cpp | 44 +++++++++++++++++++ src/logic/scripting/scripting_hud.cpp | 7 ++- src/logic/scripting/scripting_hud.hpp | 14 +++--- src/presets/ParticlesPreset.cpp | 15 +++++++ src/presets/ParticlesPreset.hpp | 12 +++++ 14 files changed, 125 insertions(+), 47 deletions(-) create mode 100644 res/content/base/scripts/world.lua create mode 100644 src/logic/scripting/lua/libs/libparticles.cpp diff --git a/res/content/base/scripts/world.lua b/res/content/base/scripts/world.lua new file mode 100644 index 00000000..db8be79a --- /dev/null +++ b/res/content/base/scripts/world.lua @@ -0,0 +1,8 @@ +function on_block_broken(id, x, y, z, playerid) + particles.emit({x+0.5, y+0.5, z+0.5}, 100, { + lifetime=1.0, + spawn_interval=0.0001, + explosion={4, 4, 4}, + texture="blocks:"..block.get_textures(id)[1] + }) +end diff --git a/src/frontend/screens/LevelScreen.cpp b/src/frontend/screens/LevelScreen.cpp index c0d4aa88..b8bb59e6 100644 --- a/src/frontend/screens/LevelScreen.cpp +++ b/src/frontend/screens/LevelScreen.cpp @@ -66,7 +66,7 @@ void LevelScreen::initializeContent() { for (auto& entry : content->getPacks()) { initializePack(entry.second.get()); } - scripting::on_frontend_init(hud.get()); + scripting::on_frontend_init(hud.get(), worldRenderer.get()); } void LevelScreen::initializePack(ContentPackRuntime* pack) { diff --git a/src/graphics/render/Emitter.cpp b/src/graphics/render/Emitter.cpp index 7e4d55f7..7c7cb30b 100644 --- a/src/graphics/render/Emitter.cpp +++ b/src/graphics/render/Emitter.cpp @@ -12,18 +12,17 @@ Emitter::Emitter( const Level& level, std::variant origin, - Particle prototype, + ParticlesPreset preset, const Texture* texture, - float spawnInterval, + const UVRegion& region, int count ) : level(level), origin(std::move(origin)), - prototype(std::move(prototype)), + prototype({this, 0, glm::vec3(), preset.velocity, preset.lifetime, region}), texture(texture), - spawnInterval(spawnInterval), count(count), - preset() { + preset(std::move(preset)) { this->prototype.emitter = this; } @@ -36,6 +35,7 @@ void Emitter::update( const glm::vec3& cameraPosition, std::vector& particles ) { + const float spawnInterval = preset.spawnInterval; if (count == 0 || (count == -1 && spawnInterval < FLT_EPSILON)) { return; } @@ -67,7 +67,7 @@ void Emitter::update( particle.emitter = this; particle.random = random.rand32(); particle.position = position; - particle.velocity += glm::ballRand(1.0f) * explosion; + particle.velocity += glm::ballRand(1.0f) * preset.explosion; particles.push_back(std::move(particle)); timer -= spawnInterval; if (count > 0) { @@ -76,10 +76,6 @@ void Emitter::update( } } -void Emitter::setExplosion(const glm::vec3& magnitude) { - explosion = magnitude; -} - bool Emitter::isDead() const { return count == 0; } diff --git a/src/graphics/render/Emitter.hpp b/src/graphics/render/Emitter.hpp index 04355eeb..749c82fd 100644 --- a/src/graphics/render/Emitter.hpp +++ b/src/graphics/render/Emitter.hpp @@ -31,24 +31,22 @@ struct Particle { class Texture; +using EmitterOrigin = std::variant; + class Emitter { const Level& level; /// @brief Static position or entity - std::variant origin; + EmitterOrigin origin; /// @brief Particle prototype Particle prototype; /// @brief Particle const Texture* texture; - /// @brief Particles spawn interval - float spawnInterval; /// @brief Number of particles should be spawned before emitter deactivation. /// -1 is infinite. int count; /// @brief Spawn timer used to determine number of particles /// to spawn on update. May be innacurate. float timer = 0.0f; - /// @brief Random velocity magnitude applying to spawned particles. - glm::vec3 explosion {8.0f}; util::PseudoRandom random; public: @@ -57,9 +55,9 @@ public: Emitter( const Level& level, std::variant origin, - Particle prototype, + ParticlesPreset preset, const Texture* texture, - float spawnInterval, + const UVRegion& region, int count ); @@ -77,10 +75,7 @@ public: const glm::vec3& cameraPosition, std::vector& particles ); - - /// @brief Set initial random velocity magitude - void setExplosion(const glm::vec3& magnitude); - + /// @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 8838f9e8..ab099058 100644 --- a/src/graphics/render/ParticlesRenderer.cpp +++ b/src/graphics/render/ParticlesRenderer.cpp @@ -1,7 +1,6 @@ #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" @@ -18,17 +17,7 @@ ParticlesRenderer::ParticlesRenderer( ) : batch(std::make_unique(1024)), level(level), - settings(settings) { - auto region = util::get_texture_region(assets, "blocks:grass_side", ""); - emitters.push_back(std::make_unique( - level, - glm::vec3(0, 80, 0), - Particle {nullptr, 0, glm::vec3(), glm::vec3(), 5.0f, region.region}, - region.texture, - 0.002f, - -1 - )); -} + settings(settings) {} ParticlesRenderer::~ParticlesRenderer() = default; @@ -68,21 +57,22 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) { auto iter = vec.begin(); while (iter != vec.end()) { auto& particle = *iter; + auto& preset = particle.emitter->preset; update_particle(particle, delta, chunks); glm::vec4 light(1, 1, 1, 0); - if (particle.emitter->preset.lighting) { + if (preset.lighting) { light = MainBatch::sampleLight( particle.position, chunks, backlight ); - light *= 0.8f + (particle.random % 200) * 0.001f; + light *= 0.9f + (particle.random % 100) * 0.001f; } batch->quad( particle.position, right, up, - glm::vec2(0.3f), + preset.size, light, glm::vec3(1.0f), particle.region @@ -128,3 +118,7 @@ void ParticlesRenderer::render(const Camera& camera, float delta) { iter++; } } + +void ParticlesRenderer::add(std::unique_ptr emitter) { + emitters.push_back(std::move(emitter)); +} diff --git a/src/graphics/render/ParticlesRenderer.hpp b/src/graphics/render/ParticlesRenderer.hpp index ca7906da..6986db05 100644 --- a/src/graphics/render/ParticlesRenderer.hpp +++ b/src/graphics/render/ParticlesRenderer.hpp @@ -31,6 +31,8 @@ public: void render(const Camera& camera, float delta); + void add(std::unique_ptr emitter); + static size_t visibleParticles; static size_t aliveEmitters; }; diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 730125ad..874a9894 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -44,6 +44,7 @@ #include "ChunksRenderer.hpp" #include "ModelBatch.hpp" #include "Skybox.hpp" +#include "Emitter.hpp" bool WorldRenderer::showChunkBorders = false; bool WorldRenderer::showEntitiesDebug = false; @@ -534,6 +535,10 @@ void WorldRenderer::drawBorders( lineBatch->flush(); } +void WorldRenderer::addEmitter(std::unique_ptr emitter) { + particles->add(std::move(emitter)); +} + void WorldRenderer::clear() { renderer->clear(); } diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index d2ed639a..cf74c6dd 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -8,8 +8,6 @@ #include -#include "Emitter.hpp" - class Level; class Player; class Camera; @@ -27,6 +25,7 @@ class PostProcessing; class DrawContext; class ModelBatch; class Assets; +class Emitter; struct EngineSettings; namespace model { @@ -109,5 +108,7 @@ public: bool pause ); + void addEmitter(std::unique_ptr emitter); + void clear(); }; diff --git a/src/logic/scripting/lua/libs/api_lua.hpp b/src/logic/scripting/lua/libs/api_lua.hpp index f9c8b3f8..a6edc434 100644 --- a/src/logic/scripting/lua/libs/api_lua.hpp +++ b/src/logic/scripting/lua/libs/api_lua.hpp @@ -31,6 +31,7 @@ extern const luaL_Reg itemlib[]; extern const luaL_Reg jsonlib[]; extern const luaL_Reg mat4lib[]; extern const luaL_Reg packlib[]; +extern const luaL_Reg particleslib[]; extern const luaL_Reg playerlib[]; extern const luaL_Reg quatlib[]; // quat.cpp extern const luaL_Reg timelib[]; diff --git a/src/logic/scripting/lua/libs/libparticles.cpp b/src/logic/scripting/lua/libs/libparticles.cpp new file mode 100644 index 00000000..932318ea --- /dev/null +++ b/src/logic/scripting/lua/libs/libparticles.cpp @@ -0,0 +1,44 @@ +#include "api_lua.hpp" + +#include "logic/scripting/scripting_hud.hpp" +#include "graphics/render/WorldRenderer.hpp" +#include "graphics/render/Emitter.hpp" +#include "assets/assets_util.hpp" +#include "engine.hpp" + +using namespace scripting; + +static int l_emit(lua::State* L) { + EmitterOrigin origin; + if (lua::istable(L, 1)) { + origin = lua::tovec3(L, 1); + } else { + origin = static_cast(lua::tointeger(L, 1)); + } + int count = lua::tointeger(L, 2); + auto preset = lua::tovalue(L, 3); + auto extension = lua::tovalue(L, 4); + + ParticlesPreset particlesPreset {}; + particlesPreset.deserialize(preset); + if (extension != nullptr) { + particlesPreset.deserialize(extension); + } + auto& assets = *engine->getAssets(); + auto region = util::get_texture_region(assets, particlesPreset.texture, ""); + auto emitter = std::make_unique( + *level, + std::move(origin), + std::move(particlesPreset), + region.texture, + region.region, + count + ); + renderer->addEmitter(std::move(emitter)); + return 0; +} + +const luaL_Reg particleslib[] = { + {"emit", lua::wrap}, + {NULL, NULL} +}; diff --git a/src/logic/scripting/scripting_hud.cpp b/src/logic/scripting/scripting_hud.cpp index a8856837..f065a692 100644 --- a/src/logic/scripting/scripting_hud.cpp +++ b/src/logic/scripting/scripting_hud.cpp @@ -4,6 +4,7 @@ #include "engine.hpp" #include "files/files.hpp" #include "frontend/hud.hpp" +#include "graphics/render/WorldRenderer.hpp" #include "objects/Player.hpp" #include "lua/libs/api_lua.hpp" #include "lua/lua_engine.hpp" @@ -14,10 +15,14 @@ using namespace scripting; static debug::Logger logger("scripting-hud"); Hud* scripting::hud = nullptr; +WorldRenderer* scripting::renderer = nullptr; -void scripting::on_frontend_init(Hud* hud) { +void scripting::on_frontend_init(Hud* hud, WorldRenderer* renderer) { scripting::hud = hud; + scripting::renderer = renderer; + lua::openlib(lua::get_main_state(), "hud", hudlib); + lua::openlib(lua::get_main_state(), "particles", particleslib); for (auto& pack : engine->getContentPacks()) { lua::emit_event( diff --git a/src/logic/scripting/scripting_hud.hpp b/src/logic/scripting/scripting_hud.hpp index c2d9b7f5..cea7e8ec 100644 --- a/src/logic/scripting/scripting_hud.hpp +++ b/src/logic/scripting/scripting_hud.hpp @@ -8,20 +8,20 @@ namespace fs = std::filesystem; class Hud; +class WorldRenderer; namespace scripting { extern Hud *hud; + extern WorldRenderer* renderer; - void on_frontend_init(Hud *hud); + void on_frontend_init(Hud* hud, WorldRenderer* renderer); void on_frontend_render(); void on_frontend_close(); - /** - * Load package-specific hud script - * @param env environment id - * @param packid content-pack id - * @param file script file path - */ + /// @brief Load package-specific hud script + /// @param env environment id + /// @param packid content-pack id + /// @param file script file path void load_hud_script( const scriptenv &env, const std::string &packid, const fs::path &file ); diff --git a/src/presets/ParticlesPreset.cpp b/src/presets/ParticlesPreset.cpp index 028b73a4..61833672 100644 --- a/src/presets/ParticlesPreset.cpp +++ b/src/presets/ParticlesPreset.cpp @@ -4,17 +4,32 @@ dv::value ParticlesPreset::serialize() const { auto root = dv::object(); + root["texture"] = texture; root["collision"] = collision; root["lighting"] = lighting; root["max_distance"] = maxDistance; + root["spawn_interval"] = spawnInterval; + root["lifetime"] = lifetime; root["acceleration"] = dv::to_value(acceleration); + root["explosion"] = dv::to_value(explosion); + root["size"] = dv::to_value(size); return root; } void ParticlesPreset::deserialize(const dv::value& src) { + src.at("texture").get(texture); src.at("collision").get(collision); src.at("lighting").get(lighting); + src.at("max_distance").get(maxDistance); + src.at("spawn_interval").get(spawnInterval); + src.at("lifetime").get(lifetime); if (src.has("acceleration")) { dv::get_vec(src["acceleration"], acceleration); } + if (src.has("size")) { + dv::get_vec(src["size"], size); + } + if (src.has("explosion")) { + dv::get_vec(src["explosion"], explosion); + } } diff --git a/src/presets/ParticlesPreset.hpp b/src/presets/ParticlesPreset.hpp index 07068344..4bd2c07d 100644 --- a/src/presets/ParticlesPreset.hpp +++ b/src/presets/ParticlesPreset.hpp @@ -11,8 +11,20 @@ struct ParticlesPreset : public Serializable { bool lighting = true; /// @brief Max distance of actually spawning particles. float maxDistance = 32.0f; + /// @brief Particles spawn interval + float spawnInterval = 0.1f; + /// @brief Particle life time + float lifetime = 5.0f; + /// @brief Initial velocity + glm::vec3 velocity {}; /// @brief Velocity acceleration glm::vec3 acceleration {0.0f, -16.0f, 0.0f}; + /// @brief Random velocity magnitude applying to spawned particles. + glm::vec3 explosion {2.0f}; + /// @brief Particle size + glm::vec3 size {0.1f}; + /// @brief Texture name + std::string texture = ""; dv::value serialize() const override; void deserialize(const dv::value& src) override;