]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/script/common/c_converter.cpp
set_sky improvements, set_sun, set_moon and set_stars
[dragonfireclient.git] / src / script / common / c_converter.cpp
index fc489ea9574d00726009eee8ab8a849fbfcfbcc5..3c2f7564133d067524b5e2bd2daef7b65749f987 100644 (file)
@@ -23,22 +23,43 @@ extern "C" {
 }
 
 #include "util/numeric.h"
+#include "util/serialize.h"
+#include "util/string.h"
 #include "common/c_converter.h"
+#include "common/c_internal.h"
 #include "constants.h"
 
 
-#define CHECK_TYPE(index, name, type) do { \
-       int t = lua_type(L, (index)); \
-       if (t != (type)) { \
-               throw LuaError(std::string("Invalid ") + (name) + \
-                       " (expected " + lua_typename(L, (type)) + \
-                       " got " + lua_typename(L, t) + ")."); \
-       } \
-} while(0)
+#define CHECK_TYPE(index, name, type) { \
+               int t = lua_type(L, (index)); \
+               if (t != (type)) { \
+                       std::string traceback = script_get_backtrace(L); \
+                       throw LuaError(std::string("Invalid ") + (name) + \
+                               " (expected " + lua_typename(L, (type)) + \
+                               " got " + lua_typename(L, t) + ").\n" + traceback); \
+               } \
+       }
 #define CHECK_POS_COORD(name) CHECK_TYPE(-1, "position coordinate '" name "'", LUA_TNUMBER)
+#define CHECK_FLOAT_RANGE(value, name) \
+if (value < F1000_MIN || value > F1000_MAX) { \
+       std::ostringstream error_text; \
+       error_text << "Invalid float vector dimension range '" name "' " << \
+       "(expected " << F1000_MIN << " < " name " < " << F1000_MAX << \
+       " got " << value << ")." << std::endl; \
+       throw LuaError(error_text.str()); \
+}
 #define CHECK_POS_TAB(index) CHECK_TYPE(index, "position", LUA_TTABLE)
 
 
+void push_float_string(lua_State *L, float value)
+{
+       std::stringstream ss;
+       std::string str;
+       ss << value;
+       str = ss.str();
+       lua_pushstring(L, str.c_str());
+}
+
 void push_v3f(lua_State *L, v3f p)
 {
        lua_newtable(L);
@@ -59,6 +80,26 @@ void push_v2f(lua_State *L, v2f p)
        lua_setfield(L, -2, "y");
 }
 
+void push_v3_float_string(lua_State *L, v3f p)
+{
+       lua_newtable(L);
+       push_float_string(L, p.X);
+       lua_setfield(L, -2, "x");
+       push_float_string(L, p.Y);
+       lua_setfield(L, -2, "y");
+       push_float_string(L, p.Z);
+       lua_setfield(L, -2, "z");
+}
+
+void push_v2_float_string(lua_State *L, v2f p)
+{
+       lua_newtable(L);
+       push_float_string(L, p.X);
+       lua_setfield(L, -2, "x");
+       push_float_string(L, p.Y);
+       lua_setfield(L, -2, "y");
+}
+
 v2s16 read_v2s16(lua_State *L, int index)
 {
        v2s16 p;
@@ -72,19 +113,22 @@ v2s16 read_v2s16(lua_State *L, int index)
        return p;
 }
 
-v2s16 check_v2s16(lua_State *L, int index)
+void push_v2s16(lua_State *L, v2s16 p)
 {
-       v2s16 p;
-       CHECK_POS_TAB(index);
-       lua_getfield(L, index, "x");
-       CHECK_POS_COORD("x");
-       p.X = lua_tonumber(L, -1);
-       lua_pop(L, 1);
-       lua_getfield(L, index, "y");
-       CHECK_POS_COORD("y");
-       p.Y = lua_tonumber(L, -1);
-       lua_pop(L, 1);
-       return p;
+       lua_newtable(L);
+       lua_pushnumber(L, p.X);
+       lua_setfield(L, -2, "x");
+       lua_pushnumber(L, p.Y);
+       lua_setfield(L, -2, "y");
+}
+
+void push_v2s32(lua_State *L, v2s32 p)
+{
+       lua_newtable(L);
+       lua_pushnumber(L, p.X);
+       lua_setfield(L, -2, "x");
+       lua_pushnumber(L, p.Y);
+       lua_setfield(L, -2, "y");
 }
 
 v2s32 read_v2s32(lua_State *L, int index)
