split scriptapi.cpp
[oweals/minetest.git] / src / scriptapi_noise.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "scriptapi.h"
21 #include "scriptapi_noise.h"
22 #include "scriptapi_types.h"
23 #include "script.h"
24
25 #include <irr_v2d.h>
26
27
28 // garbage collector
29 int LuaPerlinNoise::gc_object(lua_State *L)
30 {
31         LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
32         delete o;
33         return 0;
34 }
35
36 int LuaPerlinNoise::l_get2d(lua_State *L)
37 {
38         LuaPerlinNoise *o = checkobject(L, 1);
39         v2f pos2d = read_v2f(L,2);
40         lua_Number val = noise2d_perlin(pos2d.X/o->scale, pos2d.Y/o->scale, o->seed, o->octaves, o->persistence);
41         lua_pushnumber(L, val);
42         return 1;
43 }
44 int LuaPerlinNoise::l_get3d(lua_State *L)
45 {
46         LuaPerlinNoise *o = checkobject(L, 1);
47         v3f pos3d = read_v3f(L,2);
48         lua_Number val = noise3d_perlin(pos3d.X/o->scale, pos3d.Y/o->scale, pos3d.Z/o->scale, o->seed, o->octaves, o->persistence);
49         lua_pushnumber(L, val);
50         return 1;
51 }
52
53
54 LuaPerlinNoise::LuaPerlinNoise(int a_seed, int a_octaves, float a_persistence,
55                 float a_scale):
56         seed(a_seed),
57         octaves(a_octaves),
58         persistence(a_persistence),
59         scale(a_scale)
60 {
61 }
62
63 LuaPerlinNoise::~LuaPerlinNoise()
64 {
65 }
66
67 // LuaPerlinNoise(seed, octaves, persistence, scale)
68 // Creates an LuaPerlinNoise and leaves it on top of stack
69 int LuaPerlinNoise::create_object(lua_State *L)
70 {
71         int seed = luaL_checkint(L, 1);
72         int octaves = luaL_checkint(L, 2);
73         float persistence = luaL_checknumber(L, 3);
74         float scale = luaL_checknumber(L, 4);
75         LuaPerlinNoise *o = new LuaPerlinNoise(seed, octaves, persistence, scale);
76         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
77         luaL_getmetatable(L, className);
78         lua_setmetatable(L, -2);
79         return 1;
80 }
81
82 LuaPerlinNoise* LuaPerlinNoise::checkobject(lua_State *L, int narg)
83 {
84         luaL_checktype(L, narg, LUA_TUSERDATA);
85         void *ud = luaL_checkudata(L, narg, className);
86         if(!ud) luaL_typerror(L, narg, className);
87         return *(LuaPerlinNoise**)ud;  // unbox pointer
88 }
89
90 void LuaPerlinNoise::Register(lua_State *L)
91 {
92         lua_newtable(L);
93         int methodtable = lua_gettop(L);
94         luaL_newmetatable(L, className);
95         int metatable = lua_gettop(L);
96
97         lua_pushliteral(L, "__metatable");
98         lua_pushvalue(L, methodtable);
99         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
100
101         lua_pushliteral(L, "__index");
102         lua_pushvalue(L, methodtable);
103         lua_settable(L, metatable);
104
105         lua_pushliteral(L, "__gc");
106         lua_pushcfunction(L, gc_object);
107         lua_settable(L, metatable);
108
109         lua_pop(L, 1);  // drop metatable
110
111         luaL_openlib(L, 0, methods, 0);  // fill methodtable
112         lua_pop(L, 1);  // drop methodtable
113
114         // Can be created from Lua (PerlinNoise(seed, octaves, persistence)
115         lua_register(L, className, create_object);
116 }
117
118 const char LuaPerlinNoise::className[] = "PerlinNoise";
119 const luaL_reg LuaPerlinNoise::methods[] = {
120         luamethod(LuaPerlinNoise, get2d),
121         luamethod(LuaPerlinNoise, get3d),
122         {0,0}
123 };
124
125 /*
126   PerlinNoiseMap
127  */
128
129
130 int LuaPerlinNoiseMap::gc_object(lua_State *L)
131 {
132         LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1));
133         delete o;
134         return 0;
135 }
136
137 int LuaPerlinNoiseMap::l_get2dMap(lua_State *L)
138 {
139         int i = 0;
140
141         LuaPerlinNoiseMap *o = checkobject(L, 1);
142         v2f p = read_v2f(L, 2);
143
144         Noise *n = o->noise;
145         n->perlinMap2D(p.X, p.Y);
146
147         lua_newtable(L);
148         for (int y = 0; y != n->sy; y++) {
149                 lua_newtable(L);
150                 for (int x = 0; x != n->sx; x++) {
151                         float noiseval = n->np->offset + n->np->scale * n->result[i++];
152                         lua_pushnumber(L, noiseval);
153                         lua_rawseti(L, -2, x + 1);
154                 }
155                 lua_rawseti(L, -2, y + 1);
156         }
157         return 1;
158 }
159
160 int LuaPerlinNoiseMap::l_get3dMap(lua_State *L)
161 {
162         int i = 0;
163
164         LuaPerlinNoiseMap *o = checkobject(L, 1);
165         v3f p = read_v3f(L, 2);
166
167         Noise *n = o->noise;
168         n->perlinMap3D(p.X, p.Y, p.Z);
169
170         lua_newtable(L);
171         for (int z = 0; z != n->sz; z++) {
172                 lua_newtable(L);
173                 for (int y = 0; y != n->sy; y++) {
174                         lua_newtable(L);
175                         for (int x = 0; x != n->sx; x++) {
176                                 lua_pushnumber(L, n->np->offset + n->np->scale * n->result[i++]);
177                                 lua_rawseti(L, -2, x + 1);
178                         }
179                         lua_rawseti(L, -2, y + 1);
180                 }
181                 lua_rawseti(L, -2, z + 1);
182         }
183         return 1;
184 }
185
186 LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *np, int seed, v3s16 size) {
187         noise = new Noise(np, seed, size.X, size.Y, size.Z);
188 }
189
190 LuaPerlinNoiseMap::~LuaPerlinNoiseMap()
191 {
192         delete noise->np;
193         delete noise;
194 }
195
196 // LuaPerlinNoiseMap(np, size)
197 // Creates an LuaPerlinNoiseMap and leaves it on top of stack
198 int LuaPerlinNoiseMap::create_object(lua_State *L)
199 {
200         NoiseParams *np = read_noiseparams(L, 1);
201         if (!np)
202                 return 0;
203         v3s16 size = read_v3s16(L, 2);
204
205         LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(np, 0, size);
206         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
207         luaL_getmetatable(L, className);
208         lua_setmetatable(L, -2);
209         return 1;
210 }
211
212 LuaPerlinNoiseMap* LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
213 {
214         luaL_checktype(L, narg, LUA_TUSERDATA);
215
216         void *ud = luaL_checkudata(L, narg, className);
217         if (!ud)
218                 luaL_typerror(L, narg, className);
219
220         return *(LuaPerlinNoiseMap **)ud;  // unbox pointer
221 }
222
223 void LuaPerlinNoiseMap::Register(lua_State *L)
224 {
225         lua_newtable(L);
226         int methodtable = lua_gettop(L);
227         luaL_newmetatable(L, className);
228         int metatable = lua_gettop(L);
229
230         lua_pushliteral(L, "__metatable");
231         lua_pushvalue(L, methodtable);
232         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
233
234         lua_pushliteral(L, "__index");
235         lua_pushvalue(L, methodtable);
236         lua_settable(L, metatable);
237
238         lua_pushliteral(L, "__gc");
239         lua_pushcfunction(L, gc_object);
240         lua_settable(L, metatable);
241
242         lua_pop(L, 1);  // drop metatable
243
244         luaL_openlib(L, 0, methods, 0);  // fill methodtable
245         lua_pop(L, 1);  // drop methodtable
246
247         // Can be created from Lua (PerlinNoiseMap(np, size)
248         lua_register(L, className, create_object);
249 }
250
251 const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap";
252 const luaL_reg LuaPerlinNoiseMap::methods[] = {
253         luamethod(LuaPerlinNoiseMap, get2dMap),
254         luamethod(LuaPerlinNoiseMap, get3dMap),
255         {0,0}
256 };
257
258 /*
259         NoiseParams
260 */
261 NoiseParams *read_noiseparams(lua_State *L, int index)
262 {
263         if (index < 0)
264                 index = lua_gettop(L) + 1 + index;
265
266         if (!lua_istable(L, index))
267                 return NULL;
268
269         NoiseParams *np = new NoiseParams;
270
271         np->offset  = getfloatfield_default(L, index, "offset", 0.0);
272         np->scale   = getfloatfield_default(L, index, "scale", 0.0);
273         lua_getfield(L, index, "spread");
274         np->spread  = read_v3f(L, -1);
275         np->seed    = getintfield_default(L, index, "seed", 0);
276         np->octaves = getintfield_default(L, index, "octaves", 0);
277         np->persist = getfloatfield_default(L, index, "persist", 0.0);
278
279         return np;
280 }
281
282 /*
283         LuaPseudoRandom
284 */
285
286 // garbage collector
287 int LuaPseudoRandom::gc_object(lua_State *L)
288 {
289         LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
290         delete o;
291         return 0;
292 }
293
294 // next(self, min=0, max=32767) -> get next value
295 int LuaPseudoRandom::l_next(lua_State *L)
296 {
297         LuaPseudoRandom *o = checkobject(L, 1);
298         int min = 0;
299         int max = 32767;
300         lua_settop(L, 3); // Fill 2 and 3 with nil if they don't exist
301         if(!lua_isnil(L, 2))
302                 min = luaL_checkinteger(L, 2);
303         if(!lua_isnil(L, 3))
304                 max = luaL_checkinteger(L, 3);
305         if(max < min){
306                 errorstream<<"PseudoRandom.next(): max="<<max<<" min="<<min<<std::endl;
307                 throw LuaError(L, "PseudoRandom.next(): max < min");
308         }
309         if(max - min != 32767 && max - min > 32767/5)
310                 throw LuaError(L, "PseudoRandom.next() max-min is not 32767 and is > 32768/5. This is disallowed due to the bad random distribution the implementation would otherwise make.");
311         PseudoRandom &pseudo = o->m_pseudo;
312         int val = pseudo.next();
313         val = (val % (max-min+1)) + min;
314         lua_pushinteger(L, val);
315         return 1;
316 }
317
318
319 LuaPseudoRandom::LuaPseudoRandom(int seed):
320         m_pseudo(seed)
321 {
322 }
323
324 LuaPseudoRandom::~LuaPseudoRandom()
325 {
326 }
327
328 const PseudoRandom& LuaPseudoRandom::getItem() const
329 {
330         return m_pseudo;
331 }
332 PseudoRandom& LuaPseudoRandom::getItem()
333 {
334         return m_pseudo;
335 }
336
337 // LuaPseudoRandom(seed)
338 // Creates an LuaPseudoRandom and leaves it on top of stack
339 int LuaPseudoRandom::create_object(lua_State *L)
340 {
341         int seed = luaL_checknumber(L, 1);
342         LuaPseudoRandom *o = new LuaPseudoRandom(seed);
343         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
344         luaL_getmetatable(L, className);
345         lua_setmetatable(L, -2);
346         return 1;
347 }
348
349 LuaPseudoRandom* LuaPseudoRandom::checkobject(lua_State *L, int narg)
350 {
351         luaL_checktype(L, narg, LUA_TUSERDATA);
352         void *ud = luaL_checkudata(L, narg, className);
353         if(!ud) luaL_typerror(L, narg, className);
354         return *(LuaPseudoRandom**)ud;  // unbox pointer
355 }
356
357 void LuaPseudoRandom::Register(lua_State *L)
358 {
359         lua_newtable(L);
360         int methodtable = lua_gettop(L);
361         luaL_newmetatable(L, className);
362         int metatable = lua_gettop(L);
363
364         lua_pushliteral(L, "__metatable");
365         lua_pushvalue(L, methodtable);
366         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
367
368         lua_pushliteral(L, "__index");
369         lua_pushvalue(L, methodtable);
370         lua_settable(L, metatable);
371
372         lua_pushliteral(L, "__gc");
373         lua_pushcfunction(L, gc_object);
374         lua_settable(L, metatable);
375
376         lua_pop(L, 1);  // drop metatable
377
378         luaL_openlib(L, 0, methods, 0);  // fill methodtable
379         lua_pop(L, 1);  // drop methodtable
380
381         // Can be created from Lua (LuaPseudoRandom(seed))
382         lua_register(L, className, create_object);
383 }
384
385 const char LuaPseudoRandom::className[] = "PseudoRandom";
386 const luaL_reg LuaPseudoRandom::methods[] = {
387         luamethod(LuaPseudoRandom, next),
388         {0,0}
389 };