From c7a97d3c1f23806b4f0249e35c5d277e704d04cb Mon Sep 17 00:00:00 2001 From: Riyyi Date: Wed, 27 Jan 2021 23:03:21 +0100 Subject: [PATCH] Implement sol3 into lua script --- inferno/src/inferno/script/lua.cpp | 197 ++++---------------- inferno/src/inferno/script/lua.h | 37 ++-- inferno/src/inferno/script/registration.cpp | 82 ++++++++ inferno/src/inferno/script/registration.h | 60 ++++++ 4 files changed, 201 insertions(+), 175 deletions(-) create mode 100644 inferno/src/inferno/script/registration.cpp create mode 100644 inferno/src/inferno/script/registration.h diff --git a/inferno/src/inferno/script/lua.cpp b/inferno/src/inferno/script/lua.cpp index adde069..0ccbc9b 100644 --- a/inferno/src/inferno/script/lua.cpp +++ b/inferno/src/inferno/script/lua.cpp @@ -1,205 +1,78 @@ -extern "C" { - #include - #include - #include -} +#include "sol/unsafe_function_result.hpp" #include "inferno/assertions.h" #include "inferno/file.h" #include "inferno/scene/components.h" #include "inferno/scene/scene.h" #include "inferno/script/lua.h" +#include "inferno/script/registration.h" namespace Inferno { void Lua::initialize() { - m_state = luaL_newstate(); + // Type registration + // --------------------------------- + + Registration::fill(m_state); - // Add GetComponent() + // Load libraries // --------------------------------- - constexpr int32_t componentUpValueAmount = 1; - lua_pushlightuserdata(m_state, this); - lua_pushcclosure(m_state, Lua::getComponent, componentUpValueAmount); - lua_setglobal(m_state, "GetComponent"); + m_state.open_libraries(sol::lib::base); - // Add Metatable + // Component get functions // --------------------------------- - luaL_newmetatable(m_state, "ComponentMetatable"); + m_state.set_function("getTagComponent", [this]() -> TagComponent* { + return &m_scene->getComponent(m_entity); + }); - constexpr int32_t indexUpValueAmount = 1; - lua_pushstring(m_state, "__index"); - lua_pushlightuserdata(m_state, this); - lua_pushcclosure(m_state, Lua::componentIndex, indexUpValueAmount); - lua_settable(m_state, -3); // Pops the string and table + m_state.set_function("getTransformComponent", [this]() -> TransformComponent* { + return &m_scene->getComponent(m_entity); + }); - constexpr int32_t newIndexUpValueAmount = 1; - lua_pushstring(m_state, "__newindex"); - lua_pushlightuserdata(m_state, this); - lua_pushcclosure(m_state, Lua::componentNewIndex, newIndexUpValueAmount); - lua_settable(m_state, -3); // Pops the string and table + // (*m_state).set_function("GetComponent", &Lua::getComponentSol); + m_state.set_function("getCameraComponent", [this]() -> CameraComponent* { + return &m_scene->getComponent(m_entity); + }); - // Load and Initialize Script + m_state.set_function("getSpriteComponent", [this]() -> SpriteComponent* { + return &m_scene->getComponent(m_entity); + }); + + // Load and Initialize script // --------------------------------- loadScript(); - getFunction("LuaScript", "initialize"); - callFunction(); + callFunction("LuaScript", "initialize"); } void Lua::destroy() { - getFunction("LuaScript", "destroy"); - callFunction(); - - lua_close(m_state); - m_state = nullptr; + callFunction("LuaScript", "destroy"); } void Lua::update(float deltaTime) { - getFunction("LuaScript", "update"); - lua_pushnumber(m_state, deltaTime); // Push float argument - callFunction(1); - } - - void Lua::valid(int32_t error) - { - ASSERT(error == LUA_OK, "{}", lua_tostring(m_state, -1)); + m_state["LuaScript"]["transform"] = &m_scene->getComponent(m_entity); + callFunction("LuaScript", "update", deltaTime); } void Lua::loadScript() { std::string script = File::read(m_path); - int32_t error = luaL_dostring(m_state, script.c_str()); - valid(error); - } - - void Lua::getFunction(const char* table, const char* function) - { - Lua::isTable(m_state, table); // Push table - int32_t tableIdx = lua_gettop(m_state); // Get table stack index - lua_pushstring(m_state, function); // Push string - lua_gettable(m_state, -2); // Pop string key, push value - lua_pushvalue(m_state, tableIdx); // Push table - } - - void Lua::callFunction(int32_t parameters) - { - int32_t error = lua_pcall(m_state, parameters + 1, 0, 0); // Call function() - valid(error); - } - - void Lua::isTable(lua_State* state, int32_t table) - { - ASSERT(lua_istable(state, table)); - } - - void Lua::isTable(lua_State* state, const char* table) - { - lua_getglobal(state, table); // Push table on the stack - Lua::isTable(state, -1); - } - - int32_t Lua::getComponent(lua_State* state) // Local scope state, so stack begins at 1! - { - ASSERT(lua_gettop(state) == 1, "Lua called with wrong amount of arguments"); - - ASSERT(lua_islightuserdata(state, lua_upvalueindex(1)), "Lua did not receive required lightuserdata"); - Lua* self = static_cast(lua_touserdata(state, lua_upvalueindex(1))); - - // Verify parameter - std::string componentName = lua_tostring(state, -1); - ASSERT(lua_isstring(state, -1), "Lua did not receive correct parameter"); - - // Create userdata - /*void* pointer =*/ lua_newuserdatauv(state, sizeof(0), 2); // Push userdata - ASSERT(lua_isuserdata(state, -1), "Lua could not create userdata"); - - // Get component - void* component = nullptr; - if (componentName.compare("CameraComponent") == 0) { - component = static_cast(&self->m_scene->getComponent(self->m_entity)); - } - - // Add metatable to userdata - luaL_getmetatable(state, "ComponentMetatable"); // Push table - ASSERT(lua_istable(state, -1), "Lua could not find metatable"); - lua_setmetatable(state, -2); // Pop table, set it as metatable onto userdata - - // Add uservalues to userdata - lua_pushstring(state, componentName.c_str()); // Push string - lua_setiuservalue(state, -2, 1); // Pop value, set it as the n-th uservalue onto userdata - lua_pushlightuserdata(state, component); // Push pointer - lua_setiuservalue(state, -2, 2); // Pop value, set it as the n-th uservalue onto userdata - - return 1; // Return amount of stack items pushed + auto result = m_state.script(script.c_str(), + [](lua_State*, sol::protected_function_result pfr) { return pfr; }); + ASSERT(result.valid(), "Lua script {}", ((sol::error)result).what()); } - int32_t Lua::componentIndex(lua_State* state) // Local scope state, so stack begins at 1! + sol::table Lua::getTable(const char* name) { - ASSERT(lua_gettop(state) == 2, "Lua called with wrong amount of arguments"); - ASSERT(lua_isuserdata(state, -2)); // 1 // .x - ASSERT(lua_isstring(state, -1)); // 2 // component. - - // ASSERT(lua_islightuserdata(state, lua_upvalueindex(1)), "Lua did not receive required lightuserdata"); - // Lua* self = static_cast(lua_touserdata(state, lua_upvalueindex(1))); - - lua_getiuservalue(state, 1, 1); // Push the n-th uservalue from userdata - ASSERT(lua_isstring(state, -1), "Lua did not receive component type correctly"); - std::string componentName = lua_tostring(state, -1); - - if (componentName.compare("CameraComponent") == 0) { - - lua_getiuservalue(state, 1, 2); // Push the n-th uservalue from userdata - ASSERT(lua_islightuserdata(state, -1), "Lua did not receive component pointer correctly"); - CameraComponent* component = (CameraComponent*)lua_touserdata(state, -1); - - std::string index = lua_tostring(state, 2); - if (index.compare("fov") == 0) { - lua_pushnumber(state, component->fov); - return 1; - } - else { - ASSERT_NOT_REACHED(); - } - - } - - return 0; - } - - int32_t Lua::componentNewIndex(lua_State* state) // Local scope state, so stack begins at 1! - { - ASSERT(lua_gettop(state) == 3, "Lua called with wrong amount of arguments"); - ASSERT(lua_isuserdata(state, -3)); // 1 // .x = thing - ASSERT(lua_isstring(state, -2)); // 2 // component. = thing - // Value we want to set -1 // 3 // component.x = - - lua_getiuservalue(state, 1, 1); // Push the n-th uservalue from userdata - ASSERT(lua_isstring(state, -1), "Lua did not receive component type correctly"); - std::string componentName = lua_tostring(state, -1); - - if (componentName.compare("CameraComponent") == 0) { - - lua_getiuservalue(state, 1, 2); // Push the n-th uservalue from userdata - ASSERT(lua_islightuserdata(state, -1), "Lua did not receive component pointer correctly"); - CameraComponent* component = (CameraComponent*)lua_touserdata(state, -1); - - std::string index = lua_tostring(state, 2); - if (index.compare("fov") == 0) { - component->fov = lua_tonumber(state, 3); - } - else { - ASSERT_NOT_REACHED(); - } - - } - - return 0; + sol::table table = m_state[name]; + ASSERT(table.valid(), "Lua table does not exist"); + return table; } } diff --git a/inferno/src/inferno/script/lua.h b/inferno/src/inferno/script/lua.h index 6c8dd9a..acf16d3 100644 --- a/inferno/src/inferno/script/lua.h +++ b/inferno/src/inferno/script/lua.h @@ -1,10 +1,16 @@ #ifndef LUA_H #define LUA_H -#include // int32_t, uint32_t +#include // uint32_t #include // std::string -#include // lua_State +#define SOL_ALL_SAFETIES_ON 1 +#include "sol/protected_function.hpp" +#include "sol/protected_function_result.hpp" +#include "sol/state.hpp" +#include "sol/table.hpp" + +#include "inferno/assertions.h" namespace Inferno { @@ -18,21 +24,26 @@ namespace Inferno { void destroy(); void update(float deltaTime); - void valid(int32_t error); void loadScript(); - void getFunction(const char* table, const char* function); - void callFunction(int32_t parameters = 0); private: - static void isTable(lua_State* state, int32_t table); - static void isTable(lua_State* state, const char* table); - - static int32_t getComponent(lua_State* state); - static int32_t componentIndex(lua_State* state); - static int32_t componentNewIndex(lua_State* state); - + sol::table getTable(const char* name); + + template + void callFunction(const char* table, const char* function, P&&... parameters) + { + sol::table solTable = getTable(table); + sol::protected_function solFunction = solTable[function]; + + // Only call function if it exists + if (solFunction.valid()) { + sol::protected_function_result result = solFunction(solTable, parameters...); + ASSERT(result.valid(), "Lua function {}", ((sol::error)result).what()); + } + } + + sol::state m_state; std::string m_path = ""; - lua_State* m_state = nullptr; Scene* m_scene = nullptr; uint32_t m_entity = 0; diff --git a/inferno/src/inferno/script/registration.cpp b/inferno/src/inferno/script/registration.cpp new file mode 100644 index 0000000..1c55230 --- /dev/null +++ b/inferno/src/inferno/script/registration.cpp @@ -0,0 +1,82 @@ +#include "glm/ext/vector_float2.hpp" // glm::vec2 +#include "glm/ext/vector_float3.hpp" // glm::vec3 +#include "glm/ext/vector_float4.hpp" // glm::vec4 + +#include "inferno/scene/components.h" +#include "inferno/script/registration.h" + +namespace Inferno { + + void Registration::fill(sol::state_view &state) + { + glm(state); + component(state); + } + + void Registration::glm(sol::state_view& state) + { + auto vec2 = state.new_usertype( + "vec2", + sol::call_constructor, sol::constructors(), + "x", &glm::vec2::x, "y", &glm::vec2::y, + "r", &glm::vec2::r, "g", &glm::vec2::g, + "s", &glm::vec2::s, "t", &glm::vec2::t, + "__add", addition(), + "__sub", subtraction(), + "__mul", multiplication(), + "__div", division() + ); + + auto vec3 = state.new_usertype( + "vec3", + sol::call_constructor, sol::constructors(), + "x", &glm::vec3::x, "y", &glm::vec3::y, "z", &glm::vec3::z, + "r", &glm::vec3::r, "g", &glm::vec3::g, "b", &glm::vec3::b, + "s", &glm::vec3::s, "t", &glm::vec3::t, "p", &glm::vec3::p, + "__add", addition(), + "__sub", subtraction(), + "__mul", multiplication(), + "__div", division() + // "__tostring", [](glm::vec3 self) { return self.x; } // Template!!! convert via logstream + ); + + auto vec4 = state.new_usertype( + "vec4", + sol::call_constructor, sol::constructors(), + "x", &glm::vec4::x, "y", &glm::vec4::y, "z", &glm::vec4::z, "w", &glm::vec4::w, + "r", &glm::vec4::r, "g", &glm::vec4::g, "b", &glm::vec4::b, "a", &glm::vec4::a, + "s", &glm::vec4::s, "t", &glm::vec4::t, "p", &glm::vec4::p, "q", &glm::vec4::q, + "__add", addition(), + "__sub", subtraction(), + "__mul", multiplication(), + "__div", division() + ); + } + + void Registration::component(sol::state_view& state) + { + auto tagComponent = state.new_usertype("TagComponent", sol::no_constructor); + tagComponent["tag"] = &TagComponent::tag; + + auto transformComponent = state.new_usertype("TransformComponent", sol::no_constructor); + transformComponent["translate"] = &TransformComponent::translate; + transformComponent["rotate"] = &TransformComponent::rotate; + transformComponent["scale"] = &TransformComponent::scale; + transformComponent["transform"] = &TransformComponent::transform; + + auto cameraComponent = state.new_usertype("CameraComponent", sol::no_constructor); + cameraComponent["type"] = &CameraComponent::type; + cameraComponent["zoomLevel"] = &CameraComponent::zoomLevel; + cameraComponent["rotateAxis"] = &CameraComponent::rotateAxis; + cameraComponent["fov"] = &CameraComponent::fov; + cameraComponent["pitch"] = &CameraComponent::pitch; + cameraComponent["yaw"] = &CameraComponent::yaw; + cameraComponent["up"] = &CameraComponent::up; + cameraComponent["projection"] = &CameraComponent::projection; + + auto spriteComponent = state.new_usertype("SpriteComponent", sol::no_constructor); + spriteComponent["color"] = &SpriteComponent::color; + spriteComponent["texture"] = &SpriteComponent::texture; + } + +} diff --git a/inferno/src/inferno/script/registration.h b/inferno/src/inferno/script/registration.h new file mode 100644 index 0000000..7081e44 --- /dev/null +++ b/inferno/src/inferno/script/registration.h @@ -0,0 +1,60 @@ +#ifndef REGISTRATION_H +#define REGISTRATION_H + +#include "sol/overload.hpp" // sol::overload +#include "sol/state_view.hpp" // sol::state_view + +namespace Inferno { + + class Registration final { + public: + static void fill(sol::state_view& state); + + private: + static void glm(sol::state_view& state); + static void component(sol::state_view& state); + + template + static auto addition() + { + return sol::overload( + [](const T& lhs, const T& rhs) { return lhs + rhs; }, + [](const T& lhs, const V& rhs) { return lhs + rhs; }, + [](const V& lhs, const T& rhs) { return lhs + rhs; } + ); + } + + template + static auto subtraction() + { + return sol::overload( + [](const T& lhs, const T& rhs) { return lhs - rhs; }, + [](const T& lhs, const V& rhs) { return lhs - rhs; }, + [](const V& lhs, const T& rhs) { return lhs - rhs; } + ); + } + + template + static auto multiplication() + { + return sol::overload( + [](const T& lhs, const T& rhs) { return lhs * rhs; }, + [](const T& lhs, const V& rhs) { return lhs * rhs; }, + [](const V& lhs, const T& rhs) { return lhs * rhs; } + ); + } + + template + static auto division() + { + return sol::overload( + [](const T& lhs, const T& rhs) { return lhs / rhs; }, + [](const T& lhs, const V& rhs) { return lhs / rhs; }, + [](const V& lhs, const T& rhs) { return lhs / rhs; } + ); + } + }; + +} + +#endif // REGISTRATION_H