diff --git a/res/content/base/generators/demo.files/script.lua b/res/content/base/generators/demo.files/script.lua index 8a108964..73c4698d 100644 --- a/res/content/base/generators/demo.files/script.lua +++ b/res/content/base/generators/demo.files/script.lua @@ -11,7 +11,7 @@ function place_structures(x, z, w, d, seed, hmap) return placements end -local function _generate_heightmap(x, y, w, h, seed, s) +function generate_heightmap(x, y, w, h, seed, s) local umap = Heightmap(w, h) local vmap = Heightmap(w, h) umap.noiseSeed = seed @@ -37,18 +37,7 @@ local function _generate_heightmap(x, y, w, h, seed, s) return map end -function generate_heightmap(x, y, w, h, seed) - -- blocks per dot - local bpd = 4 - local map = _generate_heightmap( - math.floor(x/bpd), math.floor(y/bpd), - math.floor(w/bpd)+1, math.floor(h/bpd)+1, seed, bpd) - map:resize(w+bpd, h+bpd, 'linear') - map:crop(0, 0, w, h) - return map -end - -local function _generate_biome_parameters(x, y, w, h, seed, s) +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) @@ -59,16 +48,3 @@ local function _generate_biome_parameters(x, y, w, h, seed, s) hummap:pow(3) return tempmap, hummap end - -function generate_biome_parameters(x, y, w, h, seed) - local bpd = 8 - local tmap, hmap = _generate_biome_parameters( - math.floor(x/bpd), math.floor(y/bpd), - math.floor(w/bpd)+1, math.floor(h/bpd)+1, seed, bpd) - tmap:resize(w+bpd, h+bpd, 'linear') - tmap:crop(0, 0, w, h) - - hmap:resize(w+bpd, h+bpd, 'linear') - hmap:crop(0, 0, w, h) - return tmap, hmap -end diff --git a/src/content/loading/GeneratorLoader.cpp b/src/content/loading/GeneratorLoader.cpp index 90cbc4c1..2657ddd1 100644 --- a/src/content/loading/GeneratorLoader.cpp +++ b/src/content/loading/GeneratorLoader.cpp @@ -127,13 +127,13 @@ static VoxelStructureMeta load_structure_meta( return meta; } -static std::vector> load_structures( +static std::vector> load_structures( const fs::path& structuresFile ) { auto structuresDir = structuresFile.parent_path() / fs::path("fragments"); auto map = files::read_json(structuresFile); - std::vector> structures; + std::vector> structures; for (auto& [name, config] : map.asObject()) { auto structFile = structuresDir / fs::u8path(name + ".vox"); logger.debug() << "loading voxel fragment " << structFile.u8string(); @@ -144,7 +144,7 @@ static std::vector> load_structures( auto fragment = std::make_unique(); fragment->deserialize(files::read_binary_json(structFile)); - structures.push_back(std::make_unique( + structures.push_back(std::make_unique( load_structure_meta(name, config), std::move(fragment) )); @@ -193,6 +193,8 @@ void ContentLoader::loadGenerator( } auto map = files::read_toml(generatorsDir / fs::u8path(name + ".toml")); map.at("biome_parameters").get(def.biomeParameters); + map.at("biome-bpd").get(def.biomesBPD); + map.at("heights-bpd").get(def.heightsBPD); map.at("sea_level").get(def.seaLevel); auto folder = generatorsDir / fs::u8path(name + ".files"); diff --git a/src/logic/scripting/scripting_world_generation.cpp b/src/logic/scripting/scripting_world_generation.cpp index a68f4277..ff7175a0 100644 --- a/src/logic/scripting/scripting_world_generation.cpp +++ b/src/logic/scripting/scripting_world_generation.cpp @@ -26,7 +26,7 @@ public: {} std::shared_ptr generateHeightmap( - const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed + const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, uint bpd ) override { auto L = lua::get_main_thread(); lua::pushenv(L, *env); @@ -34,7 +34,8 @@ public: lua::pushivec_stack(L, offset); lua::pushivec_stack(L, size); lua::pushinteger(L, seed); - if (lua::call_nothrow(L, 5)) { + lua::pushinteger(L, bpd); + if (lua::call_nothrow(L, 6)) { auto map = lua::touserdata(L, -1)->getHeightmap(); lua::pop(L, 2); return map; @@ -45,7 +46,7 @@ public: } std::vector> generateParameterMaps( - const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed + const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, uint bpd ) override { std::vector> maps; @@ -56,7 +57,8 @@ public: lua::pushivec_stack(L, offset); lua::pushivec_stack(L, size); lua::pushinteger(L, seed); - if (lua::call_nothrow(L, 5, biomeParameters)) { + lua::pushinteger(L, bpd); + if (lua::call_nothrow(L, 6, biomeParameters)) { for (int i = biomeParameters-1; i >= 0; i--) { maps.push_back( lua::touserdata(L, -1-i)->getHeightmap()); diff --git a/src/world/generator/GeneratorDef.cpp b/src/world/generator/GeneratorDef.cpp index c372cde4..515d27e7 100644 --- a/src/world/generator/GeneratorDef.cpp +++ b/src/world/generator/GeneratorDef.cpp @@ -5,7 +5,7 @@ #include "util/stringutil.hpp" #include "voxels/Block.hpp" -GeneratingVoxelStructure::GeneratingVoxelStructure( +VoxelStructure::VoxelStructure( VoxelStructureMeta meta, std::unique_ptr structure ) : fragments({std::move(structure)}), meta(std::move(meta)) {} diff --git a/src/world/generator/GeneratorDef.hpp b/src/world/generator/GeneratorDef.hpp index 7209b4c4..02d9bc69 100644 --- a/src/world/generator/GeneratorDef.hpp +++ b/src/world/generator/GeneratorDef.hpp @@ -123,27 +123,51 @@ class GeneratorScript { public: virtual ~GeneratorScript() = default; - /// @brief Generates a heightmap with values in range 0..1 + /// @brief Generate a heightmap with values in range 0..1 /// @param offset position of the heightmap in the world /// @param size size of the heightmap /// @param seed world seed - /// @return generated heightmap of given size (can't be nullptr) + /// @param bpd blocks per dot + /// @return generated heightmap (can't be nullptr) virtual std::shared_ptr generateHeightmap( - const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0; + const glm::ivec2& offset, + const glm::ivec2& size, + uint64_t seed, + uint bpd + ) = 0; + /// @brief Generate a biomes parameters maps + /// @param offset position of maps in the world + /// @param size maps size + /// @param seed world seed + /// @param bpd blocks per dot + /// @return generated maps (can't be nullptr) virtual std::vector> generateParameterMaps( - const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed) = 0; + const glm::ivec2& offset, + const glm::ivec2& size, + uint64_t seed, + uint bpd + ) = 0; + /// @brief Generate a list of structures placements. Structures may be + /// placed to nearest chunks also (position of out area). + /// @param offset position of the area + /// @param size size of the area (blocks) + /// @param seed world seed + /// @param heightmap area heightmap + /// @return structure placements virtual std::vector placeStructures( const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, const std::shared_ptr& heightmap) = 0; }; -struct GeneratingVoxelStructure { +/// @brief Structure voxel fragments and metadata +struct VoxelStructure { VoxelStructureMeta meta; + /// @brief voxel fragment and 3 pre-calculated rotated versions std::array, 4> fragments; - GeneratingVoxelStructure( + VoxelStructure( VoxelStructureMeta meta, std::unique_ptr structure ); @@ -161,8 +185,14 @@ struct GeneratorDef { /// @brief Number of biome parameters, that biome choosing depending on uint biomeParameters = 0; + /// @brief Biome parameter map blocks per dot + uint biomesBPD = 8; + + /// @brief Heightmap blocks per dot + uint heightsBPD = 4; + std::unordered_map structuresIndices; - std::vector> structures; + std::vector> structures; std::vector biomes; GeneratorDef(std::string name); diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index 6c54cb65..b70fae35 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -10,6 +10,7 @@ #include "VoxelFragment.hpp" #include "util/timeutil.hpp" #include "util/listutil.hpp" +#include "maths/voxmaths.hpp" #include "debug/Logger.hpp" static debug::Logger logger("world-generator"); @@ -229,8 +230,19 @@ void WorldGenerator::generateBiomes( if (prototype.level >= ChunkPrototypeLevel::BIOMES) { return; } + uint bpd = def.biomesBPD; auto biomeParams = def.script->generateParameterMaps( - {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed); + {floordiv(chunkX * CHUNK_W, bpd), floordiv(chunkZ * CHUNK_D, bpd)}, + {floordiv(CHUNK_W, bpd)+1, floordiv(CHUNK_D, bpd)+1}, + seed, + bpd + ); + for (const auto& map : biomeParams) { + map->resize( + CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR + ); + map->crop(0, 0, CHUNK_W, CHUNK_D); + } const auto& biomes = def.biomes; auto chunkBiomes = std::make_unique(CHUNK_W*CHUNK_D); @@ -250,8 +262,17 @@ void WorldGenerator::generateHeightmap( if (prototype.level >= ChunkPrototypeLevel::HEIGHTMAP) { return; } + uint bpd = def.heightsBPD; prototype.heightmap = def.script->generateHeightmap( - {chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed); + {floordiv(chunkX * CHUNK_W, bpd), floordiv(chunkZ * CHUNK_D, bpd)}, + {floordiv(CHUNK_W, bpd)+1, floordiv(CHUNK_D, bpd)+1}, + seed, + bpd + ); + prototype.heightmap->resize( + CHUNK_W + bpd, CHUNK_D + bpd, InterpolationType::LINEAR + ); + prototype.heightmap->crop(0, 0, CHUNK_W, CHUNK_D); prototype.level = ChunkPrototypeLevel::HEIGHTMAP; }