]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_noise.cpp
bf3dca58968f4f3accdc42ae9a738fa3de4cd3da
[dragonfireclient.git] / src / script / lua_api / l_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 "lua_api/l_noise.h"
21 #include "lua_api/l_internal.h"
22 #include "common/c_converter.h"
23 #include "common/c_content.h"
24 #include "log.h"
25
26 ///////////////////////////////////////
27 /*
28   LuaPerlinNoise
29 */
30
31 LuaPerlinNoise::LuaPerlinNoise(NoiseParams *params) :
32         np(*params)
33 {
34 }
35
36
37 LuaPerlinNoise::~LuaPerlinNoise()
38 {
39 }
40
41
42 int LuaPerlinNoise::l_get2d(lua_State *L)
43 {
44         NO_MAP_LOCK_REQUIRED;
45         LuaPerlinNoise *o = checkobject(L, 1);
46         v2f p = read_v2f(L, 2);
47         lua_Number val = NoisePerlin2D(&o->np, p.X, p.Y, 0);
48         lua_pushnumber(L, val);
49         return 1;
50 }
51
52
53 int LuaPerlinNoise::l_get3d(lua_State *L)
54 {
55         NO_MAP_LOCK_REQUIRED;
56         LuaPerlinNoise *o = checkobject(L, 1);
57         v3f p = read_v3f(L, 2);
58         lua_Number val = NoisePerlin3D(&o->np, p.X, p.Y, p.Z, 0);
59         lua_pushnumber(L, val);
60         return 1;
61 }
62
63
64 int LuaPerlinNoise::create_object(lua_State *L)
65 {
66         NO_MAP_LOCK_REQUIRED;
67
68         NoiseParams params;
69
70         if (lua_istable(L, 1)) {
71                 read_noiseparams(L, 1, &params);
72         } else {
73                 params.seed    = luaL_checkint(L, 1);
74                 params.octaves = luaL_checkint(L, 2);
75                 params.persist = luaL_checknumber(L, 3);
76                 params.spread  = v3f(1, 1, 1) * luaL_checknumber(L, 4);
77         }
78
79         LuaPerlinNoise *o = new LuaPerlinNoise(&params);
80
81         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
82         luaL_getmetatable(L, className);
83         lua_setmetatable(L, -2);
84         return 1;
85 }
86
87
88 int LuaPerlinNoise::gc_object(lua_State *L)
89 {
90         LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
91         delete o;
92         return 0;
93 }
94
95
96 LuaPerlinNoise *LuaPerlinNoise::checkobject(lua_State *L, int narg)
97 {
98         NO_MAP_LOCK_REQUIRED;
99         luaL_checktype(L, narg, LUA_TUSERDATA);
100         void *ud = luaL_checkudata(L, narg, className);
101         if (!ud)
102                 luaL_typerror(L, narg, className);
103         return *(LuaPerlinNoise **)ud;
104 }
105
106
107 void LuaPerlinNoise::Register(lua_State *L)
108 {
109         lua_newtable(L);
110         int methodtable = lua_gettop(L);
111         luaL_newmetatable(L, className);
112         int metatable = lua_gettop(L);
113
114         lua_pushliteral(L, "__metatable");
115         lua_pushvalue(L, methodtable);
116         lua_settable(L, metatable);
117
118         lua_pushliteral(L, "__index");
119         lua_pushvalue(L, methodtable);
120         lua_settable(L, metatable);
121
122         lua_pushliteral(L, "__gc");
123         lua_pushcfunction(L, gc_object);
124         lua_settable(L, metatable);
125
126         lua_pop(L, 1);
127
128         luaL_openlib(L, 0, methods, 0);
129         lua_pop(L, 1);
130
131         lua_register(L, className, create_object);
132 }
133
134
135 const char LuaPerlinNoise::className[] = "PerlinNoise";
136 const luaL_reg LuaPerlinNoise::methods[] = {
137         luamethod(LuaPerlinNoise, get2d),
138         luamethod(LuaPerlinNoise, get3d),
139         {0,0}
140 };
141
142 ///////////////////////////////////////
143 /*
144   LuaPerlinNoiseMap
145 */
146
147 LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *params, int seed, v3s16 size)
148 {
149         m_is3d = size.Z > 1;
150         np = *params;
151         try {
152                 noise = new Noise(&np, seed, size.X, size.Y, size.Z);
153         } catch (InvalidNoiseParamsException &e) {
154                 throw LuaError(e.what());
155         }
156 }
157
158
159 LuaPerlinNoiseMap::~LuaPerlinNoiseMap()
160 {
161         delete noise;
162 }
163
164
165 int LuaPerlinNoiseMap::l_get2dMap(lua_State *L)
166 {
167         NO_MAP_LOCK_REQUIRED;
168         size_t i = 0;
169
170         LuaPerlinNoiseMap *o = checkobject(L, 1);
171         v2f p = read_v2f(L, 2);
172
173         Noise *n = o->noise;
174         n->perlinMap2D(p.X, p.Y);
175
176         lua_newtable(L);
177         for (int y = 0; y != n->sy; y++) {
178                 lua_newtable(L);
179                 for (int x = 0; x != n->sx; x++) {
180                         lua_pushnumber(L, n->result[i++]);
181                         lua_rawseti(L, -2, x + 1);
182                 }
183                 lua_rawseti(L, -2, y + 1);
184         }
185         return 1;
186 }
187
188
189 int LuaPerlinNoiseMap::l_get2dMap_flat(lua_State *L)
190 {
191         NO_MAP_LOCK_REQUIRED;
192
193         LuaPerlinNoiseMap *o = checkobject(L, 1);
194         v2f p = read_v2f(L, 2);
195
196         Noise *n = o->noise;
197         n->perlinMap2D(p.X, p.Y);
198
199         size_t maplen = n->sx * n->sy;
200
201         lua_newtable(L);
202         for (size_t i = 0; i != maplen; i++) {
203                 lua_pushnumber(L, n->result[i]);
204                 lua_rawseti(L, -2, i + 1);
205         }
206         return 1;
207 }
208
209
210 int LuaPerlinNoiseMap::l_get3dMap(lua_State *L)
211 {
212         NO_MAP_LOCK_REQUIRED;
213         size_t i = 0;
214
215         LuaPerlinNoiseMap *o = checkobject(L, 1);
216         v3f p = read_v3f(L, 2);
217
218         if (!o->m_is3d)
219                 return 0;
220
221         Noise *n = o->noise;
222         n->perlinMap3D(p.X, p.Y, p.Z);
223
224         lua_newtable(L);
225         for (int z = 0; z != n->sz; z++) {
226                 lua_newtable(L);
227                 for (int y = 0; y != n->sy; y++) {
228                         lua_newtable(L);
229                         for (int x = 0; x != n->sx; x++) {
230                                 lua_pushnumber(L, n->result[i++]);
231                                 lua_rawseti(L, -2, x + 1);
232                         }
233                         lua_rawseti(L, -2, y + 1);
234                 }
235                 lua_rawseti(L, -2, z + 1);
236         }
237         return 1;
238 }
239
240
241 int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L)
242 {
243         NO_MAP_LOCK_REQUIRED;
244
245         LuaPerlinNoiseMap *o = checkobject(L, 1);
246         v3f p = read_v3f(L, 2);
247
248         if (!o->m_is3d)
249                 return 0;
250
251         Noise *n = o->noise;
252         n->perlinMap3D(p.X, p.Y, p.Z);
253
254         size_t maplen = n->sx * n->sy * n->sz;
255
256         lua_newtable(L);
257         for (size_t i = 0; i != maplen; i++) {
258                 lua_pushnumber(L, n->result[i]);
259                 lua_rawseti(L, -2, i + 1);
260         }
261         return 1;
262 }
263
264
265 int LuaPerlinNoiseMap::create_object(lua_State *L)
266 {
267         NoiseParams np;
268         if (!read_noiseparams(L, 1, &np))
269                 return 0;
270         v3s16 size = read_v3s16(L, 2);
271
272         LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(&np, 0, size);
273         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
274         luaL_getmetatable(L, className);
275         lua_setmetatable(L, -2);
276         return 1;
277 }
278
279
280 int LuaPerlinNoiseMap::gc_object(lua_State *L)
281 {
282         LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1));
283         delete o;
284         return 0;
285 }
286
287
288 LuaPerlinNoiseMap *LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
289 {
290         luaL_checktype(L, narg, LUA_TUSERDATA);
291
292         void *ud = luaL_checkudata(L, narg, className);
293         if (!ud)
294                 luaL_typerror(L, narg, className);
295
296         return *(LuaPerlinNoiseMap **)ud;
297 }
298
299
300 void LuaPerlinNoiseMap::Register(lua_State *L)
301 {
302         lua_newtable(L);
303         int methodtable = lua_gettop(L);
304         luaL_newmetatable(L, className);
305         int metatable = lua_gettop(L);
306
307         lua_pushliteral(L, "__metatable");
308         lua_pushvalue(L, methodtable);
309         lua_settable(L, metatable);
310
311         lua_pushliteral(L, "__index");
312         lua_pushvalue(L, methodtable);
313         lua_settable(L, metatable);
314
315         lua_pushliteral(L, "__gc");
316         lua_pushcfunction(L, gc_object);
317         lua_settable(L, metatable);
318
319         lua_pop(L, 1);
320
321         luaL_openlib(L, 0, methods, 0);
322         lua_pop(L, 1);
323
324         lua_register(L, className, create_object);
325 }
326
327
328 const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap";
329 const luaL_reg LuaPerlinNoiseMap::methods[] = {
330         luamethod(LuaPerlinNoiseMap, get2dMap),
331         luamethod(LuaPerlinNoiseMap, get2dMap_flat),
332         luamethod(LuaPerlinNoiseMap, get3dMap),
333         luamethod(LuaPerlinNoiseMap, get3dMap_flat),
334         {0,0}
335 };
336
337 ///////////////////////////////////////
338 /*
339         LuaPseudoRandom
340 */
341
342 int LuaPseudoRandom::l_next(lua_State *L)
343 {
344         NO_MAP_LOCK_REQUIRED;
345         LuaPseudoRandom *o = checkobject(L, 1);
346         int min = 0;
347         int max = 32767;
348         lua_settop(L, 3);
349         if (lua_isnumber(L, 2))
350                 min = luaL_checkinteger(L, 2);
351         if (lua_isnumber(L, 3))
352                 max = luaL_checkinteger(L, 3);
353         if (max < min) {
354                 errorstream<<"PseudoRandom.next(): max="<<max<<" min="<<min<<std::endl;
355                 throw LuaError("PseudoRandom.next(): max < min");
356         }
357         if(max - min != 32767 && max - min > 32767/5)
358                 throw LuaError("PseudoRandom.next() max-min is not 32767"
359                                 " and is > 32768/5. This is disallowed due to"
360                                 " the bad random distribution the"
361                                 " implementation would otherwise make.");
362         PseudoRandom &pseudo = o->m_pseudo;
363         int val = pseudo.next();
364         val = (val % (max-min+1)) + min;
365         lua_pushinteger(L, val);
366         return 1;
367 }
368
369
370 int LuaPseudoRandom::create_object(lua_State *L)
371 {
372         int seed = luaL_checknumber(L, 1);
373         LuaPseudoRandom *o = new LuaPseudoRandom(seed);
374         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
375         luaL_getmetatable(L, className);
376         lua_setmetatable(L, -2);
377         return 1;
378 }
379
380
381 int LuaPseudoRandom::gc_object(lua_State *L)
382 {
383         LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
384         delete o;
385         return 0;
386 }
387
388
389 LuaPseudoRandom *LuaPseudoRandom::checkobject(lua_State *L, int narg)
390 {
391         luaL_checktype(L, narg, LUA_TUSERDATA);
392         void *ud = luaL_checkudata(L, narg, className);
393         if (!ud)
394                 luaL_typerror(L, narg, className);
395         return *(LuaPseudoRandom **)ud;
396 }
397
398
399 void LuaPseudoRandom::Register(lua_State *L)
400 {
401         lua_newtable(L);
402         int methodtable = lua_gettop(L);
403         luaL_newmetatable(L, className);
404         int metatable = lua_gettop(L);
405
406         lua_pushliteral(L, "__metatable");
407         lua_pushvalue(L, methodtable);
408         lua_settable(L, metatable);
409
410         lua_pushliteral(L, "__index");
411         lua_pushvalue(L, methodtable);
412         lua_settable(L, metatable);
413
414         lua_pushliteral(L, "__gc");
415         lua_pushcfunction(L, gc_object);
416         lua_settable(L, metatable);
417
418         lua_pop(L, 1);
419
420         luaL_openlib(L, 0, methods, 0);
421         lua_pop(L, 1);
422
423         lua_register(L, className, create_object);
424 }
425
426
427 const char LuaPseudoRandom::className[] = "PseudoRandom";
428 const luaL_reg LuaPseudoRandom::methods[] = {
429         luamethod(LuaPseudoRandom, next),
430         {0,0}
431 };
432
433 ///////////////////////////////////////
434 /*
435         LuaPcgRandom
436 */
437
438 int LuaPcgRandom::l_next(lua_State *L)
439 {
440         NO_MAP_LOCK_REQUIRED;
441
442         LuaPcgRandom *o = checkobject(L, 1);
443         u32 min = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : o->m_rnd.RANDOM_MIN;
444         u32 max = lua_isnumber(L, 3) ? lua_tointeger(L, 3) : o->m_rnd.RANDOM_MAX;
445
446         lua_pushinteger(L, o->m_rnd.range(min, max));
447         return 1;
448 }
449
450
451 int LuaPcgRandom::l_rand_normal_dist(lua_State *L)
452 {
453         NO_MAP_LOCK_REQUIRED;
454
455         LuaPcgRandom *o = checkobject(L, 1);
456         u32 min = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : o->m_rnd.RANDOM_MIN;
457         u32 max = lua_isnumber(L, 3) ? lua_tointeger(L, 3) : o->m_rnd.RANDOM_MAX;
458         int num_trials = lua_isnumber(L, 4) ? lua_tointeger(L, 4) : 6;
459
460         lua_pushinteger(L, o->m_rnd.randNormalDist(min, max, num_trials));
461         return 1;
462 }
463
464
465 int LuaPcgRandom::create_object(lua_State *L)
466 {
467         lua_Integer seed = luaL_checknumber(L, 1);
468         LuaPcgRandom *o  = lua_isnumber(L, 2) ?
469                 new LuaPcgRandom(seed, lua_tointeger(L, 2)) :
470                 new LuaPcgRandom(seed);
471         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
472         luaL_getmetatable(L, className);
473         lua_setmetatable(L, -2);
474         return 1;
475 }
476
477
478 int LuaPcgRandom::gc_object(lua_State *L)
479 {
480         LuaPcgRandom *o = *(LuaPcgRandom **)(lua_touserdata(L, 1));
481         delete o;
482         return 0;
483 }
484
485
486 LuaPcgRandom *LuaPcgRandom::checkobject(lua_State *L, int narg)
487 {
488         luaL_checktype(L, narg, LUA_TUSERDATA);
489         void *ud = luaL_checkudata(L, narg, className);
490         if (!ud)
491                 luaL_typerror(L, narg, className);
492         return *(LuaPcgRandom **)ud;
493 }
494
495
496 void LuaPcgRandom::Register(lua_State *L)
497 {
498         lua_newtable(L);
499         int methodtable = lua_gettop(L);
500         luaL_newmetatable(L, className);
501         int metatable = lua_gettop(L);
502
503         lua_pushliteral(L, "__metatable");
504         lua_pushvalue(L, methodtable);
505         lua_settable(L, metatable);
506
507         lua_pushliteral(L, "__index");
508         lua_pushvalue(L, methodtable);
509         lua_settable(L, metatable);
510
511         lua_pushliteral(L, "__gc");
512         lua_pushcfunction(L, gc_object);
513         lua_settable(L, metatable);
514
515         lua_pop(L, 1);
516
517         luaL_openlib(L, 0, methods, 0);
518         lua_pop(L, 1);
519
520         lua_register(L, className, create_object);
521 }
522
523
524 const char LuaPcgRandom::className[] = "PcgRandom";
525 const luaL_reg LuaPcgRandom::methods[] = {
526         luamethod(LuaPcgRandom, next),
527         luamethod(LuaPcgRandom, rand_normal_dist),
528         {0,0}
529 };