From 8fb0f6a1bbe8dacb815921dfdf9360972582158f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 18 Aug 2024 00:08:36 +0300 Subject: [PATCH] add basic heightmaps generator optimization --- res/generators/default.lua | 39 +++++++++++++------ .../scripting/lua/lua_type_heightmap.cpp | 14 +++++++ src/maths/Heightmap.cpp | 30 ++++++++++++++ src/maths/Heightmap.hpp | 2 + src/world/generator/WorldGenerator.cpp | 1 + 5 files changed, 74 insertions(+), 12 deletions(-) diff --git a/res/generators/default.lua b/res/generators/default.lua index 38c33ed0..22f7e9a0 100644 --- a/res/generators/default.lua +++ b/res/generators/default.lua @@ -7,34 +7,49 @@ layers = { {block="base:bazalt", height=1}, } -function generate_heightmap(x, y, w, h, seed) +local function _generate_heightmap(x, y, w, h, seed, s) local umap = Heightmap(w, h) local vmap = Heightmap(w, h) umap.noiseSeed = seed vmap.noiseSeed = seed - umap:noise({x+521, y+73}, 0.05, 1, 20.8) - umap:noise({x+51, y+75}, 0.05, 1, 21.8) - vmap:noise({x+521, y+70}, 0.1, 3, 35.8) - vmap:noise({x+95, y+246}, 0.15, 3, 35.8) + vmap:noise({x+521, y+70}, 0.1*s, 3, 25.8) + vmap:noise({x+95, y+246}, 0.15*s, 3, 25.8) local map = Heightmap(w, h) map.noiseSeed = seed - map:noise({x, y}, 0.02, 7, 0.2) - map:noise({x, y}, 0.06, 8, 0.4, umap, vmap) + map:noise({x, y}, 0.8*s, 4, 0.04) + map:cellnoise({x, y}, 0.1*s, 3, 0.7, umap, vmap) map:mul(0.5) - map:add(0.1) - map:pow(2.0) + map:add(0.3) local rivermap = Heightmap(w, h) rivermap.noiseSeed = seed - rivermap:noise({x+21, y+12}, 0.1, 4) + rivermap:noise({x+21, y+12}, 0.1*s, 4) rivermap:abs() rivermap:mul(2.0) - rivermap:pow(0.4) + rivermap:pow(0.3) rivermap:max(0.6) map:add(0.4) map:mul(rivermap) - map:add(-0.2) + map:add(-0.15) return map end + +function generate_heightmap(x, y, w, h, seed) + -- blocks per dot + -- 8 - linear interpolation is visible, but not so much (Minecraft) + -- 4 - high quality, but slower + -- 2 - you really don't need it + -- 1 - please have mercy on your CPU + local bpd = 8 + 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 map = generate_heightmap(0, 0, 1024, 1024, 0) +map:dump("heightmap.png") diff --git a/src/logic/scripting/lua/lua_type_heightmap.cpp b/src/logic/scripting/lua/lua_type_heightmap.cpp index ebc58952..e5fd46ac 100644 --- a/src/logic/scripting/lua/lua_type_heightmap.cpp +++ b/src/logic/scripting/lua/lua_type_heightmap.cpp @@ -166,6 +166,19 @@ static int l_resize(lua::State* L) { return 0; } +static int l_crop(lua::State* L) { + if (auto heightmap = touserdata(L, 1)) { + uint srcX = touinteger(L, 2); + uint srcY = touinteger(L, 3); + + uint dstWidth = touinteger(L, 4); + uint dstHeight = touinteger(L, 5); + + heightmap->getHeightmap()->crop(srcX, srcY, dstWidth, dstHeight); + } + return 0; +} + static std::unordered_map methods { {"dump", lua::wrap}, {"noise", lua::wrap>}, @@ -177,6 +190,7 @@ static std::unordered_map methods { {"max", lua::wrap>}, {"abs", lua::wrap>}, {"resize", lua::wrap}, + {"crop", lua::wrap}, }; static int l_meta_meta_call(lua::State* L) { diff --git a/src/maths/Heightmap.cpp b/src/maths/Heightmap.cpp index 5b7996a7..165c0040 100644 --- a/src/maths/Heightmap.cpp +++ b/src/maths/Heightmap.cpp @@ -1,6 +1,7 @@ #include "Heightmap.hpp" #include +#include #include #include @@ -59,6 +60,9 @@ static inline float sample_at( void Heightmap::resize( uint dstwidth, uint dstheight, InterpolationType interp ) { + if (width == dstwidth && height == dstheight) { + return; + } std::vector dst; dst.resize(dstwidth*dstheight); @@ -75,3 +79,29 @@ void Heightmap::resize( height = dstheight; buffer = std::move(dst); } + +void Heightmap::crop( + uint srcx, uint srcy, uint dstwidth, uint dstheight +) { + if (srcx + dstwidth > width || srcy + dstheight > height) { + throw std::runtime_error( + "crop zone is not fully inside of the source image"); + } + if (dstwidth == width && dstheight == height) { + return; + } + + std::vector dst; + dst.resize(dstwidth*dstheight); + + for (uint y = 0; y < dstheight; y++) { + std::memcpy( + dst.data()+y*dstwidth, + buffer.data()+(y+srcy)*width+srcx, + dstwidth*sizeof(float)); + } + + width = dstwidth; + height = dstheight; + buffer = std::move(dst); +} diff --git a/src/maths/Heightmap.hpp b/src/maths/Heightmap.hpp index f8185f4c..5b9f4cfa 100644 --- a/src/maths/Heightmap.hpp +++ b/src/maths/Heightmap.hpp @@ -27,6 +27,8 @@ public: void resize(uint width, uint height, InterpolationType interpolation); + void crop(uint srcX, uint srcY, uint dstWidth, uint dstHeight); + uint getWidth() const { return width; } diff --git a/src/world/generator/WorldGenerator.cpp b/src/world/generator/WorldGenerator.cpp index d92050a8..fa25d49d 100644 --- a/src/world/generator/WorldGenerator.cpp +++ b/src/world/generator/WorldGenerator.cpp @@ -34,6 +34,7 @@ void WorldGenerator::generate( for (uint x = 0; x < CHUNK_W; x++) { // generate water int height = values[z * CHUNK_W + x] * CHUNK_H; + height = std::max(0, height); for (uint y = height+1; y <= seaLevel; y++) { voxels[vox_index(x, y, z)].id = baseWater; }