diff --git a/res/scripts/world.lua b/res/scripts/world.lua index 964100e7..a63f8ee1 100644 --- a/res/scripts/world.lua +++ b/res/scripts/world.lua @@ -1,3 +1,48 @@ -- use for engine development tests -- must be empty in release -- must not be modified by content-packs + +local W = 16 +local H = 16 + +for t=1,1 do + local tm = time.uptime() + + local umap = Heightmap(W, H) + local vmap = Heightmap(W, H) + umap:noise({521, 73}, 0.2, 1, 11.8) + umap:noise({51, 73}, 0.2, 1, 11.8) + umap:noise({521, 73}, 0.4, 6, 5.8) + vmap:noise({95, 246}, 0.6, 6, 5.8) + + local bmap = Heightmap(W, H) + bmap:noise({3, 6}, 0.1, 1, 3) + local map = Heightmap(W, H) + + + map:noise({0, 0}, 0.06, 4, 0.2, umap, vmap) + map:noise({0, 0}, 0.25, 6, 0.5, umap, vmap) + map:mul(bmap) + map:mul(0.7) + + local rivermap = Heightmap(W, H) + rivermap:noise({21, 12}, 0.05, 3) + rivermap:abs() + rivermap:min(0.02) + rivermap:mul(50.0) + rivermap:pow(0.4) + map:add(1.7) + map:mul(rivermap) + map:add(-1.0) + map:mul(0.5) + + local overmap = Heightmap(W, H) + overmap:noise({1, 5122}, 0.02, 2, 0.2) + overmap:abs() + overmap:pow(0.5) + overmap:mul(-1.0) + map:add(overmap) + + print(math.floor((time.uptime() - tm) * 1000000).." mcs") + map:dump("heightmap.png") +end diff --git a/src/logic/scripting/lua/lua_custom_types.hpp b/src/logic/scripting/lua/lua_custom_types.hpp index b9d6f5ef..885052ce 100644 --- a/src/logic/scripting/lua/lua_custom_types.hpp +++ b/src/logic/scripting/lua/lua_custom_types.hpp @@ -49,6 +49,14 @@ namespace lua { return TYPENAME; } + float* getValues() { + return buffer.data(); + } + + const float* getValues() const { + return buffer.data(); + } + static int createMetatable(lua::State*); inline static std::string TYPENAME = "heightmap"; }; diff --git a/src/logic/scripting/lua/lua_type_bytearray.cpp b/src/logic/scripting/lua/lua_type_bytearray.cpp index 9c81c380..cf41f318 100644 --- a/src/logic/scripting/lua/lua_type_bytearray.cpp +++ b/src/logic/scripting/lua/lua_type_bytearray.cpp @@ -53,7 +53,7 @@ static int l_remove(lua::State* L) { return 0; } -static std::unordered_map bytearray_methods { +static std::unordered_map methods { {"append", lua::wrap}, {"insert", lua::wrap}, {"remove", lua::wrap}, @@ -85,8 +85,8 @@ static int l_meta_index(lua::State* L) { } auto& data = buffer->data(); if (isstring(L, 2)) { - auto found = bytearray_methods.find(tostring(L, 2)); - if (found != bytearray_methods.end()) { + auto found = methods.find(tostring(L, 2)); + if (found != methods.end()) { return pushcfunction(L, found->second); } } diff --git a/src/logic/scripting/lua/lua_type_heightmap.cpp b/src/logic/scripting/lua/lua_type_heightmap.cpp index 253d56f7..e53ecb48 100644 --- a/src/logic/scripting/lua/lua_type_heightmap.cpp +++ b/src/logic/scripting/lua/lua_type_heightmap.cpp @@ -3,11 +3,17 @@ #include #include #include +#include +#include "maths/FastNoiseLite.h" +#include "coders/png.hpp" +#include "graphics/core/ImageData.hpp" #include "lua_util.hpp" using namespace lua; +static fnl_state noise = fnlCreateState(); + Heightmap::Heightmap(uint width, uint height) : width(width), height(height) { buffer.resize(width*height); } @@ -15,6 +21,230 @@ Heightmap::Heightmap(uint width, uint height) : width(width), height(height) { Heightmap::~Heightmap() { } +static int l_dump(lua::State* L) { + if (auto heightmap = touserdata(L, 1)) { + auto filename = tostring(L, 2); + uint w = heightmap->getWidth(); + uint h = heightmap->getHeight(); + ImageData image(ImageFormat::rgb888, w, h); + auto heights = heightmap->getValues(); + auto raster = image.getData(); + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + int val = heights[i] * 127 + 128; + val = std::max(std::min(val, 255), 0); + raster[i*3] = val; + raster[i*3 + 1] = val; + raster[i*3 + 2] = val; + } + } + png::write_image(filename, &image); + } + return 0; +} + +static int l_noise(lua::State* L) { + if (auto heightmap = touserdata(L, 1)) { + uint w = heightmap->getWidth(); + uint h = heightmap->getHeight(); + auto heights = heightmap->getValues(); + + auto offset = tovec<2>(L, 2); + + float s = tonumber(L, 3); + int octaves = 1; + float multiplier = 1.0f; + if (gettop(L) > 3) { + octaves = tointeger(L, 4); + } + if (gettop(L) > 4) { + multiplier = tonumber(L, 5); + } + const Heightmap* shiftMapX = nullptr; + const Heightmap* shiftMapY = nullptr; + if (gettop(L) > 5) { + shiftMapX = touserdata(L, 6); + } + if (gettop(L) > 6) { + shiftMapY = touserdata(L, 7); + } + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + for (uint c = 0; c < octaves; c++) { + float m = s * (1 << c); + float value = heights[i]; + float u = (x + offset.x) * m; + float v = (y + offset.y) * m; + if (shiftMapX) { + u += shiftMapX->getValues()[i]; + } + if (shiftMapY) { + v += shiftMapY->getValues()[i]; + } + + value += fnlGetNoise2D(&noise, u, v) / + static_cast(1 << c) * multiplier; + heights[i] = value; + } + } + } + } + return 0; +} + +static int l_pow(lua::State* L) { + if (auto heightmap = touserdata(L, 1)) { + uint w = heightmap->getWidth(); + uint h = heightmap->getHeight(); + auto heights = heightmap->getValues(); + float power = tonumber(L, 2); + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + heights[i] = glm::pow(heights[i], power); + } + } + } + return 0; +} + +static int l_add(lua::State* L) { + if (auto heightmap = touserdata(L, 1)) { + uint w = heightmap->getWidth(); + uint h = heightmap->getHeight(); + auto heights = heightmap->getValues(); + + if (isnumber(L, 2)) { + float scalar = tonumber(L, 2); + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + heights[i] += scalar; + } + } + } else { + auto map = touserdata(L, 2); + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + heights[i] += map->getValues()[i]; + } + } + } + } + return 0; +} + +static int l_mul(lua::State* L) { + if (auto heightmap = touserdata(L, 1)) { + uint w = heightmap->getWidth(); + uint h = heightmap->getHeight(); + auto heights = heightmap->getValues(); + + if (isnumber(L, 2)) { + float scalar = tonumber(L, 2); + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + heights[i] *= scalar; + } + } + } else { + auto map = touserdata(L, 2); + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + heights[i] *= map->getValues()[i]; + } + } + } + } + return 0; +} + +static int l_max(lua::State* L) { + if (auto heightmap = touserdata(L, 1)) { + uint w = heightmap->getWidth(); + uint h = heightmap->getHeight(); + auto heights = heightmap->getValues(); + + if (isnumber(L, 2)) { + float scalar = tonumber(L, 2); + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + heights[i] *= scalar; + } + } + } else { + auto map = touserdata(L, 2); + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + heights[i] = glm::max(map->getValues()[i], heights[i]); + } + } + } + } + return 0; +} + +static int l_min(lua::State* L) { + if (auto heightmap = touserdata(L, 1)) { + uint w = heightmap->getWidth(); + uint h = heightmap->getHeight(); + auto heights = heightmap->getValues(); + + if (isnumber(L, 2)) { + float scalar = tonumber(L, 2); + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + heights[i] *= scalar; + } + } + } else { + auto map = touserdata(L, 2); + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + heights[i] = glm::min(map->getValues()[i], heights[i]); + } + } + } + } + return 0; +} + +static int l_abs(lua::State* L) { + if (auto heightmap = touserdata(L, 1)) { + uint w = heightmap->getWidth(); + uint h = heightmap->getHeight(); + auto heights = heightmap->getValues(); + float power = tonumber(L, 2); + for (uint y = 0; y < h; y++) { + for (uint x = 0; x < w; x++) { + uint i = y * w + x; + heights[i] = glm::abs(heights[i]); + } + } + } + return 0; +} + +static std::unordered_map methods { + {"dump", lua::wrap}, + {"noise", lua::wrap}, + {"pow", lua::wrap}, + {"add", lua::wrap}, + {"mul", lua::wrap}, + {"min", lua::wrap}, + {"max", lua::wrap}, + {"abs", lua::wrap}, +}; + static int l_meta_meta_call(lua::State* L) { auto width = tointeger(L, 2); auto height = tointeger(L, 3); @@ -37,6 +267,11 @@ static int l_meta_index(lua::State* L) { return pushinteger(L, map->getWidth()); } else if (!std::strcmp(fieldname, "height")) { return pushinteger(L, map->getHeight()); + } else { + auto found = methods.find(tostring(L, 2)); + if (found != methods.end()) { + return pushcfunction(L, found->second); + } } } return 0;