From 74ded5a052358dd59031e873aa78dbf9ce0b999e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 22 Sep 2024 01:58:59 +0300 Subject: [PATCH] implement structures rotation --- res/generators/default.lua | 5 +-- .../scripting/scripting_world_generation.cpp | 6 +++- src/world/generator/StructurePlacement.hpp | 10 ++++-- src/world/generator/VoxelStructure.cpp | 32 +++++++++++++++++++ src/world/generator/VoxelStructure.hpp | 4 +++ src/world/generator/WorldGenerator.cpp | 21 ++++++++---- src/world/generator/WorldGenerator.hpp | 3 +- 7 files changed, 67 insertions(+), 14 deletions(-) diff --git a/res/generators/default.lua b/res/generators/default.lua index 41f7f500..cea18b91 100644 --- a/res/generators/default.lua +++ b/res/generators/default.lua @@ -77,7 +77,8 @@ function place_structures(x, z, w, d, seed, hmap) if py <= sea_level then goto continue end - table.insert(placements, {math.floor(math.random() * 3), {px-8, py, pz-8}}) + table.insert(placements, + {math.floor(math.random() * 3), {px-8, py, pz-8}, math.floor(math.random()*4)}) ::continue:: end @@ -85,7 +86,7 @@ function place_structures(x, z, w, d, seed, hmap) local px = math.random() * w local pz = math.random() * d local py = hmap:at(px, pz) * 256 - table.insert(placements, {3, {px-8, py, pz-8}}) + table.insert(placements, {3, {px-8, py, pz-8}, 0}) end return placements end diff --git a/src/logic/scripting/scripting_world_generation.cpp b/src/logic/scripting/scripting_world_generation.cpp index 99605da6..01a8e56e 100644 --- a/src/logic/scripting/scripting_world_generation.cpp +++ b/src/logic/scripting/scripting_world_generation.cpp @@ -127,9 +127,13 @@ public: glm::ivec3 pos = lua::tovec3(L, -1); lua::pop(L); + lua::rawgeti(L, 3); + int rotation = lua::tointeger(L, -1) & 0b11; lua::pop(L); - placements.emplace_back(structIndex, pos); + lua::pop(L); + + placements.emplace_back(structIndex, pos, rotation); } lua::pop(L); } diff --git a/src/world/generator/StructurePlacement.hpp b/src/world/generator/StructurePlacement.hpp index 584ec1dd..ba688ddb 100644 --- a/src/world/generator/StructurePlacement.hpp +++ b/src/world/generator/StructurePlacement.hpp @@ -1,12 +1,16 @@ #pragma once +#include #include struct StructurePlacement { int structure; - glm::ivec3 position; + uint8_t rotation; - StructurePlacement(int structure, glm::ivec3 position) - : structure(structure), position(std::move(position)) {} + StructurePlacement(int structure, glm::ivec3 position, uint8_t rotation) + : structure(structure), + position(std::move(position)), + rotation(rotation) { + } }; diff --git a/src/world/generator/VoxelStructure.cpp b/src/world/generator/VoxelStructure.cpp index 6e27e086..38732363 100644 --- a/src/world/generator/VoxelStructure.cpp +++ b/src/world/generator/VoxelStructure.cpp @@ -92,3 +92,35 @@ void VoxelStructure::prepare(const Content& content) { voxelsRuntime[i].state = voxels[i].state; } } + +std::unique_ptr VoxelStructure::rotated(const Content& content) const { + std::vector newVoxels(voxels.size()); + + for (int y = 0; y < size.y; y++) { + for (int z = 0; z < size.z; z++) { + for (int x = 0; x < size.x; x++) { + auto& voxel = newVoxels[vox_index(x, y, z, size.x, size.z)]; + voxel = voxels[vox_index(size.z-z-1, y, x, size.z, size.x)]; + // swap X and Z segment bits + voxel.state.segment = ((voxel.state.segment & 0b001) << 2) + | (voxel.state.segment & 0b010) + | ((voxel.state.segment & 0b100) >> 2); + auto& def = content.blocks.require(blockNames[voxel.id]); + if (def.rotations.name == BlockRotProfile::PANE_NAME || + def.rotations.name == BlockRotProfile::PIPE_NAME){ + if (voxel.state.rotation < 4) { + voxel.state.rotation = (voxel.state.rotation + 3) & 0b11; + } + } + } + } + } + auto newStructure = std::make_unique( + // swap X and Z on 90 deg. rotation + glm::ivec3(size.z, size.y, size.x), + std::move(newVoxels), + blockNames + ); + newStructure->prepare(content); + return newStructure; +} diff --git a/src/world/generator/VoxelStructure.hpp b/src/world/generator/VoxelStructure.hpp index 938df3cd..ef70c229 100644 --- a/src/world/generator/VoxelStructure.hpp +++ b/src/world/generator/VoxelStructure.hpp @@ -40,6 +40,9 @@ public: /// @param content world content void prepare(const Content& content); + /// @brief Create structure copy rotated 90 deg. clockwise + std::unique_ptr rotated(const Content& content) const; + static std::unique_ptr create( Level* level, const glm::ivec3& a, const glm::ivec3& b, bool entities); @@ -47,6 +50,7 @@ public: return size; } + /// @return Voxels with indices valid to current world content const std::vector& getRuntimeVoxels() { assert(!voxelsRuntime.empty()); return voxelsRuntime; diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index 12078ae5..933f2901 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -1,7 +1,6 @@ #include "WorldGenerator.hpp" #include -#include #include "maths/util.hpp" #include "content/Content.hpp" @@ -50,9 +49,16 @@ WorldGenerator::WorldGenerator( generateStructures(requirePrototype(x, z), x, z); }); - structures = def.script->loadStructures(); - for (auto& structure : structures) { - structure->prepare(*content); + auto rawStructures = def.script->loadStructures(); + structures.resize(rawStructures.size()); + + for (int i = 0; i < rawStructures.size(); i++) { + structures[i][0] = std::move(rawStructures[i]); + structures[i][0]->prepare(*content); + // pre-calculate rotated structure variants + for (int j = 1; j < 4; j++) { + structures[i][j] = structures[i][j-1]->rotated(*content); + } } } @@ -150,7 +156,7 @@ void WorldGenerator::generateStructures( logger.error() << "invalid structure index " << placement.structure; continue; } - auto& structure = *structures[placement.structure]; + auto& structure = *structures[placement.structure][placement.rotation]; auto position = glm::ivec3(chunkX * CHUNK_W, 0, chunkZ * CHUNK_D)+offset; auto size = structure.getSize() + glm::ivec3(0, CHUNK_H, 0); AABB aabb(position, position + size); @@ -167,7 +173,8 @@ void WorldGenerator::generateStructures( otherPrototype.structures.emplace_back( placement.structure, placement.position - - glm::ivec3(lcx * CHUNK_W, 0, lcz * CHUNK_D) + glm::ivec3(lcx * CHUNK_W, 0, lcz * CHUNK_D), + placement.rotation ); } } @@ -258,7 +265,7 @@ void WorldGenerator::generate(voxel* voxels, int chunkX, int chunkZ) { logger.error() << "invalid structure index " << placement.structure; continue; } - auto& structure = *structures[placement.structure]; + auto& structure = *structures[placement.structure][placement.rotation]; auto& structVoxels = structure.getRuntimeVoxels(); const auto& offset = placement.position; const auto& size = structure.getSize(); diff --git a/src/world/generator/WorldGenerator.hpp b/src/world/generator/WorldGenerator.hpp index b8685599..8783bc15 100644 --- a/src/world/generator/WorldGenerator.hpp +++ b/src/world/generator/WorldGenerator.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -46,7 +47,7 @@ class WorldGenerator { /// @brief Chunk prototypes loading surround map SurroundMap surroundMap; - std::vector> structures; + std::vector, 4>> structures; /// @brief Generate chunk prototype (see ChunkPrototype) /// @param x chunk position X divided by CHUNK_W