diff --git a/doc/lua_api.txt b/doc/lua_api.txt index b4a5fa1d8..2acb94a68 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -2640,16 +2640,30 @@ Format of `size` is `{x=dimx, y=dimy, z=dimz}`. The `z` conponent is ommitted for 2D noise, and it must be must be larger than 1 for 3D noise (otherwise `nil` is returned). +For each of the functions with an optional `buffer` parameter: If `buffer` is not +nil, this table will be used to store the result instead of creating a new table. + + #### Methods * `get2dMap(pos)`: returns a `` times `` 2D array of 2D noise with values starting at `pos={x=,y=}` * `get3dMap(pos)`: returns a `` times `` times `` 3D array of 3D noise with values starting at `pos={x=,y=,z=}` -* `get2dMap_flat(pos)`: returns a flat `` element array of 2D noise +* `get2dMap_flat(pos, buffer)`: returns a flat `` element array of 2D noise with values starting at `pos={x=,y=}` - * if the param `buffer` is present, this table will be used to store the result instead -* `get3dMap_flat(pos)`: Same as `get2dMap_flat`, but 3D noise - * if the param `buffer` is present, this table will be used to store the result instead +* `get3dMap_flat(pos, buffer)`: Same as `get2dMap_flat`, but 3D noise +* `calc2dMap(pos)`: Calculates the 2d noise map starting at `pos`. The result is stored internally. +* `calc3dMap(pos)`: Calculates the 3d noise map starting at `pos`. The result is stored internally. +* `getMapSlice(slice_offset, slice_size, buffer)`: In the form of an array, returns a slice of the + most recently computed noise results. The result slice begins at coordinates `slice_offset` and + takes a chunk of `slice_size`. + E.g. to grab a 2-slice high horizontal 2d plane of noise starting at buffer offset y = 20: + `noisevals = noise:getMapSlice({y=20}, {y=2})` + It is important to note that `slice_offset` offset coordinates begin at 1, and are relative to + the starting position of the most recently calculated noise. + To grab a single vertical column of noise starting at map coordinates x = 1023, y=1000, z = 1000: + `noise:calc3dMap({x=1000, y=1000, z=1000})` + `noisevals = noise:getMapSlice({x=24, z=1}, {x=1, z=1})` ### `VoxelManip` An interface to the `MapVoxelManipulator` for Lua. diff --git a/src/irr_v3d.h b/src/irr_v3d.h index 7bc73ad10..f74d601e8 100644 --- a/src/irr_v3d.h +++ b/src/irr_v3d.h @@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., typedef core::vector3df v3f; typedef core::vector3d v3s16; +typedef core::vector3d v3u16; typedef core::vector3d v3s32; #endif 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);