@@ -151,18 +195,72 @@ v3f check_v3f(lua_State *L, int index)
        lua_getfield(L, index, "x");
        CHECK_POS_COORD("x");
        pos.X = lua_tonumber(L, -1);
+       CHECK_FLOAT_RANGE(pos.X, "x")
        lua_pop(L, 1);
        lua_getfield(L, index, "y");
        CHECK_POS_COORD("y");
        pos.Y = lua_tonumber(L, -1);
+       CHECK_FLOAT_RANGE(pos.Y, "y")
        lua_pop(L, 1);
        lua_getfield(L, index, "z");
        CHECK_POS_COORD("z");
        pos.Z = lua_tonumber(L, -1);
+       CHECK_FLOAT_RANGE(pos.Z, "z")
        lua_pop(L, 1);
        return pos;
 }
 
+v3d read_v3d(lua_State *L, int index)
+{
+       v3d pos;
+       CHECK_POS_TAB(index);
+       lua_getfield(L, index, "x");
+       pos.X = lua_tonumber(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, index, "y");
+       pos.Y = lua_tonumber(L, -1);
+       lua_pop(L, 1);
+       lua_getfield(L, index, "z");
+       pos.Z = lua_tonumber(L, -1);
+       lua_pop(L, 1);
+       return pos;
+}
+
+v3d check_v3d(lua_State *L, int index)
+{
+       v3d pos;
+       CHECK_POS_TAB(index);
+       lua_getfield(L, index, "x");
+       CHECK_POS_COORD("x");
+       pos.X = lua_tonumber(L, -1);
+       CHECK_FLOAT_RANGE(pos.X, "x")
+       lua_pop(L, 1);
+       lua_getfield(L, index, "y");
+       CHECK_POS_COORD("y");
+       pos.Y = lua_tonumber(L, -1);
+       CHECK_FLOAT_RANGE(pos.Y, "y")
+       lua_pop(L, 1);
+       lua_getfield(L, index, "z");
+       CHECK_POS_COORD("z");
+       pos.Z = lua_tonumber(L, -1);
+       CHECK_FLOAT_RANGE(pos.Z, "z")
+       lua_pop(L, 1);
+       return pos;
+}
+
+void push_ARGB8(lua_State *L, video::SColor color)
+{
+       lua_newtable(L);
+       lua_pushnumber(L, color.getAlpha());
+       lua_setfield(L, -2, "a");
+       lua_pushnumber(L, color.getRed());
+       lua_setfield(L, -2, "r");
+       lua_pushnumber(L, color.getGreen());
+       lua_setfield(L, -2, "g");
+       lua_pushnumber(L, color.getBlue());
+       lua_setfield(L, -2, "b");
+}
+
 void pushFloatPos(lua_State *L, v3f p)
 {
        p /= BS;
@@ -188,24 +286,42 @@ void push_v3s16(lua_State *L, v3s16 p)
 v3s16 read_v3s16(lua_State *L, int index)
 {
        // Correct rounding at <0
-       v3f pf = read_v3f(L, index);
-       return floatToInt(pf, 1.0);
+       v3d pf = read_v3d(L, index);
+       return doubleToInt(pf, 1.0);
 }
 
 v3s16 check_v3s16(lua_State *L, int index)
 {
        // Correct rounding at <0
-       v3f pf = check_v3f(L, index);
-       return floatToInt(pf, 1.0);
+       v3d pf = check_v3d(L, index);
+       return doubleToInt(pf, 1.0);
 }
 
-video::SColor readARGB8(lua_State *L, int index)
+bool read_color(lua_State *L, int index, video::SColor *color)
+{
+       if (lua_istable(L, index)) {
+               *color = read_ARGB8(L, index);
+       } else if (lua_isnumber(L, index)) {
+               color->set(lua_tonumber(L, index));
+       } else if (lua_isstring(L, index)) {
+               video::SColor parsed_color;
+               if (!parseColorString(lua_tostring(L, index), parsed_color, true))
+                       return false;
+
+               *color = parsed_color;
+       } else {
+               return false;
+       }
+
+       return true;
+}
+
+video::SColor read_ARGB8(lua_State *L, int index)
 {
        video::SColor color(0);
        CHECK_TYPE(index, "ARGB color", LUA_TTABLE);
        lua_getfield(L, index, "a");
-       if(lua_isnumber(L, -1))
-               color.setAlpha(lua_tonumber(L, -1));
+       color.setAlpha(lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0xFF);
        lua_pop(L, 1);
        lua_getfield(L, index, "r");
        color.setRed(lua_tonumber(L, -1));
@@ -219,6 +335,28 @@ video::SColor readARGB8(lua_State *L, int index)
        return color;
 }
 
+bool is_color_table(lua_State *L, int index)
+{
+       // Check whole table in case of missing ColorSpec keys:
+       // This check does not remove the checked value from the stack.
+       // Only update the value if we know we have a valid ColorSpec key pair.
+       if (!lua_istable(L, index))
+               return false;
+
+       bool is_color_table = false;
+       lua_getfield(L, index, "r");
+       if (!is_color_table)
+               is_color_table = lua_isnumber(L, -1);
+       lua_getfield(L, index, "g");
+       if (!is_color_table)
+               is_color_table = lua_isnumber(L, -1);
+       lua_getfield(L, index, "b");
+       if (!is_color_table)
+               is_color_table = lua_isnumber(L, -1);
+       lua_pop(L, 3); // b, g, r values
+       return is_color_table;
+}
+
 aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
 {
        aabb3f box;
@@ -242,9 +380,27 @@ aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
                box.MaxEdge.Z = lua_tonumber(L, -1) * scale;
                lua_pop(L, 1);
        }
+       box.repair();
        return box;
 }
 
