]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/common/c_converter.cpp
set_sky improvements, set_sun, set_moon and set_stars
[dragonfireclient.git] / src / script / common / c_converter.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 extern "C" {
21 #include "lua.h"
22 #include "lauxlib.h"
23 }
24
25 #include "util/numeric.h"
26 #include "util/serialize.h"
27 #include "util/string.h"
28 #include "common/c_converter.h"
29 #include "common/c_internal.h"
30 #include "constants.h"
31
32
33 #define CHECK_TYPE(index, name, type) { \
34                 int t = lua_type(L, (index)); \
35                 if (t != (type)) { \
36                         std::string traceback = script_get_backtrace(L); \
37                         throw LuaError(std::string("Invalid ") + (name) + \
38                                 " (expected " + lua_typename(L, (type)) + \
39                                 " got " + lua_typename(L, t) + ").\n" + traceback); \
40                 } \
41         }
42 #define CHECK_POS_COORD(name) CHECK_TYPE(-1, "position coordinate '" name "'", LUA_TNUMBER)
43 #define CHECK_FLOAT_RANGE(value, name) \
44 if (value < F1000_MIN || value > F1000_MAX) { \
45         std::ostringstream error_text; \
46         error_text << "Invalid float vector dimension range '" name "' " << \
47         "(expected " << F1000_MIN << " < " name " < " << F1000_MAX << \
48         " got " << value << ")." << std::endl; \
49         throw LuaError(error_text.str()); \
50 }
51 #define CHECK_POS_TAB(index) CHECK_TYPE(index, "position", LUA_TTABLE)
52
53
54 void push_float_string(lua_State *L, float value)
55 {
56         std::stringstream ss;
57         std::string str;
58         ss << value;
59         str = ss.str();
60         lua_pushstring(L, str.c_str());
61 }
62
63 void push_v3f(lua_State *L, v3f p)
64 {
65         lua_newtable(L);
66         lua_pushnumber(L, p.X);
67         lua_setfield(L, -2, "x");
68         lua_pushnumber(L, p.Y);
69         lua_setfield(L, -2, "y");
70         lua_pushnumber(L, p.Z);
71         lua_setfield(L, -2, "z");
72 }
73
74 void push_v2f(lua_State *L, v2f p)
75 {
76         lua_newtable(L);
77         lua_pushnumber(L, p.X);
78         lua_setfield(L, -2, "x");
79         lua_pushnumber(L, p.Y);
80         lua_setfield(L, -2, "y");
81 }
82
83 void push_v3_float_string(lua_State *L, v3f p)
84 {
85         lua_newtable(L);
86         push_float_string(L, p.X);
87         lua_setfield(L, -2, "x");
88         push_float_string(L, p.Y);
89         lua_setfield(L, -2, "y");
90         push_float_string(L, p.Z);
91         lua_setfield(L, -2, "z");
92 }
93
94 void push_v2_float_string(lua_State *L, v2f p)
95 {
96         lua_newtable(L);
97         push_float_string(L, p.X);
98         lua_setfield(L, -2, "x");
99         push_float_string(L, p.Y);
100         lua_setfield(L, -2, "y");
101 }
102
103 v2s16 read_v2s16(lua_State *L, int index)
104 {
105         v2s16 p;
106         CHECK_POS_TAB(index);
107         lua_getfield(L, index, "x");
108         p.X = lua_tonumber(L, -1);
109         lua_pop(L, 1);
110         lua_getfield(L, index, "y");
111         p.Y = lua_tonumber(L, -1);
112         lua_pop(L, 1);
113         return p;
114 }
115
116 void push_v2s16(lua_State *L, v2s16 p)
117 {
118         lua_newtable(L);
119         lua_pushnumber(L, p.X);
120         lua_setfield(L, -2, "x");
121         lua_pushnumber(L, p.Y);
122         lua_setfield(L, -2, "y");
123 }
124
125 void push_v2s32(lua_State *L, v2s32 p)
126 {
127         lua_newtable(L);
128         lua_pushnumber(L, p.X);
129         lua_setfield(L, -2, "x");
130         lua_pushnumber(L, p.Y);
131         lua_setfield(L, -2, "y");
132 }
133
134 v2s32 read_v2s32(lua_State *L, int index)
135 {
136         v2s32 p;
137         CHECK_POS_TAB(index);
138         lua_getfield(L, index, "x");
139         p.X = lua_tonumber(L, -1);
140         lua_pop(L, 1);
141         lua_getfield(L, index, "y");
142         p.Y = lua_tonumber(L, -1);
143         lua_pop(L, 1);
144         return p;
145 }
146
147 v2f read_v2f(lua_State *L, int index)
148 {
149         v2f p;
150         CHECK_POS_TAB(index);
151         lua_getfield(L, index, "x");
152         p.X = lua_tonumber(L, -1);
153         lua_pop(L, 1);
154         lua_getfield(L, index, "y");
155         p.Y = lua_tonumber(L, -1);
156         lua_pop(L, 1);
157         return p;
158 }
159
160 v2f check_v2f(lua_State *L, int index)
161 {
162         v2f p;
163         CHECK_POS_TAB(index);
164         lua_getfield(L, index, "x");
165         CHECK_POS_COORD("x");
166         p.X = lua_tonumber(L, -1);
167         lua_pop(L, 1);
168         lua_getfield(L, index, "y");
169         CHECK_POS_COORD("y");
170         p.Y = lua_tonumber(L, -1);
171         lua_pop(L, 1);
172         return p;
173 }
174
175 v3f read_v3f(lua_State *L, int index)
176 {
177         v3f pos;
178         CHECK_POS_TAB(index);
179         lua_getfield(L, index, "x");
180         pos.X = lua_tonumber(L, -1);
181         lua_pop(L, 1);
182         lua_getfield(L, index, "y");
183         pos.Y = lua_tonumber(L, -1);
184         lua_pop(L, 1);
185         lua_getfield(L, index, "z");
186         pos.Z = lua_tonumber(L, -1);
187         lua_pop(L, 1);
188         return pos;
189 }
190
191 v3f check_v3f(lua_State *L, int index)
192 {
193         v3f pos;
194         CHECK_POS_TAB(index);
195         lua_getfield(L, index, "x");
196         CHECK_POS_COORD("x");
197         pos.X = lua_tonumber(L, -1);
198         CHECK_FLOAT_RANGE(pos.X, "x")
199         lua_pop(L, 1);
200         lua_getfield(L, index, "y");
201         CHECK_POS_COORD("y");
202         pos.Y = lua_tonumber(L, -1);
203         CHECK_FLOAT_RANGE(pos.Y, "y")
204         lua_pop(L, 1);
205         lua_getfield(L, index, "z");
206         CHECK_POS_COORD("z");
207         pos.Z = lua_tonumber(L, -1);
208         CHECK_FLOAT_RANGE(pos.Z, "z")
209         lua_pop(L, 1);
210         return pos;
211 }
212
213 v3d read_v3d(lua_State *L, int index)
214 {
215         v3d pos;
216         CHECK_POS_TAB(index);
217         lua_getfield(L, index, "x");
218         pos.X = lua_tonumber(L, -1);
219         lua_pop(L, 1);
220         lua_getfield(L, index, "y");
221         pos.Y = lua_tonumber(L, -1);
222         lua_pop(L, 1);
223         lua_getfield(L, index, "z");
224         pos.Z = lua_tonumber(L, -1);
225         lua_pop(L, 1);
226         return pos;
227 }
228
229 v3d check_v3d(lua_State *L, int index)
230 {
231         v3d pos;
232         CHECK_POS_TAB(index);
233         lua_getfield(L, index, "x");
234         CHECK_POS_COORD("x");
235         pos.X = lua_tonumber(L, -1);
236         CHECK_FLOAT_RANGE(pos.X, "x")
237         lua_pop(L, 1);
238         lua_getfield(L, index, "y");
239         CHECK_POS_COORD("y");
240         pos.Y = lua_tonumber(L, -1);
241         CHECK_FLOAT_RANGE(pos.Y, "y")
242         lua_pop(L, 1);
243         lua_getfield(L, index, "z");
244         CHECK_POS_COORD("z");
245         pos.Z = lua_tonumber(L, -1);
246         CHECK_FLOAT_RANGE(pos.Z, "z")
247         lua_pop(L, 1);
248         return pos;
249 }
250
251 void push_ARGB8(lua_State *L, video::SColor color)
252 {
253         lua_newtable(L);
254         lua_pushnumber(L, color.getAlpha());
255         lua_setfield(L, -2, "a");
256         lua_pushnumber(L, color.getRed());
257         lua_setfield(L, -2, "r");
258         lua_pushnumber(L, color.getGreen());
259         lua_setfield(L, -2, "g");
260         lua_pushnumber(L, color.getBlue());
261         lua_setfield(L, -2, "b");
262 }
263
264 void pushFloatPos(lua_State *L, v3f p)
265 {
266         p /= BS;
267         push_v3f(L, p);
268 }
269
270 v3f checkFloatPos(lua_State *L, int index)
271 {
272         return check_v3f(L, index) * BS;
273 }
274
275 void push_v3s16(lua_State *L, v3s16 p)
276 {
277         lua_newtable(L);
278         lua_pushnumber(L, p.X);
279         lua_setfield(L, -2, "x");
280         lua_pushnumber(L, p.Y);
281         lua_setfield(L, -2, "y");
282         lua_pushnumber(L, p.Z);
283         lua_setfield(L, -2, "z");
284 }
285
286 v3s16 read_v3s16(lua_State *L, int index)
287 {
288         // Correct rounding at <0
289         v3d pf = read_v3d(L, index);
290         return doubleToInt(pf, 1.0);
291 }
292
293 v3s16 check_v3s16(lua_State *L, int index)
294 {
295         // Correct rounding at <0
296         v3d pf = check_v3d(L, index);
297         return doubleToInt(pf, 1.0);
298 }
299
300 bool read_color(lua_State *L, int index, video::SColor *color)
301 {
302         if (lua_istable(L, index)) {
303                 *color = read_ARGB8(L, index);
304         } else if (lua_isnumber(L, index)) {
305                 color->set(lua_tonumber(L, index));
306         } else if (lua_isstring(L, index)) {
307                 video::SColor parsed_color;
308                 if (!parseColorString(lua_tostring(L, index), parsed_color, true))
309                         return false;
310
311                 *color = parsed_color;
312         } else {
313                 return false;
314         }
315
316         return true;
317 }
318
319 video::SColor read_ARGB8(lua_State *L, int index)
320 {
321         video::SColor color(0);
322         CHECK_TYPE(index, "ARGB color", LUA_TTABLE);
323         lua_getfield(L, index, "a");
324         color.setAlpha(lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0xFF);
325         lua_pop(L, 1);
326         lua_getfield(L, index, "r");
327         color.setRed(lua_tonumber(L, -1));
328         lua_pop(L, 1);
329         lua_getfield(L, index, "g");
330         color.setGreen(lua_tonumber(L, -1));
331         lua_pop(L, 1);
332         lua_getfield(L, index, "b");
333         color.setBlue(lua_tonumber(L, -1));
334         lua_pop(L, 1);
335         return color;
336 }
337
338 bool is_color_table(lua_State *L, int index)
339 {
340         // Check whole table in case of missing ColorSpec keys:
341         // This check does not remove the checked value from the stack.
342         // Only update the value if we know we have a valid ColorSpec key pair.
343         if (!lua_istable(L, index))
344                 return false;
345
346         bool is_color_table = false;
347         lua_getfield(L, index, "r");
348         if (!is_color_table)
349                 is_color_table = lua_isnumber(L, -1);
350         lua_getfield(L, index, "g");
351         if (!is_color_table)
352                 is_color_table = lua_isnumber(L, -1);
353         lua_getfield(L, index, "b");
354         if (!is_color_table)
355                 is_color_table = lua_isnumber(L, -1);
356         lua_pop(L, 3); // b, g, r values
357         return is_color_table;
358 }
359
360 aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
361 {
362         aabb3f box;
363         if(lua_istable(L, index)){
364                 lua_rawgeti(L, index, 1);
365                 box.MinEdge.X = lua_tonumber(L, -1) * scale;
366                 lua_pop(L, 1);
367                 lua_rawgeti(L, index, 2);
368                 box.MinEdge.Y = lua_tonumber(L, -1) * scale;
369                 lua_pop(L, 1);
370                 lua_rawgeti(L, index, 3);
371                 box.MinEdge.Z = lua_tonumber(L, -1) * scale;
372                 lua_pop(L, 1);
373                 lua_rawgeti(L, index, 4);
374                 box.MaxEdge.X = lua_tonumber(L, -1) * scale;
375                 lua_pop(L, 1);
376                 lua_rawgeti(L, index, 5);
377                 box.MaxEdge.Y = lua_tonumber(L, -1) * scale;
378                 lua_pop(L, 1);
379                 lua_rawgeti(L, index, 6);
380                 box.MaxEdge.Z = lua_tonumber(L, -1) * scale;
381                 lua_pop(L, 1);
382         }
383         box.repair();
384         return box;
385 }
386
387 void push_aabb3f(lua_State *L, aabb3f box)
388 {
389         lua_newtable(L);
390         lua_pushnumber(L, box.MinEdge.X);
391         lua_rawseti(L, -2, 1);
392         lua_pushnumber(L, box.MinEdge.Y);
393         lua_rawseti(L, -2, 2);
394         lua_pushnumber(L, box.MinEdge.Z);
395         lua_rawseti(L, -2, 3);
396         lua_pushnumber(L, box.MaxEdge.X);
397         lua_rawseti(L, -2, 4);
398         lua_pushnumber(L, box.MaxEdge.Y);
399         lua_rawseti(L, -2, 5);
400         lua_pushnumber(L, box.MaxEdge.Z);
401         lua_rawseti(L, -2, 6);
402 }
403
404 std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
405 {
406         std::vector<aabb3f> boxes;
407         if(lua_istable(L, index)){
408                 int n = lua_objlen(L, index);
409                 // Check if it's a single box or a list of boxes
410                 bool possibly_single_box = (n == 6);
411                 for(int i = 1; i <= n && possibly_single_box; i++){
412                         lua_rawgeti(L, index, i);
413                         if(!lua_isnumber(L, -1))
414                                 possibly_single_box = false;
415                         lua_pop(L, 1);
416                 }
417                 if(possibly_single_box){
418                         // Read a single box
419                         boxes.push_back(read_aabb3f(L, index, scale));
420                 } else {
421                         // Read a list of boxes
422                         for(int i = 1; i <= n; i++){
423                                 lua_rawgeti(L, index, i);
424                                 boxes.push_back(read_aabb3f(L, -1, scale));
425                                 lua_pop(L, 1);
426                         }
427                 }
428         }
429         return boxes;
430 }
431
432 size_t read_stringlist(lua_State *L, int index, std::vector<std::string> *result)
433 {
434         if (index < 0)
435                 index = lua_gettop(L) + 1 + index;
436
437         size_t num_strings = 0;
438
439         if (lua_istable(L, index)) {
440                 lua_pushnil(L);
441                 while (lua_next(L, index)) {
442                         if (lua_isstring(L, -1)) {
443                                 result->push_back(lua_tostring(L, -1));
444                                 num_strings++;
445                         }
446                         lua_pop(L, 1);
447                 }
448         } else if (lua_isstring(L, index)) {
449                 result->push_back(lua_tostring(L, index));
450                 num_strings++;
451         }
452
453         return num_strings;
454 }
455
456 /*
457         Table field getters
458 */
459
460 bool getstringfield(lua_State *L, int table,
461                 const char *fieldname, std::string &result)
462 {
463         lua_getfield(L, table, fieldname);
464         bool got = false;
465         if(lua_isstring(L, -1)){
466                 size_t len = 0;
467                 const char *ptr = lua_tolstring(L, -1, &len);
468                 if (ptr) {
469                         result.assign(ptr, len);
470                         got = true;
471                 }
472         }
473         lua_pop(L, 1);
474         return got;
475 }
476
477 bool getfloatfield(lua_State *L, int table,
478                 const char *fieldname, float &result)
479 {
480         lua_getfield(L, table, fieldname);
481         bool got = false;
482         if(lua_isnumber(L, -1)){
483                 result = lua_tonumber(L, -1);
484                 got = true;
485         }
486         lua_pop(L, 1);
487         return got;
488 }
489
490 bool getboolfield(lua_State *L, int table,
491                 const char *fieldname, bool &result)
492 {
493         lua_getfield(L, table, fieldname);
494         bool got = false;
495         if(lua_isboolean(L, -1)){
496                 result = lua_toboolean(L, -1);
497                 got = true;
498         }
499         lua_pop(L, 1);
500         return got;
501 }
502
503 size_t getstringlistfield(lua_State *L, int table, const char *fieldname,
504                 std::vector<std::string> *result)
505 {
506         lua_getfield(L, table, fieldname);
507
508         size_t num_strings_read = read_stringlist(L, -1, result);
509
510         lua_pop(L, 1);
511         return num_strings_read;
512 }
513
514 std::string checkstringfield(lua_State *L, int table,
515                 const char *fieldname)
516 {
517         lua_getfield(L, table, fieldname);
518         CHECK_TYPE(-1, std::string("field \"") + fieldname + '"', LUA_TSTRING);
519         size_t len;
520         const char *s = lua_tolstring(L, -1, &len);
521         lua_pop(L, 1);
522         return std::string(s, len);
523 }
524
525 std::string getstringfield_default(lua_State *L, int table,
526                 const char *fieldname, const std::string &default_)
527 {
528         std::string result = default_;
529         getstringfield(L, table, fieldname, result);
530         return result;
531 }
532
533 int getintfield_default(lua_State *L, int table,
534                 const char *fieldname, int default_)
535 {
536         int result = default_;
537         getintfield(L, table, fieldname, result);
538         return result;
539 }
540
541 float getfloatfield_default(lua_State *L, int table,
542                 const char *fieldname, float default_)
543 {
544         float result = default_;
545         getfloatfield(L, table, fieldname, result);
546         return result;
547 }
548
549 bool getboolfield_default(lua_State *L, int table,
550                 const char *fieldname, bool default_)
551 {
552         bool result = default_;
553         getboolfield(L, table, fieldname, result);
554         return result;
555 }
556
557 v3s16 getv3s16field_default(lua_State *L, int table,
558                 const char *fieldname, v3s16 default_)
559 {
560         getv3intfield(L, table, fieldname, default_);
561         return default_;
562 }
563
564 void setstringfield(lua_State *L, int table,
565                 const char *fieldname, const std::string &value)
566 {
567         lua_pushlstring(L, value.c_str(), value.length());
568         if(table < 0)
569                 table -= 1;
570         lua_setfield(L, table, fieldname);
571 }
572
573 void setintfield(lua_State *L, int table,
574                 const char *fieldname, int value)
575 {
576         lua_pushinteger(L, value);
577         if(table < 0)
578                 table -= 1;
579         lua_setfield(L, table, fieldname);
580 }
581
582 void setfloatfield(lua_State *L, int table,
583                 const char *fieldname, float value)
584 {
585         lua_pushnumber(L, value);
586         if(table < 0)
587                 table -= 1;
588         lua_setfield(L, table, fieldname);
589 }
590
591 void setboolfield(lua_State *L, int table,
592                 const char *fieldname, bool value)
593 {
594         lua_pushboolean(L, value);
595         if(table < 0)
596                 table -= 1;
597         lua_setfield(L, table, fieldname);
598 }
599
600
601 ////
602 //// Array table slices
603 ////
604
605 size_t write_array_slice_float(
606         lua_State *L,
607         int table_index,
608         float *data,
609         v3u16 data_size,
610         v3u16 slice_offset,
611         v3u16 slice_size)
612 {
613         v3u16 pmin, pmax(data_size);
614
615         if (slice_offset.X > 0) {
616                 slice_offset.X--;
617                 pmin.X = slice_offset.X;
618                 pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
619         }
620
621         if (slice_offset.Y > 0) {
622                 slice_offset.Y--;
623                 pmin.Y = slice_offset.Y;
624                 pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
625         }
626
627         if (slice_offset.Z > 0) {
628                 slice_offset.Z--;
629                 pmin.Z = slice_offset.Z;
630                 pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
631         }
632
633         const u32 ystride = data_size.X;
634         const u32 zstride = data_size.X * data_size.Y;
635
636         u32 elem_index = 1;
637         for (u32 z = pmin.Z; z != pmax.Z; z++)
638         for (u32 y = pmin.Y; y != pmax.Y; y++)
639         for (u32 x = pmin.X; x != pmax.X; x++) {
640                 u32 i = z * zstride + y * ystride + x;
641                 lua_pushnumber(L, data[i]);
642                 lua_rawseti(L, table_index, elem_index);
643                 elem_index++;
644         }
645
646         return elem_index - 1;
647 }
648
649
650 size_t write_array_slice_u16(
651         lua_State *L,
652         int table_index,
653         u16 *data,
654         v3u16 data_size,
655         v3u16 slice_offset,
656         v3u16 slice_size)
657 {
658         v3u16 pmin, pmax(data_size);
659
660         if (slice_offset.X > 0) {
661                 slice_offset.X--;
662                 pmin.X = slice_offset.X;
663                 pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
664         }
665
666         if (slice_offset.Y > 0) {
667                 slice_offset.Y--;
668                 pmin.Y = slice_offset.Y;
669                 pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
670         }
671
672         if (slice_offset.Z > 0) {
673                 slice_offset.Z--;
674                 pmin.Z = slice_offset.Z;
675                 pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
676         }
677
678         const u32 ystride = data_size.X;
679         const u32 zstride = data_size.X * data_size.Y;
680
681         u32 elem_index = 1;
682         for (u32 z = pmin.Z; z != pmax.Z; z++)
683         for (u32 y = pmin.Y; y != pmax.Y; y++)
684         for (u32 x = pmin.X; x != pmax.X; x++) {
685                 u32 i = z * zstride + y * ystride + x;
686                 lua_pushinteger(L, data[i]);
687                 lua_rawseti(L, table_index, elem_index);
688                 elem_index++;
689         }
690
691         return elem_index - 1;
692 }