diff --git a/assets/lua/cameracontroller.lua b/assets/lua/cameracontroller.lua new file mode 100644 index 0000000..a5a9856 --- /dev/null +++ b/assets/lua/cameracontroller.lua @@ -0,0 +1,32 @@ +LuaScript = { + + camera = nil, + + initialize = function(self) + -- + end, + + destroy = function(self) + -- + end, + + update = function(self, deltaTime) + self.camera = GetComponent("CameraComponent") + LuaScript:updateOrthographic(deltaTime) + LuaScript:updatePerspective(deltaTime) + + local tmp = self.camera.fov + self.camera.fov = 30.0 + + -- + end, + + updateOrthographic = function(self, deltaTime) + -- + end, + + updatePerspective = function(self, deltaTime) + -- + end, + +} diff --git a/inferno/src/inferno/script/lua.cpp b/inferno/src/inferno/script/lua.cpp new file mode 100644 index 0000000..adde069 --- /dev/null +++ b/inferno/src/inferno/script/lua.cpp @@ -0,0 +1,205 @@ +extern "C" { + #include + #include + #include +} + +#include "inferno/assertions.h" +#include "inferno/file.h" +#include "inferno/scene/components.h" +#include "inferno/scene/scene.h" +#include "inferno/script/lua.h" + +namespace Inferno { + + void Lua::initialize() + { + m_state = luaL_newstate(); + + // Add GetComponent() + // --------------------------------- + + constexpr int32_t componentUpValueAmount = 1; + lua_pushlightuserdata(m_state, this); + lua_pushcclosure(m_state, Lua::getComponent, componentUpValueAmount); + lua_setglobal(m_state, "GetComponent"); + + // Add Metatable + // --------------------------------- + + luaL_newmetatable(m_state, "ComponentMetatable"); + + 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 + + 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 + + // Load and Initialize Script + // --------------------------------- + + loadScript(); + + getFunction("LuaScript", "initialize"); + callFunction(); + } + + void Lua::destroy() + { + getFunction("LuaScript", "destroy"); + callFunction(); + + lua_close(m_state); + m_state = nullptr; + } + + 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)); + } + + 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 + } + + int32_t Lua::componentIndex(lua_State* state) // Local scope state, so stack begins at 1! + { + 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; + } + +} diff --git a/inferno/src/inferno/script/lua.h b/inferno/src/inferno/script/lua.h new file mode 100644 index 0000000..6c8dd9a --- /dev/null +++ b/inferno/src/inferno/script/lua.h @@ -0,0 +1,46 @@ +#ifndef LUA_H +#define LUA_H + +#include // int32_t, uint32_t +#include // std::string + +#include // lua_State + +namespace Inferno { + + struct TransformComponent; + + class Scene; + + class Lua { + public: + void initialize(); + 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); + + std::string m_path = ""; + lua_State* m_state = nullptr; + + Scene* m_scene = nullptr; + uint32_t m_entity = 0; + TransformComponent* transform = nullptr; + + friend class ScriptSystem; + }; + +} + +#endif // LUA_H