add block particles property

This commit is contained in:
MihailRis 2024-11-04 22:48:39 +03:00
parent 24af455bf0
commit 0eeb6b6eb2
11 changed files with 180 additions and 23 deletions

View File

@ -15,5 +15,21 @@
"obstacle": false,
"grounded": true,
"rotation": "pipe",
"material": "base:wood"
"material": "base:wood",
"particles": {
"lifetime": 2.0,
"spawn_interval": 0.3,
"acceleration": [0, 0, 0],
"velocity": [0, 0.3, 0],
"explosion": [0, 0, 0],
"size": [0.2, 0.2, 0.2],
"spawn_shape": "ball",
"spawn_spread": [0.05, 0.05, 0.05],
"lighting": false,
"frames": [
"particles:fire_0",
"particles:smoke_0",
"particles:smoke_1"
]
}
}

View File

@ -1,18 +0,0 @@
function on_placed(x, y, z)
particles.emit({x + 0.5, y + 0.4, z + 0.5}, -1, {
lifetime=2.0,
spawn_interval=0.3,
acceleration={0, 0, 0},
velocity={0, 0.3, 0},
explosion={0, 0, 0},
size={0.2, 0.2, 0.2},
spawn_shape="ball",
spawn_spread={0.05, 0.05, 0.05},
lighting=false,
frames={
"particles:fire_0",
"particles:smoke_0",
"particles:smoke_1"
}
})
end

View File

@ -22,6 +22,7 @@
#include "voxels/Block.hpp"
#include "data/dv_util.hpp"
#include "data/StructLayout.hpp"
#include "presets/ParticlesPreset.hpp"
namespace fs = std::filesystem;
using namespace data;
@ -335,6 +336,11 @@ void ContentLoader::loadBlock(
perform_user_block_fields(def.name, *def.dataStruct);
}
if (root.has("particles")) {
def.particles = std::make_unique<ParticlesPreset>();
def.particles->deserialize(root["particles"]);
}
if (def.tickInterval == 0) {
def.tickInterval = 1;
}

View File

