From a52d68669d0a860a3ce0aba4ee5ee98ea7743566 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 8 Nov 2024 17:44:57 +0300 Subject: [PATCH 01/80] add 'size_spread' particles parameter --- src/graphics/render/ParticlesRenderer.cpp | 4 +++- src/presets/ParticlesPreset.cpp | 2 ++ src/presets/ParticlesPreset.hpp | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/graphics/render/ParticlesRenderer.cpp b/src/graphics/render/ParticlesRenderer.cpp index 0e030dbc..c5048c55 100644 --- a/src/graphics/render/ParticlesRenderer.cpp +++ b/src/graphics/render/ParticlesRenderer.cpp @@ -89,11 +89,13 @@ void ParticlesRenderer::renderParticles(const Camera& camera, float delta) { ); light *= 0.9f + (particle.random % 100) * 0.001f; } + float scale = 1.0f + ((particle.random ^ 2628172) % 1000) * + 0.001f * preset.sizeSpread; batch->quad( particle.position, right, preset.globalUpVector ? glm::vec3(0, 1, 0) : up, - preset.size, + preset.size * scale, light, glm::vec3(1.0f), particle.region diff --git a/src/presets/ParticlesPreset.cpp b/src/presets/ParticlesPreset.cpp index 31b0cff2..181dbeb5 100644 --- a/src/presets/ParticlesPreset.cpp +++ b/src/presets/ParticlesPreset.cpp @@ -42,6 +42,7 @@ dv::value ParticlesPreset::serialize() const { root["acceleration"] = dv::to_value(acceleration); root["explosion"] = dv::to_value(explosion); root["size"] = dv::to_value(size); + root["size_spread"] = sizeSpread; root["spawn_spread"] = dv::to_value(size); root["spawn_shape"] = to_string(spawnShape); root["random_sub_uv"] = randomSubUV; @@ -67,6 +68,7 @@ void ParticlesPreset::deserialize(const dv::value& src) { if (src.has("size")) { dv::get_vec(src["size"], size); } + src.at("size_spread").get(sizeSpread); if (src.has("spawn_spread")) { dv::get_vec(src["spawn_spread"], spawnSpread); } diff --git a/src/presets/ParticlesPreset.hpp b/src/presets/ParticlesPreset.hpp index 483ce1b4..eb9f06dd 100644 --- a/src/presets/ParticlesPreset.hpp +++ b/src/presets/ParticlesPreset.hpp @@ -42,6 +42,8 @@ struct ParticlesPreset : public Serializable { glm::vec3 explosion {2.0f}; /// @brief Particle size glm::vec3 size {0.1f}; + /// @brief Particles size spread + float sizeSpread = 0.2f; /// @brief Spawn spread shape ParticleSpawnShape spawnShape = BALL; /// @brief Spawn spread From 3ff79a0210c33e90980ae57eaed423d447596fd8 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 9 Nov 2024 20:20:17 +0300 Subject: [PATCH 02/80] update docs --- doc/ru/particles.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/ru/particles.md b/doc/ru/particles.md index bc20a4a3..167337f8 100644 --- a/doc/ru/particles.md +++ b/doc/ru/particles.md @@ -17,6 +17,7 @@ | acceleration | Ускорение частиц. | {0, -16, 0} | | explosion | Сила разлёта частиц при спавне. | {2, 2, 2} | | size | Размер частиц. | {0.1, 0.1, 0.1} | +| size_spread | Максимальное отклонение времени размера частиц. | 0.2 | | spawn_shape | Форма области спавна частиц. (ball/sphere/box) | ball | | spawn_spread | Размер области спавна частиц. | {0, 0, 0} | | random_sub_uv | Размер случайного подрегиона текстуры (1 - будет использована вся текстура). | 1.0 | From 5793c52ac6aff52a9730ddcce938672bff8f5f71 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Fri, 15 Nov 2024 06:47:03 +0300 Subject: [PATCH 03/80] Revert "remove 'translucent' block property (will be reverted later)" This reverts commit 7aacadc926432da2583b95f6a02af08ee51c2c91. --- res/content/base/blocks/water.json | 3 ++- src/content/ContentLoader.cpp | 1 + src/voxels/Block.cpp | 1 + src/voxels/Block.hpp | 3 +++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/res/content/base/blocks/water.json b/res/content/base/blocks/water.json index 943640e8..f7785044 100644 --- a/res/content/base/blocks/water.json +++ b/res/content/base/blocks/water.json @@ -6,5 +6,6 @@ "sky-light-passing": false, "obstacle": false, "selectable": false, - "replaceable": true + "replaceable": true, + "translucent": true } diff --git a/src/content/ContentLoader.cpp b/src/content/ContentLoader.cpp index a801500e..4414999d 100644 --- a/src/content/ContentLoader.cpp +++ b/src/content/ContentLoader.cpp @@ -333,6 +333,7 @@ void ContentLoader::loadBlock( root.at("inventory-size").get(def.inventorySize); root.at("tick-interval").get(def.tickInterval); root.at("overlay-texture").get(def.overlayTexture); + root.at("translucent").get(def.translucent); if (root.has("fields")) { def.dataStruct = std::make_unique(); diff --git a/src/voxels/Block.cpp b/src/voxels/Block.cpp index 51d9662b..6d4ff761 100644 --- a/src/voxels/Block.cpp +++ b/src/voxels/Block.cpp @@ -140,6 +140,7 @@ void Block::cloneTo(Block& dst) { dst.inventorySize = inventorySize; dst.tickInterval = tickInterval; dst.overlayTexture = overlayTexture; + dst.translucent = translucent; if (particles) { dst.particles = std::make_unique(*particles); } diff --git a/src/voxels/Block.hpp b/src/voxels/Block.hpp index 26b38469..84835534 100644 --- a/src/voxels/Block.hpp +++ b/src/voxels/Block.hpp @@ -172,6 +172,9 @@ public: /// @brief Turns off block item generation bool hidden = false; + /// @brief Block has semi-transparent texture + bool translucent = false; + /// @brief Set of block physical hitboxes std::vector hitboxes; From 5b6256e0fa93183c1da9371d65877398ef5f6542 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 04:13:00 +0300 Subject: [PATCH 04/80] introduce ChunkMesh --- src/graphics/render/BlocksRenderer.cpp | 154 ++++++++++++++++++++----- src/graphics/render/BlocksRenderer.hpp | 12 +- src/graphics/render/ChunksRenderer.cpp | 14 ++- src/graphics/render/ChunksRenderer.hpp | 5 +- src/graphics/render/commons.hpp | 29 +++++ 5 files changed, 172 insertions(+), 42 deletions(-) create mode 100644 src/graphics/render/commons.hpp diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index bf55ef12..25e8997d 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -12,6 +12,8 @@ #include +#include "util/timeutil.hpp" + const uint BlocksRenderer::VERTEX_SIZE = 6; const glm::vec3 BlocksRenderer::SUN_VECTOR (0.411934f, 0.863868f, -0.279161f); @@ -433,21 +435,9 @@ glm::vec4 BlocksRenderer::pickSoftLight( right, up); } -void BlocksRenderer::render(const voxel* voxels) { - int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D); - int totalEnd = chunk->top * (CHUNK_W * CHUNK_D); - - int beginEnds[256][2] {}; - for (int i = totalBegin; i < totalEnd; i++) { - const voxel& vox = voxels[i]; - blockid_t id = vox.id; - const auto& def = *blockDefsCache[id]; - - if (beginEnds[def.drawGroup][0] == 0) { - beginEnds[def.drawGroup][0] = i+1; - } - beginEnds[def.drawGroup][1] = i; - } +void BlocksRenderer::render( + const voxel* voxels, int beginEnds[256][2] +) { for (const auto drawGroup : *content.drawGroups) { int begin = beginEnds[drawGroup][0]; if (begin == 0) { @@ -462,13 +452,13 @@ void BlocksRenderer::render(const voxel* voxels) { if (id == 0 || def.drawGroup != drawGroup || state.segment) { continue; } + //if (def.translucent) { + // continue; + //} const UVRegion texfaces[6] { - cache.getRegion(id, 0), - cache.getRegion(id, 1), - cache.getRegion(id, 2), - cache.getRegion(id, 3), - cache.getRegion(id, 4), - cache.getRegion(id, 5) + cache.getRegion(id, 0), cache.getRegion(id, 1), + cache.getRegion(id, 2), cache.getRegion(id, 3), + cache.getRegion(id, 4), cache.getRegion(id, 5) }; int x = i % CHUNK_W; int y = i / (CHUNK_D * CHUNK_W); @@ -503,43 +493,143 @@ void BlocksRenderer::render(const voxel* voxels) { } } +SortingMeshData BlocksRenderer::renderTranslucent( + const voxel* voxels, int beginEnds[256][2] +) { + timeutil::ScopeLogTimer log(555); + SortingMeshData sortingMesh {{}}; + + for (const auto drawGroup : *content.drawGroups) { + int begin = beginEnds[drawGroup][0]; + if (begin == 0) { + continue; + } + int end = beginEnds[drawGroup][1]; + for (int i = begin-1; i <= end; i++) { + const voxel& vox = voxels[i]; + blockid_t id = vox.id; + blockstate state = vox.state; + const auto& def = *blockDefsCache[id]; + if (id == 0 || def.drawGroup != drawGroup || state.segment) { + continue; + } + if (!def.translucent) { + continue; + } + const UVRegion texfaces[6] { + cache.getRegion(id, 0), cache.getRegion(id, 1), + cache.getRegion(id, 2), cache.getRegion(id, 3), + cache.getRegion(id, 4), cache.getRegion(id, 5) + }; + int x = i % CHUNK_W; + int y = i / (CHUNK_D * CHUNK_W); + int z = (i / CHUNK_D) % CHUNK_W; + switch (def.model) { + case BlockModel::block: + blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless, + def.ambientOcclusion); + break; + case BlockModel::xsprite: { + blockXSprite(x, y, z, glm::vec3(1.0f), + texfaces[FACE_MX], texfaces[FACE_MZ], 1.0f); + break; + } + case BlockModel::aabb: { + blockAABB({x, y, z}, texfaces, &def, vox.state.rotation, + !def.shadeless, def.ambientOcclusion); + break; + } + case BlockModel::custom: { + blockCustomModel({x, y, z}, &def, vox.state.rotation, + !def.shadeless, def.ambientOcclusion); + break; + } + default: + break; + } + if (vertexOffset == 0) { + continue; + } + SortingMeshEntry entry {glm::vec3( + x + chunk->x * CHUNK_W, y, z + chunk->z * CHUNK_D + ), util::Buffer(indexSize * VERTEX_SIZE)}; + + for (int j = 0; j < indexSize; j++) { + std::memcpy( + entry.vertexData.data(), + vertexBuffer.get() + indexBuffer[j] * VERTEX_SIZE, + sizeof(float) * VERTEX_SIZE + ); + } + sortingMesh.entries.push_back(std::move(entry)); + vertexOffset = 0; + indexOffset = indexSize = 0; + } + } + return sortingMesh; +} + void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { this->chunk = chunk; voxelsBuffer->setPosition( chunk->x * CHUNK_W - voxelBufferPadding, 0, chunk->z * CHUNK_D - voxelBufferPadding); chunks->getVoxels(voxelsBuffer.get(), settings.graphics.backlight.get()); - overflow = false; - vertexOffset = 0; - indexOffset = indexSize = 0; + if (voxelsBuffer->pickBlockId( chunk->x * CHUNK_W, 0, chunk->z * CHUNK_D ) == BLOCK_VOID) { cancelled = true; return; } - cancelled = false; const voxel* voxels = chunk->voxels; - render(voxels); + + int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D); + int totalEnd = chunk->top * (CHUNK_W * CHUNK_D); + + int beginEnds[256][2] {}; + for (int i = totalBegin; i < totalEnd; i++) { + const voxel& vox = voxels[i]; + blockid_t id = vox.id; + const auto& def = *blockDefsCache[id]; + + if (beginEnds[def.drawGroup][0] == 0) { + beginEnds[def.drawGroup][0] = i+1; + } + beginEnds[def.drawGroup][1] = i; + } + cancelled = false; + + overflow = false; + vertexOffset = 0; + indexOffset = indexSize = 0; + + sortingMesh = std::move(renderTranslucent(voxels, beginEnds)); + + overflow = false; + vertexOffset = 0; + indexOffset = indexSize = 0; + + render(voxels, beginEnds); } -MeshData BlocksRenderer::createMesh() { +ChunkMeshData BlocksRenderer::createMesh() { const vattr attrs[]{ {3}, {2}, {1}, {0} }; - return MeshData( + return ChunkMeshData{MeshData( util::Buffer(vertexBuffer.get(), vertexOffset), util::Buffer(indexBuffer.get(), indexSize), util::Buffer({{3}, {2}, {1}, {0}}) - ); + ), std::move(sortingMesh)}; } -std::shared_ptr BlocksRenderer::render(const Chunk* chunk, const Chunks* chunks) { +ChunkMesh BlocksRenderer::render(const Chunk* chunk, const Chunks* chunks) { build(chunk, chunks); const vattr attrs[]{ {3}, {2}, {1}, {0} }; size_t vcount = vertexOffset / BlocksRenderer::VERTEX_SIZE; - return std::make_shared( + return ChunkMesh{std::make_shared( vertexBuffer.get(), vcount, indexBuffer.get(), indexSize, attrs - ); + ), std::move(sortingMesh)}; } VoxelsVolume* BlocksRenderer::getVoxelsBuffer() const { diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index 828ddf7d..cdb20749 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -12,6 +12,7 @@ #include "voxels/VoxelsVolume.hpp" #include "graphics/core/MeshData.hpp" #include "maths/util.hpp" +#include "commons.hpp" class Content; class Mesh; @@ -45,6 +46,8 @@ class BlocksRenderer { util::PseudoRandom randomizer; + SortingMeshData sortingMesh; + void vertex(const glm::vec3& coord, float u, float v, const glm::vec4& light); void index(int a, int b, int c, int d, int e, int f); @@ -115,7 +118,6 @@ class BlocksRenderer { bool isOpenForLight(int x, int y, int z) const; - // Does block allow to see other blocks sides (is it transparent) inline bool isOpen(const glm::ivec3& pos, ubyte group) const { auto id = voxelsBuffer->pickBlockId( @@ -135,7 +137,9 @@ class BlocksRenderer { glm::vec4 pickLight(const glm::ivec3& coord) const; glm::vec4 pickSoftLight(const glm::ivec3& coord, const glm::ivec3& right, const glm::ivec3& up) const; glm::vec4 pickSoftLight(float x, float y, float z, const glm::ivec3& right, const glm::ivec3& up) const; - void render(const voxel* voxels); + + void render(const voxel* voxels, int beginEnds[256][2]); + SortingMeshData renderTranslucent(const voxel* voxels, int beginEnds[256][2]); public: BlocksRenderer( size_t capacity, @@ -146,8 +150,8 @@ public: virtual ~BlocksRenderer(); void build(const Chunk* chunk, const Chunks* chunks); - std::shared_ptr render(const Chunk* chunk, const Chunks* chunks); - MeshData createMesh(); + ChunkMesh render(const Chunk* chunk, const Chunks* chunks); + ChunkMeshData createMesh(); VoxelsVolume* getVoxelsBuffer() const; bool isCancelled() const { diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index d0ae56b4..847163fc 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -62,7 +62,11 @@ ChunksRenderer::ChunksRenderer( [&](){return std::make_shared(*level, cache, settings);}, [&](RendererResult& result){ if (!result.cancelled) { - meshes[result.key] = std::make_shared(result.meshData); + auto meshData = std::move(result.meshData); + meshes[result.key] = ChunkMesh { + std::make_shared(meshData.mesh), + std::move(meshData.sortingMesh) + }; } inwork.erase(result.key); }, settings.graphics.chunkMaxRenderers.get()) @@ -82,8 +86,10 @@ std::shared_ptr ChunksRenderer::render(const std::shared_ptr& chunk chunk->flags.modified = false; if (important) { auto mesh = renderer->render(chunk.get(), level.chunks.get()); - meshes[glm::ivec2(chunk->x, chunk->z)] = mesh; - return mesh; + meshes[glm::ivec2(chunk->x, chunk->z)] = ChunkMesh { + std::move(mesh.mesh), std::move(mesh.sortingMesh) + }; + return meshes[glm::ivec2(chunk->x, chunk->z)].mesh; } glm::ivec2 key(chunk->x, chunk->z); if (inwork.find(key) != inwork.end()) { @@ -115,7 +121,7 @@ std::shared_ptr ChunksRenderer::getOrRender(const std::shared_ptr& if (chunk->flags.modified) { render(chunk, important); } - return found->second; + return found->second.mesh; } void ChunksRenderer::update() { diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index c08266bb..e44940ea 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -10,6 +10,7 @@ #include "voxels/ChunksStorage.hpp" #include "util/ThreadPool.hpp" #include "graphics/core/MeshData.hpp" +#include "commons.hpp" class Mesh; class Chunk; @@ -35,7 +36,7 @@ struct ChunksSortEntry { struct RendererResult { glm::ivec2 key; bool cancelled; - MeshData meshData; + ChunkMeshData meshData; }; class ChunksRenderer { @@ -45,7 +46,7 @@ class ChunksRenderer { const EngineSettings& settings; std::unique_ptr renderer; - std::unordered_map> meshes; + std::unordered_map meshes; std::unordered_map inwork; std::vector indices; util::ThreadPool, RendererResult> threadPool; diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp new file mode 100644 index 00000000..4101f8a8 --- /dev/null +++ b/src/graphics/render/commons.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include + +#include "graphics/core/MeshData.hpp" +#include "util/Buffer.hpp" + +class Mesh; + +struct SortingMeshEntry { + glm::vec3 position; + util::Buffer vertexData; +}; + +struct SortingMeshData { + std::vector entries; +}; + +struct ChunkMeshData { + MeshData mesh; + SortingMeshData sortingMesh; +}; + +struct ChunkMesh { + std::shared_ptr mesh; + SortingMeshData sortingMesh; +}; From faadfca8c3ec490c196fdb3c15970cb3f4d69710 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 07:34:58 +0300 Subject: [PATCH 05/80] add base:ice block --- res/content/base/blocks/ice.json | 7 +++++++ res/content/base/content.json | 15 ++++++++------- res/content/base/textures/blocks/ice.png | Bin 0 -> 7220 bytes 3 files changed, 15 insertions(+), 7 deletions(-) create mode 100644 res/content/base/blocks/ice.json create mode 100644 res/content/base/textures/blocks/ice.png diff --git a/res/content/base/blocks/ice.json b/res/content/base/blocks/ice.json new file mode 100644 index 00000000..19d9af12 --- /dev/null +++ b/res/content/base/blocks/ice.json @@ -0,0 +1,7 @@ +{ + "texture": "ice", + "material": "base:glass", + "draw-group": 4, + "light-passing": true, + "translucent": true +} diff --git a/res/content/base/content.json b/res/content/base/content.json index cec825a8..db13bae2 100644 --- a/res/content/base/content.json +++ b/res/content/base/content.json @@ -1,6 +1,8 @@ { - "items": [ - "bazalt_breaker" + "entities": [ + "drop", + "player", + "falling_block" ], "blocks": [ "dirt", @@ -27,11 +29,10 @@ "lightbulb", "torch", "wooden_door", - "coal_ore" + "coal_ore", + "ice" ], - "entities": [ - "drop", - "player", - "falling_block" + "items": [ + "bazalt_breaker" ] } \ No newline at end of file diff --git a/res/content/base/textures/blocks/ice.png b/res/content/base/textures/blocks/ice.png new file mode 100644 index 0000000000000000000000000000000000000000..36592775c01375a6799eb81ee7ff0a40bc01bc03 GIT binary patch literal 7220 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 yJGo6U-?7Gwz^t=3wtUgfC Date: Sat, 16 Nov 2024 07:41:36 +0300 Subject: [PATCH 06/80] feat: actually working slow prototype --- src/graphics/render/BlocksRenderer.cpp | 26 ++++++----- src/graphics/render/ChunksRenderer.cpp | 60 ++++++++++++++++++++++++++ src/graphics/render/ChunksRenderer.hpp | 2 + src/graphics/render/commons.hpp | 5 +++ 4 files changed, 83 insertions(+), 10 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 25e8997d..fcba92c3 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -452,9 +452,9 @@ void BlocksRenderer::render( if (id == 0 || def.drawGroup != drawGroup || state.segment) { continue; } - //if (def.translucent) { - // continue; - //} + if (def.translucent) { + continue; + } const UVRegion texfaces[6] { cache.getRegion(id, 0), cache.getRegion(id, 1), cache.getRegion(id, 2), cache.getRegion(id, 3), @@ -496,7 +496,6 @@ void BlocksRenderer::render( SortingMeshData BlocksRenderer::renderTranslucent( const voxel* voxels, int beginEnds[256][2] ) { - timeutil::ScopeLogTimer log(555); SortingMeshData sortingMesh {{}}; for (const auto drawGroup : *content.drawGroups) { @@ -550,16 +549,23 @@ SortingMeshData BlocksRenderer::renderTranslucent( if (vertexOffset == 0) { continue; } - SortingMeshEntry entry {glm::vec3( - x + chunk->x * CHUNK_W, y, z + chunk->z * CHUNK_D - ), util::Buffer(indexSize * VERTEX_SIZE)}; - + SortingMeshEntry entry { + glm::vec3( + x + chunk->x * CHUNK_W + 0.5f, + y + 0.5f, + z + chunk->z * CHUNK_D + 0.5f + ), + util::Buffer(indexSize * VERTEX_SIZE)}; + for (int j = 0; j < indexSize; j++) { std::memcpy( - entry.vertexData.data(), + entry.vertexData.data() + j * VERTEX_SIZE, vertexBuffer.get() + indexBuffer[j] * VERTEX_SIZE, sizeof(float) * VERTEX_SIZE ); + entry.vertexData[j * VERTEX_SIZE + 0] += chunk->x * CHUNK_W + 0.5f; + entry.vertexData[j * VERTEX_SIZE + 1] += 0.5f; + entry.vertexData[j * VERTEX_SIZE + 2] += chunk->z * CHUNK_D + 0.5f; } sortingMesh.entries.push_back(std::move(entry)); vertexOffset = 0; @@ -569,7 +575,7 @@ SortingMeshData BlocksRenderer::renderTranslucent( return sortingMesh; } -void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { +void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {; this->chunk = chunk; voxelsBuffer->setPosition( chunk->x * CHUNK_W - voxelBufferPadding, 0, diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 847163fc..ed313e08 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -18,6 +18,8 @@ #include #include +#include "util/timeutil.hpp" + static debug::Logger logger("chunks-render"); size_t ChunksRenderer::visibleChunks = 0; @@ -204,4 +206,62 @@ void ChunksRenderer::drawChunks( visibleChunks += drawChunk(indices[i].index, camera, shader, culling); } //} + drawSortedMeshes(camera, shader); +} + +void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { + const vattr attrs[]{ {3}, {2}, {1}, {0} }; + + std::vector entries; + + auto pposition = camera.position; + + size_t size = 0; + bool culling = settings.graphics.frustumCulling.get(); + for (size_t i = 0; i < indices.size(); i++) { + auto chunk = level.chunks->getChunks()[indices[i].index]; + if (chunk == nullptr || !chunk->flags.lighted) { + continue; + } + const auto& found = meshes.find(glm::ivec2(chunk->x, chunk->z)); + if (found == meshes.end()) { + continue; + } + + glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D); + glm::vec3 max( + chunk->x * CHUNK_W + CHUNK_W, + chunk->top, + chunk->z * CHUNK_D + CHUNK_D + ); + + if (!frustum.isBoxVisible(min, max)) continue; + + auto& chunkEntries = found->second.sortingMesh.entries; + for (auto& entry : chunkEntries) { + entry.distance = glm::distance2(entry.position, pposition); + } + for (const auto& entry : chunkEntries) { + size += entry.vertexData.size(); + entries.push_back(&entry); + } + } + std::sort(entries.begin(), entries.end(), [=](const auto& a, const auto& b) { + return *a < *b; + }); + + util::Buffer buffer(size); + size_t offset = 0; + for (const auto& entry : entries) { + std::memcpy( + (buffer.data() + offset), + entry->vertexData.data(), + entry->vertexData.size() * sizeof(float) + ); + offset += entry->vertexData.size(); + } + Mesh mesh(buffer.data(), size / 6, attrs); + + shader.uniformMatrix("u_model", glm::mat4(1.0f)); + mesh.draw(); } diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index e44940ea..cd1df2fb 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -75,6 +75,8 @@ public: ); void drawChunks(const Camera& camera, Shader& shader); + void drawSortedMeshes(const Camera& camera, Shader& shader); + void update(); static size_t visibleChunks; diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index 4101f8a8..3ef8fa26 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -12,6 +12,11 @@ class Mesh; struct SortingMeshEntry { glm::vec3 position; util::Buffer vertexData; + float distance; + + inline bool operator<(const SortingMeshEntry& o) const noexcept { + return distance > o.distance; + } }; struct SortingMeshData { From b28bcf052b3bf33cd6bfe46cc09811fd8f397e97 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 09:18:14 +0300 Subject: [PATCH 07/80] optimize (part 1) --- src/graphics/core/Mesh.cpp | 7 ++--- src/graphics/render/BlocksRenderer.cpp | 39 ++++++++++++++++++++++++-- src/graphics/render/ChunksRenderer.cpp | 30 +++++++++++++------- src/graphics/render/ChunksRenderer.hpp | 1 + src/graphics/render/commons.hpp | 2 +- 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/src/graphics/core/Mesh.cpp b/src/graphics/core/Mesh.cpp index 78380ae1..c8c114c2 100644 --- a/src/graphics/core/Mesh.cpp +++ b/src/graphics/core/Mesh.cpp @@ -58,10 +58,9 @@ void Mesh::reload(const float* vertexBuffer, size_t vertices, const int* indexBu glBindVertexArray(vao); glBindBuffer(GL_ARRAY_BUFFER, vbo); if (vertexBuffer != nullptr && vertices != 0) { - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, vertexBuffer, GL_STATIC_DRAW); - } - else { - glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertexSize * vertices, vertexBuffer, GL_STREAM_DRAW); + } else { + glBufferData(GL_ARRAY_BUFFER, 0, {}, GL_STREAM_DRAW); } if (indexBuffer != nullptr && indices != 0) { if (ibo == 0) glGenBuffers(1, &ibo); diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index fcba92c3..6a8c8176 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -498,6 +498,9 @@ SortingMeshData BlocksRenderer::renderTranslucent( ) { SortingMeshData sortingMesh {{}}; + AABB aabb {}; + bool aabbInit = false; + size_t totalSize = 0; for (const auto drawGroup : *content.drawGroups) { int begin = beginEnds[drawGroup][0]; if (begin == 0) { @@ -557,21 +560,51 @@ SortingMeshData BlocksRenderer::renderTranslucent( ), util::Buffer(indexSize * VERTEX_SIZE)}; + totalSize += entry.vertexData.size(); + for (int j = 0; j < indexSize; j++) { std::memcpy( entry.vertexData.data() + j * VERTEX_SIZE, vertexBuffer.get() + indexBuffer[j] * VERTEX_SIZE, sizeof(float) * VERTEX_SIZE ); - entry.vertexData[j * VERTEX_SIZE + 0] += chunk->x * CHUNK_W + 0.5f; - entry.vertexData[j * VERTEX_SIZE + 1] += 0.5f; - entry.vertexData[j * VERTEX_SIZE + 2] += chunk->z * CHUNK_D + 0.5f; + float& vx = entry.vertexData[j * VERTEX_SIZE + 0]; + float& vy = entry.vertexData[j * VERTEX_SIZE + 1]; + float& vz = entry.vertexData[j * VERTEX_SIZE + 2]; + + if (!aabbInit) { + aabbInit = true; + aabb.a = aabb.b = {vx, vy, vz}; + } else { + aabb.addPoint(glm::vec3(vx, vy, vz)); + } + vx += chunk->x * CHUNK_W + 0.5f; + vy += 0.5f; + vz += chunk->z * CHUNK_D + 0.5f; } sortingMesh.entries.push_back(std::move(entry)); vertexOffset = 0; indexOffset = indexSize = 0; } } + + // additional powerful optimization + auto size = aabb.size(); + if (glm::abs(size.y) < 0.01f && sortingMesh.entries.size() > 1 && false) { + SortingMeshEntry newEntry { + sortingMesh.entries[0].position, + util::Buffer(totalSize) + }; + size_t offset = 0; + for (const auto& entry : sortingMesh.entries) { + std::memcpy( + newEntry.vertexData.data() + offset, + entry.vertexData.data(), entry.vertexData.size() * sizeof(float) + ); + offset += entry.vertexData.size(); + } + return SortingMeshData {{std::move(newEntry)}}; + } return sortingMesh; } diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index ed313e08..9a508831 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -79,6 +79,10 @@ ChunksRenderer::ChunksRenderer( *level->content, cache, settings ); logger.info() << "created " << threadPool.getWorkersCount() << " workers"; + + const vattr attrs[]{ {3}, {2}, {1}, {0} }; + float buf[]{}; + sortedMesh = std::make_unique(buf, 0, attrs); } ChunksRenderer::~ChunksRenderer() { @@ -210,16 +214,19 @@ void ChunksRenderer::drawChunks( } void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { - const vattr attrs[]{ {3}, {2}, {1}, {0} }; + timeutil::ScopeLogTimer log(444); std::vector entries; + const auto& chunks = level.chunks->getChunks(); + auto pposition = camera.position; size_t size = 0; bool culling = settings.graphics.frustumCulling.get(); - for (size_t i = 0; i < indices.size(); i++) { - auto chunk = level.chunks->getChunks()[indices[i].index]; + + for (const auto& index : indices) { + const auto& chunk = chunks[index.index]; if (chunk == nullptr || !chunk->flags.lighted) { continue; } @@ -238,19 +245,22 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { if (!frustum.isBoxVisible(min, max)) continue; auto& chunkEntries = found->second.sortingMesh.entries; + for (auto& entry : chunkEntries) { - entry.distance = glm::distance2(entry.position, pposition); + entry.distance = static_cast(glm::distance2(entry.position, pposition)); } + std::sort(chunkEntries.begin(), chunkEntries.end()); for (const auto& entry : chunkEntries) { size += entry.vertexData.size(); entries.push_back(&entry); } } - std::sort(entries.begin(), entries.end(), [=](const auto& a, const auto& b) { - return *a < *b; - }); - util::Buffer buffer(size); + static util::Buffer buffer; + + if (buffer.size() < size) { + buffer = util::Buffer(size); + } size_t offset = 0; for (const auto& entry : entries) { std::memcpy( @@ -260,8 +270,8 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { ); offset += entry->vertexData.size(); } - Mesh mesh(buffer.data(), size / 6, attrs); + sortedMesh->reload(buffer.data(), size / 6); shader.uniformMatrix("u_model", glm::mat4(1.0f)); - mesh.draw(); + sortedMesh->draw(); } diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index cd1df2fb..a631ae8a 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -54,6 +54,7 @@ class ChunksRenderer { bool drawChunk( size_t index, const Camera& camera, Shader& shader, bool culling ); + std::unique_ptr sortedMesh; public: ChunksRenderer( const Level* level, diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index 3ef8fa26..c4c850e1 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -12,7 +12,7 @@ class Mesh; struct SortingMeshEntry { glm::vec3 position; util::Buffer vertexData; - float distance; + long long distance; inline bool operator<(const SortingMeshEntry& o) const noexcept { return distance > o.distance; From 171cbb48d099032d7e78c51a46c374104f96f0d1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 09:30:02 +0300 Subject: [PATCH 08/80] fix blocks selection with semi-transparent blocks --- src/graphics/render/ChunksRenderer.cpp | 5 ++++- src/graphics/render/WorldRenderer.cpp | 9 ++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 9a508831..39dbb08d 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -210,11 +210,14 @@ void ChunksRenderer::drawChunks( visibleChunks += drawChunk(indices[i].index, camera, shader, culling); } //} - drawSortedMeshes(camera, shader); } void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { timeutil::ScopeLogTimer log(444); + + const auto& atlas = assets.require("blocks"); + + atlas.getTexture()->bind(); std::vector entries; diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 1ad16a62..0593305d 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -164,10 +164,18 @@ void WorldRenderer::renderLevel( particles->render(camera, delta * !pause); auto& shader = assets.require("main"); + auto& linesShader = assets.require("lines"); + setupWorldShader(shader, camera, settings, fogFactor); chunks->drawChunks(camera, shader); + if (hudVisible) { + renderLines(camera, linesShader, ctx); + } + shader.use(); + chunks->drawSortedMeshes(camera, shader); + if (!pause) { scripting::on_frontend_render(); } @@ -326,7 +334,6 @@ void WorldRenderer::draw( ctx, camera, *lineBatch, linesShader, showChunkBorders ); } - renderLines(camera, linesShader, ctx); if (player->currentCamera == player->fpCamera) { renderHands(camera, delta * !pause); } From 2327f0ddf8b5cc0d668a274147a79a5fef63368d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 09:31:33 +0300 Subject: [PATCH 09/80] fix msvc error C2466: cannot allocate an array of constant size 0 --- src/graphics/render/ChunksRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 39dbb08d..1fddfd66 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -81,7 +81,7 @@ ChunksRenderer::ChunksRenderer( logger.info() << "created " << threadPool.getWorkersCount() << " workers"; const vattr attrs[]{ {3}, {2}, {1}, {0} }; - float buf[]{}; + float buf[1]{}; sortedMesh = std::make_unique(buf, 0, attrs); } From 99f159464511592f974b726be65a5eea30157497 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 15:08:25 +0300 Subject: [PATCH 10/80] fix Mesh --- src/graphics/core/Mesh.cpp | 8 ++++---- src/graphics/core/Mesh.hpp | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/graphics/core/Mesh.cpp b/src/graphics/core/Mesh.cpp index c8c114c2..e0cc5484 100644 --- a/src/graphics/core/Mesh.cpp +++ b/src/graphics/core/Mesh.cpp @@ -21,8 +21,8 @@ Mesh::Mesh(const MeshData& data) Mesh::Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const vattr* attrs) : ibo(0), - vertices(vertices), - indices(indices) + vertices(0), + indices(0) { meshesCount++; vertexSize = 0; @@ -74,7 +74,7 @@ void Mesh::reload(const float* vertexBuffer, size_t vertices, const int* indexBu this->indices = indices; } -void Mesh::draw(unsigned int primitive){ +void Mesh::draw(unsigned int primitive) const { drawCalls++; glBindVertexArray(vao); if (ibo != 0) { @@ -86,6 +86,6 @@ void Mesh::draw(unsigned int primitive){ glBindVertexArray(0); } -void Mesh::draw() { +void Mesh::draw() const { draw(GL_TRIANGLES); } diff --git a/src/graphics/core/Mesh.hpp b/src/graphics/core/Mesh.hpp index 87c8e69b..b36b044d 100644 --- a/src/graphics/core/Mesh.hpp +++ b/src/graphics/core/Mesh.hpp @@ -28,10 +28,10 @@ public: /// @brief Draw mesh with specified primitives type /// @param primitive primitives type - void draw(unsigned int primitive); + void draw(unsigned int primitive) const; /// @brief Draw mesh as triangles - void draw(); + void draw() const; /// @brief Total numbers of alive mesh objects static int meshesCount; From 1ff89491e6f85ed04193d62a7878ecf64242e049 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 15:11:05 +0300 Subject: [PATCH 11/80] optimize (part 2) --- src/graphics/render/BlocksRenderer.cpp | 2 +- src/graphics/render/ChunksRenderer.cpp | 69 ++++++++++++++------------ src/graphics/render/commons.hpp | 3 +- 3 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 6a8c8176..aa36ead6 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -590,7 +590,7 @@ SortingMeshData BlocksRenderer::renderTranslucent( // additional powerful optimization auto size = aabb.size(); - if (glm::abs(size.y) < 0.01f && sortingMesh.entries.size() > 1 && false) { + if (glm::abs(size.y) < 0.01f && sortingMesh.entries.size() > 1) { SortingMeshEntry newEntry { sortingMesh.entries[0].position, util::Buffer(totalSize) diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 1fddfd66..fc3b3eb6 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -49,6 +49,8 @@ public: } }; +const vattr ATTRS[]{ {3}, {2}, {1}, {0} }; + ChunksRenderer::ChunksRenderer( const Level* level, const Assets& assets, @@ -80,9 +82,8 @@ ChunksRenderer::ChunksRenderer( ); logger.info() << "created " << threadPool.getWorkersCount() << " workers"; - const vattr attrs[]{ {3}, {2}, {1}, {0} }; float buf[1]{}; - sortedMesh = std::make_unique(buf, 0, attrs); + sortedMesh = std::make_unique(buf, 0, ATTRS); } ChunksRenderer::~ChunksRenderer() { @@ -93,7 +94,7 @@ std::shared_ptr ChunksRenderer::render(const std::shared_ptr& chunk if (important) { auto mesh = renderer->render(chunk.get(), level.chunks.get()); meshes[glm::ivec2(chunk->x, chunk->z)] = ChunkMesh { - std::move(mesh.mesh), std::move(mesh.sortingMesh) + std::move(mesh.mesh), std::move(mesh.sortingMeshData) }; return meshes[glm::ivec2(chunk->x, chunk->z)].mesh; } @@ -214,19 +215,18 @@ void ChunksRenderer::drawChunks( void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { timeutil::ScopeLogTimer log(444); - + const auto& atlas = assets.require("blocks"); atlas.getTexture()->bind(); - std::vector entries; - const auto& chunks = level.chunks->getChunks(); auto pposition = camera.position; size_t size = 0; bool culling = settings.graphics.frustumCulling.get(); + shader.uniformMatrix("u_model", glm::mat4(1.0f)); for (const auto& index : indices) { const auto& chunk = chunks[index.index]; @@ -238,43 +238,50 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { continue; } - glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D); + glm::vec3 min( + chunk->x * CHUNK_W - CHUNK_W, 0, chunk->z * CHUNK_D - CHUNK_D + ); glm::vec3 max( - chunk->x * CHUNK_W + CHUNK_W, - chunk->top, - chunk->z * CHUNK_D + CHUNK_D + chunk->x * CHUNK_W + CHUNK_W*2, + CHUNK_H, + chunk->z * CHUNK_D + CHUNK_D*2 ); if (!frustum.isBoxVisible(min, max)) continue; - auto& chunkEntries = found->second.sortingMesh.entries; + auto& chunkEntries = found->second.sortingMeshData.entries; for (auto& entry : chunkEntries) { entry.distance = static_cast(glm::distance2(entry.position, pposition)); } + + if (chunkEntries.size() == 1) { + auto& entry = chunkEntries.at(0); + if (found->second.planesMesh == nullptr) { + found->second.planesMesh = std::make_shared( + entry.vertexData.data(), entry.vertexData.size() / 6, ATTRS + ); + } + found->second.planesMesh->draw(); + continue; + } + std::sort(chunkEntries.begin(), chunkEntries.end()); + size_t size = 0; for (const auto& entry : chunkEntries) { size += entry.vertexData.size(); - entries.push_back(&entry); } + util::Buffer buffer(size); + size_t offset = 0; + for (const auto& entry : chunkEntries) { + std::memcpy( + (buffer.data() + offset), + entry.vertexData.data(), + entry.vertexData.size() * sizeof(float) + ); + offset += entry.vertexData.size(); + } + sortedMesh->reload(buffer.data(), size / 6); + sortedMesh->draw(); } - - static util::Buffer buffer; - - if (buffer.size() < size) { - buffer = util::Buffer(size); - } - size_t offset = 0; - for (const auto& entry : entries) { - std::memcpy( - (buffer.data() + offset), - entry->vertexData.data(), - entry->vertexData.size() * sizeof(float) - ); - offset += entry->vertexData.size(); - } - sortedMesh->reload(buffer.data(), size / 6); - - shader.uniformMatrix("u_model", glm::mat4(1.0f)); - sortedMesh->draw(); } diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index c4c850e1..fe633012 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -30,5 +30,6 @@ struct ChunkMeshData { struct ChunkMesh { std::shared_ptr mesh; - SortingMeshData sortingMesh; + SortingMeshData sortingMeshData; + std::shared_ptr planesMesh = nullptr; }; From 7bdeba982b29fc166873e1c1202ad80116806fbc Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 15:24:46 +0300 Subject: [PATCH 12/80] optimize (part 3) --- src/graphics/render/ChunksRenderer.cpp | 45 ++++++++++++++++---------- src/graphics/render/commons.hpp | 2 +- 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index fc3b3eb6..02929c25 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -257,31 +257,42 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { if (chunkEntries.size() == 1) { auto& entry = chunkEntries.at(0); - if (found->second.planesMesh == nullptr) { - found->second.planesMesh = std::make_shared( + if (found->second.sortedMesh == nullptr) { + found->second.sortedMesh = std::make_shared( entry.vertexData.data(), entry.vertexData.size() / 6, ATTRS ); } - found->second.planesMesh->draw(); + found->second.sortedMesh->draw(); continue; } - std::sort(chunkEntries.begin(), chunkEntries.end()); - size_t size = 0; - for (const auto& entry : chunkEntries) { - size += entry.vertexData.size(); + if (chunkEntries.empty()) { + continue; } - util::Buffer buffer(size); - size_t offset = 0; - for (const auto& entry : chunkEntries) { - std::memcpy( - (buffer.data() + offset), - entry.vertexData.data(), - entry.vertexData.size() * sizeof(float) + + if (found->second.sortedMesh == nullptr) { + std::sort(chunkEntries.begin(), chunkEntries.end()); + size_t size = 0; + for (const auto& entry : chunkEntries) { + size += entry.vertexData.size(); + } + static util::Buffer buffer; + if (buffer.size() < size) { + buffer = util::Buffer(size); + } + size_t offset = 0; + for (const auto& entry : chunkEntries) { + std::memcpy( + (buffer.data() + offset), + entry.vertexData.data(), + entry.vertexData.size() * sizeof(float) + ); + offset += entry.vertexData.size(); + } + found->second.sortedMesh = std::make_shared( + buffer.data(), size / 6, ATTRS ); - offset += entry.vertexData.size(); } - sortedMesh->reload(buffer.data(), size / 6); - sortedMesh->draw(); + found->second.sortedMesh->draw(); } } diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index fe633012..1bff70f5 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -31,5 +31,5 @@ struct ChunkMeshData { struct ChunkMesh { std::shared_ptr mesh; SortingMeshData sortingMeshData; - std::shared_ptr planesMesh = nullptr; + std::shared_ptr sortedMesh = nullptr; }; From 399943b253e5ae70a20c347d98c30e6d2acc24e9 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 15:37:30 +0300 Subject: [PATCH 13/80] fix --- src/graphics/render/ChunksRenderer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 02929c25..ba340548 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -270,7 +270,7 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { continue; } - if (found->second.sortedMesh == nullptr) { + if (found->second.sortedMesh == nullptr || true) { std::sort(chunkEntries.begin(), chunkEntries.end()); size_t size = 0; for (const auto& entry : chunkEntries) { From ebc890bdd62a3ca1a66c66e79a303fc64ae6424a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 15:49:53 +0300 Subject: [PATCH 14/80] optimize (part 4) & format ChunkRenderer --- src/graphics/render/ChunksRenderer.cpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index ba340548..2c1534b2 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -50,6 +50,7 @@ public: }; const vattr ATTRS[]{ {3}, {2}, {1}, {0} }; +inline constexpr int VERTEX_SIZE = 6; ChunksRenderer::ChunksRenderer( const Level* level, @@ -89,7 +90,9 @@ ChunksRenderer::ChunksRenderer( ChunksRenderer::~ChunksRenderer() { } -std::shared_ptr ChunksRenderer::render(const std::shared_ptr& chunk, bool important) { +std::shared_ptr ChunksRenderer::render( + const std::shared_ptr& chunk, bool important +) { chunk->flags.modified = false; if (important) { auto mesh = renderer->render(chunk.get(), level.chunks.get()); @@ -120,7 +123,9 @@ void ChunksRenderer::clear() { threadPool.clearQueue(); } -std::shared_ptr ChunksRenderer::getOrRender(const std::shared_ptr& chunk, bool important) { +std::shared_ptr ChunksRenderer::getOrRender( + const std::shared_ptr& chunk, bool important +) { auto found = meshes.find(glm::ivec2(chunk->x, chunk->z)); if (found == meshes.end()) { return render(chunk, important); @@ -216,6 +221,10 @@ void ChunksRenderer::drawChunks( void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { timeutil::ScopeLogTimer log(444); + const int sortInterval = 6; + static int frameid = 0; + frameid++; + const auto& atlas = assets.require("blocks"); atlas.getTexture()->bind(); @@ -252,14 +261,17 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { auto& chunkEntries = found->second.sortingMeshData.entries; for (auto& entry : chunkEntries) { - entry.distance = static_cast(glm::distance2(entry.position, pposition)); + entry.distance = + static_cast(glm::distance2(entry.position, pposition)); } if (chunkEntries.size() == 1) { auto& entry = chunkEntries.at(0); if (found->second.sortedMesh == nullptr) { found->second.sortedMesh = std::make_shared( - entry.vertexData.data(), entry.vertexData.size() / 6, ATTRS + entry.vertexData.data(), + entry.vertexData.size() / VERTEX_SIZE, + ATTRS ); } found->second.sortedMesh->draw(); @@ -270,7 +282,8 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { continue; } - if (found->second.sortedMesh == nullptr || true) { + if (found->second.sortedMesh == nullptr || + (frameid + chunk->x) % sortInterval == 0) { std::sort(chunkEntries.begin(), chunkEntries.end()); size_t size = 0; for (const auto& entry : chunkEntries) { @@ -290,7 +303,7 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { offset += entry.vertexData.size(); } found->second.sortedMesh = std::make_shared( - buffer.data(), size / 6, ATTRS + buffer.data(), size / VERTEX_SIZE, ATTRS ); } found->second.sortedMesh->draw(); From 71788e4eb9d35db01a30bb21c1532dd3be63cffc Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 16:04:00 +0300 Subject: [PATCH 15/80] remove unnecessary shared_ptrs from ChunksRenderer and ChunkMesh --- src/graphics/render/BlocksRenderer.cpp | 2 +- src/graphics/render/ChunksRenderer.cpp | 40 +++++++++++--------------- src/graphics/render/ChunksRenderer.hpp | 4 +-- src/graphics/render/commons.hpp | 4 +-- 4 files changed, 21 insertions(+), 29 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index aa36ead6..04622e46 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -666,7 +666,7 @@ ChunkMesh BlocksRenderer::render(const Chunk* chunk, const Chunks* chunks) { const vattr attrs[]{ {3}, {2}, {1}, {0} }; size_t vcount = vertexOffset / BlocksRenderer::VERTEX_SIZE; - return ChunkMesh{std::make_shared( + return ChunkMesh{std::make_unique( vertexBuffer.get(), vcount, indexBuffer.get(), indexSize, attrs ), std::move(sortingMesh)}; } diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 2c1534b2..7ef3ea68 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -69,7 +69,7 @@ ChunksRenderer::ChunksRenderer( if (!result.cancelled) { auto meshData = std::move(result.meshData); meshes[result.key] = ChunkMesh { - std::make_shared(meshData.mesh), + std::make_unique(meshData.mesh), std::move(meshData.sortingMesh) }; } @@ -90,7 +90,7 @@ ChunksRenderer::ChunksRenderer( ChunksRenderer::~ChunksRenderer() { } -std::shared_ptr ChunksRenderer::render( +const Mesh* ChunksRenderer::render( const std::shared_ptr& chunk, bool important ) { chunk->flags.modified = false; @@ -99,7 +99,7 @@ std::shared_ptr ChunksRenderer::render( meshes[glm::ivec2(chunk->x, chunk->z)] = ChunkMesh { std::move(mesh.mesh), std::move(mesh.sortingMeshData) }; - return meshes[glm::ivec2(chunk->x, chunk->z)].mesh; + return meshes[glm::ivec2(chunk->x, chunk->z)].mesh.get(); } glm::ivec2 key(chunk->x, chunk->z); if (inwork.find(key) != inwork.end()) { @@ -123,7 +123,7 @@ void ChunksRenderer::clear() { threadPool.clearQueue(); } -std::shared_ptr ChunksRenderer::getOrRender( +const Mesh* ChunksRenderer::getOrRender( const std::shared_ptr& chunk, bool important ) { auto found = meshes.find(glm::ivec2(chunk->x, chunk->z)); @@ -133,7 +133,7 @@ std::shared_ptr ChunksRenderer::getOrRender( if (chunk->flags.modified) { render(chunk, important); } - return found->second.mesh; + return found->second.mesh.get(); } void ChunksRenderer::update() { @@ -225,16 +225,12 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { static int frameid = 0; frameid++; + bool culling = settings.graphics.frustumCulling.get(); + const auto& chunks = level.chunks->getChunks(); + const auto& cameraPos = camera.position; const auto& atlas = assets.require("blocks"); atlas.getTexture()->bind(); - - const auto& chunks = level.chunks->getChunks(); - - auto pposition = camera.position; - - size_t size = 0; - bool culling = settings.graphics.frustumCulling.get(); shader.uniformMatrix("u_model", glm::mat4(1.0f)); for (const auto& index : indices) { @@ -259,16 +255,13 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { if (!frustum.isBoxVisible(min, max)) continue; auto& chunkEntries = found->second.sortingMeshData.entries; - - for (auto& entry : chunkEntries) { - entry.distance = - static_cast(glm::distance2(entry.position, pposition)); - } - if (chunkEntries.size() == 1) { + if (chunkEntries.empty()) { + continue; + } else if (chunkEntries.size() == 1) { auto& entry = chunkEntries.at(0); if (found->second.sortedMesh == nullptr) { - found->second.sortedMesh = std::make_shared( + found->second.sortedMesh = std::make_unique( entry.vertexData.data(), entry.vertexData.size() / VERTEX_SIZE, ATTRS @@ -277,11 +270,10 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { found->second.sortedMesh->draw(); continue; } - - if (chunkEntries.empty()) { - continue; + for (auto& entry : chunkEntries) { + entry.distance = + static_cast(glm::distance2(entry.position, cameraPos)); } - if (found->second.sortedMesh == nullptr || (frameid + chunk->x) % sortInterval == 0) { std::sort(chunkEntries.begin(), chunkEntries.end()); @@ -302,7 +294,7 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { ); offset += entry.vertexData.size(); } - found->second.sortedMesh = std::make_shared( + found->second.sortedMesh = std::make_unique( buffer.data(), size / VERTEX_SIZE, ATTRS ); } diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index a631ae8a..55e3b90e 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -65,13 +65,13 @@ public: ); virtual ~ChunksRenderer(); - std::shared_ptr render( + const Mesh* render( const std::shared_ptr& chunk, bool important ); void unload(const Chunk* chunk); void clear(); - std::shared_ptr getOrRender( + const Mesh* getOrRender( const std::shared_ptr& chunk, bool important ); void drawChunks(const Camera& camera, Shader& shader); diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index 1bff70f5..5cd92631 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -29,7 +29,7 @@ struct ChunkMeshData { }; struct ChunkMesh { - std::shared_ptr mesh; + std::unique_ptr mesh; SortingMeshData sortingMeshData; - std::shared_ptr sortedMesh = nullptr; + std::unique_ptr sortedMesh = nullptr; }; From 608eb60514aa4345c8581cd124bb591c10fe9274 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 16 Nov 2024 16:13:18 +0300 Subject: [PATCH 16/80] add 'u_alphaClip' to the blocks shader --- res/shaders/main.glslf | 4 ++-- src/graphics/render/ChunksRenderer.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/res/shaders/main.glslf b/res/shaders/main.glslf index 4c1cb014..7db1a544 100644 --- a/res/shaders/main.glslf +++ b/res/shaders/main.glslf @@ -9,14 +9,14 @@ uniform samplerCube u_cubemap; uniform vec3 u_fogColor; uniform float u_fogFactor; uniform float u_fogCurve; +uniform bool u_alphaClip; void main() { vec3 fogColor = texture(u_cubemap, a_dir).rgb; vec4 tex_color = texture(u_texture0, a_texCoord); float depth = (a_distance/256.0); float alpha = a_color.a * tex_color.a; - // anyway it's any alpha-test alternative required - if (alpha < 0.3f) + if (u_alphaClip && alpha < 0.9f) discard; f_color = mix(a_color * tex_color, vec4(fogColor,1.0), min(1.0, pow(depth*u_fogFactor, u_fogCurve))); diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 7ef3ea68..e52cd3eb 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -209,6 +209,7 @@ void ChunksRenderer::drawChunks( bool culling = settings.graphics.frustumCulling.get(); visibleChunks = 0; + shader.uniform1i("u_alphaClip", true); //if (GLEW_ARB_multi_draw_indirect && false) { // TODO: implement Multi Draw Indirect chunks draw //} else { @@ -232,6 +233,7 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { atlas.getTexture()->bind(); shader.uniformMatrix("u_model", glm::mat4(1.0f)); + shader.uniform1i("u_alphaClip", false); for (const auto& index : indices) { const auto& chunk = chunks[index.index]; From 65287b327326709f0d48edbff2b244aefd68ab04 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 00:54:10 +0300 Subject: [PATCH 17/80] move chunk vertex attributes info to commons.hpp --- src/graphics/render/BlocksRenderer.cpp | 45 +++++++++++++------------- src/graphics/render/BlocksRenderer.hpp | 1 - src/graphics/render/ChunksRenderer.cpp | 11 +++---- src/graphics/render/commons.hpp | 5 +++ 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 04622e46..8b041b58 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -14,7 +14,6 @@ #include "util/timeutil.hpp" -const uint BlocksRenderer::VERTEX_SIZE = 6; const glm::vec3 BlocksRenderer::SUN_VECTOR (0.411934f, 0.863868f, -0.279161f); BlocksRenderer::BlocksRenderer( @@ -23,7 +22,7 @@ BlocksRenderer::BlocksRenderer( const ContentGfxCache& cache, const EngineSettings& settings ) : content(content), - vertexBuffer(std::make_unique(capacity * VERTEX_SIZE)), + vertexBuffer(std::make_unique(capacity * CHUNK_VERTEX_SIZE)), indexBuffer(std::make_unique(capacity)), vertexOffset(0), indexOffset(0), @@ -87,7 +86,7 @@ void BlocksRenderer::face( const glm::vec4(&lights)[4], const glm::vec4& tint ) { - if (vertexOffset + BlocksRenderer::VERTEX_SIZE * 4 > capacity) { + if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) { overflow = true; return; } @@ -127,7 +126,7 @@ void BlocksRenderer::faceAO( const UVRegion& region, bool lights ) { - if (vertexOffset + BlocksRenderer::VERTEX_SIZE * 4 > capacity) { + if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) { overflow = true; return; } @@ -165,7 +164,7 @@ void BlocksRenderer::face( glm::vec4 tint, bool lights ) { - if (vertexOffset + BlocksRenderer::VERTEX_SIZE * 4 > capacity) { + if (vertexOffset + CHUNK_VERTEX_SIZE * 4 > capacity) { overflow = true; return; } @@ -290,7 +289,7 @@ void BlocksRenderer::blockCustomModel( const auto& model = cache.getModel(block->rt.id); for (const auto& mesh : model.meshes) { - if (vertexOffset + BlocksRenderer::VERTEX_SIZE * mesh.vertices.size() > capacity) { + if (vertexOffset + CHUNK_VERTEX_SIZE * mesh.vertices.size() > capacity) { overflow = true; return; } @@ -558,19 +557,19 @@ SortingMeshData BlocksRenderer::renderTranslucent( y + 0.5f, z + chunk->z * CHUNK_D + 0.5f ), - util::Buffer(indexSize * VERTEX_SIZE)}; + util::Buffer(indexSize * CHUNK_VERTEX_SIZE)}; totalSize += entry.vertexData.size(); for (int j = 0; j < indexSize; j++) { std::memcpy( - entry.vertexData.data() + j * VERTEX_SIZE, - vertexBuffer.get() + indexBuffer[j] * VERTEX_SIZE, - sizeof(float) * VERTEX_SIZE + entry.vertexData.data() + j * CHUNK_VERTEX_SIZE, + vertexBuffer.get() + indexBuffer[j] * CHUNK_VERTEX_SIZE, + sizeof(float) * CHUNK_VERTEX_SIZE ); - float& vx = entry.vertexData[j * VERTEX_SIZE + 0]; - float& vy = entry.vertexData[j * VERTEX_SIZE + 1]; - float& vz = entry.vertexData[j * VERTEX_SIZE + 2]; + float& vx = entry.vertexData[j * CHUNK_VERTEX_SIZE + 0]; + float& vy = entry.vertexData[j * CHUNK_VERTEX_SIZE + 1]; + float& vz = entry.vertexData[j * CHUNK_VERTEX_SIZE + 2]; if (!aabbInit) { aabbInit = true; @@ -653,21 +652,23 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {; } ChunkMeshData BlocksRenderer::createMesh() { - const vattr attrs[]{ {3}, {2}, {1}, {0} }; - return ChunkMeshData{MeshData( - util::Buffer(vertexBuffer.get(), vertexOffset), - util::Buffer(indexBuffer.get(), indexSize), - util::Buffer({{3}, {2}, {1}, {0}}) - ), std::move(sortingMesh)}; + return ChunkMeshData { + MeshData( + util::Buffer(vertexBuffer.get(), vertexOffset), + util::Buffer(indexBuffer.get(), indexSize), + util::Buffer( + CHUNK_VATTRS, sizeof(CHUNK_VATTRS) / sizeof(vattr) + ) + ), + std::move(sortingMesh)}; } ChunkMesh BlocksRenderer::render(const Chunk* chunk, const Chunks* chunks) { build(chunk, chunks); - const vattr attrs[]{ {3}, {2}, {1}, {0} }; - size_t vcount = vertexOffset / BlocksRenderer::VERTEX_SIZE; + size_t vcount = vertexOffset / CHUNK_VERTEX_SIZE; return ChunkMesh{std::make_unique( - vertexBuffer.get(), vcount, indexBuffer.get(), indexSize, attrs + vertexBuffer.get(), vcount, indexBuffer.get(), indexSize, CHUNK_VATTRS ), std::move(sortingMesh)}; } diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index cdb20749..c0e0086e 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -27,7 +27,6 @@ struct UVRegion; class BlocksRenderer { static const glm::vec3 SUN_VECTOR; - static const uint VERTEX_SIZE; const Content& content; std::unique_ptr vertexBuffer; std::unique_ptr indexBuffer; diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index e52cd3eb..7176500b 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -49,9 +49,6 @@ public: } }; -const vattr ATTRS[]{ {3}, {2}, {1}, {0} }; -inline constexpr int VERTEX_SIZE = 6; - ChunksRenderer::ChunksRenderer( const Level* level, const Assets& assets, @@ -84,7 +81,7 @@ ChunksRenderer::ChunksRenderer( logger.info() << "created " << threadPool.getWorkersCount() << " workers"; float buf[1]{}; - sortedMesh = std::make_unique(buf, 0, ATTRS); + sortedMesh = std::make_unique(buf, 0, CHUNK_VATTRS); } ChunksRenderer::~ChunksRenderer() { @@ -265,8 +262,8 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { if (found->second.sortedMesh == nullptr) { found->second.sortedMesh = std::make_unique( entry.vertexData.data(), - entry.vertexData.size() / VERTEX_SIZE, - ATTRS + entry.vertexData.size() / CHUNK_VERTEX_SIZE, + CHUNK_VATTRS ); } found->second.sortedMesh->draw(); @@ -297,7 +294,7 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { offset += entry.vertexData.size(); } found->second.sortedMesh = std::make_unique( - buffer.data(), size / VERTEX_SIZE, ATTRS + buffer.data(), size / CHUNK_VERTEX_SIZE, CHUNK_VATTRS ); } found->second.sortedMesh->draw(); diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index 5cd92631..b6d18003 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -7,6 +7,11 @@ #include "graphics/core/MeshData.hpp" #include "util/Buffer.hpp" +/// @brief Chunk mesh vertex attributes +inline const vattr CHUNK_VATTRS[]{ {3}, {2}, {1}, {0} }; +/// @brief Chunk mesh vertex size divided by sizeof(float) +inline constexpr int CHUNK_VERTEX_SIZE = 6; + class Mesh; struct SortingMeshEntry { From 5240fe62263242fe5b0a154f9708a702848a6274 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 01:00:27 +0300 Subject: [PATCH 18/80] rename vattr to VertexAttribute --- src/graphics/core/Batch2D.cpp | 2 +- src/graphics/core/Batch3D.cpp | 2 +- src/graphics/core/LineBatch.cpp | 2 +- src/graphics/core/Mesh.cpp | 4 ++-- src/graphics/core/Mesh.hpp | 4 ++-- src/graphics/core/MeshData.hpp | 6 +++--- src/graphics/core/PostProcessing.cpp | 2 +- src/graphics/render/BlocksRenderer.cpp | 4 ++-- src/graphics/render/MainBatch.cpp | 2 +- src/graphics/render/Skybox.cpp | 2 +- src/graphics/render/commons.hpp | 2 +- 11 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/graphics/core/Batch2D.cpp b/src/graphics/core/Batch2D.cpp index 13b48586..c4c67db2 100644 --- a/src/graphics/core/Batch2D.cpp +++ b/src/graphics/core/Batch2D.cpp @@ -11,7 +11,7 @@ inline constexpr uint B2D_VERTEX_SIZE = 8; Batch2D::Batch2D(size_t capacity) : capacity(capacity), color(1.0f){ - const vattr attrs[] = { + const VertexAttribute attrs[] = { {2}, {2}, {4}, {0} }; diff --git a/src/graphics/core/Batch3D.cpp b/src/graphics/core/Batch3D.cpp index 1770fc21..a81f4ffb 100644 --- a/src/graphics/core/Batch3D.cpp +++ b/src/graphics/core/Batch3D.cpp @@ -12,7 +12,7 @@ inline constexpr uint B3D_VERTEX_SIZE = 9; Batch3D::Batch3D(size_t capacity) : capacity(capacity) { - const vattr attrs[] = { + const VertexAttribute attrs[] = { {3}, {2}, {4}, {0} }; diff --git a/src/graphics/core/LineBatch.cpp b/src/graphics/core/LineBatch.cpp index dd3f8067..aed8a249 100644 --- a/src/graphics/core/LineBatch.cpp +++ b/src/graphics/core/LineBatch.cpp @@ -6,7 +6,7 @@ inline constexpr uint LB_VERTEX_SIZE = (3+4); LineBatch::LineBatch(size_t capacity) : capacity(capacity) { - const vattr attrs[] = { {3},{4}, {0} }; + const VertexAttribute attrs[] = { {3},{4}, {0} }; buffer = std::make_unique(capacity * LB_VERTEX_SIZE * 2); mesh = std::make_unique(buffer.get(), 0, attrs); index = 0; diff --git a/src/graphics/core/Mesh.cpp b/src/graphics/core/Mesh.cpp index e0cc5484..e8cffe6f 100644 --- a/src/graphics/core/Mesh.cpp +++ b/src/graphics/core/Mesh.cpp @@ -4,7 +4,7 @@ int Mesh::meshesCount = 0; int Mesh::drawCalls = 0; -inline size_t calc_vertex_size(const vattr* attrs) { +inline size_t calc_vertex_size(const VertexAttribute* attrs) { size_t vertexSize = 0; for (int i = 0; attrs[i].size; i++) { vertexSize += attrs[i].size; @@ -19,7 +19,7 @@ Mesh::Mesh(const MeshData& data) data.indices.size(), data.attrs.data()) {} -Mesh::Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const vattr* attrs) : +Mesh::Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const VertexAttribute* attrs) : ibo(0), vertices(0), indices(0) diff --git a/src/graphics/core/Mesh.hpp b/src/graphics/core/Mesh.hpp index b36b044d..482c82bf 100644 --- a/src/graphics/core/Mesh.hpp +++ b/src/graphics/core/Mesh.hpp @@ -14,8 +14,8 @@ class Mesh { size_t vertexSize; public: Mesh(const MeshData& data); - Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const vattr* attrs); - Mesh(const float* vertexBuffer, size_t vertices, const vattr* attrs) : + Mesh(const float* vertexBuffer, size_t vertices, const int* indexBuffer, size_t indices, const VertexAttribute* attrs); + Mesh(const float* vertexBuffer, size_t vertices, const VertexAttribute* attrs) : Mesh(vertexBuffer, vertices, nullptr, 0, attrs) {}; ~Mesh(); diff --git a/src/graphics/core/MeshData.hpp b/src/graphics/core/MeshData.hpp index 62b32903..39220119 100644 --- a/src/graphics/core/MeshData.hpp +++ b/src/graphics/core/MeshData.hpp @@ -6,7 +6,7 @@ #include "util/Buffer.hpp" /// @brief Vertex attribute info -struct vattr { +struct VertexAttribute { ubyte size; }; @@ -14,7 +14,7 @@ struct vattr { struct MeshData { util::Buffer vertices; util::Buffer indices; - util::Buffer attrs; + util::Buffer attrs; MeshData() = default; @@ -24,7 +24,7 @@ struct MeshData { MeshData( util::Buffer vertices, util::Buffer indices, - util::Buffer attrs + util::Buffer attrs ) : vertices(std::move(vertices)), indices(std::move(indices)), attrs(std::move(attrs)) {} diff --git a/src/graphics/core/PostProcessing.cpp b/src/graphics/core/PostProcessing.cpp index 7352c3b5..3478ca08 100644 --- a/src/graphics/core/PostProcessing.cpp +++ b/src/graphics/core/PostProcessing.cpp @@ -14,7 +14,7 @@ PostProcessing::PostProcessing() { -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f }; - vattr attrs[] {{2}, {0}}; + VertexAttribute attrs[] {{2}, {0}}; quadMesh = std::make_unique(vertices, 6, attrs); } diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 8b041b58..5570de4c 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -656,8 +656,8 @@ ChunkMeshData BlocksRenderer::createMesh() { MeshData( util::Buffer(vertexBuffer.get(), vertexOffset), util::Buffer(indexBuffer.get(), indexSize), - util::Buffer( - CHUNK_VATTRS, sizeof(CHUNK_VATTRS) / sizeof(vattr) + util::Buffer( + CHUNK_VATTRS, sizeof(CHUNK_VATTRS) / sizeof(VertexAttribute) ) ), std::move(sortingMesh)}; diff --git a/src/graphics/render/MainBatch.cpp b/src/graphics/render/MainBatch.cpp index 1cbb6c42..e3a87db7 100644 --- a/src/graphics/render/MainBatch.cpp +++ b/src/graphics/render/MainBatch.cpp @@ -6,7 +6,7 @@ #include "voxels/Chunks.hpp" #include "voxels/Chunk.hpp" -static const vattr attrs[] = { +static const VertexAttribute attrs[] = { {3}, {2}, {3}, {1}, {0} }; diff --git a/src/graphics/render/Skybox.cpp b/src/graphics/render/Skybox.cpp index e96e894a..af3a1587 100644 --- a/src/graphics/render/Skybox.cpp +++ b/src/graphics/render/Skybox.cpp @@ -39,7 +39,7 @@ Skybox::Skybox(uint size, Shader& shader) -1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f }; - vattr attrs[] {{2}, {0}}; + VertexAttribute attrs[] {{2}, {0}}; mesh = std::make_unique(vertices, 6, attrs); sprites.push_back(skysprite { diff --git a/src/graphics/render/commons.hpp b/src/graphics/render/commons.hpp index b6d18003..79b77393 100644 --- a/src/graphics/render/commons.hpp +++ b/src/graphics/render/commons.hpp @@ -8,7 +8,7 @@ #include "util/Buffer.hpp" /// @brief Chunk mesh vertex attributes -inline const vattr CHUNK_VATTRS[]{ {3}, {2}, {1}, {0} }; +inline const VertexAttribute CHUNK_VATTRS[]{ {3}, {2}, {1}, {0} }; /// @brief Chunk mesh vertex size divided by sizeof(float) inline constexpr int CHUNK_VERTEX_SIZE = 6; From bd4a5ef7fc2d753177d9391ea501d55588af1975 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 03:19:55 +0300 Subject: [PATCH 19/80] optimize a bit --- src/graphics/render/BlocksRenderer.cpp | 4 +- src/graphics/render/ChunksRenderer.cpp | 89 +++++++++++++------------- src/graphics/render/ChunksRenderer.hpp | 4 +- 3 files changed, 46 insertions(+), 51 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 5570de4c..2202931b 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -12,8 +12,6 @@ #include -#include "util/timeutil.hpp" - const glm::vec3 BlocksRenderer::SUN_VECTOR (0.411934f, 0.863868f, -0.279161f); BlocksRenderer::BlocksRenderer( @@ -607,7 +605,7 @@ SortingMeshData BlocksRenderer::renderTranslucent( return sortingMesh; } -void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {; +void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { this->chunk = chunk; voxelsBuffer->setPosition( chunk->x * CHUNK_W - voxelBufferPadding, 0, diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index 7176500b..edbf83f3 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -14,12 +14,9 @@ #include "util/listutil.hpp" #include "settings.hpp" -#include #include #include -#include "util/timeutil.hpp" - static debug::Logger logger("chunks-render"); size_t ChunksRenderer::visibleChunks = 0; @@ -79,9 +76,6 @@ ChunksRenderer::ChunksRenderer( *level->content, cache, settings ); logger.info() << "created " << threadPool.getWorkersCount() << " workers"; - - float buf[1]{}; - sortedMesh = std::make_unique(buf, 0, CHUNK_VATTRS); } ChunksRenderer::~ChunksRenderer() { @@ -137,12 +131,12 @@ void ChunksRenderer::update() { threadPool.update(); } -bool ChunksRenderer::drawChunk( +const Mesh* ChunksRenderer::retrieveChunk( size_t index, const Camera& camera, Shader& shader, bool culling ) { auto chunk = level.chunks->getChunks()[index]; if (chunk == nullptr || !chunk->flags.lighted) { - return false; + return nullptr; } float distance = glm::distance( camera.position, @@ -154,7 +148,7 @@ bool ChunksRenderer::drawChunk( ); auto mesh = getOrRender(chunk, distance < CHUNK_W * 1.5f); if (mesh == nullptr) { - return false; + return nullptr; } if (culling) { glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D); @@ -164,13 +158,9 @@ bool ChunksRenderer::drawChunk( chunk->z * CHUNK_D + CHUNK_D ); - if (!frustum.isBoxVisible(min, max)) return false; + if (!frustum.isBoxVisible(min, max)) return nullptr; } - glm::vec3 coord(chunk->x * CHUNK_W + 0.5f, 0.5f, chunk->z * CHUNK_D + 0.5f); - glm::mat4 model = glm::translate(glm::mat4(1.0f), coord); - shader.uniformMatrix("u_model", model); - mesh->draw(); - return true; + return mesh; } void ChunksRenderer::drawChunks( @@ -207,19 +197,38 @@ void ChunksRenderer::drawChunks( visibleChunks = 0; shader.uniform1i("u_alphaClip", true); - //if (GLEW_ARB_multi_draw_indirect && false) { - // TODO: implement Multi Draw Indirect chunks draw - //} else { - for (size_t i = 0; i < indices.size(); i++) { - visibleChunks += drawChunk(indices[i].index, camera, shader, culling); + + // TODO: minimize draw calls number + for (size_t i = 0; i < indices.size(); i++) { + auto chunk = chunks.getChunks()[indices[i].index]; + auto mesh = retrieveChunk(indices[i].index, camera, shader, culling); + + if (mesh) { + glm::vec3 coord(chunk->x * CHUNK_W + 0.5f, 0.5f, chunk->z * CHUNK_D + 0.5f); + glm::mat4 model = glm::translate(glm::mat4(1.0f), coord); + shader.uniformMatrix("u_model", model); + mesh->draw(); + visibleChunks++; } - //} + } +} + +static inline void write_sorting_mesh_entries( + float* buffer, const std::vector& chunkEntries +) { + for (const auto& entry : chunkEntries) { + const auto& vertexData = entry.vertexData; + std::memcpy( + buffer, + vertexData.data(), + vertexData.size() * sizeof(float) + ); + buffer += vertexData.size(); + } } void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { - timeutil::ScopeLogTimer log(444); - - const int sortInterval = 6; + const int sortInterval = 8; static int frameid = 0; frameid++; @@ -238,26 +247,22 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { continue; } const auto& found = meshes.find(glm::ivec2(chunk->x, chunk->z)); - if (found == meshes.end()) { + if (found == meshes.end() || found->second.sortingMeshData.entries.empty()) { continue; } - glm::vec3 min( - chunk->x * CHUNK_W - CHUNK_W, 0, chunk->z * CHUNK_D - CHUNK_D - ); + glm::vec3 min(chunk->x * CHUNK_W, chunk->bottom, chunk->z * CHUNK_D); glm::vec3 max( - chunk->x * CHUNK_W + CHUNK_W*2, - CHUNK_H, - chunk->z * CHUNK_D + CHUNK_D*2 + chunk->x * CHUNK_W + CHUNK_W, + chunk->top, + chunk->z * CHUNK_D + CHUNK_D ); if (!frustum.isBoxVisible(min, max)) continue; auto& chunkEntries = found->second.sortingMeshData.entries; - if (chunkEntries.empty()) { - continue; - } else if (chunkEntries.size() == 1) { + if (chunkEntries.size() == 1) { auto& entry = chunkEntries.at(0); if (found->second.sortedMesh == nullptr) { found->second.sortedMesh = std::make_unique( @@ -270,8 +275,9 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { continue; } for (auto& entry : chunkEntries) { - entry.distance = - static_cast(glm::distance2(entry.position, cameraPos)); + entry.distance = static_cast( + glm::distance2(entry.position, cameraPos) + ); } if (found->second.sortedMesh == nullptr || (frameid + chunk->x) % sortInterval == 0) { @@ -280,19 +286,12 @@ void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { for (const auto& entry : chunkEntries) { size += entry.vertexData.size(); } + static util::Buffer buffer; if (buffer.size() < size) { buffer = util::Buffer(size); } - size_t offset = 0; - for (const auto& entry : chunkEntries) { - std::memcpy( - (buffer.data() + offset), - entry.vertexData.data(), - entry.vertexData.size() * sizeof(float) - ); - offset += entry.vertexData.size(); - } + write_sorting_mesh_entries(buffer.data(), chunkEntries); found->second.sortedMesh = std::make_unique( buffer.data(), size / CHUNK_VERTEX_SIZE, CHUNK_VATTRS ); diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index 55e3b90e..5317c544 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -50,11 +50,9 @@ class ChunksRenderer { std::unordered_map inwork; std::vector indices; util::ThreadPool, RendererResult> threadPool; - - bool drawChunk( + const Mesh* retrieveChunk( size_t index, const Camera& camera, Shader& shader, bool culling ); - std::unique_ptr sortedMesh; public: ChunksRenderer( const Level* level, From 3c94061fd33bbaa50ee9d5ef3c2777c4ae7f3bff Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 04:01:02 +0300 Subject: [PATCH 20/80] update ice texture --- res/content/base/textures/blocks/ice.png | Bin 7220 -> 7429 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/res/content/base/textures/blocks/ice.png b/res/content/base/textures/blocks/ice.png index 36592775c01375a6799eb81ee7ff0a40bc01bc03..707ee89ae82e4f4c612a9cd504c28fd073aea062 100644 GIT binary patch delta 2554 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 From 5f71522653d3bbcf7ffcf638ad5c16bfc8280cd8 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 04:31:07 +0300 Subject: [PATCH 21/80] extend that one optimization --- src/graphics/render/BlocksRenderer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index 2202931b..cb590bcb 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -587,7 +587,8 @@ SortingMeshData BlocksRenderer::renderTranslucent( // additional powerful optimization auto size = aabb.size(); - if (glm::abs(size.y) < 0.01f && sortingMesh.entries.size() > 1) { + if ((size.y < 0.01f || size.x < 0.01f || size.z < 0.01f) && + sortingMesh.entries.size() > 1) { SortingMeshEntry newEntry { sortingMesh.entries[0].position, util::Buffer(totalSize) From 71d18ae3a99140e5c2b76df3a8365e5ee9277aa8 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 04:58:15 +0300 Subject: [PATCH 22/80] minor refactor --- src/constants.hpp | 8 +++++--- src/graphics/render/ChunksRenderer.cpp | 9 ++++----- src/graphics/render/ChunksRenderer.hpp | 5 +++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/constants.hpp b/src/constants.hpp index 12e12c75..84d8b22c 100644 --- a/src/constants.hpp +++ b/src/constants.hpp @@ -35,9 +35,6 @@ inline constexpr int CHUNK_D = 16; inline constexpr uint VOXEL_USER_BITS = 8; inline constexpr uint VOXEL_USER_BITS_OFFSET = sizeof(blockstate_t)*8-VOXEL_USER_BITS; -/// @brief pixel size of an item inventory icon -inline constexpr int ITEM_ICON_SIZE = 48; - /// @brief chunk volume (count of voxels per Chunk) inline constexpr int CHUNK_VOL = (CHUNK_W * CHUNK_H * CHUNK_D); @@ -53,6 +50,11 @@ inline constexpr uint vox_index(uint x, uint y, uint z, uint w=CHUNK_W, uint d=C return (y * d + z) * w + x; } +/// @brief pixel size of an item inventory icon +inline constexpr int ITEM_ICON_SIZE = 48; + +inline constexpr int TRANSLUCENT_BLOCKS_SORT_INTERVAL = 8; + inline const std::string SHADERS_FOLDER = "shaders"; inline const std::string TEXTURES_FOLDER = "textures"; inline const std::string FONTS_FOLDER = "fonts"; diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index edbf83f3..d3686a86 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -14,9 +14,6 @@ #include "util/listutil.hpp" #include "settings.hpp" -#include -#include - static debug::Logger logger("chunks-render"); size_t ChunksRenderer::visibleChunks = 0; @@ -204,7 +201,9 @@ void ChunksRenderer::drawChunks( auto mesh = retrieveChunk(indices[i].index, camera, shader, culling); if (mesh) { - glm::vec3 coord(chunk->x * CHUNK_W + 0.5f, 0.5f, chunk->z * CHUNK_D + 0.5f); + glm::vec3 coord( + chunk->x * CHUNK_W + 0.5f, 0.5f, chunk->z * CHUNK_D + 0.5f + ); glm::mat4 model = glm::translate(glm::mat4(1.0f), coord); shader.uniformMatrix("u_model", model); mesh->draw(); @@ -228,7 +227,7 @@ static inline void write_sorting_mesh_entries( } void ChunksRenderer::drawSortedMeshes(const Camera& camera, Shader& shader) { - const int sortInterval = 8; + const int sortInterval = TRANSLUCENT_BLOCKS_SORT_INTERVAL; static int frameid = 0; frameid++; diff --git a/src/graphics/render/ChunksRenderer.hpp b/src/graphics/render/ChunksRenderer.hpp index 5317c544..859bca9e 100644 --- a/src/graphics/render/ChunksRenderer.hpp +++ b/src/graphics/render/ChunksRenderer.hpp @@ -4,10 +4,12 @@ #include #include #include + #include +#define GLM_ENABLE_EXPERIMENTAL +#include #include "voxels/Block.hpp" -#include "voxels/ChunksStorage.hpp" #include "util/ThreadPool.hpp" #include "graphics/core/MeshData.hpp" #include "commons.hpp" @@ -17,7 +19,6 @@ class Chunk; class Level; class Camera; class Shader; -class Chunks; class Assets; class Frustum; class BlocksRenderer; From 0a33970a7ad4e3389dcc2a25a97edd4c7eef9550 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 05:19:39 +0300 Subject: [PATCH 23/80] fix base:glass visibility --- res/content/base/blocks/glass.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/content/base/blocks/glass.json b/res/content/base/blocks/glass.json index 902a2cf1..9bd4f021 100644 --- a/res/content/base/blocks/glass.json +++ b/res/content/base/blocks/glass.json @@ -3,5 +3,6 @@ "material": "base:glass", "draw-group": 2, "light-passing": true, - "sky-light-passing": true + "sky-light-passing": true, + "translucent": true } From eaa5150d3edbb4dacb72afccc4c8d6396ff0cbd0 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 05:23:50 +0300 Subject: [PATCH 24/80] update doc/*/block-properties.md --- doc/en/block-properties.md | 6 ++++++ doc/ru/block-properties.md | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/doc/en/block-properties.md b/doc/en/block-properties.md index cef58a9a..18c068ca 100644 --- a/doc/en/block-properties.md +++ b/doc/en/block-properties.md @@ -39,6 +39,12 @@ Block model type from list: Integer specifying number of block draw group (render order). Used for semi-transparent blocks. +### *translucent* + +Enables translucency support in block textures (examples: water, ice). +Should only be used when needed, as it impacts performance. +Not required for full transparency (grass, flowers). + ### *rotation* Rotation profile (set of available block rotations and behaviour of placing block rotation) from list: diff --git a/doc/ru/block-properties.md b/doc/ru/block-properties.md index 62ef8ec4..79b08da2 100644 --- a/doc/ru/block-properties.md +++ b/doc/ru/block-properties.md @@ -40,6 +40,12 @@ Целое число определяющее номер группы отрисовки данного блока. Актуально для полупрозрачных блоков - решает проблемы невидимых сторон блоков за этим блоком. +### Полупрозрачность - *translucent* + +Включает поддержку полупрозрачности в текстурах блока (примеры: вода, лёд). +Следует использовать только при надобности, так как влияет на производительность. +Не требуется для полной прозрачности (трава, цветы). + ### Вращение - *rotation* Профиль вращения (набор положений, в которые можно установить блок) из списка: From 255c49916cf61c6f44d5f9b4f090b584eb88871c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 06:38:13 +0300 Subject: [PATCH 25/80] add 'ice' translation to ru_RU.txt --- res/content/base/texts/ru_RU.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/res/content/base/texts/ru_RU.txt b/res/content/base/texts/ru_RU.txt index f6a3ab51..cf55ec54 100644 --- a/res/content/base/texts/ru_RU.txt +++ b/res/content/base/texts/ru_RU.txt @@ -1,3 +1,4 @@ +bazalt breaker=крушитель базальта bazalt=базальт blue lamp=синяя лампа brick=кирпич @@ -5,8 +6,8 @@ dirt=земля flower=цветок glass=стекло grass block=дёрн -tall grass=высокая трава green lamp=зелёная лампа +ice=лёд lamp=лампа leaves=листва light bulb=лампочка @@ -18,8 +19,8 @@ red lamp=красная лампа rust=ржавчина sand=песок stone=камень +tall grass=высокая трава +torch=факел water=вода wood=бревно -torch=факел -bazalt breaker=крушитель базальта wooden door=деревянная дверь From 3ea213e8d3cee7be55ec39ffb18dc557dec7557b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 15:53:25 +0300 Subject: [PATCH 26/80] fix console position --- res/layouts/console.xml | 2 +- src/frontend/hud.cpp | 7 +++++-- src/graphics/core/DrawContext.cpp | 2 +- src/graphics/core/DrawContext.hpp | 2 +- src/graphics/ui/elements/Container.cpp | 4 ++-- src/window/Window.cpp | 16 ++++++++-------- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/res/layouts/console.xml b/res/layouts/console.xml index 3e1b802d..bae396bf 100644 --- a/res/layouts/console.xml +++ b/res/layouts/console.xml @@ -14,7 +14,7 @@ diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index bfaac141..f0bbf20a 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -615,8 +615,11 @@ void Hud::updateElementsPosition(const Viewport& viewport) { } if (secondUI->getPositionFunc() == nullptr) { secondUI->setPos(glm::vec2( - glm::min(width/2-invwidth/2, width-caWidth-(inventoryView ? 10 : 0)-invwidth), - height/2-totalHeight/2 + glm::min( + width / 2.f - invwidth / 2.f, + width - caWidth - (inventoryView ? 10 : 0) - invwidth + ), + height / 2.f - totalHeight / 2.f )); } } diff --git a/src/graphics/core/DrawContext.cpp b/src/graphics/core/DrawContext.cpp index 29afae2e..314bd7b5 100644 --- a/src/graphics/core/DrawContext.cpp +++ b/src/graphics/core/DrawContext.cpp @@ -148,7 +148,7 @@ void DrawContext::setBlendMode(BlendMode mode) { set_blend_mode(mode); } -void DrawContext::setScissors(glm::vec4 area) { +void DrawContext::setScissors(const glm::vec4& area) { Window::pushScissor(area); scissorsCount++; } diff --git a/src/graphics/core/DrawContext.hpp b/src/graphics/core/DrawContext.hpp index 9174be1b..736b053e 100644 --- a/src/graphics/core/DrawContext.hpp +++ b/src/graphics/core/DrawContext.hpp @@ -34,6 +34,6 @@ public: void setDepthTest(bool flag); void setCullFace(bool flag); void setBlendMode(BlendMode mode); - void setScissors(glm::vec4 area); + void setScissors(const glm::vec4& area); void setLineWidth(float width); }; diff --git a/src/graphics/ui/elements/Container.cpp b/src/graphics/ui/elements/Container.cpp index 3b8fd0ac..72a44d52 100644 --- a/src/graphics/ui/elements/Container.cpp +++ b/src/graphics/ui/elements/Container.cpp @@ -90,7 +90,7 @@ void Container::draw(const DrawContext* pctx, Assets* assets) { if (!nodes.empty()) { batch->flush(); DrawContext ctx = pctx->sub(); - ctx.setScissors(glm::vec4(pos.x, pos.y, size.x, size.y)); + ctx.setScissors(glm::vec4(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y))); for (const auto& node : nodes) { if (node->isVisible()) node->draw(pctx, assets); @@ -108,7 +108,7 @@ void Container::drawBackground(const DrawContext* pctx, Assets*) { auto batch = pctx->getBatch2D(); batch->texture(nullptr); batch->setColor(color); - batch->rect(pos.x, pos.y, size.x, size.y); + batch->rect(pos.x, pos.y, glm::ceil(size.x), glm::ceil(size.y)); } void Container::add(const std::shared_ptr &node) { diff --git a/src/window/Window.cpp b/src/window/Window.cpp index fdfde141..99a549ca 100644 --- a/src/window/Window.cpp +++ b/src/window/Window.cpp @@ -258,14 +258,14 @@ void Window::pushScissor(glm::vec4 area) { } scissorStack.push(scissorArea); - area.z += area.x; - area.w += area.y; + area.z += glm::ceil(area.x); + area.w += glm::ceil(area.y); - area.x = fmax(area.x, scissorArea.x); - area.y = fmax(area.y, scissorArea.y); + area.x = glm::max(area.x, scissorArea.x); + area.y = glm::max(area.y, scissorArea.y); - area.z = fmin(area.z, scissorArea.z); - area.w = fmin(area.w, scissorArea.w); + area.z = glm::min(area.z, scissorArea.z); + area.w = glm::min(area.w, scissorArea.w); if (area.z < 0.0f || area.w < 0.0f) { glScissor(0, 0, 0, 0); @@ -273,8 +273,8 @@ void Window::pushScissor(glm::vec4 area) { glScissor( area.x, Window::height - area.w, - std::max(0, int(area.z - area.x)), - std::max(0, int(area.w - area.y)) + std::max(0, static_cast(glm::ceil(area.z - area.x))), + std::max(0, static_cast(glm::ceil(area.w - area.y))) ); } scissorArea = area; From 352ef6485a4b796d1cdc8dd0e00ab1a1d72a2c0a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 16:12:59 +0300 Subject: [PATCH 27/80] fix falling block hitbox --- res/content/base/entities/falling_block.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/content/base/entities/falling_block.json b/res/content/base/entities/falling_block.json index cd0459b5..cf5146fd 100644 --- a/res/content/base/entities/falling_block.json +++ b/res/content/base/entities/falling_block.json @@ -3,5 +3,5 @@ "base:falling_block" ], "skeleton-name": "base:block", - "hitbox": [0.8, 0.8, 0.8] + "hitbox": [0.98, 0.98, 0.98] } From 1ba5b0ce33103e539ccb199ee1cd52095e286a1f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 17 Nov 2024 16:58:58 +0300 Subject: [PATCH 28/80] fix: actual block inventory size not updating on inventory-size property update --- src/items/Inventory.cpp | 4 ++++ src/items/Inventory.hpp | 2 ++ src/voxels/ChunksStorage.cpp | 22 +++++++++++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/items/Inventory.cpp b/src/items/Inventory.cpp index 92f925ef..282f361f 100644 --- a/src/items/Inventory.cpp +++ b/src/items/Inventory.cpp @@ -45,6 +45,10 @@ void Inventory::move( } } +void Inventory::resize(uint newSize) { + slots.resize(newSize); +} + void Inventory::deserialize(const dv::value& src) { id = src["id"].asInteger(1); auto& slotsarr = src["slots"]; diff --git a/src/items/Inventory.hpp b/src/items/Inventory.hpp index e12029f8..176ad7ee 100644 --- a/src/items/Inventory.hpp +++ b/src/items/Inventory.hpp @@ -35,6 +35,8 @@ public: size_t end = -1 ); + void resize(uint newSize); + void deserialize(const dv::value& src) override; dv::value serialize() const override; diff --git a/src/voxels/ChunksStorage.cpp b/src/voxels/ChunksStorage.cpp index 596c4b78..272332fb 100644 --- a/src/voxels/ChunksStorage.cpp +++ b/src/voxels/ChunksStorage.cpp @@ -39,10 +39,10 @@ void ChunksStorage::remove(int x, int z) { } } -static void verifyLoadedChunk(ContentIndices* indices, Chunk* chunk) { +static void check_voxels(const ContentIndices& indices, Chunk* chunk) { for (size_t i = 0; i < CHUNK_VOL; i++) { blockid_t id = chunk->voxels[i].id; - if (indices->blocks.get(id) == nullptr) { + if (indices.blocks.get(id) == nullptr) { auto logline = logger.error(); logline << "corruped block detected at " << i << " of chunk "; logline << chunk->x << "x" << chunk->z; @@ -59,9 +59,26 @@ std::shared_ptr ChunksStorage::create(int x, int z) { auto chunk = std::make_shared(x, z); store(chunk); if (auto data = regions.getVoxels(chunk->x, chunk->z)) { + const auto& indices = *level->content->getIndices(); + chunk->decode(data.get()); + check_voxels(indices, chunk.get()); auto invs = regions.fetchInventories(chunk->x, chunk->z); + auto iterator = invs.begin(); + while (iterator != invs.end()) { + uint index = iterator->first; + const auto& def = indices.blocks.require(chunk->voxels[index].id); + if (def.inventorySize == 0) { + iterator = invs.erase(iterator); + continue; + } + auto& inventory = iterator->second; + if (def.inventorySize != inventory->size()) { + inventory->resize(def.inventorySize); + } + ++iterator; + } chunk->setBlockInventories(std::move(invs)); auto entitiesData = regions.fetchEntities(chunk->x, chunk->z); @@ -74,7 +91,6 @@ std::shared_ptr ChunksStorage::create(int x, int z) { for (auto& entry : chunk->inventories) { level->inventories->store(entry.second); } - verifyLoadedChunk(level->content->getIndices(), chunk.get()); } if (auto lights = regions.getLights(chunk->x, chunk->z)) { chunk->lightmap.set(lights.get()); From e034bda477c35efe96548e78ecc722966a7a2197 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 18 Nov 2024 04:15:51 +0300 Subject: [PATCH 29/80] fix crosshair --- src/frontend/hud.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index bfaac141..032d0602 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -571,7 +571,7 @@ void Hud::draw(const DrawContext& ctx){ // Crosshair if (!pause && !inventoryOpen && !player->debug) { - DrawContext chctx = ctx.sub(); + DrawContext chctx = ctx.sub(batch); chctx.setBlendMode(BlendMode::inversion); auto texture = assets->get("gui/crosshair"); batch->texture(texture); From 8e1d6b9f0309c2e060c16d5e856197067c7e8993 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 18 Nov 2024 05:24:16 +0300 Subject: [PATCH 30/80] set default margin to 0,0,0,0 --- src/graphics/ui/elements/UINode.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/ui/elements/UINode.hpp b/src/graphics/ui/elements/UINode.hpp index 666fa01c..53967f4c 100644 --- a/src/graphics/ui/elements/UINode.hpp +++ b/src/graphics/ui/elements/UINode.hpp @@ -81,7 +81,7 @@ namespace gui { /// @brief element color when clicked glm::vec4 pressedColor {1.0f}; /// @brief element margin (only supported for Panel sub-nodes) - glm::vec4 margin {1.0f}; + glm::vec4 margin {0.0f}; /// @brief is element visible bool visible = true; /// @brief is mouse over the element From 618a9f04118302875120c83ad7897bc396a34b96 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 18 Nov 2024 07:11:07 +0300 Subject: [PATCH 31/80] add RadioButton Lua class --- res/layouts/pages/settings.xml | 10 +++++----- res/layouts/pages/settings.xml.lua | 20 +++++++++----------- res/scripts/stdlib.lua | 23 +++++++++++++++++++++++ 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/res/layouts/pages/settings.xml b/res/layouts/pages/settings.xml index f5ec33d7..00437e68 100644 --- a/res/layouts/pages/settings.xml +++ b/res/layouts/pages/settings.xml @@ -1,9 +1,9 @@ - - - - + + + + @@ -11,7 +11,7 @@ - + diff --git a/res/layouts/pages/settings.xml.lua b/res/layouts/pages/settings.xml.lua index 24256c84..8b41491a 100644 --- a/res/layouts/pages/settings.xml.lua +++ b/res/layouts/pages/settings.xml.lua @@ -3,15 +3,13 @@ function on_open() "%s: %s", gui.str("Language", "settings"), gui.get_locales_info()[core.get_setting("ui.language")].name ) - set_page("s_gfx", "settings_graphics") -end - -function set_page(btn, page) - document.s_aud.enabled = true - document.s_dsp.enabled = true - document.s_gfx.enabled = true - document.s_ctl.enabled = true - document.s_rst.enabled = true - document[btn].enabled = false - document.menu.page = page + sections = RadioGroup({ + audio=document.s_aud, + display=document.s_dsp, + graphics=document.s_gfx, + controls=document.s_ctl, + reset=document.s_rst + }, function (page) + document.menu.page = "settings_"..page + end, "graphics") end diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index f53323db..4bade31d 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -84,6 +84,29 @@ function Document.new(docname) }) end +local _RadioGroup = {} +function _RadioGroup.set(self, key) + if self.current then + self.elements[self.current].enabled = true + end + self.elements[key].enabled = false + self.current = key + if self.callback then + self.callback(key) + end +end +function _RadioGroup.__call(self, elements, onset, default) + local group = setmetatable({ + elements=elements, + callback=onset, + current=nil + }, {__index=_RadioGroup}) + group:set(default) + return group +end +setmetatable(_RadioGroup, _RadioGroup) +RadioGroup = _RadioGroup + _GUI_ROOT = Document.new("core:root") _MENU = _GUI_ROOT.menu menu = _MENU From dcd8871ee19e3615a7480dfaa5a312ca587e1e0c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 18 Nov 2024 09:21:16 +0300 Subject: [PATCH 32/80] add utf8.escape, string.escape & reformat extensions.md --- doc/en/scripting/builtins/libutf8.md | 3 + doc/ru/scripting/builtins/libutf8.md | 3 + doc/ru/scripting/extensions.md | 111 ++++++++++++++--------- res/scripts/stdmin.lua | 1 + src/logic/scripting/lua/libs/libutf8.cpp | 6 ++ src/util/stringutil.cpp | 3 +- src/util/stringutil.hpp | 2 +- 7 files changed, 85 insertions(+), 44 deletions(-) diff --git a/doc/en/scripting/builtins/libutf8.md b/doc/en/scripting/builtins/libutf8.md index 86714fce..bd8dd22b 100644 --- a/doc/en/scripting/builtins/libutf8.md +++ b/doc/en/scripting/builtins/libutf8.md @@ -27,4 +27,7 @@ utf8.upper(text: str) -> str -- Converts a string to lowercase utf8.lower(text: str) -> str + +-- Escapes a string +utf8.escape(text: str) -> str ``` diff --git a/doc/ru/scripting/builtins/libutf8.md b/doc/ru/scripting/builtins/libutf8.md index 394eb522..ce933417 100644 --- a/doc/ru/scripting/builtins/libutf8.md +++ b/doc/ru/scripting/builtins/libutf8.md @@ -27,4 +27,7 @@ utf8.upper(text: str) -> str -- Переводит строку в нижний регистр utf8.lower(text: str) -> str + +-- Экранирует строку +utf8.escape(text: str) -> str ``` diff --git a/doc/ru/scripting/extensions.md b/doc/ru/scripting/extensions.md index a6b40a38..d4502f64 100644 --- a/doc/ru/scripting/extensions.md +++ b/doc/ru/scripting/extensions.md @@ -4,92 +4,109 @@ ## Расширения для table -Создаёт и возвращает копию переданной таблицы путём создания новой и копирования в неё всех элементов из переданной ```lua -function table.copy(t: table) -> table +table.copy(t: table) -> table ``` -Возвращает количество пар в переданной таблице +Создаёт и возвращает копию переданной таблицы путём создания новой и копирования в неё всех элементов из переданной. + ```lua -function table.count_pairs(t: table) -> integer +table.count_pairs(t: table) -> integer ``` -Возвращает один элемент из переданной таблицы на случайной позиции +Возвращает количество пар в переданной таблице. + ```lua -function table.random(t: table) -> object +table.random(t: table) -> object ``` -Возвращает **true**, если **x** содержится в **t** +Возвращает один элемент из переданной таблицы на случайной позиции. + ```lua -function table.has(t: table, x: object) -> bool +table.has(t: table, x: object) -> bool ``` -Возвращает индекс обьекта **x** в **t**. Если переданный обьект не содержится в таблице, то функция вернёт значение **-1** +Возвращает **true**, если **x** содержится в **t**. + ```lua -function table.index(t: table, x: object) -> integer +table.index(t: table, x: object) -> integer ``` -Удаляет элемент **x** из **t** +Возвращает индекс обьекта **x** в **t**. Если переданный обьект не содержится в таблице, то функция вернёт значение **-1**. + ```lua -function table.remove_value(t: table, x: object) +table.remove_value(t: table, x: object) ``` -Конвертирует переданную таблицу в строку +Удаляет элемент **x** из **t**. + ```lua -function table.tostring(t: table) -> string +table.tostring(t: table) -> string ``` +Конвертирует переданную таблицу в строку. + ## Расширения для string -Разбивает строку **str** на части по указанному разделителю/выражению **separator** и возвращает результат ввиде таблицы из строк. Если **withpattern** равен **true**, то параметр **separator** будет определяться как регулярное выражение ```lua -function string.explode(separator: string, str: string, withpattern: bool) -> table[string] +string.explode(separator: string, str: string, withpattern: bool) -> table[string] ``` -Разбивает строку **str** на части по указанному разделителю **delimiter** и возвращает результат ввиде таблицы из строк +Разбивает строку **str** на части по указанному разделителю/выражению **separator** и возвращает результат ввиде таблицы из строк. Если **withpattern** равен **true**, то параметр **separator** будет определяться как регулярное выражение. + ```lua -function string.split(str: string, delimiter: string) -> table[string] +string.split(str: string, delimiter: string) -> table[string] ``` -Экранирует специальные символы в строке, такие как `()[]+-.$%^?*` в формате `%символ`. Символ `NUL` (`\0`) будет преобразован в `%z` +Разбивает строку **str** на части по указанному разделителю **delimiter** и возвращает результат ввиде таблицы из строк. + ```lua -function string.pattern_safe(str: string) +string.pattern_safe(str: string) ``` -Разбивает секунды на часы, минуты и миллисекунды и форматирует в **format** с следующим порядком параметров: `минуты, секунды, миллисекунды` и после возвращает результат. Если **format** не указан, то возвращает таблицу, где: **h** - hours, **m** - minutes, **s** - seconds, **ms** - milliseconds +Экранирует специальные символы в строке, такие как `()[]+-.$%^?*` в формате `%символ`. Символ `NUL` (`\0`) будет преобразован в `%z`. + ```lua -function string.formatted_time(seconds: number, format: string) -> string | table +string.formatted_time(seconds: number, format: string) -> string | table ``` -Заменяет все подстроки в **str**, равные **tofind** на **toreplace** и возвращает строку со всеми измененными подстроками +Разбивает секунды на часы, минуты и миллисекунды и форматирует в **format** с следующим порядком параметров: `минуты, секунды, миллисекунды` и после возвращает результат. Если **format** не указан, то возвращает таблицу, где: **h** - hours, **m** - minutes, **s** - seconds, **ms** - milliseconds. + ```lua -function string.replace(str: string, tofind: string, toreplace: string) -> string +string.replace(str: string, tofind: string, toreplace: string) -> string +``` + +Заменяет все подстроки в **str**, равные **tofind** на **toreplace** и возвращает строку со всеми измененными подстроками. + +```lua +string.trim(str: string, char: string) -> string ``` Удаляет все символы, равные **char** из строки **str** с левого и правого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы. + ```lua -function string.trim(str: string, char: string) -> string +string.trim_left(str: string, char: string) -> string ``` Удаляет все символы, равные **char** из строки **str** с левого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы. + ```lua -function string.trim_left(str: string, char: string) -> string +string.trim_right(str: string, char: string) -> string ``` Удаляет все символы, равные **char** из строки **str** с правого конца и возвращает результат. Если параметр **char** не определен, то будут выбраны все пустые символы. + ```lua -function string.trim_right(str: string, char: string) -> string +string.starts_with(str: string, start: string) -> bool ``` Возвращает **true**, если строка **str** начинается на подстроку **start** + ```lua -function string.starts_with(str: string, start: string) -> bool +string.ends_with(str: string, endStr: string) -> bool ``` Возвращает **true**, если строка **str** заканчивается на подстроку **endStr** -```lua -function string.ends_with(str: string, endStr: string) -> bool -``` Также важно подметить, что все выше перечисленные функции, расширяющие **string** можно использовать как мета-методы на экземплярах строк, т.е.: @@ -103,39 +120,51 @@ end Также функции `string.lower` и `string.upper` переопределены на `utf8.lower` и `utf8.upper` +```lua +string.escape(str: string) -> string +``` + +Экранирует строку. Является псевдонимом `utf8.escape`. + ## Расширения для math -Ограничивает число **_in** по лимитам **low** и **high**. Т.е.: Если **_in** больше чем **high** - вернётся **high**, если **_in** меньше чем **low** - вернётся **low**. В противном случае вернётся само число ```lua -function math.clamp(_in, low, high) +math.clamp(_in, low, high) ``` -Возвращает случайное дробное число в диапазоне от **low** до **high** +Ограничивает число **_in** по лимитам **low** и **high**. Т.е.: Если **_in** больше чем **high** - вернётся **high**, если **_in** меньше чем **low** - вернётся **low**. В противном случае вернётся само число. + ```lua -function math.rand(low, high) +math.rand(low, high) ``` +Возвращает случайное дробное число в диапазоне от **low** до **high**. + ## Дополнительные глобальные функции В этом же скрипте также определены и другие глобальные функции которые доступны для использования. Ниже их список -Возвращает **true**, если переданная таблица является массивом, тоесть если каждый ключ это целое число больше или равное единице и если каждый ключ следует за прошлым ```lua -function is_array(x: table) -> bool +is_array(x: table) -> bool ``` -Разбивает путь на две части и возвращает их: входную точку и путь к файлу +Возвращает **true**, если переданная таблица является массивом, тоесть если каждый ключ это целое число больше или равное единице и если каждый ключ следует за прошлым. + ```lua function parse_path(path: string) -> string, string ``` -Вызывает функцию **func** **iters** раз, передавая ей аргументы `...`, а после выводит в консоль время в микросекундах, которое прошло с момента вызова **timeit** +Разбивает путь на две части и возвращает их: входную точку и путь к файлу. + ```lua function timeit(iters: integer, func: func, ...) ``` -Вызывает остановку корутины до тех пор, пока не пройдёт количество секунд, указанное в **timesec**. Функция может быть использована только внутри корутины +Вызывает функцию **func** **iters** раз, передавая ей аргументы `...`, а после выводит в консоль время в микросекундах, которое прошло с момента вызова **timeit**. + ```lua function sleep(timesec: number) -``` \ No newline at end of file +``` + +Вызывает остановку корутины до тех пор, пока не пройдёт количество секунд, указанное в **timesec**. Функция может быть использована только внутри корутины. diff --git a/res/scripts/stdmin.lua b/res/scripts/stdmin.lua index 530ec091..762610a7 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -162,6 +162,7 @@ end string.lower = utf8.lower string.upper = utf8.upper +string.escape = utf8.escape local meta = getmetatable("") diff --git a/src/logic/scripting/lua/libs/libutf8.cpp b/src/logic/scripting/lua/libs/libutf8.cpp index 85895c5d..4c1f484f 100644 --- a/src/logic/scripting/lua/libs/libutf8.cpp +++ b/src/logic/scripting/lua/libs/libutf8.cpp @@ -94,6 +94,11 @@ static int l_encode(lua::State* L) { return lua::pushlstring(L, bytes, count); } +static int l_escape(lua::State* L) { + auto string = lua::require_lstring(L, 1); + return lua::pushstring(L, util::escape(string)); +} + const luaL_Reg utf8lib[] = { {"tobytes", lua::wrap}, {"tostring", lua::wrap}, @@ -103,5 +108,6 @@ const luaL_Reg utf8lib[] = { {"upper", lua::wrap}, {"lower", lua::wrap}, {"encode", lua::wrap}, + {"escape", lua::wrap}, {NULL, NULL} }; diff --git a/src/util/stringutil.cpp b/src/util/stringutil.cpp index ca7e8e46..12f4e74c 100644 --- a/src/util/stringutil.cpp +++ b/src/util/stringutil.cpp @@ -7,8 +7,7 @@ #include #include -// TODO: finish -std::string util::escape(const std::string& s) { +std::string util::escape(std::string_view s) { std::stringstream ss; ss << '"'; size_t pos = 0; diff --git a/src/util/stringutil.hpp b/src/util/stringutil.hpp index f584a53c..b0cd5d56 100644 --- a/src/util/stringutil.hpp +++ b/src/util/stringutil.hpp @@ -8,7 +8,7 @@ namespace util { /// @brief Function used for string serialization in text formats - std::string escape(const std::string& s); + std::string escape(std::string_view s); /// @brief Function used for error messages std::string quote(const std::string& s); From 712c0756b8cb607e6a226798aeb283ed303b2b7a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 18 Nov 2024 11:09:27 +0300 Subject: [PATCH 33/80] add debug.get_traceback --- res/scripts/stdmin.lua | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/res/scripts/stdmin.lua b/res/scripts/stdmin.lua index 762610a7..2b6a10fe 100644 --- a/res/scripts/stdmin.lua +++ b/res/scripts/stdmin.lua @@ -228,6 +228,20 @@ function file.readlines(path) return lines end +function debug.get_trackback() + local frames = {} + local n = 0 + while true do + local info = debug.getinfo(n) + if info then + table.insert(frames, info) + else + return frames + end + n = n + 1 + end +end + package = { loaded={} } From 0bfc5d2ad4a40388ae0ee1c71561a3ba349786f3 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 18 Nov 2024 11:52:06 +0300 Subject: [PATCH 34/80] add base64 library --- src/logic/scripting/lua/libs/api_lua.hpp | 1 + src/logic/scripting/lua/libs/libbase64.cpp | 52 ++++++++++++++++++++++ src/logic/scripting/lua/lua_engine.cpp | 1 + src/logic/scripting/lua/lua_util.hpp | 5 +++ src/util/stringutil.cpp | 4 +- src/util/stringutil.hpp | 2 +- 6 files changed, 62 insertions(+), 3 deletions(-) create mode 100644 src/logic/scripting/lua/libs/libbase64.cpp diff --git a/src/logic/scripting/lua/libs/api_lua.hpp b/src/logic/scripting/lua/libs/api_lua.hpp index bd810833..b0edba79 100644 --- a/src/logic/scripting/lua/libs/api_lua.hpp +++ b/src/logic/scripting/lua/libs/api_lua.hpp @@ -15,6 +15,7 @@ // Libraries extern const luaL_Reg audiolib[]; +extern const luaL_Reg base64lib[]; extern const luaL_Reg bjsonlib[]; extern const luaL_Reg blocklib[]; extern const luaL_Reg cameralib[]; diff --git a/src/logic/scripting/lua/libs/libbase64.cpp b/src/logic/scripting/lua/libs/libbase64.cpp new file mode 100644 index 00000000..26f77eb6 --- /dev/null +++ b/src/logic/scripting/lua/libs/libbase64.cpp @@ -0,0 +1,52 @@ +#include "api_lua.hpp" + +#include "util/stringutil.hpp" + +static int l_encode(lua::State* L) { + if (lua::istable(L, 1)) { + lua::pushvalue(L, 1); + size_t size = lua::objlen(L, 1); + util::Buffer buffer(size); + for (size_t i = 0; i < size; i++) { + lua::rawgeti(L, i + 1); + buffer[i] = lua::tointeger(L, -1); + lua::pop(L); + } + lua::pop(L); + return lua::pushstring(L, util::base64_encode( + reinterpret_cast(buffer.data()), buffer.size() + )); + } else if (auto bytes = lua::touserdata(L, 1)) { + return lua::pushstring( + L, + util::base64_encode( + bytes->data().data(), + bytes->data().size() + ) + ); + } + throw std::runtime_error("array or ByteArray expected"); +} + +static int l_decode(lua::State* L) { + auto buffer = util::base64_decode(lua::require_lstring(L, 1)); + if (lua::toboolean(L, 2)) { + lua::createtable(L, buffer.size(), 0); + for (size_t i = 0; i < buffer.size(); i++) { + lua::pushinteger(L, buffer[i] & 0xFF); + lua::rawseti(L, i+1); + } + } else { + lua::newuserdata(L, buffer.size()); + auto bytearray = lua::touserdata(L, -1); + bytearray->data().reserve(buffer.size()); + std::memcpy(bytearray->data().data(), buffer.data(), buffer.size()); + } + return 1; +} + +const luaL_Reg base64lib[] = { + {"encode", lua::wrap}, + {"decode", lua::wrap}, + {NULL, NULL} +}; diff --git a/src/logic/scripting/lua/lua_engine.cpp b/src/logic/scripting/lua/lua_engine.cpp index fe3e75b5..1d24ec93 100644 --- a/src/logic/scripting/lua/lua_engine.cpp +++ b/src/logic/scripting/lua/lua_engine.cpp @@ -39,6 +39,7 @@ static void remove_lib_funcs( } static void create_libs(State* L, StateType stateType) { + openlib(L, "base64", base64lib); openlib(L, "bjson", bjsonlib); openlib(L, "block", blocklib); openlib(L, "core", corelib); diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index f2b51c53..70dd7705 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -240,6 +240,11 @@ namespace lua { inline const char* tostring(lua::State* L, int idx) { return lua_tostring(L, idx); } + inline std::string_view tolstring(lua::State* L, int idx) { + size_t len = 0; + auto string = lua_tolstring(L, idx, &len); + return std::string_view(string, len); + } inline const void* topointer(lua::State* L, int idx) { return lua_topointer(L, idx); } diff --git a/src/util/stringutil.cpp b/src/util/stringutil.cpp index 12f4e74c..1fabcd2c 100644 --- a/src/util/stringutil.cpp +++ b/src/util/stringutil.cpp @@ -363,8 +363,8 @@ util::Buffer util::base64_decode(const char* str, size_t size) { return bytes; } -util::Buffer util::base64_decode(const std::string& str) { - return base64_decode(str.c_str(), str.size()); +util::Buffer util::base64_decode(std::string_view str) { + return base64_decode(str.data(), str.size()); } int util::replaceAll( diff --git a/src/util/stringutil.hpp b/src/util/stringutil.hpp index b0cd5d56..edd0df17 100644 --- a/src/util/stringutil.hpp +++ b/src/util/stringutil.hpp @@ -63,7 +63,7 @@ namespace util { std::string base64_encode(const ubyte* data, size_t size); util::Buffer base64_decode(const char* str, size_t size); - util::Buffer base64_decode(const std::string& str); + util::Buffer base64_decode(std::string_view str); std::string tohex(uint64_t value); From d6608803652a7cc3e36b65b91e2aea9bb2c1afe0 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 18 Nov 2024 12:37:48 +0300 Subject: [PATCH 35/80] fix util::base64_encode --- src/util/stringutil.cpp | 2 +- test/util/stringutil.cpp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/util/stringutil.cpp b/src/util/stringutil.cpp index 1fabcd2c..d1148da5 100644 --- a/src/util/stringutil.cpp +++ b/src/util/stringutil.cpp @@ -317,7 +317,7 @@ std::string util::base64_encode(const ubyte* data, size_t size) { ending[i - fullsegments] = data[i]; } size_t trailing = size - fullsegments; - { + if (trailing) { char output[] = "===="; output[0] = B64ABC[(ending[0] & 0b11111100) >> 2]; output[1] = diff --git a/test/util/stringutil.cpp b/test/util/stringutil.cpp index 7bd0f85c..2f27a243 100644 --- a/test/util/stringutil.cpp +++ b/test/util/stringutil.cpp @@ -15,3 +15,19 @@ TEST(stringutil, utf8) { std::string str2 = util::u32str2str_utf8(u32str); EXPECT_EQ(str, str2); } + +TEST(stringutil, base64) { + srand(2019); + for (size_t size = 0; size < 30; size++) { + auto bytes = std::make_unique(size); + for (int i = 0; i < size; i++) { + bytes[i] = rand(); + } + auto base64 = util::base64_encode(bytes.get(), size); + auto decoded = util::base64_decode(base64); + ASSERT_EQ(size, decoded.size()); + for (size_t i = 0; i < size; i++) { + ASSERT_EQ(bytes[i], decoded[i]); + } + } +} From 801650824ecd00d0a9024701fb65b4d35b2f229b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 18 Nov 2024 14:03:30 +0300 Subject: [PATCH 36/80] add 'text-color' textbox property --- doc/en/xml-ui-layouts.md | 1 + doc/ru/xml-ui-layouts.md | 1 + src/graphics/ui/elements/TextBox.cpp | 11 ++++++++++- src/graphics/ui/elements/TextBox.hpp | 4 ++++ src/graphics/ui/gui_xml.cpp | 3 +++ src/logic/scripting/lua/libs/libgui.cpp | 14 ++++++++++++++ 6 files changed, 33 insertions(+), 1 deletion(-) diff --git a/doc/en/xml-ui-layouts.md b/doc/en/xml-ui-layouts.md index ac657e44..f4db96c6 100644 --- a/doc/en/xml-ui-layouts.md +++ b/doc/en/xml-ui-layouts.md @@ -105,6 +105,7 @@ Inner text - initially entered text - `text-wrap` - allows automatic text wrapping (works only with multiline: "true") - `editable` - determines whether the text can be edited. - `error-color` - color when entering incorrect data (the text does not pass the validator check). Type: RGBA color. +- `text-color` - text color. Type: RGBA color. - `validator` - lua function that checks text for correctness. Takes a string as input, returns true if the text is correct. - `onup` - lua function called when the up arrow is pressed. - `ondown` - lua function called when the down arrow is pressed. diff --git a/doc/ru/xml-ui-layouts.md b/doc/ru/xml-ui-layouts.md index bdf82f1b..adffcd73 100644 --- a/doc/ru/xml-ui-layouts.md +++ b/doc/ru/xml-ui-layouts.md @@ -106,6 +106,7 @@ - `text-wrap` - разрешает автоматический перенос текста (работает только при multiline: "true") - `editable`- определяет возможность редактирования текста. - `error-color` - цвет при вводе некорректных данных (текст не проходит проверку валидатора). Тип: RGBA цвет. +- `text-color` - цвет текста. Тип: RGBA цвет. - `validator` - lua функция, проверяющая текст на корректность. Принимает на вход строку, возвращает true если текст корректен. - `onup` - lua функция вызываемая при нажатии стрелки вверх. - `ondown` - lua функция вызываемая при нажатии стрелки вниз. diff --git a/src/graphics/ui/elements/TextBox.cpp b/src/graphics/ui/elements/TextBox.cpp index 9fe44327..a4e613d3 100644 --- a/src/graphics/ui/elements/TextBox.cpp +++ b/src/graphics/ui/elements/TextBox.cpp @@ -126,7 +126,7 @@ void TextBox::drawBackground(const DrawContext* pctx, Assets*) { } void TextBox::refreshLabel() { - label->setColor(glm::vec4(input.empty() ? 0.5f : 1.0f)); + label->setColor(textColor * glm::vec4(input.empty() ? 0.5f : 1.0f)); label->setText(input.empty() && !hint.empty() ? hint : getText()); if (autoresize && font) { @@ -619,6 +619,15 @@ glm::vec4 TextBox::getFocusedColor() const { return focusedColor; } + +void TextBox::setTextColor(glm::vec4 color) { + this->textColor = color; +} + +glm::vec4 TextBox::getTextColor() const { + return textColor; +} + void TextBox::setErrorColor(glm::vec4 color) { this->invalidColor = color; } diff --git a/src/graphics/ui/elements/TextBox.hpp b/src/graphics/ui/elements/TextBox.hpp index 834f7a64..27b6e9c9 100644 --- a/src/graphics/ui/elements/TextBox.hpp +++ b/src/graphics/ui/elements/TextBox.hpp @@ -12,6 +12,7 @@ namespace gui { protected: glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f}; glm::vec4 invalidColor {0.1f, 0.05f, 0.03f, 1.0f}; + glm::vec4 textColor {1.0f, 1.0f, 1.0f, 1.0f}; std::shared_ptr