add heightmap:resize(int, int, str)

This commit is contained in:
MihailRis 2024-08-17 22:09:31 +03:00
parent e560236a8c
commit 8c0a3f4260
4 changed files with 114 additions and 1 deletions

View File

@ -53,6 +53,7 @@ static int l_dump(lua::State* L) {
return 0;
}
template<fnl_noise_type noise_type>
static int l_noise(lua::State* L) {
if (auto heightmap = touserdata<LuaHeightmap>(L, 1)) {
uint w = heightmap->getWidth();
@ -79,6 +80,7 @@ static int l_noise(lua::State* L) {
if (gettop(L) > 6) {
shiftMapY = touserdata<LuaHeightmap>(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<LuaHeightmap>(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<std::string, lua_CFunction> methods {
{"dump", lua::wrap<l_dump>},
{"noise", lua::wrap<l_noise>},
{"noise", lua::wrap<l_noise<FNL_NOISE_OPENSIMPLEX2>>},
{"cellnoise", lua::wrap<l_noise<FNL_NOISE_CELLULAR>>},
{"pow", lua::wrap<l_binop_func<util::pow>>},
{"add", lua::wrap<l_binop_func<std::plus>>},
{"mul", lua::wrap<l_binop_func<std::multiplies>>},
{"min", lua::wrap<l_binop_func<util::min>>},
{"max", lua::wrap<l_binop_func<util::max>>},
{"abs", lua::wrap<l_unaryop_func<util::abs>>},
{"resize", lua::wrap<l_resize>},
};
static int l_meta_meta_call(lua::State* L) {

View File

@ -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<uint64_t>(val);
}
inline lua::Number tonumber(lua::State* L, int idx) {
return lua_tonumber(L, idx);
}

77
src/maths/Heightmap.cpp Normal file
View File

@ -0,0 +1,77 @@
#include "Heightmap.hpp"
#include <cmath>
#include <stdexcept>
#include <glm/glm.hpp>
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<uint>(x);
uint iy = static_cast<uint>(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<float> 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<float>(x) / dstwidth * width;
float sy = static_cast<float>(y) / dstheight * height;
dst[index] = sample_at(buffer.data(), width, height, sx, sy, interp);
}
}
width = dstwidth;
height = dstheight;
buffer = std::move(dst);
}

View File

@ -5,6 +5,12 @@
#include "typedefs.hpp"
enum class InterpolationType {
NEAREST,
LINEAR,
CUBIC,
};
class Heightmap {
std::vector<float> buffer;
uint width, height;
@ -14,8 +20,13 @@ public:
buffer.resize(width*height);
}
Heightmap(uint width, uint height, std::vector<float> buffer)
: width(width), height(height), buffer(std::move(buffer)) {}
~Heightmap() = default;
void resize(uint width, uint height, InterpolationType interpolation);
uint getWidth() const {
return width;
}