From 4c9a8a91c4988b3567a38af622a3eb0d0ec19f6b Mon Sep 17 00:00:00 2001 From: kwolekr Date: Sun, 17 May 2015 03:38:39 -0400 Subject: SAPI/Noise: Add PerlinNoiseMap:getMapSlice() function This adds the ability to grab 'slices' of noise calculated by PerlinNoiseMap. Retrieving smaller slices of noise from the computation result as needed optimizes memory usage while maintaining a reasonable amount of CPU overhead. --- src/script/common/c_converter.cpp | 92 +++++++++++++++++++++++++++++++++++++++ src/script/common/c_converter.h | 5 +++ src/script/lua_api/l_noise.cpp | 58 ++++++++++++++++++++++++ src/script/lua_api/l_noise.h | 4 ++ 4 files changed, 159 insertions(+) (limited to 'src/script') diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp index 6fb6f623a..211121552 100644 --- a/src/script/common/c_converter.cpp +++ b/src/script/common/c_converter.cpp @@ -510,3 +510,95 @@ void setboolfield(lua_State *L, int table, } +//// +//// Array table slices +//// + +size_t write_array_slice_float( + lua_State *L, + int table_index, + float *data, + v3u16 data_size, + v3u16 slice_offset, + v3u16 slice_size) +{ + v3u16 pmin, pmax(data_size); + + if (slice_offset.X > 0) { + slice_offset.X--; + pmin.X = slice_offset.X; + pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X); + } + + if (slice_offset.Y > 0) { + slice_offset.Y--; + pmin.Y = slice_offset.Y; + pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y); + } + + if (slice_offset.Z > 0) { + slice_offset.Z--; + pmin.Z = slice_offset.Z; + pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z); + } + + const u32 ystride = data_size.X; + const u32 zstride = data_size.X * data_size.Y; + + u32 elem_index = 1; + for (u32 z = pmin.Z; z != pmax.Z; z++) + for (u32 y = pmin.Y; y != pmax.Y; y++) + for (u32 x = pmin.X; x != pmax.X; x++) { + u32 i = z * zstride + y * ystride + x; + lua_pushnumber(L, data[i]); + lua_rawseti(L, table_index, elem_index); + elem_index++; + } + + return elem_index - 1; +} + + +size_t write_array_slice_u16( + lua_State *L, + int table_index, + u16 *data, + v3u16 data_size, + v3u16 slice_offset, + v3u16 slice_size) +{ + v3u16 pmin, pmax(data_size); + + if (slice_offset.X > 0) { + slice_offset.X--; + pmin.X = slice_offset.X; + pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X); + } + + if (slice_offset.Y > 0) { + slice_offset.Y--; + pmin.Y = slice_offset.Y; + pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y); + } + + if (slice_offset.Z > 0) { + slice_offset.Z--; + pmin.Z = slice_offset.Z; + pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z); + } + + const u32 ystride = data_size.X; + const u32 zstride = data_size.X * data_size.Y; + + u32 elem_index = 1; + for (u32 z = pmin.Z; z != pmax.Z; z++) + for (u32 y = pmin.Y; y != pmax.Y; y++) + for (u32 x = pmin.X; x != pmax.X; x++) { + u32 i = z * zstride + y * ystride + x; + lua_pushinteger(L, data[i]); + lua_rawseti(L, table_index, elem_index); + elem_index++; + } + + return elem_index - 1; +} diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h index e99826404..e4466d97f 100644 --- a/src/script/common/c_converter.h +++ b/src/script/common/c_converter.h @@ -106,4 +106,9 @@ void warn_if_field_exists(lua_State *L, int table, const char *fieldname, const std::string &message); +size_t write_array_slice_float(lua_State *L, int table_index, float *data, + v3u16 data_size, v3u16 slice_offset, v3u16 slice_size); +size_t write_array_slice_u16(lua_State *L, int table_index, u16 *data, + v3u16 data_size, v3u16 slice_offset, v3u16 slice_size); + #endif /* C_CONVERTER_H_ */ diff --git a/src/script/lua_api/l_noise.cpp b/src/script/lua_api/l_noise.cpp index 86ae9dba7..c8dc2d2dc 100644 --- a/src/script/lua_api/l_noise.cpp +++ b/src/script/lua_api/l_noise.cpp @@ -272,6 +272,61 @@ int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L) } +int LuaPerlinNoiseMap::l_calc2dMap(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + LuaPerlinNoiseMap *o = checkobject(L, 1); + v2f p = check_v2f(L, 2); + + Noise *n = o->noise; + n->perlinMap2D(p.X, p.Y); + + return 0; +} + +int LuaPerlinNoiseMap::l_calc3dMap(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + LuaPerlinNoiseMap *o = checkobject(L, 1); + v3f p = check_v3f(L, 2); + + if (!o->m_is3d) + return 0; + + Noise *n = o->noise; + n->perlinMap3D(p.X, p.Y, p.Z); + + return 0; +} + + +int LuaPerlinNoiseMap::l_getMapSlice(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + LuaPerlinNoiseMap *o = checkobject(L, 1); + v3s16 slice_offset = read_v3s16(L, 2); + v3s16 slice_size = read_v3s16(L, 3); + bool use_buffer = lua_istable(L, 4); + + Noise *n = o->noise; + + if (use_buffer) + lua_pushvalue(L, 3); + else + lua_newtable(L); + + write_array_slice_float(L, lua_gettop(L), n->result, + v3u16(n->sx, n->sy, n->sz), + v3u16(slice_offset.X, slice_offset.Y, slice_offset.Z), + v3u16(slice_size.X, slice_size.Y, slice_size.Z)); + + return 1; +} + + int LuaPerlinNoiseMap::create_object(lua_State *L) { NoiseParams np; @@ -339,8 +394,11 @@ const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap"; const luaL_reg LuaPerlinNoiseMap::methods[] = { luamethod(LuaPerlinNoiseMap, get2dMap), luamethod(LuaPerlinNoiseMap, get2dMap_flat), + luamethod(LuaPerlinNoiseMap, calc2dMap), luamethod(LuaPerlinNoiseMap, get3dMap), luamethod(LuaPerlinNoiseMap, get3dMap_flat), + luamethod(LuaPerlinNoiseMap, calc3dMap), + luamethod(LuaPerlinNoiseMap, getMapSlice), {0,0} }; diff --git a/src/script/lua_api/l_noise.h b/src/script/lua_api/l_noise.h index 56d2d59f8..e958c5a23 100644 --- a/src/script/lua_api/l_noise.h +++ b/src/script/lua_api/l_noise.h @@ -74,6 +74,10 @@ class LuaPerlinNoiseMap : public ModApiBase { static int l_get3dMap(lua_State *L); static int l_get3dMap_flat(lua_State *L); + static int l_calc2dMap(lua_State *L); + static int l_calc3dMap(lua_State *L); + static int l_getMapSlice(lua_State *L); + public: LuaPerlinNoiseMap(NoiseParams *np, int seed, v3s16 size); -- cgit v1.2.3