From 59c4e26eda48609c3aaa5cbecce42c6b884a6e06 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 16 Oct 2024 00:38:58 +0300 Subject: [PATCH] feat: heightmap-inputs --- .../base/generators/demo.files/biomes.toml | 10 +++++----- .../base/generators/demo.files/script.lua | 10 +++++++++- res/content/base/generators/demo.toml | 1 + src/content/loading/GeneratorLoader.cpp | 15 ++++++++++++++- .../scripting/scripting_world_generation.cpp | 16 ++++++++++++++-- src/maths/Heightmap.cpp | 6 ++++++ src/maths/Heightmap.hpp | 2 ++ src/world/generator/GeneratorDef.hpp | 9 +++++++-- src/world/generator/WorldGenerator.cpp | 18 +++++++++++++++--- src/world/generator/WorldGenerator.hpp | 3 +++ 10 files changed, 76 insertions(+), 14 deletions(-) diff --git a/res/content/base/generators/demo.files/biomes.toml b/res/content/base/generators/demo.files/biomes.toml index bd2e11e8..70305655 100644 --- a/res/content/base/generators/demo.files/biomes.toml +++ b/res/content/base/generators/demo.files/biomes.toml @@ -1,6 +1,6 @@ [forest] parameters = [ - {weight=1, value=1}, + {weight=1, value=0}, {weight=0.5, value=0.2} ] layers = [ @@ -28,8 +28,8 @@ structures = [ [desert] parameters = [ - {weight=0.3, value=0}, - {weight=0.1, value=0} + {weight=1.0, value=1}, + {weight=0.5, value=0} ] layers = [ {height=6, block="base:sand"}, @@ -43,8 +43,8 @@ sea-layers = [ [plains] parameters = [ - {weight=0.6, value=0.5}, - {weight=0.6, value=0.5} + {weight=0.8, value=0.5}, + {weight=0.8, value=0.0} ] layers = [ {below-sea-level=false, height=1, block="base:grass_block"}, diff --git a/res/content/base/generators/demo.files/script.lua b/res/content/base/generators/demo.files/script.lua index 7596d226..ffec458d 100644 --- a/res/content/base/generators/demo.files/script.lua +++ b/res/content/base/generators/demo.files/script.lua @@ -43,7 +43,7 @@ function place_structures_wide(x, z, w, d, seed, chunk_height) return placements end -function generate_heightmap(x, y, w, h, seed, s) +function generate_heightmap(x, y, w, h, seed, s, inputs) local umap = Heightmap(w, h) local vmap = Heightmap(w, h) umap.noiseSeed = seed @@ -65,6 +65,12 @@ function generate_heightmap(x, y, w, h, seed, s) rivermap:pow(0.15) rivermap:max(0.5) map:mul(rivermap) + + local desertmap = Heightmap(w, h) + desertmap.noiseSeed = seed + desertmap:cellnoise({x+52, y+326}, 0.3*s, 2, 0.2) + desertmap:add(0.4) + map:mixin(desertmap, inputs[1]) return map end @@ -72,6 +78,8 @@ function generate_biome_parameters(x, y, w, h, seed, s) local tempmap = Heightmap(w, h) tempmap.noiseSeed = seed + 5324 tempmap:noise({x, y}, 0.04*s, 6) + tempmap:mul(0.5) + tempmap:add(0.5) local hummap = Heightmap(w, h) hummap.noiseSeed = seed + 953 hummap:noise({x, y}, 0.04*s, 6) diff --git a/res/content/base/generators/demo.toml b/res/content/base/generators/demo.toml index f9952f61..43def20e 100644 --- a/res/content/base/generators/demo.toml +++ b/res/content/base/generators/demo.toml @@ -2,3 +2,4 @@ # 2 - humidity biome-parameters = 2 sea-level = 64 +heightmap-inputs = [1] diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index fcbcebc5..c2f1bb26 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -202,7 +202,20 @@ void ContentLoader::loadGenerator( map.at("heights-bpd").get(def.heightsBPD); map.at("sea-level").get(def.seaLevel); map.at("wide-structs-chunks-radius").get(def.wideStructsChunksRadius); - + if (map.has("heightmap-inputs")) { + for (const auto& element : map["heightmap-inputs"]) { + int index = element.asInteger(); + if (index <= 0 || index > def.biomeParameters) { + throw std::runtime_error( + "invalid biome parameter index " + std::to_string(index)); + } + def.heightmapInputs.push_back(index - 1); + } + } + if (!def.heightmapInputs.empty() && def.biomesBPD != def.heightsBPD) { + logger.warning() << "generator has heightmap-inputs but biomes-bpd " + "is not equal to heights-bpd, generator will work slower!"; + } auto folder = generatorsDir / fs::u8path(name + ".files"); auto scriptFile = folder / fs::u8path("script.lua"); diff --git a/src/logic/scripting/scripting_world_generation.cpp b/src/logic/scripting/scripting_world_generation.cpp index a1865e48..caa08d6c 100644 --- a/src/logic/scripting/scripting_world_generation.cpp +++ b/src/logic/scripting/scripting_world_generation.cpp @@ -38,7 +38,11 @@ public: } std::shared_ptr generateHeightmap( - const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, uint bpd + const glm::ivec2& offset, + const glm::ivec2& size, + uint64_t seed, + uint bpd, + const std::vector>& inputs ) override { pushenv(L, *env); if (getfield(L, "generate_heightmap")) { @@ -46,7 +50,15 @@ public: pushivec_stack(L, size); pushinteger(L, seed); pushinteger(L, bpd); - if (call_nothrow(L, 6)) { + if (!inputs.empty()) { + size_t inputsNum = def.heightmapInputs.size(); + createtable(L, inputsNum, 0); + for (size_t i = 0; i < inputsNum; i++) { + newuserdata(L, inputs[i]); + rawseti(L, i+1); + } + } + if (call_nothrow(L, 6 + (!inputs.empty()))) { auto map = touserdata(L, -1)->getHeightmap(); pop(L, 2); return map; diff --git a/src/maths/Heightmap.cpp b/src/maths/Heightmap.cpp index d3b048de..8db33f6b 100644 --- a/src/maths/Heightmap.cpp +++ b/src/maths/Heightmap.cpp @@ -105,3 +105,9 @@ void Heightmap::crop( height = dstheight; buffer = std::move(dst); } + +void Heightmap::clamp() { + for (uint i = 0; i < width * height; i++) { + buffer[i] = std::min(1.0f, std::max(0.0f, buffer[i])); + } +} diff --git a/src/maths/Heightmap.hpp b/src/maths/Heightmap.hpp index 8e7e5594..5f903756 100644 --- a/src/maths/Heightmap.hpp +++ b/src/maths/Heightmap.hpp @@ -30,6 +30,8 @@ public: void crop(uint srcX, uint srcY, uint dstWidth, uint dstHeight); + void clamp(); + uint getWidth() const { return width; } diff --git a/src/world/generator/GeneratorDef.hpp b/src/world/generator/GeneratorDef.hpp index d978a41c..3a1e110b 100644 --- a/src/world/generator/GeneratorDef.hpp +++ b/src/world/generator/GeneratorDef.hpp @@ -128,12 +128,14 @@ public: /// @param size size of the heightmap /// @param seed world seed /// @param bpd blocks per dot + /// @param inputs biome parameter maps passed to generate_heightmap /// @return generated heightmap (can't be nullptr) virtual std::shared_ptr generateHeightmap( const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, - uint bpd + uint bpd, + const std::vector>& inputs ) = 0; /// @brief Generate a biomes parameters maps @@ -207,12 +209,15 @@ struct GeneratorDef { uint biomesBPD = 8; /// @brief Heightmap blocks per dot - uint heightsBPD = 4; + uint heightsBPD = 8; /// @brief Number of chunks must be generated before and after wide /// structures placement triggered uint wideStructsChunksRadius = 3; + /// @brief Indices of biome parameter maps passed to generate_heightmap + std::vector heightmapInputs; + std::unordered_map structuresIndices; std::vector> structures; std::vector biomes; diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index b0236ec2..7fb699f6 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -300,6 +300,16 @@ void WorldGenerator::generateBiomes( seed, bpd ); + for (auto index : def.heightmapInputs) { + // copy non-scaled maps + auto copy = std::make_shared(*biomeParams[index]); + copy->resize( + floordiv(CHUNK_W, def.heightsBPD) + 1, + floordiv(CHUNK_D, def.heightsBPD) + 1, + InterpolationType::LINEAR + ); + prototype.heightmapInputs.push_back(std::move(copy)); + } for (const auto& map : biomeParams) { map->resize( CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR @@ -330,8 +340,10 @@ void WorldGenerator::generateHeightmap( {floordiv(chunkX * CHUNK_W, bpd), floordiv(chunkZ * CHUNK_D, bpd)}, {floordiv(CHUNK_W, bpd)+1, floordiv(CHUNK_D, bpd)+1}, seed, - bpd + bpd, + prototype.heightmapInputs ); + prototype.heightmap->clamp(); prototype.heightmap->resize( CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR ); @@ -363,9 +375,9 @@ void WorldGenerator::generatePlants( const Biome* biome = biomes[z * CHUNK_W + x]; int height = heights[z * CHUNK_W + x] * CHUNK_H; - height = std::max(0, height); + height = std::min(std::max(0, height), CHUNK_H-1); - if (height+1 > def.seaLevel) { + if (height+1 > def.seaLevel && height+1 < CHUNK_H) { float rand = plantsRand.randFloat(); blockid_t plant = biome->plants.choose(rand); if (plant) { diff --git a/src/world/generator/WorldGenerator.hpp b/src/world/generator/WorldGenerator.hpp index fa8a51e0..285f0ed6 100644 --- a/src/world/generator/WorldGenerator.hpp +++ b/src/world/generator/WorldGenerator.hpp @@ -32,6 +32,9 @@ struct ChunkPrototype { std::shared_ptr heightmap; std::vector placements; + + /// @brief biome parameters maps saved until heightmaps generation + std::vector> heightmapInputs {}; }; struct WorldGenDebugInfo {