PerlinNoise for Lua.
authorSergey Gilfanov <inkelyad@gmail.com>
Sat, 31 Mar 2012 19:52:25 +0000 (23:52 +0400)
committerPerttu Ahola <celeron55@gmail.com>
Sat, 7 Apr 2012 10:39:01 +0000 (13:39 +0300)
doc/lua_api.txt
src/scriptapi.cpp

index afcee18438cc6729bfbd131e8d77e66a62bdf0fd..25653dd0f55de8d8596d16d642540976744d4e3e 100644 (file)
@@ -648,6 +648,8 @@ methods:
 - get_timeofday()
 - find_node_near(pos, radius, nodenames) -> pos or nil
   ^ nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
+- get_perlin(seeddiff, octaves, persistence, scale)
+  ^ Return world-specific perlin noise (int(worldseed)+seeddiff)
 Deprecated:
 - add_rat(pos): Add C++ rat object (no-op)
 - add_firefly(pos): Add C++ firefly object (no-op)
@@ -768,6 +770,13 @@ methods:
                   (max - min) must be 32767 or <= 6553 due to the simple
                   implementation making bad distribution otherwise.
 
+PerlinNoise: A perlin noise generator
+- Can be created via PerlinNoise(seed, octaves, persistence, scale)
+- Also minetest.env:get_perlin(seeddiff, octaves, persistence, scale)
+methods:
+- get2d(pos) -> 2d noise value at pos={x=,y=}
+- get3d(pos) -> 3d noise value at pos={x=,y=,z=}
+
 Registered entities
 --------------------
 - Functions receive a "luaentity" as self:
index 87526678f6a2b4bdb3b8ab337df38e438e95c270..7ce10c415f32f64aa9d823eecb3bc59d676cae1d 100644 (file)
@@ -2877,6 +2877,120 @@ static void objectref_get_or_create(lua_State *L,
        }
 }
 
+
+/*
+  PerlinNoise
+ */
+
+class LuaPerlinNoise
+{
+private:
+       int seed;
+       int octaves;
+       double persistence;
+       double scale;
+       static const char className[];
+       static const luaL_reg methods[];
+
+       // Exported functions
+
+       // garbage collector
+       static int gc_object(lua_State *L)
+       {
+               LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
+               delete o;
+               return 0;
+       }
+
+       static int l_get2d(lua_State *L)
+       {
+               LuaPerlinNoise *o = checkobject(L, 1);
+               v2f pos2d = read_v2f(L,2);
+               lua_Number val = noise2d_perlin(pos2d.X/o->scale, pos2d.Y/o->scale, o->seed, o->octaves, o->persistence);
+               lua_pushnumber(L, val);
+               return 1;
+       }
+       static int l_get3d(lua_State *L)
+       {
+               LuaPerlinNoise *o = checkobject(L, 1);
+               v3f pos3d = read_v3f(L,2);
+               lua_Number val = noise3d_perlin(pos3d.X/o->scale, pos3d.Y/o->scale, pos3d.Z/o->scale, o->seed, o->octaves, o->persistence);
+               lua_pushnumber(L, val);
+               return 1;
+       }
+
+public:
+       LuaPerlinNoise(int a_seed, int a_octaves, double a_persistence,
+                       double a_scale):
+               seed(a_seed),
+               octaves(a_octaves),
+               persistence(a_persistence),
+               scale(a_scale)
+       {
+       }
+
+       ~LuaPerlinNoise()
+       {
+       }
+
+       // LuaPerlinNoise(seed, octaves, persistence, scale)
+       // Creates an LuaPerlinNoise and leaves it on top of stack
+       static int create_object(lua_State *L)
+       {
+               int seed = luaL_checkint(L, 1);
+               int octaves = luaL_checkint(L, 2);
+               double persistence = luaL_checknumber(L, 3);
+               double scale = luaL_checknumber(L, 4);
+               LuaPerlinNoise *o = new LuaPerlinNoise(seed, octaves, persistence, scale);
+               *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
+               luaL_getmetatable(L, className);
+               lua_setmetatable(L, -2);
+               return 1;
+       }
+
+       static LuaPerlinNoise* checkobject(lua_State *L, int narg)
+       {
+               luaL_checktype(L, narg, LUA_TUSERDATA);
+               void *ud = luaL_checkudata(L, narg, className);
+               if(!ud) luaL_typerror(L, narg, className);
+               return *(LuaPerlinNoise**)ud;  // unbox pointer
+       }
+
+       static void Register(lua_State *L)
+       {
+               lua_newtable(L);
+               int methodtable = lua_gettop(L);
+               luaL_newmetatable(L, className);
+               int metatable = lua_gettop(L);
+
+               lua_pushliteral(L, "__metatable");
+               lua_pushvalue(L, methodtable);
+               lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
+
+               lua_pushliteral(L, "__index");
+               lua_pushvalue(L, methodtable);
+               lua_settable(L, metatable);
+
+               lua_pushliteral(L, "__gc");
+               lua_pushcfunction(L, gc_object);
+               lua_settable(L, metatable);
+
+               lua_pop(L, 1);  // drop metatable
+
+               luaL_openlib(L, 0, methods, 0);  // fill methodtable
+               lua_pop(L, 1);  // drop methodtable
+
+               // Can be created from Lua (PerlinNoise(seed, octaves, persistence)
+               lua_register(L, className, create_object);
+       }
+};
+const char LuaPerlinNoise::className[] = "PerlinNoise";
+const luaL_reg LuaPerlinNoise::methods[] = {
+       method(LuaPerlinNoise, get2d),
+       method(LuaPerlinNoise, get3d),
+       {0,0}
+};
+
 /*
        EnvRef
 */
