add Heightmap methods

This commit is contained in:
MihailRis 2024-08-13 20:57:46 +03:00
parent da4b8bd7d4
commit 13b97f4398
4 changed files with 291 additions and 3 deletions

View File

@ -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

View File

@ -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";
};

View File

@ -53,7 +53,7 @@ static int l_remove(lua::State* L) {
return 0;
}
static std::unordered_map<std::string, lua_CFunction> bytearray_methods {
static std::unordered_map<std::string, lua_CFunction> methods {
{"append", lua::wrap<l_append>},
{"insert", lua::wrap<l_insert>},
{"remove", lua::wrap<l_remove>},
@ -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);
}
}

View File

@ -3,11 +3,17 @@
#include <cstring>
#include <sstream>
#include <iomanip>
#include <filesystem>
#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<Heightmap>(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<Heightmap>(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<Heightmap>(L, 6);
}
if (gettop(L) > 6) {
shiftMapY = touserdata<Heightmap>(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<float>(1 << c) * multiplier;
heights[i] = value;
}
}
}
}
return 0;
}
static int l_pow(lua::State* L) {
if (auto heightmap = touserdata<Heightmap>(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<Heightmap>(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<Heightmap>(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<Heightmap>(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<Heightmap>(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<Heightmap>(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<Heightmap>(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<Heightmap>(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<Heightmap>(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<Heightmap>(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<std::string, lua_CFunction> methods {
{"dump", lua::wrap<l_dump>},
{"noise", lua::wrap<l_noise>},
{"pow", lua::wrap<l_pow>},
{"add", lua::wrap<l_add>},
{"mul", lua::wrap<l_mul>},
{"min", lua::wrap<l_min>},
{"max", lua::wrap<l_max>},
{"abs", lua::wrap<l_abs>},
};
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;