| #ifdef WITH_RIVE_SCRIPTING | |
| #include "rive/lua/rive_lua_libs.hpp" | |
| #include "rive/data_bind/data_values/data_value_number.hpp" | |
| #include <math.h> | |
| #include <stdio.h> | |
| using namespace rive; | |
| ScriptedDataValue::~ScriptedDataValue() | |
| { | |
| if (m_dataValue) | |
| { | |
| delete m_dataValue; | |
| } | |
| } | |
| static int property_namecall_atom(lua_State* L, | |
| ScriptedDataValue* scriptedDataValue, | |
| uint8_t tag, | |
| int atom, | |
| bool& error) | |
| { | |
| switch (atom) | |
| { | |
| case (int)LuaAtoms::value: | |
| { | |
| assert(scriptedDataValue->state() == L); | |
| switch (tag) | |
| { | |
| case ScriptedDataValueNumber::luaTag: | |
| { | |
| auto dataValue = | |
| scriptedDataValue->dataValue()->as<DataValueNumber>(); | |
| lua_pushnumber(L, dataValue->value()); | |
| return 1; | |
| } | |
| case ScriptedDataValueString::luaTag: | |
| { | |
| auto dataValue = | |
| scriptedDataValue->dataValue()->as<DataValueString>(); | |
| lua_pushstring(L, dataValue->value().c_str()); | |
| return 1; | |
| } | |
| case ScriptedDataValueBoolean::luaTag: | |
| { | |
| auto dataValue = | |
| scriptedDataValue->dataValue()->as<DataValueBoolean>(); | |
| lua_pushboolean(L, dataValue->value() ? 1 : 0); | |
| return 1; | |
| } | |
| case ScriptedDataValueColor::luaTag: | |
| { | |
| auto dataValue = | |
| scriptedDataValue->dataValue()->as<DataValueColor>(); | |
| lua_pushinteger(L, dataValue->value()); | |
| return 1; | |
| } | |
| } | |
| } | |
| case (int)LuaAtoms::red: | |
| { | |
| assert(scriptedDataValue->state() == L); | |
| switch (tag) | |
| { | |
| case ScriptedDataValueColor::luaTag: | |
| { | |
| auto dataValue = | |
| scriptedDataValue->dataValue()->as<DataValueColor>(); | |
| lua_pushinteger(L, dataValue->red()); | |
| return 1; | |
| } | |
| } | |
| } | |
| case (int)LuaAtoms::green: | |
| { | |
| assert(scriptedDataValue->state() == L); | |
| switch (tag) | |
| { | |
| case ScriptedDataValueColor::luaTag: | |
| { | |
| auto dataValue = | |
| scriptedDataValue->dataValue()->as<DataValueColor>(); | |
| lua_pushinteger(L, dataValue->green()); | |
| return 1; | |
| } | |
| } | |
| } | |
| case (int)LuaAtoms::blue: | |
| { | |
| assert(scriptedDataValue->state() == L); | |
| switch (tag) | |
| { | |
| case ScriptedDataValueColor::luaTag: | |
| { | |
| auto dataValue = | |
| scriptedDataValue->dataValue()->as<DataValueColor>(); | |
| lua_pushinteger(L, dataValue->blue()); | |
| return 1; | |
| } | |
| } | |
| } | |
| case (int)LuaAtoms::alpha: | |
| { | |
| assert(scriptedDataValue->state() == L); | |
| switch (tag) | |
| { | |
| case ScriptedDataValueColor::luaTag: | |
| { | |
| auto dataValue = | |
| scriptedDataValue->dataValue()->as<DataValueColor>(); | |
| lua_pushinteger(L, dataValue->alpha()); | |
| return 1; | |
| } | |
| } | |
| } | |
| } | |
| error = true; | |
| return 0; | |
| } | |
| // Direct field getters dispatched per-tag. Each ScriptedDataValue subtype has | |
| // its own luaTag, so we can register without needing the inner tag switch the | |
| // slow path uses. | |
| static void data_value_number_direct_value(void* udata, void* result) | |
| { | |
| auto* self = (ScriptedDataValue*)udata; | |
| lua_userdatadirectfield_setnumber( | |
| result, | |
| self->dataValue()->as<DataValueNumber>()->value()); | |
| } | |
| static void data_value_boolean_direct_value(void* udata, void* result) | |
| { | |
| auto* self = (ScriptedDataValue*)udata; | |
| lua_userdatadirectfield_setboolean( | |
| result, | |
| self->dataValue()->as<DataValueBoolean>()->value() ? 1 : 0); | |
| } | |
| static void data_value_color_direct_value(void* udata, void* result) | |
| { | |
| auto* self = (ScriptedDataValue*)udata; | |
| lua_userdatadirectfield_setnumber( | |
| result, | |
| (double)self->dataValue()->as<DataValueColor>()->value()); | |
| } | |
| static void data_value_color_direct_red(void* udata, void* result) | |
| { | |
| auto* self = (ScriptedDataValue*)udata; | |
| lua_userdatadirectfield_setnumber( | |
| result, | |
| (double)self->dataValue()->as<DataValueColor>()->red()); | |
| } | |
| static void data_value_color_direct_green(void* udata, void* result) | |
| { | |
| auto* self = (ScriptedDataValue*)udata; | |
| lua_userdatadirectfield_setnumber( | |
| result, | |
| (double)self->dataValue()->as<DataValueColor>()->green()); | |
| } | |
| static void data_value_color_direct_blue(void* udata, void* result) | |
| { | |
| auto* self = (ScriptedDataValue*)udata; | |
| lua_userdatadirectfield_setnumber( | |
| result, | |
| (double)self->dataValue()->as<DataValueColor>()->blue()); | |
| } | |
| static void data_value_color_direct_alpha(void* udata, void* result) | |
| { | |
| auto* self = (ScriptedDataValue*)udata; | |
| lua_userdatadirectfield_setnumber( | |
| result, | |
| (double)self->dataValue()->as<DataValueColor>()->alpha()); | |
| } | |
| static int data_value_index(lua_State* L) | |
| { | |
| int atom; | |
| lua_tostringatom(L, 2, &atom); | |
| size_t namelen = 0; | |
| const char* name = luaL_checklstring(L, 2, &namelen); | |
| auto tag = lua_userdatatag(L, 1); | |
| auto scriptedDataValue = (ScriptedDataValue*)lua_touserdata(L, 1); | |
| bool error = false; | |
| int stackChange = | |
| property_namecall_atom(L, scriptedDataValue, tag, atom, error); | |
| if (!error) | |
| { | |
| return stackChange; | |
| } | |
| luaL_error(L, "'%s' is not a valid index of DataValue", name); | |
| return 0; | |
| } | |
| static int data_value_newindex(lua_State* L) | |
| { | |
| int atom; | |
| const char* key = lua_tostringatom(L, 2, &atom); | |
| if (!key) | |
| { | |
| luaL_typeerrorL(L, 2, lua_typename(L, LUA_TSTRING)); | |
| return 0; | |
| } | |
| auto tag = lua_userdatatag(L, 1); | |
| auto scriptedDataValue = (ScriptedDataValue*)lua_touserdata(L, 1); | |
| switch (atom) | |
| { | |
| case (int)LuaAtoms::value: | |
| { | |
| switch (tag) | |
| { | |
| case ScriptedDataValueNumber::luaTag: | |
| { | |
| auto val = float(luaL_checknumber(L, 3)); | |
| scriptedDataValue->dataValue() | |
| ->as<DataValueNumber>() | |
| ->value(val); | |
| return 1; | |
| } | |
| case ScriptedDataValueString::luaTag: | |
| { | |
| auto val = luaL_checkstring(L, 3); | |
| scriptedDataValue->dataValue() | |
| ->as<DataValueString>() | |
| ->value(val); | |
| return 1; | |
| } | |
| case ScriptedDataValueBoolean::luaTag: | |
| { | |
| auto val = luaL_checkboolean(L, 3); | |
| scriptedDataValue->dataValue() | |
| ->as<DataValueBoolean>() | |
| ->value(val != 0); | |
| return 1; | |
| } | |
| case ScriptedDataValueColor::luaTag: | |
| { | |
| auto val = luaL_checkunsigned(L, 3); | |
| scriptedDataValue->dataValue()->as<DataValueColor>()->value( | |
| val); | |
| return 1; | |
| } | |
| } | |
| } | |
| case (int)LuaAtoms::red: | |
| { | |
| switch (tag) | |
| { | |
| case ScriptedDataValueColor::luaTag: | |
| { | |
| auto val = luaL_checkinteger(L, 3); | |
| scriptedDataValue->dataValue()->as<DataValueColor>()->red( | |
| val); | |
| return 1; | |
| } | |
| default: | |
| return 1; | |
| } | |
| } | |
| case (int)LuaAtoms::green: | |
| { | |
| switch (tag) | |
| { | |
| case ScriptedDataValueColor::luaTag: | |
| { | |
| auto val = luaL_checkinteger(L, 3); | |
| scriptedDataValue->dataValue()->as<DataValueColor>()->green( | |
| val); | |
| return 1; | |
| } | |
| default: | |
| return 1; | |
| } | |
| } | |
| case (int)LuaAtoms::blue: | |
| { | |
| switch (tag) | |
| { | |
| case ScriptedDataValueColor::luaTag: | |
| { | |
| auto val = luaL_checkinteger(L, 3); | |
| scriptedDataValue->dataValue()->as<DataValueColor>()->blue( | |
| val); | |
| return 1; | |
| } | |
| default: | |
| return 1; | |
| } | |
| } | |
| case (int)LuaAtoms::alpha: | |
| { | |
| switch (tag) | |
| { | |
| case ScriptedDataValueColor::luaTag: | |
| { | |
| auto val = luaL_checkinteger(L, 3); | |
| scriptedDataValue->dataValue()->as<DataValueColor>()->alpha( | |
| val); | |
| return 1; | |
| } | |
| default: | |
| return 1; | |
| } | |
| } | |
| default: | |
| return 0; | |
| } | |
| return 0; | |
| } | |
| static int dataValue_number(lua_State* L) | |
| { | |
| lua_newrive<ScriptedDataValueNumber>(L, L, 0); | |
| return 1; | |
| } | |
| static int dataValue_string(lua_State* L) | |
| { | |
| lua_newrive<ScriptedDataValueString>(L, L, ""); | |
| return 1; | |
| } | |
| static int dataValue_boolean(lua_State* L) | |
| { | |
| lua_newrive<ScriptedDataValueBoolean>(L, L, false); | |
| return 1; | |
| } | |
| static int dataValue_color(lua_State* L) | |
| { | |
| lua_newrive<ScriptedDataValueColor>(L, L, 0); | |
| return 1; | |
| } | |
| static int data_value_namecall(lua_State* L) | |
| { | |
| int atom; | |
| const char* str = lua_namecallatom(L, &atom); | |
| if (str != nullptr) | |
| { | |
| auto dataValue = (ScriptedDataValue*)lua_touserdata(L, 1); | |
| switch (atom) | |
| { | |
| case (int)LuaAtoms::isNumber: | |
| { | |
| assert(dataValue->state() == L); | |
| lua_pushboolean(L, dataValue->isNumber() ? 1 : 0); | |
| return 1; | |
| } | |
| case (int)LuaAtoms::isString: | |
| { | |
| assert(dataValue->state() == L); | |
| lua_pushboolean(L, dataValue->isString() ? 1 : 0); | |
| return 1; | |
| } | |
| case (int)LuaAtoms::isBoolean: | |
| { | |
| assert(dataValue->state() == L); | |
| lua_pushboolean(L, dataValue->isBoolean() ? 1 : 0); | |
| return 1; | |
| } | |
| case (int)LuaAtoms::isColor: | |
| { | |
| assert(dataValue->state() == L); | |
| lua_pushboolean(L, dataValue->isColor() ? 1 : 0); | |
| return 1; | |
| } | |
| default: | |
| break; | |
| } | |
| } | |
| luaL_error(L, | |
| "%s is not a valid method of %s", | |
| str, | |
| ScriptedPropertyViewModel::luaName); | |
| return 0; | |
| } | |
| static const luaL_Reg dataValueStaticMethods[] = { | |
| {"number", dataValue_number}, | |
| {"string", dataValue_string}, | |
| {"boolean", dataValue_boolean}, | |
| {"color", dataValue_color}, | |
| {nullptr, nullptr}}; | |
| int luaopen_rive_data_values(lua_State* L) | |
| { | |
| { | |
| luaL_register(L, ScriptedDataValue::luaName, dataValueStaticMethods); | |
| } | |
| { | |
| lua_register_rive<ScriptedDataValueNumber>(L); | |
| lua_pushcfunction(L, data_value_index, nullptr); | |
| lua_setfield(L, -2, "__index"); | |
| lua_pushcfunction(L, data_value_newindex, nullptr); | |
| lua_setfield(L, -2, "__newindex"); | |
| lua_pushcfunction(L, data_value_namecall, nullptr); | |
| lua_setfield(L, -2, "__namecall"); | |
| lua_setreadonly(L, -1, true); | |
| lua_pop(L, 1); // pop the metatable | |
| lua_registeruserdatadirectfieldget(L, | |
| ScriptedDataValueNumber::luaTag, | |
| "value", | |
| data_value_number_direct_value); | |
| } | |
| { | |
| lua_register_rive<ScriptedDataValueString>(L); | |
| lua_pushcfunction(L, data_value_index, nullptr); | |
| lua_setfield(L, -2, "__index"); | |
| lua_pushcfunction(L, data_value_newindex, nullptr); | |
| lua_setfield(L, -2, "__newindex"); | |
| lua_pushcfunction(L, data_value_namecall, nullptr); | |
| lua_setfield(L, -2, "__namecall"); | |
| lua_setreadonly(L, -1, true); | |
| lua_pop(L, 1); // pop the metatable | |
| } | |
| { | |
| lua_register_rive<ScriptedDataValueBoolean>(L); | |
| lua_pushcfunction(L, data_value_index, nullptr); | |
| lua_setfield(L, -2, "__index"); | |
| lua_pushcfunction(L, data_value_newindex, nullptr); | |
| lua_setfield(L, -2, "__newindex"); | |
| lua_pushcfunction(L, data_value_namecall, nullptr); | |
| lua_setfield(L, -2, "__namecall"); | |
| lua_setreadonly(L, -1, true); | |
| lua_pop(L, 1); // pop the metatable | |
| lua_registeruserdatadirectfieldget(L, | |
| ScriptedDataValueBoolean::luaTag, | |
| "value", | |
| data_value_boolean_direct_value); | |
| } | |
| { | |
| lua_register_rive<ScriptedDataValueColor>(L); | |
| lua_pushcfunction(L, data_value_index, nullptr); | |
| lua_setfield(L, -2, "__index"); | |
| lua_pushcfunction(L, data_value_newindex, nullptr); | |
| lua_setfield(L, -2, "__newindex"); | |
| lua_pushcfunction(L, data_value_namecall, nullptr); | |
| lua_setfield(L, -2, "__namecall"); | |
| lua_setreadonly(L, -1, true); | |
| lua_pop(L, 1); // pop the metatable | |
| lua_registeruserdatadirectfieldget(L, | |
| ScriptedDataValueColor::luaTag, | |
| "value", | |
| data_value_color_direct_value); | |
| lua_registeruserdatadirectfieldget(L, | |
| ScriptedDataValueColor::luaTag, | |
| "red", | |
| data_value_color_direct_red); | |
| lua_registeruserdatadirectfieldget(L, | |
| ScriptedDataValueColor::luaTag, | |
| "green", | |
| data_value_color_direct_green); | |
| lua_registeruserdatadirectfieldget(L, | |
| ScriptedDataValueColor::luaTag, | |
| "blue", | |
| data_value_color_direct_blue); | |
| lua_registeruserdatadirectfieldget(L, | |
| ScriptedDataValueColor::luaTag, | |
| "alpha", | |
| data_value_color_direct_alpha); | |
| } | |
| return 1; | |
| } | |
| #endif |