@@ -3190,6 +3304,7 @@ private:
                return 1;
        }
 
+
        // EnvRef:find_node_near(pos, radius, nodenames) -> pos or nil
        // nodenames: eg. {"ignore", "group:tree"} or "default:dirt"
        static int l_find_node_near(lua_State *L)
@@ -3231,6 +3346,26 @@ private:
                return 0;
        }
 
+       //      EnvRef:get_perlin(seeddiff, octaves, persistence, scale)
+       //  returns world-specific PerlinNoise
+       static int l_get_perlin(lua_State *L)
+       {
+               EnvRef *o = checkobject(L, 1);
+               ServerEnvironment *env = o->m_env;
+               if(env == NULL) return 0;
+
+               int seeddiff = luaL_checkint(L, 2);
+               int octaves = luaL_checkint(L, 3);
+               double persistence = luaL_checknumber(L, 4);
+               double scale = luaL_checknumber(L, 5);
+
+               LuaPerlinNoise *n = new LuaPerlinNoise(seeddiff + int(env->getServerMap().getSeed()), octaves, persistence, scale);
+               *(void **)(lua_newuserdata(L, sizeof(void *))) = n;
+               luaL_getmetatable(L, "PerlinNoise");
+               lua_setmetatable(L, -2);
+               return 1;
+       }
+
 public:
        EnvRef(ServerEnvironment *env):
                m_env(env)
@@ -3306,6 +3441,7 @@ const luaL_reg EnvRef::methods[] = {
        method(EnvRef, set_timeofday),
        method(EnvRef, get_timeofday),
        method(EnvRef, find_node_near),
+       method(EnvRef, get_perlin),
        {0,0}
 };
 
@@ -3313,6 +3449,7 @@ const luaL_reg EnvRef::methods[] = {
        LuaPseudoRandom
 */
 
+
 class LuaPseudoRandom
 {
 private:
@@ -3424,6 +3561,8 @@ const luaL_reg LuaPseudoRandom::methods[] = {
        {0,0}
 };
 
+
+
 /*
        LuaABM
 */
@@ -4129,6 +4268,7 @@ void scriptapi_export(lua_State *L, Server *server)
        ObjectRef::Register(L);
        EnvRef::Register(L);
        LuaPseudoRandom::Register(L);
+       LuaPerlinNoise::Register(L);
 }
 
 bool scriptapi_loadmod(lua_State *L, const std::string &scriptpath,