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