@ -14,6 +14,7 @@
#include "graphics/core/PostProcessing.hpp"
#include "graphics/core/Viewport.hpp"
#include "graphics/render/WorldRenderer.hpp"
#include "graphics/render/Decorator.hpp"
#include "graphics/ui/elements/Menu.hpp"
#include "graphics/ui/GUI.hpp"
#include "logic/LevelController.hpp"
@ -29,20 +30,25 @@
static debug::Logger logger("level-screen");
LevelScreen::LevelScreen(Engine* engine, std::unique_ptr<Level> level)
LevelScreen::LevelScreen(Engine* engine, std::unique_ptr<Level> levelPtr)
: Screen(engine), postProcessing(std::make_unique<PostProcessing>())
{
Level* level = levelPtr.get();
auto& settings = engine->getSettings();
auto assets = engine->getAssets();
auto menu = engine->getGUI()->getMenu();
menu->reset();
controller = std::make_unique<LevelController>(engine, std::move(level));
controller = std::make_unique<LevelController>(engine, std::move(levelPtr));
frontend = std::make_unique<LevelFrontend>(controller->getPlayer(), controller.get(), assets);
worldRenderer = std::make_unique<WorldRenderer>(engine, frontend.get(), controller->getPlayer());
hud = std::make_unique<Hud>(engine, frontend.get(), controller->getPlayer());
decorator =
std::make_unique<Decorator>(*level, *worldRenderer->particles, *assets);
keepAlive(settings.graphics.backlight.observe([=](bool) {
controller->getLevel()->chunks->saveAndClear();
worldRenderer->clear();
@ -156,6 +162,7 @@ void LevelScreen::update(float delta) {
}
controller->update(glm::min(delta, 0.2f), !inputLocked, hud->isPause());
hud->update(hudVisible);
decorator->update(delta, *camera);
}
void LevelScreen::draw(float delta) {

View File

@ -12,6 +12,7 @@ class WorldRenderer;
class TextureAnimator;
class PostProcessing;
class ContentPackRuntime;
class Decorator;
class Level;
class LevelScreen : public Screen {
@ -20,6 +21,7 @@ class LevelScreen : public Screen {
std::unique_ptr<WorldRenderer> worldRenderer;
std::unique_ptr<TextureAnimator> animator;
std::unique_ptr<PostProcessing> postProcessing;
std::unique_ptr<Decorator> decorator;
std::unique_ptr<Hud> hud;
void saveWorldPreview();

View File

@ -0,0 +1,103 @@
#include "Decorator.hpp"
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/norm.hpp>
#include "ParticlesRenderer.hpp"
#include "assets/assets_util.hpp"
#include "content/Content.hpp"
#include "voxels/Chunks.hpp"
#include "voxels/Block.hpp"
#include "world/Level.hpp"
#include "window/Camera.hpp"
/// @brief Not greather than 64 for this BIG_PRIME value
inline constexpr int UPDATE_AREA_DIAMETER = 32;
/// @brief Number of blocks in the volume
inline constexpr int UPDATE_BLOCKS =
UPDATE_AREA_DIAMETER * UPDATE_AREA_DIAMETER * UPDATE_AREA_DIAMETER;
/// @brief Number of update iterations
inline constexpr int ITERATIONS = 512;
/// @brief Big prime number used for pseudo-random 3d array iteration
inline constexpr int BIG_PRIME = 666667;
Decorator::Decorator(
const Level& level, ParticlesRenderer& particles, const Assets& assets
)
: level(level), particles(particles), assets(assets) {
}
void Decorator::update(
float delta, const glm::ivec3& areaStart, const glm::ivec3& areaCenter
) {
int index = currentIndex;
currentIndex = (currentIndex + BIG_PRIME) % UPDATE_BLOCKS;
const auto& chunks = *level.chunks;
const auto& indices = *level.content->getIndices();
int lx = index % UPDATE_AREA_DIAMETER;
int lz = (index / UPDATE_AREA_DIAMETER) % UPDATE_AREA_DIAMETER;
int ly = (index / UPDATE_AREA_DIAMETER / UPDATE_AREA_DIAMETER);
auto pos = areaStart + glm::ivec3(lx, ly, lz);
if (auto vox = chunks.get(pos)) {
const auto& def = indices.blocks.require(vox->id);
if (def.particles) {
const auto& found = blockEmitters.find(pos);
if (found == blockEmitters.end()) {
auto treg = util::get_texture_region(
assets, def.particles->texture, ""
);
blockEmitters[pos] = particles.add(std::make_unique<Emitter>(
level,
glm::vec3{pos.x + 0.5, pos.y + 0.5, pos.z + 0.5},
*def.particles,
treg.texture,
treg.region,
-1
));
}
}
}
}
void Decorator::update(float delta, const Camera& camera) {
glm::ivec3 pos = camera.position;
pos -= glm::ivec3(UPDATE_AREA_DIAMETER / 2);
for (int i = 0; i < ITERATIONS; i++) {
update(delta, pos, camera.position);
}
const auto& chunks = *level.chunks;
const auto& indices = *level.content->getIndices();
auto iter = blockEmitters.begin();
while (iter != blockEmitters.end()) {
auto emitter = particles.getEmitter(iter->second);
if (emitter == nullptr) {
iter = blockEmitters.erase(iter);
continue;
}
bool remove = false;
if (auto vox = chunks.get(iter->first)) {
const auto& def = indices.blocks.require(vox->id);
if (def.particles == nullptr) {
remove = true;
}
} else {
iter = blockEmitters.erase(iter);
continue;
}
if (util::distance2(iter->first, glm::ivec3(camera.position)) >
UPDATE_AREA_DIAMETER * UPDATE_AREA_DIAMETER) {
remove = true;
}
if (remove) {
emitter->stop();
iter = blockEmitters.erase(iter);
continue;
}
iter++;
}
}

View File

@ -0,0 +1,31 @@
#pragma once
#include <glm/glm.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/hash.hpp>
#include <unordered_map>
class Level;
class Chunks;
class Camera;
class Assets;
class ParticlesRenderer;
class Decorator {
const Level& level;
const Assets& assets;
ParticlesRenderer& particles;
std::unordered_map<glm::ivec3, uint64_t> blockEmitters;
int currentIndex = 0;
void update(
float delta, const glm::ivec3& areaStart, const glm::ivec3& areaCenter
);
public:
Decorator(
const Level& level, ParticlesRenderer& particles, const Assets& assets
);
void update(float delta, const Camera& camera);
};

View File

@ -25,7 +25,7 @@ struct ParticlesPreset : public Serializable {
/// @brief Apply lighting
bool lighting = true;
/// @brief Max distance of actually spawning particles.
float maxDistance = 32.0f;
float maxDistance = 16.0f;
/// @brief Particles spawn interval
float spawnInterval = 0.1f;
/// @brief Particle life time

View File

@ -5,6 +5,7 @@
#include "core_defs.hpp"
#include "data/StructLayout.hpp"
#include "presets/ParticlesPreset.hpp"
#include "util/stringutil.hpp"
std::string to_string(BlockModel model) {
@ -142,6 +143,7 @@ void Block::cloneTo(Block& dst) {
dst.inventorySize = inventorySize;
dst.tickInterval = tickInterval;
dst.overlayTexture = overlayTexture;
dst.particles = std::make_unique<ParticlesPreset>(*particles);
}
static std::set<std::string, std::less<>> RESERVED_BLOCK_FIELDS {

View File

@ -10,6 +10,8 @@
#include "maths/aabb.hpp"
#include "typedefs.hpp"
struct ParticlesPreset;
namespace data {
class StructLayout;
}
@ -199,6 +201,8 @@ public:
std::unique_ptr<data::StructLayout> dataStruct;
std::unique_ptr<ParticlesPreset> particles;
/// @brief Runtime indices (content indexing results)
struct {
/// @brief block runtime integer id

View File

@ -60,6 +60,10 @@ public:
return get(pos.x, pos.y, pos.z);
}
inline const voxel* get(glm::ivec3 pos) const {
return get(pos.x, pos.y, pos.z);
}
light_t getLight(int32_t x, int32_t y, int32_t z) const;
ubyte getLight(int32_t x, int32_t y, int32_t z, int channel) const;
void set(int32_t x, int32_t y, int32_t z, uint32_t id, blockstate state);