add particles.emit(...) (WIP)

This commit is contained in:
MihailRis 2024-11-03 16:01:07 +03:00
parent 9728c674fc
commit c8187c5f25
14 changed files with 125 additions and 47 deletions

View File

@ -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

View File

@ -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) {

View File

@ -12,18 +12,17 @@
Emitter::Emitter(
const Level& level,
std::variant<glm::vec3, entityid_t> 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<Particle>& 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;
}

View File

@ -31,24 +31,22 @@ struct Particle {
class Texture;
using EmitterOrigin = std::variant<glm::vec3, entityid_t>;
class Emitter {
const Level& level;
/// @brief Static position or entity
std::variant<glm::vec3, entityid_t> 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<glm::vec3, entityid_t> 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<Particle>& 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;
};

View File

@ -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<MainBatch>(1024)),
level(level),
settings(settings) {
auto region = util::get_texture_region(assets, "blocks:grass_side", "");
emitters.push_back(std::make_unique<Emitter>(
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> emitter) {
emitters.push_back(std::move(emitter));
}

View File

@ -31,6 +31,8 @@ public:
void render(const Camera& camera, float delta);
void add(std::unique_ptr<Emitter> emitter);
static size_t visibleParticles;
static size_t aliveEmitters;
};

View File

@ -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> emitter) {
particles->add(std::move(emitter));
}
void WorldRenderer::clear() {
renderer->clear();
}

View File

@ -8,8 +8,6 @@
#include <glm/glm.hpp>
#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> emitter);
void clear();
};

View File

@ -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[];

View File

@ -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<entityid_t>(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<Emitter>(
*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<l_emit>},
{NULL, NULL}
};

View File

@ -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(

View File

@ -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
);

View File

@ -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);
}
}

View File

@ -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;