+void push_aabb3f(lua_State *L, aabb3f box)
+{
+       lua_newtable(L);
+       lua_pushnumber(L, box.MinEdge.X);
+       lua_rawseti(L, -2, 1);
+       lua_pushnumber(L, box.MinEdge.Y);
+       lua_rawseti(L, -2, 2);
+       lua_pushnumber(L, box.MinEdge.Z);
+       lua_rawseti(L, -2, 3);
+       lua_pushnumber(L, box.MaxEdge.X);
+       lua_rawseti(L, -2, 4);
+       lua_pushnumber(L, box.MaxEdge.Y);
+       lua_rawseti(L, -2, 5);
+       lua_pushnumber(L, box.MaxEdge.Z);
+       lua_rawseti(L, -2, 6);
+}
+
 std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
 {
        std::vector<aabb3f> boxes;
@@ -318,58 +474,6 @@ bool getstringfield(lua_State *L, int table,
        return got;
 }
 
-bool getintfield(lua_State *L, int table,
-               const char *fieldname, int &result)
-{
-       lua_getfield(L, table, fieldname);
-       bool got = false;
-       if(lua_isnumber(L, -1)){
-               result = lua_tonumber(L, -1);
-               got = true;
-       }
-       lua_pop(L, 1);
-       return got;
-}
-
-bool getintfield(lua_State *L, int table,
-               const char *fieldname, u8 &result)
-{
-       lua_getfield(L, table, fieldname);
-       bool got = false;
-       if(lua_isnumber(L, -1)){
-               result = lua_tonumber(L, -1);
-               got = true;
-       }
-       lua_pop(L, 1);
-       return got;
-}
-
-bool getintfield(lua_State *L, int table,
-               const char *fieldname, u16 &result)
-{
-       lua_getfield(L, table, fieldname);
-       bool got = false;
-       if(lua_isnumber(L, -1)){
-               result = lua_tonumber(L, -1);
-               got = true;
-       }
-       lua_pop(L, 1);
-       return got;
-}
-
-bool getintfield(lua_State *L, int table,
-               const char *fieldname, u32 &result)
-{
-       lua_getfield(L, table, fieldname);
-       bool got = false;
-       if(lua_isnumber(L, -1)){
-               result = lua_tonumber(L, -1);
-               got = true;
-       }
-       lua_pop(L, 1);
-       return got;
-}
-
 bool getfloatfield(lua_State *L, int table,
                const char *fieldname, float &result)
 {
@@ -450,6 +554,22 @@ bool getboolfield_default(lua_State *L, int table,
        return result;
 }
 
+v3s16 getv3s16field_default(lua_State *L, int table,
+               const char *fieldname, v3s16 default_)
+{
+       getv3intfield(L, table, fieldname, default_);
+       return default_;
+}
+
+void setstringfield(lua_State *L, int table,
+               const char *fieldname, const std::string &value)
+{
+       lua_pushlstring(L, value.c_str(), value.length());
+       if(table < 0)
+               table -= 1;
+       lua_setfield(L, table, fieldname);
+}
+
 void setintfield(lua_State *L, int table,
                const char *fieldname, int value)
 {
@@ -478,3 +598,95 @@ void setboolfield(lua_State *L, int table,
 }
 
 
+////
+//// Array table slices
+////
+
+size_t write_array_slice_float(
+       lua_State *L,
+       int table_index,
+       float *data,
+       v3u16 data_size,
+       v3u16 slice_offset,
+       v3u16 slice_size)
+{
+       v3u16 pmin, pmax(data_size);
+
+       if (slice_offset.X > 0) {
+               slice_offset.X--;
+               pmin.X = slice_offset.X;
+               pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
+       }
+
+       if (slice_offset.Y > 0) {
+               slice_offset.Y--;
+               pmin.Y = slice_offset.Y;
+               pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
+       }
+
+       if (slice_offset.Z > 0) {
+               slice_offset.Z--;
+               pmin.Z = slice_offset.Z;
+               pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
+       }
+
+       const u32 ystride = data_size.X;
+       const u32 zstride = data_size.X * data_size.Y;
+
+       u32 elem_index = 1;
+       for (u32 z = pmin.Z; z != pmax.Z; z++)
+       for (u32 y = pmin.Y; y != pmax.Y; y++)
+       for (u32 x = pmin.X; x != pmax.X; x++) {
+               u32 i = z * zstride + y * ystride + x;
+               lua_pushnumber(L, data[i]);
+               lua_rawseti(L, table_index, elem_index);
+               elem_index++;
+       }
+
+       return elem_index - 1;
+}
+
+
+size_t write_array_slice_u16(
+       lua_State *L,
+       int table_index,
+       u16 *data,
+       v3u16 data_size,
+       v3u16 slice_offset,
+       v3u16 slice_size)
+{
+       v3u16 pmin, pmax(data_size);
+
+       if (slice_offset.X > 0) {
+               slice_offset.X--;
+               pmin.X = slice_offset.X;
+               pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
+       }
+
+       if (slice_offset.Y > 0) {
+               slice_offset.Y--;
+               pmin.Y = slice_offset.Y;
+               pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
+       }
+
+       if (slice_offset.Z > 0) {
+               slice_offset.Z--;
+               pmin.Z = slice_offset.Z;
+               pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
+       }
+
+       const u32 ystride = data_size.X;
+       const u32 zstride = data_size.X * data_size.Y;
+
+       u32 elem_index = 1;
+       for (u32 z = pmin.Z; z != pmax.Z; z++)
+       for (u32 y = pmin.Y; y != pmax.Y; y++)
+       for (u32 x = pmin.X; x != pmax.X; x++) {
+               u32 i = z * zstride + y * ystride + x;
+               lua_pushinteger(L, data[i]);
+               lua_rawseti(L, table_index, elem_index);
+               elem_index++;
+       }
+
+       return elem_index - 1;
+}