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