From d8c39404516c69920170b28e69c51622276d476a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 28 Oct 2024 09:22:02 +0300 Subject: [PATCH 1/3] add 'heights-interpolation', 'biomes-interpolation' --- src/content/loading/GeneratorLoader.cpp | 10 ++++++++++ src/maths/Heightmap.cpp | 11 +++++++++++ src/maths/Heightmap.hpp | 3 +++ src/world/generator/GeneratorDef.hpp | 6 ++++++ src/world/generator/WorldGenerator.cpp | 6 +++--- 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index 299565a4..ebae9118 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -202,6 +202,16 @@ void ContentLoader::loadGenerator( map.at("biome-parameters").get(def.biomeParameters); map.at("biome-bpd").get(def.biomesBPD); map.at("heights-bpd").get(def.heightsBPD); + std::string interpName; + map.at("heights-interpolation").get(interpName); + if (auto interp = InterpolationType_from(interpName)) { + def.heightsInterpolation = *interp; + } + map.at("biomes-interpolation").get(interpName); + if (auto interp = InterpolationType_from(interpName)) { + def.biomesInterpolation = *interp; + } + map.at("sea-level").get(def.seaLevel); map.at("wide-structs-chunks-radius").get(def.wideStructsChunksRadius); if (map.has("heightmap-inputs")) { diff --git a/src/maths/Heightmap.cpp b/src/maths/Heightmap.cpp index 99c27098..ab6ad153 100644 --- a/src/maths/Heightmap.cpp +++ b/src/maths/Heightmap.cpp @@ -5,6 +5,17 @@ #include #include +std::optional InterpolationType_from(std::string_view str) { + if (str == "nearest") { + return InterpolationType::NEAREST; + } else if (str == "linear") { + return InterpolationType::LINEAR; + } else if (str == "cubic") { + return InterpolationType::CUBIC; + } + return std::nullopt; +} + static inline float sample_at( const float* buffer, uint width, diff --git a/src/maths/Heightmap.hpp b/src/maths/Heightmap.hpp index 5f903756..37f5130d 100644 --- a/src/maths/Heightmap.hpp +++ b/src/maths/Heightmap.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "typedefs.hpp" #include "maths/Heightmap.hpp" @@ -12,6 +13,8 @@ enum class InterpolationType { CUBIC, }; +std::optional InterpolationType_from(std::string_view str); + class Heightmap { std::vector buffer; uint width, height; diff --git a/src/world/generator/GeneratorDef.hpp b/src/world/generator/GeneratorDef.hpp index f3abd893..b21a2425 100644 --- a/src/world/generator/GeneratorDef.hpp +++ b/src/world/generator/GeneratorDef.hpp @@ -209,6 +209,12 @@ struct GeneratorDef { /// @brief Heightmap blocks per dot uint heightsBPD = 4; + /// @brief Biome parameter maps interpolation method + InterpolationType biomesInterpolation = InterpolationType::LINEAR; + + /// @brief Height maps interpolation method + InterpolationType heightsInterpolation = InterpolationType::LINEAR; + /// @brief Number of chunks must be generated before and after wide /// structures placement triggered uint wideStructsChunksRadius = 3; diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index f585e71b..c0084df4 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -307,13 +307,13 @@ void WorldGenerator::generateBiomes( copy->resize( floordiv(CHUNK_W, def.heightsBPD) + 1, floordiv(CHUNK_D, def.heightsBPD) + 1, - InterpolationType::LINEAR + def.heightsInterpolation ); prototype.heightmapInputs.push_back(std::move(copy)); } for (const auto& map : biomeParams) { map->resize( - CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR + CHUNK_W + bpd, CHUNK_D + bpd, def.biomesInterpolation ); map->crop(0, 0, CHUNK_W, CHUNK_D); } @@ -345,7 +345,7 @@ void WorldGenerator::generateHeightmap( ); prototype.heightmap->clamp(); prototype.heightmap->resize( - CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR + CHUNK_W + bpd, CHUNK_D + bpd, def.heightsInterpolation ); prototype.heightmap->crop(0, 0, CHUNK_W, CHUNK_D); prototype.level = ChunkPrototypeLevel::HEIGHTMAP; From 7819a5cd6814e43db792e79673061b20f5b8b24f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 28 Oct 2024 10:03:08 +0300 Subject: [PATCH 2/3] add fragment:place & add 'fragment.place' command --- res/scripts/stdcmd.lua | 14 +++++++++++ .../scripting/lua/libs/libgeneration.cpp | 1 + .../lua/usertypes/lua_type_voxelfragment.cpp | 13 ++++++++++ src/world/generator/VoxelFragment.cpp | 24 +++++++++++++++++++ src/world/generator/VoxelFragment.hpp | 6 +++++ 5 files changed, 58 insertions(+) diff --git a/res/scripts/stdcmd.lua b/res/scripts/stdcmd.lua index a2edd9b8..c5b832b7 100644 --- a/res/scripts/stdcmd.lua +++ b/res/scripts/stdcmd.lua @@ -187,3 +187,17 @@ console.add_command( " has been saved as "..file.resolve(filename)) end ) + +console.add_command( + "fragment.place file:str x:num~pos.x y:num~pos.y z:num~pos.z rotation:int=0", + "Place fragment to the world", + function(args, kwargs) + local filename = args[1] + local x = args[2] + local y = args[3] + local z = args[4] + local rotation = args[5] + local fragment = generation.load_fragment(filename) + fragment:place({x, y, z}, rotation) + end +) diff --git a/src/logic/scripting/lua/libs/libgeneration.cpp b/src/logic/scripting/lua/libs/libgeneration.cpp index ca97815c..034f6597 100644 --- a/src/logic/scripting/lua/libs/libgeneration.cpp +++ b/src/logic/scripting/lua/libs/libgeneration.cpp @@ -45,6 +45,7 @@ static int l_load_fragment(lua::State* L) { auto fragment = std::make_shared(); fragment->deserialize(map); + fragment->prepare(*content); return lua::newuserdata(L, std::move(fragment)); } diff --git a/src/logic/scripting/lua/usertypes/lua_type_voxelfragment.cpp b/src/logic/scripting/lua/usertypes/lua_type_voxelfragment.cpp index eb6a24ab..f123be6f 100644 --- a/src/logic/scripting/lua/usertypes/lua_type_voxelfragment.cpp +++ b/src/logic/scripting/lua/usertypes/lua_type_voxelfragment.cpp @@ -4,6 +4,7 @@ #include "world/generator/VoxelFragment.hpp" #include "util/stringutil.hpp" +#include "world/Level.hpp" using namespace lua; @@ -20,8 +21,20 @@ static int l_crop(lua::State* L) { return 0; } +static int l_place(lua::State* L) { + if (auto fragment = touserdata(L, 1)) { + auto offset = tovec3(L, 2); + int rotation = tointeger(L, 3) & 0b11; + fragment->getFragment()->place( + *scripting::level->chunks, offset, rotation + ); + } + return 0; +} + static std::unordered_map methods { {"crop", lua::wrap}, + {"place", lua::wrap}, }; static int l_meta_tostring(lua::State* L) { diff --git a/src/world/generator/VoxelFragment.cpp b/src/world/generator/VoxelFragment.cpp index 832c1109..b6e65094 100644 --- a/src/world/generator/VoxelFragment.cpp +++ b/src/world/generator/VoxelFragment.cpp @@ -6,6 +6,7 @@ #include "data/dv_util.hpp" #include "content/Content.hpp" +#include "voxels/Chunks.hpp" #include "voxels/Block.hpp" #include "voxels/ChunksStorage.hpp" #include "voxels/VoxelsVolume.hpp" @@ -168,6 +169,29 @@ void VoxelFragment::prepare(const Content& content) { } } +void VoxelFragment::place( + Chunks& chunks, const glm::ivec3& offset, ubyte rotation +) { + auto& structVoxels = getRuntimeVoxels(); + for (int y = 0; y < size.y; y++) { + int sy = y + offset.y; + if (sy < 0 || sy >= CHUNK_H) { + continue; + } + for (int z = 0; z < size.z; z++) { + int sz = z + offset.z; + for (int x = 0; x < size.x; x++) { + int sx = x + offset.x; + const auto& structVoxel = + structVoxels[vox_index(x, y, z, size.x, size.z)]; + if (structVoxel.id) { + chunks.set(sx, sy, sz, structVoxel.id, structVoxel.state); + } + } + } + } +} + std::unique_ptr VoxelFragment::rotated(const Content& content) const { std::vector newVoxels(voxels.size()); diff --git a/src/world/generator/VoxelFragment.hpp b/src/world/generator/VoxelFragment.hpp index 95a5375b..701cac0e 100644 --- a/src/world/generator/VoxelFragment.hpp +++ b/src/world/generator/VoxelFragment.hpp @@ -10,6 +10,7 @@ inline constexpr int STRUCTURE_FORMAT_VERSION = 1; class Level; class Content; +class Chunks; class VoxelFragment : public Serializable { glm::ivec3 size; @@ -41,6 +42,11 @@ public: /// @param content world content void prepare(const Content& content); + /// @brief Place fragment to the world + /// @param offset target location + /// @param rotation rotation index + void place(Chunks& chunks, const glm::ivec3& offset, ubyte rotation); + /// @brief Create structure copy rotated 90 deg. clockwise std::unique_ptr rotated(const Content& content) const; From 016336ee4da46c702bde332a3bbb8ab05ce45928 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 28 Oct 2024 10:07:56 +0300 Subject: [PATCH 3/3] update doc/*/world-generator.md --- doc/en/world-generator.md | 10 +++++++++- doc/ru/world-generator.md | 10 +++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/doc/en/world-generator.md b/doc/en/world-generator.md index b6e053ac..47f46b80 100644 --- a/doc/en/world-generator.md +++ b/doc/en/world-generator.md @@ -351,7 +351,15 @@ generation.save_fragment( The fragment size is available as the `size` property. -A fragment can be cropped to fit its contents (air is ignored) by calling the `fragment:crop()` method. +### Methods + +```lua +-- Crop a fragment to content +fragment:crop() + +-- Set a fragment to the world at the specified position +fragment:place(position: vec3, [optional] rotation:int=0) +``` ## Generating a height map diff --git a/doc/ru/world-generator.md b/doc/ru/world-generator.md index 5ccdbc68..284ea067 100644 --- a/doc/ru/world-generator.md +++ b/doc/ru/world-generator.md @@ -355,7 +355,15 @@ generation.save_fragment( Размер фрагмента доступен как свойство `size`. -Фрагмент может быть обрезан до размеров содержимого (воздух игнорируется) вызовом метода `fragment:crop()`. +### Методы + +```lua +-- Обрезает фрагмент до размеров содержимого +fragment:crop() + +-- Устанавливает фрагмент в мир на указанной позиции +fragment:place(position: vec3, [опционально] rotation:int=0) +``` ## Генерация карты высот