SAPI/Noise: Add PerlinNoiseMap:getMapSlice() function
authorkwolekr <kwolekr@minetest.net>
Sun, 17 May 2015 07:38:39 +0000 (03:38 -0400)
committerkwolekr <kwolekr@minetest.net>
Sun, 17 May 2015 08:04:17 +0000 (04:04 -0400)
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.

doc/lua_api.txt
src/irr_v3d.h
src/script/common/c_converter.cpp
src/script/common/c_converter.h
src/script/lua_api/l_noise.cpp
src/script/lua_api/l_noise.h

index b4a5fa1d8777c24852e11d58fb2e2218342c38b2..2acb94a68b4f83c8346497d5d817c3fd2e3af82b 100644 (file)
@@ -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 `<size.x>` times `<size.y>` 2D array of 2D noise
   with values starting at `pos={x=,y=}`
 * `get3dMap(pos)`: returns a `<size.x>` times `<size.y>` times `<size.z>` 3D array
   of 3D noise with values starting at `pos={x=,y=,z=}`
-* `get2dMap_flat(pos)`: returns a flat `<size.x * size.y>` element array of 2D noise
+* `get2dMap_flat(pos, buffer)`: returns a flat `<size.x * size.y>` 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.
index 7bc73ad1088bc0c146af2cb614bffb8b1701a346..f74d601e8d548036fa74fc4837eb7844474f9569 100644 (file)
@@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 typedef core::vector3df v3f;
 typedef core::vector3d<s16> v3s16;
+typedef core::vector3d<u16> v3u16;
 typedef core::vector3d<s32> v3s32;
 
 #endif
index 6fb6f623a66d361a3b930ae8eff88d0c6771f83f..2111215529b960b0c0e243ffcdf800a95809d0dd 100644 (file)
@@ -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;
+}
index e99826404f058527ad603c185c72ca7f3fe357e7..e4466d97f21e8a795920c4c92d32afe2deaf3d5d 100644 (file)
@@ -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_ */
index 86ae9dba7b77a023fc8271c404f15efd80f85b30..c8dc2d2dccfdc3bb2d62f48322c6e40be6b887ef 100644 (file)
@@ -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}
 };
 
index 56d2d59f8fb1a335f602727096dc552a0011b460..e958c5a2388b3005e69e992677e0c5af7fa70a92 100644 (file)
@@ -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);