diff --git a/src/logic/scripting/lua/lua_type_heightmap.cpp b/src/logic/scripting/lua/lua_type_heightmap.cpp index 4fc7d278..ebc58952 100644 --- a/src/logic/scripting/lua/lua_type_heightmap.cpp +++ b/src/logic/scripting/lua/lua_type_heightmap.cpp @@ -53,6 +53,7 @@ static int l_dump(lua::State* L) { return 0; } +template static int l_noise(lua::State* L) { if (auto heightmap = touserdata(L, 1)) { uint w = heightmap->getWidth(); @@ -79,6 +80,7 @@ static int l_noise(lua::State* L) { if (gettop(L) > 6) { shiftMapY = touserdata(L, 7); } + noise->noise_type = noise_type; for (uint y = 0; y < h; y++) { for (uint x = 0; x < w; x++) { uint i = y * w + x; @@ -150,15 +152,31 @@ static int l_unaryop_func(lua::State* L) { return 0; } +static int l_resize(lua::State* L) { + if (auto heightmap = touserdata(L, 1)) { + uint width = touinteger(L, 2); + uint height = touinteger(L, 3); + auto interpName = tostring(L, 4); + auto interpolation = InterpolationType::NEAREST; + if (!std::strcmp(interpName, "linear")) { + interpolation = InterpolationType::LINEAR; + } + heightmap->getHeightmap()->resize(width, height, interpolation); + } + return 0; +} + static std::unordered_map methods { {"dump", lua::wrap}, - {"noise", lua::wrap}, + {"noise", lua::wrap>}, + {"cellnoise", lua::wrap>}, {"pow", lua::wrap>}, {"add", lua::wrap>}, {"mul", lua::wrap>}, {"min", lua::wrap>}, {"max", lua::wrap>}, {"abs", lua::wrap>}, + {"resize", lua::wrap}, }; static int l_meta_meta_call(lua::State* L) { diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index f9fadecd..5c2287b0 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -306,6 +306,13 @@ namespace lua { inline lua::Integer tointeger(lua::State* L, int idx) { return lua_tointeger(L, idx); } + inline uint64_t touinteger(lua::State* L, int idx) { + auto val = lua_tointeger(L, idx); + if (val < 0) { + throw std::runtime_error("negative value"); + } + return static_cast(val); + } inline lua::Number tonumber(lua::State* L, int idx) { return lua_tonumber(L, idx); } diff --git a/src/maths/Heightmap.cpp b/src/maths/Heightmap.cpp new file mode 100644 index 00000000..5b7996a7 --- /dev/null +++ b/src/maths/Heightmap.cpp @@ -0,0 +1,77 @@ +#include "Heightmap.hpp" + +#include +#include +#include + +static inline float smootherstep(float x) { + return glm::smoothstep(std::floor(x), std::floor(x)+1, x); +} + +static inline float sample_at( + const float* buffer, + uint width, uint height, + uint x, uint y +) { + return buffer[y*width+x]; +} + +static inline float sample_at( + const float* buffer, + uint width, uint height, + float x, float y, + InterpolationType interp +) { + // std::floor is redundant here because x and y are positive values + uint ix = static_cast(x); + uint iy = static_cast(y); + float val = buffer[iy*width+ix]; + if (interp == InterpolationType::NEAREST) { + return val; + } + float tx = x - ix; + float ty = y - iy; + + switch (interp) { + case InterpolationType::LINEAR: { + float s00 = val; + float s10 = sample_at(buffer, width, height, + ix + 1 < width ? ix + 1 : ix, iy); + float s01 = sample_at(buffer, width, height, ix, + iy + 1 < height ? iy + 1 : iy); + float s11 = sample_at(buffer, width, height, + ix + 1 < width ? ix + 1 : ix, iy + 1 < height ? iy + 1 : iy); + + float a00 = s00; + float a10 = s10 - s00; + float a01 = s01 - s00; + float a11 = s11 - s10 - s01 + s00; + + return a00 + a10*tx + a01*ty + a11*tx*ty; + } + // TODO: implement CUBIC (Bicubic) interpolation + default: + throw std::runtime_error("interpolation type is not implemented"); + } + return val; +} + +void Heightmap::resize( + uint dstwidth, uint dstheight, InterpolationType interp +) { + std::vector dst; + dst.resize(dstwidth*dstheight); + + uint index = 0; + for (uint y = 0; y < dstheight; y++) { + for (uint x = 0; x < dstwidth; x++, index++) { + float sx = static_cast(x) / dstwidth * width; + float sy = static_cast(y) / dstheight * height; + dst[index] = sample_at(buffer.data(), width, height, sx, sy, interp); + } + } + + width = dstwidth; + height = dstheight; + buffer = std::move(dst); +} diff --git a/src/maths/Heightmap.hpp b/src/maths/Heightmap.hpp index cd125d36..f8185f4c 100644 --- a/src/maths/Heightmap.hpp +++ b/src/maths/Heightmap.hpp @@ -5,6 +5,12 @@ #include "typedefs.hpp" +enum class InterpolationType { + NEAREST, + LINEAR, + CUBIC, +}; + class Heightmap { std::vector buffer; uint width, height; @@ -14,8 +20,13 @@ public: buffer.resize(width*height); } + Heightmap(uint width, uint height, std::vector buffer) + : width(width), height(height), buffer(std::move(buffer)) {} + ~Heightmap() = default; + void resize(uint width, uint height, InterpolationType interpolation); + uint getWidth() const { return width; }