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