]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_noise.cpp
Change internal type for seeds to s32
[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 #include "porting.h"
26 #include "util/numeric.h"
27
28 ///////////////////////////////////////
29 /*
30   LuaPerlinNoise
31 */
32
33 LuaPerlinNoise::LuaPerlinNoise(NoiseParams *params) :
34         np(*params)
35 {
36 }
37
38
39 LuaPerlinNoise::~LuaPerlinNoise()
40 {
41 }
42
43
44 int LuaPerlinNoise::l_get2d(lua_State *L)
45 {
46         NO_MAP_LOCK_REQUIRED;
47         LuaPerlinNoise *o = checkobject(L, 1);
48         v2f p = check_v2f(L, 2);
49         lua_Number val = NoisePerlin2D(&o->np, p.X, p.Y, 0);
50         lua_pushnumber(L, val);
51         return 1;
52 }
53
54
55 int LuaPerlinNoise::l_get3d(lua_State *L)
56 {
57         NO_MAP_LOCK_REQUIRED;
58         LuaPerlinNoise *o = checkobject(L, 1);
59         v3f p = check_v3f(L, 2);
60         lua_Number val = NoisePerlin3D(&o->np, p.X, p.Y, p.Z, 0);
61         lua_pushnumber(L, val);
62         return 1;
63 }
64
65
66 int LuaPerlinNoise::create_object(lua_State *L)
67 {
68         NO_MAP_LOCK_REQUIRED;
69
70         NoiseParams params;
71
72         if (lua_istable(L, 1)) {
73                 read_noiseparams(L, 1, &params);
74         } else {
75                 params.seed    = luaL_checkint(L, 1);
76                 params.octaves = luaL_checkint(L, 2);
77                 params.persist = luaL_checknumber(L, 3);
78                 params.spread  = v3f(1, 1, 1) * luaL_checknumber(L, 4);
79         }
80
81         LuaPerlinNoise *o = new LuaPerlinNoise(&params);
82
83         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
84         luaL_getmetatable(L, className);
85         lua_setmetatable(L, -2);
86         return 1;
87 }
88
89
90 int LuaPerlinNoise::gc_object(lua_State *L)
91 {
92         LuaPerlinNoise *o = *(LuaPerlinNoise **)(lua_touserdata(L, 1));
93         delete o;
94         return 0;
95 }
96
97
98 LuaPerlinNoise *LuaPerlinNoise::checkobject(lua_State *L, int narg)
99 {
100         NO_MAP_LOCK_REQUIRED;
101         luaL_checktype(L, narg, LUA_TUSERDATA);
102         void *ud = luaL_checkudata(L, narg, className);
103         if (!ud)
104                 luaL_typerror(L, narg, className);
105         return *(LuaPerlinNoise **)ud;
106 }
107
108
109 void LuaPerlinNoise::Register(lua_State *L)
110 {
111         lua_newtable(L);
112         int methodtable = lua_gettop(L);
113         luaL_newmetatable(L, className);
114         int metatable = lua_gettop(L);
115
116         lua_pushliteral(L, "__metatable");
117         lua_pushvalue(L, methodtable);
118         lua_settable(L, metatable);
119
120         lua_pushliteral(L, "__index");
121         lua_pushvalue(L, methodtable);
122         lua_settable(L, metatable);
123
124         lua_pushliteral(L, "__gc");
125         lua_pushcfunction(L, gc_object);
126         lua_settable(L, metatable);
127
128         lua_pop(L, 1);
129
130         luaL_openlib(L, 0, methods, 0);
131         lua_pop(L, 1);
132
133         lua_register(L, className, create_object);
134 }
135
136
137 const char LuaPerlinNoise::className[] = "PerlinNoise";
138 const luaL_reg LuaPerlinNoise::methods[] = {
139         luamethod(LuaPerlinNoise, get2d),
140         luamethod(LuaPerlinNoise, get3d),
141         {0,0}
142 };
143
144 ///////////////////////////////////////
145 /*
146   LuaPerlinNoiseMap
147 */
148
149 LuaPerlinNoiseMap::LuaPerlinNoiseMap(NoiseParams *params, s32 seed, v3s16 size)
150 {
151         m_is3d = size.Z > 1;
152         np = *params;
153         try {
154                 noise = new Noise(&np, seed, size.X, size.Y, size.Z);
155         } catch (InvalidNoiseParamsException &e) {
156                 throw LuaError(e.what());
157         }
158 }
159
160
161 LuaPerlinNoiseMap::~LuaPerlinNoiseMap()
162 {
163         delete noise;
164 }
165
166
167 int LuaPerlinNoiseMap::l_get2dMap(lua_State *L)
168 {
169         NO_MAP_LOCK_REQUIRED;
170         size_t i = 0;
171
172         LuaPerlinNoiseMap *o = checkobject(L, 1);
173         v2f p = check_v2f(L, 2);
174
175         Noise *n = o->noise;
176         n->perlinMap2D(p.X, p.Y);
177
178         lua_newtable(L);
179         for (u32 y = 0; y != n->sy; y++) {
180                 lua_newtable(L);
181                 for (u32 x = 0; x != n->sx; x++) {
182                         lua_pushnumber(L, n->result[i++]);
183                         lua_rawseti(L, -2, x + 1);
184                 }
185                 lua_rawseti(L, -2, y + 1);
186         }
187         return 1;
188 }
189
190
191 int LuaPerlinNoiseMap::l_get2dMap_flat(lua_State *L)
192 {
193         NO_MAP_LOCK_REQUIRED;
194
195         LuaPerlinNoiseMap *o = checkobject(L, 1);
196         v2f p                = check_v2f(L, 2);
197         bool use_buffer      = lua_istable(L, 3);
198
199         Noise *n = o->noise;
200         n->perlinMap2D(p.X, p.Y);
201
202         size_t maplen = n->sx * n->sy;
203
204         if (use_buffer)
205                 lua_pushvalue(L, 3);
206         else
207                 lua_newtable(L);
208
209         for (size_t i = 0; i != maplen; i++) {
210                 lua_pushnumber(L, n->result[i]);
211                 lua_rawseti(L, -2, i + 1);
212         }
213         return 1;
214 }
215
216
217 int LuaPerlinNoiseMap::l_get3dMap(lua_State *L)
218 {
219         NO_MAP_LOCK_REQUIRED;
220         size_t i = 0;
221
222         LuaPerlinNoiseMap *o = checkobject(L, 1);
223         v3f p = check_v3f(L, 2);
224
225         if (!o->m_is3d)
226                 return 0;
227
228         Noise *n = o->noise;
229         n->perlinMap3D(p.X, p.Y, p.Z);
230
231         lua_newtable(L);
232         for (u32 z = 0; z != n->sz; z++) {
233                 lua_newtable(L);
234                 for (u32 y = 0; y != n->sy; y++) {
235                         lua_newtable(L);
236                         for (u32 x = 0; x != n->sx; x++) {
237                                 lua_pushnumber(L, n->result[i++]);
238                                 lua_rawseti(L, -2, x + 1);
239                         }
240                         lua_rawseti(L, -2, y + 1);
241                 }
242                 lua_rawseti(L, -2, z + 1);
243         }
244         return 1;
245 }
246
247
248 int LuaPerlinNoiseMap::l_get3dMap_flat(lua_State *L)
249 {
250         NO_MAP_LOCK_REQUIRED;
251
252         LuaPerlinNoiseMap *o = checkobject(L, 1);
253         v3f p                = check_v3f(L, 2);
254         bool use_buffer      = lua_istable(L, 3);
255
256         if (!o->m_is3d)
257                 return 0;
258
259         Noise *n = o->noise;
260         n->perlinMap3D(p.X, p.Y, p.Z);
261
262         size_t maplen = n->sx * n->sy * n->sz;
263
264         if (use_buffer)
265                 lua_pushvalue(L, 3);
266         else
267                 lua_newtable(L);
268
269         for (size_t i = 0; i != maplen; i++) {
270                 lua_pushnumber(L, n->result[i]);
271                 lua_rawseti(L, -2, i + 1);
272         }
273         return 1;
274 }
275
276
277 int LuaPerlinNoiseMap::l_calc2dMap(lua_State *L)
278 {
279         NO_MAP_LOCK_REQUIRED;
280
281         LuaPerlinNoiseMap *o = checkobject(L, 1);
282         v2f p                = check_v2f(L, 2);
283
284         Noise *n = o->noise;
285         n->perlinMap2D(p.X, p.Y);
286
287         return 0;
288 }
289
290 int LuaPerlinNoiseMap::l_calc3dMap(lua_State *L)
291 {
292         NO_MAP_LOCK_REQUIRED;
293
294         LuaPerlinNoiseMap *o = checkobject(L, 1);
295         v3f p                = check_v3f(L, 2);
296
297         if (!o->m_is3d)
298                 return 0;
299
300         Noise *n = o->noise;
301         n->perlinMap3D(p.X, p.Y, p.Z);
302
303         return 0;
304 }
305
306
307 int LuaPerlinNoiseMap::l_getMapSlice(lua_State *L)
308 {
309         NO_MAP_LOCK_REQUIRED;
310
311         LuaPerlinNoiseMap *o = checkobject(L, 1);
312         v3s16 slice_offset   = read_v3s16(L, 2);
313         v3s16 slice_size     = read_v3s16(L, 3);
314         bool use_buffer      = lua_istable(L, 4);
315
316         Noise *n = o->noise;
317
318         if (use_buffer)
319                 lua_pushvalue(L, 3);
320         else
321                 lua_newtable(L);
322
323         write_array_slice_float(L, lua_gettop(L), n->result,
324                 v3u16(n->sx, n->sy, n->sz),
325                 v3u16(slice_offset.X, slice_offset.Y, slice_offset.Z),
326                 v3u16(slice_size.X, slice_size.Y, slice_size.Z));
327
328         return 1;
329 }
330
331
332 int LuaPerlinNoiseMap::create_object(lua_State *L)
333 {
334         NoiseParams np;
335         if (!read_noiseparams(L, 1, &np))
336                 return 0;
337         v3s16 size = read_v3s16(L, 2);
338
339         LuaPerlinNoiseMap *o = new LuaPerlinNoiseMap(&np, 0, size);
340         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
341         luaL_getmetatable(L, className);
342         lua_setmetatable(L, -2);
343         return 1;
344 }
345
346
347 int LuaPerlinNoiseMap::gc_object(lua_State *L)
348 {
349         LuaPerlinNoiseMap *o = *(LuaPerlinNoiseMap **)(lua_touserdata(L, 1));
350         delete o;
351         return 0;
352 }
353
354
355 LuaPerlinNoiseMap *LuaPerlinNoiseMap::checkobject(lua_State *L, int narg)
356 {
357         luaL_checktype(L, narg, LUA_TUSERDATA);
358
359         void *ud = luaL_checkudata(L, narg, className);
360         if (!ud)
361                 luaL_typerror(L, narg, className);
362
363         return *(LuaPerlinNoiseMap **)ud;
364 }
365
366
367 void LuaPerlinNoiseMap::Register(lua_State *L)
368 {
369         lua_newtable(L);
370         int methodtable = lua_gettop(L);
371         luaL_newmetatable(L, className);
372         int metatable = lua_gettop(L);
373
374         lua_pushliteral(L, "__metatable");
375         lua_pushvalue(L, methodtable);
376         lua_settable(L, metatable);
377
378         lua_pushliteral(L, "__index");
379         lua_pushvalue(L, methodtable);
380         lua_settable(L, metatable);
381
382         lua_pushliteral(L, "__gc");
383         lua_pushcfunction(L, gc_object);
384         lua_settable(L, metatable);
385
386         lua_pop(L, 1);
387
388         luaL_openlib(L, 0, methods, 0);
389         lua_pop(L, 1);
390
391         lua_register(L, className, create_object);
392 }
393
394
395 const char LuaPerlinNoiseMap::className[] = "PerlinNoiseMap";
396 const luaL_reg LuaPerlinNoiseMap::methods[] = {
397         luamethod(LuaPerlinNoiseMap, get2dMap),
398         luamethod(LuaPerlinNoiseMap, get2dMap_flat),
399         luamethod(LuaPerlinNoiseMap, calc2dMap),
400         luamethod(LuaPerlinNoiseMap, get3dMap),
401         luamethod(LuaPerlinNoiseMap, get3dMap_flat),
402         luamethod(LuaPerlinNoiseMap, calc3dMap),
403         luamethod(LuaPerlinNoiseMap, getMapSlice),
404         {0,0}
405 };
406
407 ///////////////////////////////////////
408 /*
409         LuaPseudoRandom
410 */
411
412 int LuaPseudoRandom::l_next(lua_State *L)
413 {
414         NO_MAP_LOCK_REQUIRED;
415
416         LuaPseudoRandom *o = checkobject(L, 1);
417         int min = 0;
418         int max = 32767;
419         lua_settop(L, 3);
420         if (lua_isnumber(L, 2))
421                 min = luaL_checkinteger(L, 2);
422         if (lua_isnumber(L, 3))
423                 max = luaL_checkinteger(L, 3);
424         if (max < min) {
425                 errorstream<<"PseudoRandom.next(): max="<<max<<" min="<<min<<std::endl;
426                 throw LuaError("PseudoRandom.next(): max < min");
427         }
428         if(max - min != 32767 && max - min > 32767/5)
429                 throw LuaError("PseudoRandom.next() max-min is not 32767"
430                                 " and is > 32768/5. This is disallowed due to"
431                                 " the bad random distribution the"
432                                 " implementation would otherwise make.");
433         PseudoRandom &pseudo = o->m_pseudo;
434         int val = pseudo.next();
435         val = (val % (max-min+1)) + min;
436         lua_pushinteger(L, val);
437         return 1;
438 }
439
440
441 int LuaPseudoRandom::create_object(lua_State *L)
442 {
443         NO_MAP_LOCK_REQUIRED;
444
445         u64 seed = luaL_checknumber(L, 1);
446         LuaPseudoRandom *o = new LuaPseudoRandom(seed);
447         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
448         luaL_getmetatable(L, className);
449         lua_setmetatable(L, -2);
450         return 1;
451 }
452
453
454 int LuaPseudoRandom::gc_object(lua_State *L)
455 {
456         LuaPseudoRandom *o = *(LuaPseudoRandom **)(lua_touserdata(L, 1));
457         delete o;
458         return 0;
459 }
460
461
462 LuaPseudoRandom *LuaPseudoRandom::checkobject(lua_State *L, int narg)
463 {
464         luaL_checktype(L, narg, LUA_TUSERDATA);
465         void *ud = luaL_checkudata(L, narg, className);
466         if (!ud)
467                 luaL_typerror(L, narg, className);
468         return *(LuaPseudoRandom **)ud;
469 }
470
471
472 void LuaPseudoRandom::Register(lua_State *L)
473 {
474         lua_newtable(L);
475         int methodtable = lua_gettop(L);
476         luaL_newmetatable(L, className);
477         int metatable = lua_gettop(L);
478
479         lua_pushliteral(L, "__metatable");
480         lua_pushvalue(L, methodtable);
481         lua_settable(L, metatable);
482
483         lua_pushliteral(L, "__index");
484         lua_pushvalue(L, methodtable);
485         lua_settable(L, metatable);
486
487         lua_pushliteral(L, "__gc");
488         lua_pushcfunction(L, gc_object);
489         lua_settable(L, metatable);
490
491         lua_pop(L, 1);
492
493         luaL_openlib(L, 0, methods, 0);
494         lua_pop(L, 1);
495
496         lua_register(L, className, create_object);
497 }
498
499
500 const char LuaPseudoRandom::className[] = "PseudoRandom";
501 const luaL_reg LuaPseudoRandom::methods[] = {
502         luamethod(LuaPseudoRandom, next),
503         {0,0}
504 };
505
506 ///////////////////////////////////////
507 /*
508         LuaPcgRandom
509 */
510
511 int LuaPcgRandom::l_next(lua_State *L)
512 {
513         NO_MAP_LOCK_REQUIRED;
514
515         LuaPcgRandom *o = checkobject(L, 1);
516         u32 min = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : o->m_rnd.RANDOM_MIN;
517         u32 max = lua_isnumber(L, 3) ? lua_tointeger(L, 3) : o->m_rnd.RANDOM_MAX;
518
519         lua_pushinteger(L, o->m_rnd.range(min, max));
520         return 1;
521 }
522
523
524 int LuaPcgRandom::l_rand_normal_dist(lua_State *L)
525 {
526         NO_MAP_LOCK_REQUIRED;
527
528         LuaPcgRandom *o = checkobject(L, 1);
529         u32 min = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : o->m_rnd.RANDOM_MIN;
530         u32 max = lua_isnumber(L, 3) ? lua_tointeger(L, 3) : o->m_rnd.RANDOM_MAX;
531         int num_trials = lua_isnumber(L, 4) ? lua_tointeger(L, 4) : 6;
532
533         lua_pushinteger(L, o->m_rnd.randNormalDist(min, max, num_trials));
534         return 1;
535 }
536
537
538 int LuaPcgRandom::create_object(lua_State *L)
539 {
540         NO_MAP_LOCK_REQUIRED;
541
542         u64 seed = luaL_checknumber(L, 1);
543         LuaPcgRandom *o = lua_isnumber(L, 2) ?
544                 new LuaPcgRandom(seed, lua_tointeger(L, 2)) :
545                 new LuaPcgRandom(seed);
546         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
547         luaL_getmetatable(L, className);
548         lua_setmetatable(L, -2);
549         return 1;
550 }
551
552
553 int LuaPcgRandom::gc_object(lua_State *L)
554 {
555         LuaPcgRandom *o = *(LuaPcgRandom **)(lua_touserdata(L, 1));
556         delete o;
557         return 0;
558 }
559
560
561 LuaPcgRandom *LuaPcgRandom::checkobject(lua_State *L, int narg)
562 {
563         luaL_checktype(L, narg, LUA_TUSERDATA);
564         void *ud = luaL_checkudata(L, narg, className);
565         if (!ud)
566                 luaL_typerror(L, narg, className);
567         return *(LuaPcgRandom **)ud;
568 }
569
570
571 void LuaPcgRandom::Register(lua_State *L)
572 {
573         lua_newtable(L);
574         int methodtable = lua_gettop(L);
575         luaL_newmetatable(L, className);
576         int metatable = lua_gettop(L);
577
578         lua_pushliteral(L, "__metatable");
579         lua_pushvalue(L, methodtable);
580         lua_settable(L, metatable);
581
582         lua_pushliteral(L, "__index");
583         lua_pushvalue(L, methodtable);
584         lua_settable(L, metatable);
585
586         lua_pushliteral(L, "__gc");
587         lua_pushcfunction(L, gc_object);
588         lua_settable(L, metatable);
589
590         lua_pop(L, 1);
591
592         luaL_openlib(L, 0, methods, 0);
593         lua_pop(L, 1);
594
595         lua_register(L, className, create_object);
596 }
597
598
599 const char LuaPcgRandom::className[] = "PcgRandom";
600 const luaL_reg LuaPcgRandom::methods[] = {
601         luamethod(LuaPcgRandom, next),
602         luamethod(LuaPcgRandom, rand_normal_dist),
603         {0,0}
604 };
605
606 ///////////////////////////////////////
607 /*
608         LuaSecureRandom
609 */
610
611 bool LuaSecureRandom::fillRandBuf()
612 {
613         return porting::secure_rand_fill_buf(m_rand_buf, RAND_BUF_SIZE);
614 }
615
616 int LuaSecureRandom::l_next_bytes(lua_State *L)
617 {
618         NO_MAP_LOCK_REQUIRED;
619
620         LuaSecureRandom *o = checkobject(L, 1);
621         u32 count = lua_isnumber(L, 2) ? lua_tointeger(L, 2) : 1;
622
623         // Limit count
624         count = MYMIN(RAND_BUF_SIZE, count);
625
626         // Find out whether we can pass directly from our array, or have to do some gluing
627         size_t count_remaining = RAND_BUF_SIZE - o->m_rand_idx;
628         if (count_remaining >= count) {
629                 lua_pushlstring(L, o->m_rand_buf + o->m_rand_idx, count);
630                 o->m_rand_idx += count;
631         } else {
632                 char output_buf[RAND_BUF_SIZE];
633
634                 // Copy over with what we have left from our current buffer
635                 memcpy(output_buf, o->m_rand_buf + o->m_rand_idx, count_remaining);
636
637                 // Refill buffer and copy over the remainder of what was requested
638                 o->fillRandBuf();
639                 memcpy(output_buf + count_remaining, o->m_rand_buf, count - count_remaining);
640
641                 // Update index
642                 o->m_rand_idx = count - count_remaining;
643
644                 lua_pushlstring(L, output_buf, count);
645         }
646
647         return 1;
648 }
649
650
651 int LuaSecureRandom::create_object(lua_State *L)
652 {
653         LuaSecureRandom *o = new LuaSecureRandom();
654
655         // Fail and return nil if we can't securely fill the buffer
656         if (!o->fillRandBuf()) {
657                 delete o;
658                 return 0;
659         }
660
661         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
662         luaL_getmetatable(L, className);
663         lua_setmetatable(L, -2);
664         return 1;
665 }
666
667
668 int LuaSecureRandom::gc_object(lua_State *L)
669 {
670         LuaSecureRandom *o = *(LuaSecureRandom **)(lua_touserdata(L, 1));
671         delete o;
672         return 0;
673 }
674
675
676 LuaSecureRandom *LuaSecureRandom::checkobject(lua_State *L, int narg)
677 {
678         luaL_checktype(L, narg, LUA_TUSERDATA);
679         void *ud = luaL_checkudata(L, narg, className);
680         if (!ud)
681                 luaL_typerror(L, narg, className);
682         return *(LuaSecureRandom **)ud;
683 }
684
685
686 void LuaSecureRandom::Register(lua_State *L)
687 {
688         lua_newtable(L);
689         int methodtable = lua_gettop(L);
690         luaL_newmetatable(L, className);
691         int metatable = lua_gettop(L);
692
693         lua_pushliteral(L, "__metatable");
694         lua_pushvalue(L, methodtable);
695         lua_settable(L, metatable);
696
697         lua_pushliteral(L, "__index");
698         lua_pushvalue(L, methodtable);
699         lua_settable(L, metatable);
700
701         lua_pushliteral(L, "__gc");
702         lua_pushcfunction(L, gc_object);
703         lua_settable(L, metatable);
704
705         lua_pop(L, 1);
706
707         luaL_openlib(L, 0, methods, 0);
708         lua_pop(L, 1);
709
710         lua_register(L, className, create_object);
711 }
712
713 const char LuaSecureRandom::className[] = "SecureRandom";
714 const luaL_reg LuaSecureRandom::methods[] = {
715         luamethod(LuaSecureRandom, next_bytes),
716         {0,0}
717 };