43dd320235f52b0947599c05dc3b5ca7137930cf
[oweals/minetest.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 = check_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 = check_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 = check_v2f(L, 2);
172
173         Noise *n = o->noise;
174         n->perlinMap2D(p.X, p.Y);
175
176         lua_newtable(L);
177         for (u32 y = 0; y != n->sy; y++) {
178                 lua_newtable(L);
179                 for (u32 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                = check_v2f(L, 2);
195         bool use_buffer      = lua_istable(L, 3);
196
197         Noise *n = o->noise;
198         n->perlinMap2D(p.X, p.Y);
199
200         size_t maplen = n->sx * n->sy;
201
202         if (use_buffer)
203                 lua_pushvalue(L, 3);
204         else
205                 lua_newtable(L);
206
207         for (size_t i = 0; i != maplen; i++) {
208                 lua_pushnumber(L, n->result[i]);
209                 lua_rawseti(L, -2, i + 1);
210         }
211         return 1;
212 }
213
214
215 int LuaPerlinNoiseMap::l_get3dMap(lua_State *L)
216 {
217         NO_MAP_LOCK_REQUIRED;
218         size_t i = 0;
219
220         LuaPerlinNoiseMap *o = checkobject(L, 1);
221         v3f p = check_v3f(L, 2);
222
223         if (!o->m_is3d)
224                 return 0;
225
226         Noise *n = o->noise;
227         n->perlinMap3D(p.X, p.Y, p.Z);
228
229         lua_newtable(L);
230         for (u32 z = 0; z != n->sz; z++) {
231                 lua_newtable(L);
232                 for (u32 y = 0; y != n->sy; y++) {
233                         lua_newtable(L);
234                         for (u32 x = 0; x != n->sx; x++) {
235                                 lua_pushnumber(L, n->result[i++]);
236                                 lua_rawseti(L, -2, x + 1);
237                         }
238                         lua_rawseti(L, -2, y + 1);
239                 }
240                 lua_rawseti(L, -2, z + 1);
241         }
242         return 1;
243 }
244
245
246 int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L)
247 {
248         NO_MAP_LOCK_REQUIRED;
249
250         LuaPerlinNoiseMap *o = checkobject(L, 1);
251         v3f p                = check_v3f(L, 2);
252         bool use_buffer      = lua_istable(L, 3);
253
254         if (!o->m_is3d)
255                 return 0;
256
257         Noise *n = o->noise;
258         n->perlinMap3D(p.X, p.Y, p.Z);
259
260         size_t maplen = n->sx * n->sy * n->sz;
261
262         if (use_buffer)
263                 lua_pushvalue(L, 3);
264         else
265                 lua_newtable(L);
266
267         for (size_t i = 0; i != maplen; i++) {
268                 lua_pushnumber(L, n->result[i]);
269                 lua_rawseti(L, -2, i + 1);
270         }
271         return 1;
272 }
273
274
275 int LuaPerlinNoiseMap::l_calc2dMap(lua_State *L)
276 {
277         NO_MAP_LOCK_REQUIRED;
278
279         LuaPerlinNoiseMap *o = checkobject(L, 1);
280         v2f p                = check_v2f(L, 2);
281
282         Noise *n = o->noise;
283         n->perlinMap2D(p.X, p.Y);
284
285         return 0;
286 }
287
288 int LuaPerlinNoiseMap::l_calc3dMap(lua_State *L)
289 {
290         NO_MAP_LOCK_REQUIRED;
291
292         LuaPerlinNoiseMap *o = checkobject(L, 1);
293         v3f p                = check_v3f(L, 2);
294
295         if (!o->m_is3d)
296                 return 0;
297
298         Noise *n = o->noise;
299         n->perlinMap3D(p.X, p.Y, p.Z);
300
301         return 0;
302 }
303
304
305 int LuaPerlinNoiseMap::l_getMapSlice(lua_State *L)
306 {
307         NO_MAP_LOCK_REQUIRED;
308
309         LuaPerlinNoiseMap *o = checkobject(L, 1);
310         v3s16 slice_offset   = read_v3s16(L, 2);
311         v3s16 slice_size     = read_v3s16(L, 3);
312         bool use_buffer      = lua_istable(L, 4);
313
314         Noise *n = o->noise;
315
316         if (use_buffer)
317                 lua_pushvalue(L, 3);
318         else
319                 lua_newtable(L);
320
321         write_array_slice_float(L, lua_gettop(L), n->result,
322                 v3u16(n->sx, n->sy, n->sz),
323                 v3u16(slice_offset.X, slice_offset.Y, slice_offset.Z),
324                 v3u16(slice_size.X, slice_size.Y, slice_size.Z));
325
326         return 1;
327 }
328
329
330 int LuaPerlinNoiseMap::create_object(lua_State *L)
331 {
332         NoiseParams np;
333         if (!read_noiseparams(L, 1, &np))
334                 return 0;
335         v3s16 size = read_v3s16(L, 2);
336
337         LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(&np, 0, size);
338         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
339         luaL_getmetatable(L, className);
340         lua_setmetatable(L, -2);
341         return 1;
342 }
343
344
345 int LuaPerlinNoiseMap::gc_object(lua_State *L)
346 {
347         LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1));
348         delete o;
349         return 0;
350 }
351
352
353 LuaPerlinNoiseMap *LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
354 {
355         luaL_checktype(L, narg, LUA_TUSERDATA);
356
357         void *ud = luaL_checkudata(L, narg, className);
358         if (!ud)
359                 luaL_typerror(L, narg, className);
360
361         return *(LuaPerlinNoiseMap **)ud;
362 }
363
364
365 void LuaPerlinNoiseMap::Register(lua_State *L)
366 {
367         lua_newtable(L);
368         int methodtable = lua_gettop(L);
369         luaL_newmetatable(L, className);
370         int metatable = lua_gettop(L);
371
372         lua_pushliteral(L, "__metatable");
373         lua_pushvalue(L, methodtable);
374         lua_settable(L, metatable);
375
376         lua_pushliteral(L, "__index");
377         lua_pushvalue(L, methodtable);
378         lua_settable(L, metatable);
379
380         lua_pushliteral(L, "__gc");
381         lua_pushcfunction(L, gc_object);
382         lua_settable(L, metatable);
383
384         lua_pop(L, 1);
385
386         luaL_openlib(L, 0, methods, 0);
387         lua_pop(L, 1);
388
389         lua_register(L, className, create_object);
390 }
391
392
393 const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap";
394 const luaL_reg LuaPerlinNoiseMap::methods[] = {
395         luamethod(LuaPerlinNoiseMap, get2dMap),
396         luamethod(LuaPerlinNoiseMap, get2dMap_flat),
397         luamethod(LuaPerlinNoiseMap, calc2dMap),
398         luamethod(LuaPerlinNoiseMap, get3dMap),
399         luamethod(LuaPerlinNoiseMap, get3dMap_flat),
400         luamethod(LuaPerlinNoiseMap, calc3dMap),
401         luamethod(LuaPerlinNoiseMap, getMapSlice),
402         {0,0}
403 };
404
405 ///////////////////////////////////////
406 /*
407         LuaPseudoRandom
408 */
409
410 int LuaPseudoRandom::l_next(lua_State *L)
411 {
412         NO_MAP_LOCK_REQUIRED;
413
414         LuaPseudoRandom *o = checkobject(L, 1);
415         int min = 0;
416         int max = 32767;
417         lua_settop(L, 3);
418         if (lua_isnumber(L, 2))
419                 min = luaL_checkinteger(L, 2);
420         if (lua_isnumber(L, 3))
421                 max = luaL_checkinteger(L, 3);
422         if (max < min) {
423                 errorstream<<"PseudoRandom.next(): max="<<max<<" min="<<min<<std::endl;
424                 throw LuaError("PseudoRandom.next(): max < min");
425         }
426         if(max - min != 32767 && max - min > 32767/5)
427                 throw LuaError("PseudoRandom.next() max-min is not 32767"
428                                 " and is > 32768/5. This is disallowed due to"
429                                 " the bad random distribution the"
430                                 " implementation would otherwise make.");
431         PseudoRandom &pseudo = o->m_pseudo;
432         int val = pseudo.next();
433         val = (val % (max-min+1)) + min;
434         lua_pushinteger(L, val);
435         return 1;
436 }
437
438
439 int LuaPseudoRandom::create_object(lua_State *L)
440 {
441         NO_MAP_LOCK_REQUIRED;
442
443         int seed = luaL_checknumber(L, 1);
444         LuaPseudoRandom *o = new LuaPseudoRandom(seed);
445         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
446         luaL_getmetatable(L, className);
447         lua_setmetatable(L, -2);
448         return 1;
449 }
450
451
452 int LuaPseudoRandom::gc_object(lua_State *L)
453 {
454         LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
455         delete o;
456         return 0;
457 }
458
459
460 LuaPseudoRandom *LuaPseudoRandom::checkobject(lua_State *L, int narg)
461 {
462         luaL_checktype(L, narg, LUA_TUSERDATA);
463         void *ud = luaL_checkudata(L, narg, className);
464         if (!ud)
465                 luaL_typerror(L, narg, className);
466         return *(LuaPseudoRandom **)ud;
467 }
468
469
470 void LuaPseudoRandom::Register(lua_State *L)
471 {
472         lua_newtable(L);
473         int methodtable = lua_gettop(L);
474         luaL_newmetatable(L, className);
475         int metatable = lua_gettop(L);
476
477         lua_pushliteral(L, "__metatable");
478         lua_pushvalue(L, methodtable);
479         lua_settable(L, metatable);
480
481         lua_pushliteral(L, "__index");
482         lua_pushvalue(L, methodtable);
483         lua_settable(L, metatable);
484
485         lua_pushliteral(L, "__gc");
486         lua_pushcfunction(L, gc_object);
487         lua_settable(L, metatable);
488
489         lua_pop(L, 1);
490
491         luaL_openlib(L, 0, methods, 0);
492         lua_pop(L, 1);
493
494         lua_register(L, className, create_object);
495 }
496
497
498 const char LuaPseudoRandom::className[] = "PseudoRandom";
499 const luaL_reg LuaPseudoRandom::methods[] = {
500         luamethod(LuaPseudoRandom, next),
501         {0,0}
502 };
503
504 ///////////////////////////////////////
505 /*
506         LuaPcgRandom
507 */
508
509 int LuaPcgRandom::l_next(lua_State *L)
510 {
511         NO_MAP_LOCK_REQUIRED;
512
513         LuaPcgRandom *o = checkobject(L, 1);
514         u32 min = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : o->m_rnd.RANDOM_MIN;
515         u32 max = lua_isnumber(L, 3) ? lua_tointeger(L, 3) : o->m_rnd.RANDOM_MAX;
516
517         lua_pushinteger(L, o->m_rnd.range(min, max));
518         return 1;
519 }
520
521
522 int LuaPcgRandom::l_rand_normal_dist(lua_State *L)
523 {
524         NO_MAP_LOCK_REQUIRED;
525
526         LuaPcgRandom *o = checkobject(L, 1);
527         u32 min = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : o->m_rnd.RANDOM_MIN;
528         u32 max = lua_isnumber(L, 3) ? lua_tointeger(L, 3) : o->m_rnd.RANDOM_MAX;
529         int num_trials = lua_isnumber(L, 4) ? lua_tointeger(L, 4) : 6;
530
531         lua_pushinteger(L, o->m_rnd.randNormalDist(min, max, num_trials));
532         return 1;
533 }
534
535
536 int LuaPcgRandom::create_object(lua_State *L)
537 {
538         NO_MAP_LOCK_REQUIRED;
539
540         lua_Integer seed = luaL_checknumber(L, 1);
541         LuaPcgRandom *o  = lua_isnumber(L, 2) ?
542                 new LuaPcgRandom(seed, lua_tointeger(L, 2)) :
543                 new LuaPcgRandom(seed);
544         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
545         luaL_getmetatable(L, className);
546         lua_setmetatable(L, -2);
547         return 1;
548 }
549
550
551 int LuaPcgRandom::gc_object(lua_State *L)
552 {
553         LuaPcgRandom *o = *(LuaPcgRandom **)(lua_touserdata(L, 1));
554         delete o;
555         return 0;
556 }
557
558
559 LuaPcgRandom *LuaPcgRandom::checkobject(lua_State *L, int narg)
560 {
561         luaL_checktype(L, narg, LUA_TUSERDATA);
562         void *ud = luaL_checkudata(L, narg, className);
563         if (!ud)
564                 luaL_typerror(L, narg, className);
565         return *(LuaPcgRandom **)ud;
566 }
567
568
569 void LuaPcgRandom::Register(lua_State *L)
570 {
571         lua_newtable(L);
572         int methodtable = lua_gettop(L);
573         luaL_newmetatable(L, className);
574         int metatable = lua_gettop(L);
575
576         lua_pushliteral(L, "__metatable");
577         lua_pushvalue(L, methodtable);
578         lua_settable(L, metatable);
579
580         lua_pushliteral(L, "__index");
581         lua_pushvalue(L, methodtable);
582         lua_settable(L, metatable);
583
584         lua_pushliteral(L, "__gc");
585         lua_pushcfunction(L, gc_object);
586         lua_settable(L, metatable);
587
588         lua_pop(L, 1);
589
590         luaL_openlib(L, 0, methods, 0);
591         lua_pop(L, 1);
592
593         lua_register(L, className, create_object);
594 }
595
596
597 const char LuaPcgRandom::className[] = "PcgRandom";
598 const luaL_reg LuaPcgRandom::methods[] = {
599         luamethod(LuaPcgRandom, next),
600         luamethod(LuaPcgRandom, rand_normal_dist),
601         {0,0}
602 };