Skip to content

Commit

Permalink
SAPI/Noise: Add PerlinNoiseMap:getMapSlice() function
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kwolekr committed May 17, 2015
1 parent c0edb8e commit 4c9a8a9
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 4 deletions.
22 changes: 18 additions & 4 deletions doc/lua_api.txt
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions src/irr_v3d.h
Expand Up @@ -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
Expand Down
92 changes: 92 additions & 0 deletions src/script/common/c_converter.cpp
Expand Up @@ -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;
}
5 changes: 5 additions & 0 deletions src/script/common/c_converter.h
Expand Up @@ -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_ */
58 changes: 58 additions & 0 deletions src/script/lua_api/l_noise.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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}
};

Expand Down
4 changes: 4 additions & 0 deletions src/script/lua_api/l_noise.h
Expand Up @@ -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);

Expand Down

0 comments on commit 4c9a8a9

Please sign in to comment.