diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 37630c5a..a50979ff 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -82,7 +82,9 @@ add_library(engine STATIC "cRigidbody.cpp" "cLuaScript.cpp" "jleLuaScript.cpp" - "jleFileChangeNotifier.cpp") + "jleLuaScriptComponent.cpp" + "jleFileChangeNotifier.cpp" + "jleLuaEnvironment.cpp") if (BUILD_EDITOR) target_sources(engine PRIVATE diff --git a/engine/EditorResources/scripts/editor.lua b/engine/EditorResources/scripts/editor.lua new file mode 100644 index 00000000..9c083f21 --- /dev/null +++ b/engine/EditorResources/scripts/editor.lua @@ -0,0 +1,5 @@ +-- Main entry point for editor Lua scripts + +luaEditor = luaEditor or {} + +loadScript("ED:/scripts/pretty_table.lua") diff --git a/engine/EditorResources/scripts/pretty_table.lua b/engine/EditorResources/scripts/pretty_table.lua new file mode 100644 index 00000000..4ab954d3 --- /dev/null +++ b/engine/EditorResources/scripts/pretty_table.lua @@ -0,0 +1,82 @@ + +luaEditor = luaEditor or {} + +function luaEditor.prettyTable(node) + local cache, stack, output = {}, {}, {} + local depth = 1 + local output_str = "{\n" + + while true do + local size = 0 + + for k, v in pairs(node) do + size = size + 1 + end + + local cur_index = 1 + for k, v in pairs(node) do + if (cache[node] == nil) or (cur_index >= cache[node]) then + + if (string.find(output_str, "}", output_str:len())) then + output_str = output_str .. ",\n" + elseif not (string.find(output_str, "\n", output_str:len())) then + output_str = output_str .. "\n" + end + + -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings + table.insert(output, output_str) + output_str = "" + + local key + if (type(k) == "number" or type(k) == "boolean") then + key = "[" .. tostring(k) .. "]" + else + key = "['" .. tostring(k) .. "']" + end + + if (type(v) == "number" or type(v) == "boolean") then + output_str = output_str .. string.rep('\t', depth) .. key .. " = " .. tostring(v) + elseif (type(v) == "table") then + output_str = output_str .. string.rep('\t', depth) .. key .. " = {\n" + table.insert(stack, node) + table.insert(stack, v) + cache[node] = cur_index + 1 + break + else + output_str = output_str .. string.rep('\t', depth) .. key .. " = '" .. tostring(v) .. "'" + end + + if (cur_index == size) then + output_str = output_str .. "\n" .. string.rep('\t', depth - 1) .. "}" + else + output_str = output_str .. "," + end + else + -- close the table + if (cur_index == size) then + output_str = output_str .. "\n" .. string.rep('\t', depth - 1) .. "}" + end + end + + cur_index = cur_index + 1 + end + + if (size == 0) then + output_str = output_str .. "\n" .. string.rep('\t', depth - 1) .. "}" + end + + if (#stack > 0) then + node = stack[#stack] + stack[#stack] = nil + depth = cache[node] == nil and depth + 1 or depth - 1 + else + break + end + end + + -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings + table.insert(output, output_str) + output_str = table.concat(output) + + return output_str +end \ No newline at end of file diff --git a/engine/EngineResources/scripts/engine.lua b/engine/EngineResources/scripts/engine.lua new file mode 100644 index 00000000..b92ba270 --- /dev/null +++ b/engine/EngineResources/scripts/engine.lua @@ -0,0 +1,3 @@ +-- Main entry point for engine Lua scripts + +luaEngine = luaEngine or {} \ No newline at end of file diff --git a/engine/cLuaScript.cpp b/engine/cLuaScript.cpp index 92ce25b9..ba09470d 100644 --- a/engine/cLuaScript.cpp +++ b/engine/cLuaScript.cpp @@ -5,25 +5,30 @@ cLuaScript::cLuaScript(jleObject *owner, jleScene *scene) : jleComponent(owner, scene) {} -cLuaScript::~cLuaScript() -{ - // First destroy the 'self' object by making it empty, which is referencing the lua::state, - // which is first needed to avoid a crash. This will not do anything in editor mode, either. - _self = {}; - _luaKeepAliveRef.reset(); -} - void cLuaScript::start() { - if(!_scriptRef) - { + if (!_scriptRef) { LOGE << "Can't start script since there is a reference issue"; runUpdate = false; return; } - _luaKeepAliveRef = _scriptRef->setupLua(_self, _attachedToObject); + _scriptRef->setupLua(_self, _attachedToObject); + + if(!_specializationScript.empty()) + { + sol::load_result fx = gEngine->luaEnvironment()->getState().load(_specializationScript); + if (!fx.valid()) { + sol::error err = fx; + LOGE << "Failed to load specialization script for " << _attachedToObject->_instanceName << ": " << err.what(); + } + + fx(_self); + } + + + _scriptRef->startLua(_self); } @@ -44,8 +49,7 @@ void cLuaScript::onDestroy() { try { - if(_scriptRef) - { + if (_scriptRef) { _scriptRef->onDestroyLua(_self); } } catch (std::exception &e) { diff --git a/engine/cLuaScript.h b/engine/cLuaScript.h index 4e510634..921fb91a 100644 --- a/engine/cLuaScript.h +++ b/engine/cLuaScript.h @@ -3,7 +3,7 @@ #pragma once #include "jleComponent.h" -#include "jleLuaScript.h" +#include "jleLuaScriptComponent.h" #include "jleResourceRef.h" class cLuaScript : public jleComponent @@ -12,13 +12,11 @@ class cLuaScript : public jleComponent public: explicit cLuaScript(jleObject *owner = nullptr, jleScene *scene = nullptr); - virtual ~cLuaScript(); - template void serialize(Archive &ar) { - ar( CEREAL_NVP(_scriptRef)); + ar( CEREAL_NVP(_scriptRef), CEREAL_NVP(_specializationScript)); } void start() override; @@ -32,9 +30,8 @@ class cLuaScript : public jleComponent bool runUpdate = true; private: - jleResourceRef _scriptRef; - - std::shared_ptr _luaKeepAliveRef{}; + jleResourceRef _scriptRef; + std::string _specializationScript = "local self = ...;\n"; sol::table _self; std::function _updateLua; diff --git a/engine/editor/jleEditor.cpp b/engine/editor/jleEditor.cpp index a22b7c6d..2a2efdd3 100644 --- a/engine/editor/jleEditor.cpp +++ b/engine/editor/jleEditor.cpp @@ -102,9 +102,9 @@ jleEditor::start() // AddImGuiWindow(gameController); // menu->addWindow(gameController); - auto editorSceneObjects = std::make_shared("Scene Objects"); - addImGuiWindow(editorSceneObjects); - menu->addWindow(editorSceneObjects); + _editorSceneObjects = std::make_shared("Scene Objects"); + addImGuiWindow(_editorSceneObjects); + menu->addWindow(_editorSceneObjects); auto contentBrowser = std::make_shared("Content Browser", _textEditWindow, resourceEditor); addImGuiWindow(contentBrowser); @@ -129,6 +129,9 @@ jleEditor::start() pointLightLampGizmoMesh = jleResourceRef{jlePath{"ED:gizmos/models/gizmo_lamp.fbx"}}; directionalLightLampGizmoMesh = jleResourceRef{jlePath{"ED:gizmos/models/gizmo_sun.fbx"}}; + luaEnvironment()->loadScript("ER:/scripts/engine.lua"); + luaEnvironment()->loadScript("ED:/scripts/editor.lua"); + startRmlUi(); if (_editorSaveState->gameRunning) { @@ -454,3 +457,9 @@ jleEditor::editorTextEdit() { return *_textEditWindow; } + +jleEditorSceneObjectsWindow & +jleEditor::editorSceneObjects() +{ + return *_editorSceneObjects; +} diff --git a/engine/editor/jleEditor.h b/engine/editor/jleEditor.h index e45442e4..31aa1bf7 100644 --- a/engine/editor/jleEditor.h +++ b/engine/editor/jleEditor.h @@ -18,6 +18,7 @@ class jleFramebufferInterface; class jleSceneEditorWindow; class jleFileChangeNotifier; class jleEditorTextEdit; +class jleEditorSceneObjectsWindow; class jleEditor; inline jleEditor *gEditor; @@ -70,8 +71,9 @@ class jleEditor : public jleGameEngine std::vector> &getEditorScenes(); - jleEditorTextEdit & - editorTextEdit(); + jleEditorTextEdit &editorTextEdit(); + + jleEditorSceneObjectsWindow &editorSceneObjects(); bool checkSceneIsActiveEditor(const std::string &sceneName) @@ -136,6 +138,8 @@ class jleEditor : public jleGameEngine std::shared_ptr _sceneWindow; + std::shared_ptr _editorSceneObjects; + std::unique_ptr _fileChangeNotifier; std::shared_ptr _textEditWindow; diff --git a/engine/editor/jleEditorContentBrowser.cpp b/engine/editor/jleEditorContentBrowser.cpp index 42f06d63..32c61da9 100644 --- a/engine/editor/jleEditorContentBrowser.cpp +++ b/engine/editor/jleEditorContentBrowser.cpp @@ -565,7 +565,7 @@ jleEditorContentBrowser::selectedFilePopupObjectTemplate(std::filesystem::path & objectName.resize(dot); } - if (auto &&scene = jleEditorSceneObjectsWindow::GetSelectedScene().lock()) { + if (auto &&scene = gEditor->editorSceneObjects().GetSelectedScene().lock()) { try { std::shared_ptr object; diff --git a/engine/editor/jleEditorSceneObjectsWindow.cpp b/engine/editor/jleEditorSceneObjectsWindow.cpp index 9cbeb931..5a59bd96 100644 --- a/engine/editor/jleEditorSceneObjectsWindow.cpp +++ b/engine/editor/jleEditorSceneObjectsWindow.cpp @@ -9,6 +9,7 @@ #include "jleNetScene.h" #include "jleTypeReflectionUtils.h" +#include #include #include @@ -206,6 +207,21 @@ jleEditorSceneObjectsWindow::update(jleGameEngine &ge) } else { cereal::jleImGuiCerealArchive ar1; ar1(*selectedObjectSafePtr); + + if(!gEngine->isGameKilled()) + { + if(auto luaScript = selectedObjectSafePtr->getComponent()) + { + ImGui::Text("Lua Object:"); + + sol::protected_function f = gEditor->luaEnvironment()->getState()["luaEditor"]["prettyTable"]; + std::string prettyTable = f(luaScript->getSelf()); + + ImGui::BeginChild("LuaPretty", ImVec2(0, 0), true); + ImGui::TextWrapped("%s", prettyTable.c_str()); + ImGui::EndChild(); + } + } } ImGui::EndTabItem(); diff --git a/engine/editor/jleEditorSceneObjectsWindow.h b/engine/editor/jleEditorSceneObjectsWindow.h index 10854ee5..4f506aeb 100644 --- a/engine/editor/jleEditorSceneObjectsWindow.h +++ b/engine/editor/jleEditorSceneObjectsWindow.h @@ -4,6 +4,7 @@ #include "jleEditorImGuiWindowInterface.h" #include "jleEditorJsonToImgui.h" +#include #ifdef BUILD_EDITOR @@ -13,17 +14,17 @@ class jleEditorSceneObjectsWindow : public iEditorImGuiWindow { void update(jleGameEngine &ge) override; - static std::weak_ptr &GetSelectedObject(); + std::weak_ptr &GetSelectedObject(); - static void SetSelectedObject(std::shared_ptr object); + void SetSelectedObject(std::shared_ptr object); - static std::weak_ptr &GetSelectedScene(); + std::weak_ptr &GetSelectedScene(); private: // Using a static weak_ptr here so that it won't impact deletion - static inline std::weak_ptr selectedObject; - static inline std::weak_ptr selectedScene; + std::weak_ptr selectedObject; + std::weak_ptr selectedScene; void objectTreeRecursive(std::shared_ptr object); }; diff --git a/engine/editor/jleSceneEditorWindow.cpp b/engine/editor/jleSceneEditorWindow.cpp index 6f83d34e..32b2c5ae 100644 --- a/engine/editor/jleSceneEditorWindow.cpp +++ b/engine/editor/jleSceneEditorWindow.cpp @@ -104,7 +104,7 @@ jleSceneEditorWindow::update(jleGameEngine &ge) _framebuffer->resize(_lastGameWindowWidth, _lastGameWindowHeight); } - const auto &selectedObject = jleEditorSceneObjectsWindow::GetSelectedObject(); + const auto &selectedObject = gEditor->editorSceneObjects().GetSelectedObject(); glBindTexture(GL_TEXTURE_2D, (unsigned int)_framebuffer->texture()); jleStaticOpenGLState::globalActiveTexture = (unsigned int)_framebuffer->texture(); @@ -162,7 +162,7 @@ jleSceneEditorWindow::update(jleGameEngine &ge) std::shared_ptr o{}; object->tryFindChildWithInstanceId(pickedID, o); if (o) { - jleEditorSceneObjectsWindow::SetSelectedObject(o); + gEditor->editorSceneObjects().SetSelectedObject(o); } } } diff --git a/engine/jleGame.cpp b/engine/jleGame.cpp index 5e0e0343..0efe5406 100644 --- a/engine/jleGame.cpp +++ b/engine/jleGame.cpp @@ -27,439 +27,6 @@ jleGame::activeScenesRef() jleGame::jleGame() { - _lua = std::make_shared(); - - auto &lua = *_lua; - - setupLua(lua); } -void -jleGame::setupLua(sol::state &lua) -{ - - lua.open_libraries(sol::lib::base, - sol::lib::math, - sol::lib::string, - sol::lib::coroutine, - sol::lib::package, - sol::lib::debug, - sol::lib::io, - sol::lib::table, - sol::lib::os); - - setupLuaGLM(lua); - - lua.new_usertype("jlePath", - sol::constructors(), - "prefix", - &jlePath::getPathPrefix, - "virtual", - &jlePath::getVirtualPathConst, - "real", - &jlePath::getRealPathConst, - "isEmpty", - &jlePath::isEmpty, - "fileEnding", - &jlePath::getFileEnding, - "fileName", - &jlePath::getFileNameNoEnding, - sol::meta_function::to_string, - &jlePath::getVirtualPathConst); - - lua.new_usertype("jleTransform", - "localPos", - &jleTransform::getLocalPosition, - "worldPos", - &jleTransform::getWorldPosition, - "setLocalPos", - &jleTransform::setLocalPosition, - "setWorldPos", - &jleTransform::setWorldPosition, - "worldMatrix", - &jleTransform::getWorldMatrix, - "localMatrix", - &jleTransform::getLocalMatrix); - - lua.new_usertype( - "jleObject", - "name", - &jleObject::_instanceName, - "transform", - &jleObject::getTransform, - "addComponent", - &jleObject::addComponentByName, - "duplicate", - [](jleObject &object) { return object.duplicate().get(); }, - "destroy", - &jleObject::destroyObject, - "pendingKill", - sol::readonly(&jleObject::_pendingKill), - "isStarted", - sol::readonly(&jleObject::_isStarted), - "instanceID", - sol::readonly(&jleObject::_instanceID), - "scene", - sol::readonly(&jleObject::_containedInScene)); - - lua.new_usertype("jleScene", - "name", - &jleScene::sceneName, - "spawnObject", - &jleScene::spawnObjectWithName, - "destroy", - &jleScene::destroyScene, - "objects", - &jleScene::sceneObjects); - - lua.set_function("LOGE", [](const std::string &s) { - if (!plog::get<0>() || !plog::get<0>()->checkSeverity(plog::error)) { - ; - } else - (*plog::get<0>()) += plog::Record(plog::error, "(Lua)", 0, "(Lua)", reinterpret_cast(0), 0).ref() - << s; - }); - - lua.set_function("LOGF", [](const std::string &s) { - if (!plog::get<0>() || !plog::get<0>()->checkSeverity(plog::fatal)) { - ; - } else - (*plog::get<0>()) += plog::Record(plog::fatal, "(Lua)", 0, "(Lua)", reinterpret_cast(0), 0).ref() - << s; - }); - - lua.set_function("LOGI", [](const std::string &s) { - if (!plog::get<0>() || !plog::get<0>()->checkSeverity(plog::info)) { - ; - } else - (*plog::get<0>()) += plog::Record(plog::info, "(Lua)", 0, "(Lua)", reinterpret_cast(0), 0).ref() - << s; - }); - lua.set_function("LOGW", [](const std::string &s) { - if (!plog::get<0>() || !plog::get<0>()->checkSeverity(plog::warning)) { - ; - } else - (*plog::get<0>()) += plog::Record(plog::warning, "(Lua)", 0, "(Lua)", reinterpret_cast(0), 0).ref() - << s; - }); - lua.set_function("LOGV", [](const std::string &s) { - if (!plog::get<0>() || !plog::get<0>()->checkSeverity(plog::verbose)) { - ; - } else - (*plog::get<0>()) += plog::Record(plog::verbose, "(Lua)", 0, "(Lua)", reinterpret_cast(0), 0).ref() - << s; - }); - - for (auto &c : jleTypeReflectionUtils::registeredComponentsRef()) { - auto instance = c.second(); - auto table = lua.create_table(c.first); - instance->registerLua(lua, table); - } -} -void -jleGame::setupLuaGLM(sol::state &lua) -{ - auto multOverloadsVec2 = - sol::overload([](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 * v2; }, - [](const glm::vec2 &v1, float f) -> glm::vec2 { return v1 * f; }, - [](float f, const glm::vec2 &v1) -> glm::vec2 { return f * v1; }); - - auto divOverloadsVec2 = sol::overload([](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 / v2; }, - [](const glm::vec2 &v1, float f) -> glm::vec2 { return v1 / f; }, - [](float f, const glm::vec2 &v1) -> glm::vec2 { return f / v1; }); - - auto addOverloadsVec2 = - sol::overload([](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 + v2; }); - - auto subtractOverloadsVec2 = - sol::overload([](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 - v2; }); - - auto toStrOverloadsVec2 = sol::overload( - [](const glm::vec2 &v1) -> std::string { return std::to_string(v1.x) + ", " + std::to_string(v1.y); }); - - auto multOverloadsVec3 = - sol::overload([](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 * v2; }, - [](const glm::vec3 &v1, float f) -> glm::vec3 { return v1 * f; }, - [](float f, const glm::vec3 &v1) -> glm::vec3 { return f * v1; }); - - auto divOverloadsVec3 = sol::overload([](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 / v2; }, - [](const glm::vec3 &v1, float f) -> glm::vec3 { return v1 / f; }, - [](float f, const glm::vec3 &v1) -> glm::vec3 { return f / v1; }); - - auto addOverloadsVec3 = - sol::overload([](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 + v2; }); - - auto subtractOverloadsVec3 = - sol::overload([](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 - v2; }); - - auto toStrOverloadsVec3 = sol::overload([](const glm::vec3 &v1) -> std::string { - return std::to_string(v1.x) + ", " + std::to_string(v1.y) + ", " + std::to_string(v1.z); - }); - - auto multOverloadsVec4 = - sol::overload([](const glm::vec4 &v1, const glm::vec4 &v2) -> glm::vec4 { return v1 * v2; }, - [](const glm::vec4 &v1, float f) -> glm::vec4 { return v1 * f; }, - [](float f, const glm::vec4 &v1) -> glm::vec4 { return f * v1; }); - - auto divOverloadsVec4 = sol::overload([](const glm::vec4 &v1, const glm::vec4 &v2) -> glm::vec4 { return v1 / v2; }, - [](const glm::vec4 &v1, float f) -> glm::vec4 { return v1 / f; }, - [](float f, const glm::vec4 &v1) -> glm::vec4 { return f / v1; }); - auto addOverloadsVec4 = - sol::overload([](const glm::vec4 &v1, const glm::vec4 &v2) -> glm::vec4 { return v1 + v2; }); - - auto subtractOverloadsVec4 = - sol::overload([](const glm::vec4 &v1, const glm::vec4 &v2) -> glm::vec4 { return v1 - v2; }); - - auto toStrOverloadsVec4 = sol::overload([](const glm::vec4 &v1) -> std::string { - return std::to_string(v1.x) + ", " + std::to_string(v1.y) + ", " + std::to_string(v1.z) + ", " + - std::to_string(v1.w); - }); - - auto vec2 = lua.new_usertype( - "vec2", - sol::constructors(), - "x", - &glm::vec2::x, - "y", - &glm::vec2::y, - "length", - [&](glm::vec2 &v) { return glm::length(v); }, - sol::meta_function::multiplication, - multOverloadsVec2, - sol::meta_function::division, - divOverloadsVec2, - sol::meta_function::addition, - addOverloadsVec2, - sol::meta_function::subtraction, - subtractOverloadsVec2, - sol::meta_function::to_string, - toStrOverloadsVec2); - - auto vec3 = lua.new_usertype( - "vec3", - sol::constructors(), - "x", - &glm::vec3::x, - "y", - &glm::vec3::y, - "z", - &glm::vec3::z, - "length", - [&](glm::vec3 &v) { return glm::length(v); }, - sol::meta_function::multiplication, - multOverloadsVec3, - sol::meta_function::division, - divOverloadsVec3, - sol::meta_function::addition, - addOverloadsVec3, - sol::meta_function::subtraction, - subtractOverloadsVec3, - sol::meta_function::to_string, - toStrOverloadsVec3); - - auto vec4 = lua.new_usertype( - "vec4", - sol::constructors(), - "x", - &glm::vec4::x, - "y", - &glm::vec4::y, - "z", - &glm::vec4::z, - "w", - &glm::vec4::w, - "length", - [&](glm::vec4 &v) { return glm::length(v); }, - sol::meta_function::multiplication, - multOverloadsVec4, - sol::meta_function::division, - divOverloadsVec4, - sol::meta_function::addition, - addOverloadsVec4, - sol::meta_function::subtraction, - subtractOverloadsVec4, - sol::meta_function::to_string, - toStrOverloadsVec4); - - vec2.set_function("mix", [](glm::vec2 &v1, glm::vec2 &v2, float a) { return glm::mix(v1, v2, a); }); - vec3.set_function("mix", [](glm::vec3 &v1, glm::vec3 &v2, float a) { return glm::mix(v1, v2, a); }); - vec4.set_function("mix", [](glm::vec4 &v1, glm::vec4 &v2, float a) { return glm::mix(v1, v2, a); }); - - auto toStrOverloadsMat2 = sol::overload([](const glm::mat2 &m) -> std::string { - return "mat2=\n[" + std::to_string(m[0].x) + ", " + std::to_string(m[0].y) + +"]\n" + "[" + - std::to_string(m[1].x) + ", " + std::to_string(m[1].y) + "]"; - }); - - auto multOverloadsMat2 = - sol::overload([](const glm::mat2 &m1, const glm::mat2 &m2) -> glm::mat2 { return m1 * m2; }, - [](const glm::mat2 &m1, float f) -> glm::mat2 { return m1 * f; }, - [](float f, const glm::mat2 &m1) -> glm::mat2 { return f * m1; }); - - auto addOverloadsMat2 = sol::overload([](const glm::mat2 &m1, const glm::mat2 &m2) -> glm::mat2 { return m1 + m2; }, - [](const glm::mat2 &m1, float f) -> glm::mat2 { return m1 + f; }, - [](float f, const glm::mat2 &m1) -> glm::mat2 { return f + m1; }); - - auto subtractOverloadsMat2 = - sol::overload([](const glm::mat2 &m1, const glm::mat2 &m2) -> glm::mat2 { return m1 - m2; }, - [](const glm::mat2 &m1, float f) -> glm::mat2 { return m1 - f; }, - [](float f, const glm::mat2 &m1) -> glm::mat2 { return f - m1; }); - - auto divOverloadsMat2 = sol::overload([](const glm::mat2 &m1, const glm::mat2 &m2) -> glm::mat2 { return m1 / m2; }, - [](const glm::mat2 &m1, float f) -> glm::mat2 { return m1 / f; }, - [](float f, const glm::mat2 &m1) -> glm::mat2 { return f / m1; }); - - auto mat2 = lua.new_usertype( - "mat2", - sol::constructors(), - sol::meta_function::to_string, - toStrOverloadsMat2, - sol::meta_function::multiplication, - multOverloadsMat2, - sol::meta_function::addition, - addOverloadsMat2, - sol::meta_function::subtraction, - subtractOverloadsMat2, - sol::meta_function::division, - divOverloadsMat2, - "get", - [&](glm::mat2 &m, int index) { - if (index < 0 || index > 1) { - LOGW << "(Lua) Index out of bounds trying to get vec4 from mat4"; - return glm::vec2{}; - } - return glm::vec2{m[index]}; - }, - "set", - [&](glm::mat2 &m, int index, const glm::vec2 &v) { - if (index < 0 || index > 1) { - LOGW << "(Lua) Index out of bounds trying to set vec4 on mat4"; - return; - } - m[index] = v; - }); - - auto toStrOverloadsMat3 = sol::overload([](const glm::mat3 &m) -> std::string { - return "mat3=\n[" + std::to_string(m[0].x) + ", " + std::to_string(m[0].y) + ", " + std::to_string(m[0].z) + - +"]\n" + "[" + std::to_string(m[1].x) + ", " + std::to_string(m[1].y) + ", " + std::to_string(m[1].z) + - "]\n" + "[" + std::to_string(m[2].x) + ", " + std::to_string(m[2].y) + ", " + std::to_string(m[2].z) + - "]"; - }); - - auto multOverloadsMat3 = - sol::overload([](const glm::mat3 &m1, const glm::mat3 &m2) -> glm::mat3 { return m1 * m2; }, - [](const glm::mat3 &m1, float f) -> glm::mat3 { return m1 * f; }, - [](float f, const glm::mat3 &m1) -> glm::mat3 { return f * m1; }); - - auto addOverloadsMat3 = sol::overload([](const glm::mat3 &m1, const glm::mat3 &m2) -> glm::mat3 { return m1 + m2; }, - [](const glm::mat3 &m1, float f) -> glm::mat3 { return m1 + f; }, - [](float f, const glm::mat3 &m1) -> glm::mat3 { return f + m1; }); - - auto subtractOverloadsMat3 = - sol::overload([](const glm::mat3 &m1, const glm::mat3 &m2) -> glm::mat3 { return m1 - m2; }, - [](const glm::mat3 &m1, float f) -> glm::mat3 { return m1 - f; }, - [](float f, const glm::mat3 &m1) -> glm::mat3 { return f - m1; }); - - auto divOverloadsMat3 = sol::overload([](const glm::mat3 &m1, const glm::mat3 &m2) -> glm::mat3 { return m1 / m2; }, - [](const glm::mat3 &m1, float f) -> glm::mat3 { return m1 / f; }, - [](float f, const glm::mat3 &m1) -> glm::mat3 { return f / m1; }); - - auto mat3 = lua.new_usertype( - "mat3", - sol::constructors(), - sol::meta_function::to_string, - toStrOverloadsMat3, - sol::meta_function::multiplication, - multOverloadsMat3, - sol::meta_function::addition, - addOverloadsMat3, - sol::meta_function::subtraction, - subtractOverloadsMat3, - sol::meta_function::division, - divOverloadsMat3, - "get", - [&](glm::mat3 &m, int index) { - if (index < 0 || index > 2) { - LOGW << "(Lua) Index out of bounds trying to get vec4 from mat4"; - return glm::vec3{}; - } - return glm::vec3{m[index]}; - }, - "set", - [&](glm::mat3 &m, int index, const glm::vec3 &v) { - if (index < 0 || index > 2) { - LOGW << "(Lua) Index out of bounds trying to set vec4 on mat4"; - return; - } - m[index] = v; - }); - - auto toStrOverloadsMat4 = sol::overload([](const glm::mat4 &m) -> std::string { - return "mat4=\n[" + std::to_string(m[0].x) + ", " + std::to_string(m[0].y) + ", " + std::to_string(m[0].z) + - ", " + std::to_string(m[0].w) + "]\n" + "[" + std::to_string(m[1].x) + ", " + std::to_string(m[1].y) + - ", " + std::to_string(m[1].z) + ", " + std::to_string(m[1].w) + "]\n" + "[" + std::to_string(m[2].x) + - ", " + std::to_string(m[2].y) + ", " + std::to_string(m[2].z) + ", " + std::to_string(m[2].w) + "]\n" + - "[" + std::to_string(m[3].x) + ", " + std::to_string(m[3].y) + ", " + std::to_string(m[3].z) + ", " + - std::to_string(m[3].w) + "]"; - }); - - auto multOverloadsMat4 = - sol::overload([](const glm::mat4 &m1, const glm::mat4 &m2) -> glm::mat4 { return m1 * m2; }, - [](const glm::mat4 &m1, float f) -> glm::mat4 { return m1 * f; }, - [](float f, const glm::mat4 &m1) -> glm::mat4 { return f * m1; }); - - auto addOverloadsMat4 = sol::overload([](const glm::mat4 &m1, const glm::mat4 &m2) -> glm::mat4 { return m1 + m2; }, - [](const glm::mat4 &m1, float f) -> glm::mat4 { return m1 + f; }, - [](float f, const glm::mat4 &m1) -> glm::mat4 { return f + m1; }); - - auto subtractOverloadsMat4 = - sol::overload([](const glm::mat4 &m1, const glm::mat4 &m2) -> glm::mat4 { return m1 - m2; }, - [](const glm::mat4 &m1, float f) -> glm::mat4 { return m1 - f; }, - [](float f, const glm::mat4 &m1) -> glm::mat4 { return f - m1; }); - - auto divOverloadsMat4 = sol::overload([](const glm::mat4 &m1, const glm::mat4 &m2) -> glm::mat4 { return m1 / m2; }, - [](const glm::mat4 &m1, float f) -> glm::mat4 { return m1 / f; }, - [](float f, const glm::mat4 &m1) -> glm::mat4 { return f / m1; }); - - auto mat4 = lua.new_usertype( - "mat4", - sol::constructors(), - sol::meta_function::to_string, - toStrOverloadsMat4, - sol::meta_function::multiplication, - multOverloadsMat4, - sol::meta_function::addition, - addOverloadsMat4, - sol::meta_function::subtraction, - subtractOverloadsMat4, - sol::meta_function::division, - divOverloadsMat4, - "get", - [&](glm::mat4 &m, int index) { - if (index < 0 || index > 3) { - LOGW << "(Lua) Index out of bounds trying to get vec4 from mat4"; - return glm::vec4{}; - } - return glm::vec4{m[index]}; - }, - "set", - [&](glm::mat4 &m, int index, const glm::vec4 &v) { - if (index < 0 || index > 3) { - LOGW << "(Lua) Index out of bounds trying to set vec4 on mat4"; - return; - } - m[index] = v; - }); - - mat2.set_function("inverse", [](const glm::mat2 &m) { return glm::inverse(m); }); - mat3.set_function("inverse", [](const glm::mat3 &m) { return glm::inverse(m); }); - mat4.set_function("inverse", [](const glm::mat4 &m) { return glm::inverse(m); }); - - mat2.set_function("transpose", [](const glm::mat2 &m) { return glm::transpose(m); }); - mat3.set_function("transpose", [](const glm::mat3 &m) { return glm::transpose(m); }); - mat4.set_function("transpose", [](const glm::mat4 &m) { return glm::transpose(m); }); - - mat4.set_function("translate", [](const glm::mat4 &m, glm::vec3 &v) { return glm::translate(m, v); }); - mat4.set_function("scale", [](const glm::mat4 &m, glm::vec3 &v) { return glm::scale(m, v); }); - mat4.set_function("rotate", [](const glm::mat4 &m, float a, glm::vec3 &v) { return glm::rotate(m, a, v); }); -} diff --git a/engine/jleGame.h b/engine/jleGame.h index 501c9180..4f90f632 100644 --- a/engine/jleGame.h +++ b/engine/jleGame.h @@ -78,18 +78,7 @@ class jleGame jleCamera mainCamera{jleCameraProjection::Orthographic}; - inline std::shared_ptr & - lua() - { - return _lua; - } protected: std::vector> _activeScenes; - - void setupLua(sol::state& lua); - - void setupLuaGLM(sol::state& lua); - - std::shared_ptr _lua{}; }; \ No newline at end of file diff --git a/engine/jleGameEngine.cpp b/engine/jleGameEngine.cpp index ecf7275c..eac1097c 100644 --- a/engine/jleGameEngine.cpp +++ b/engine/jleGameEngine.cpp @@ -4,21 +4,26 @@ #include "jleFramebufferScreen.h" #include "jleFullscreenRendering.h" +#include "jleInput.h" #include "jleMouseInput.h" +#include "jlePhysics.h" #include "jleRendering.h" -#include "jleWindow.h" -#include "jleInput.h" #include "jleTimerManager.h" +#include "jleWindow.h" #include -#include "jlePhysics.h" - #include #include #include #include -jleGameEngine::jleGameEngine() : jleCore() { gEngine = this; } +jleGameEngine::jleGameEngine() : jleCore() +{ + gEngine = this; + + LOG_INFO << "Starting the lua environment"; + _luaEnvironment = std::make_unique(); +} jleGameEngine::~jleGameEngine() { gEngine = nullptr; } @@ -31,8 +36,7 @@ jleGameEngine::startGame() return; } - if(!_physics) - { + if (!_physics) { // Re-initialize the physics _physics = std::make_unique(); } @@ -118,34 +122,28 @@ jleGameEngine::startRmlUi() auto width = mainScreenFramebuffer->width(); auto height = mainScreenFramebuffer->height(); - - if (!Shell::Initialize()) - { + if (!Shell::Initialize()) { LOGE << "Failed to init Shell for RmlUi"; return; } // Constructs the system and render interfaces, creates a window, and attaches the renderer. - if (!Backend::Initialize("RmlUiWindow", width, height, true)) - { + if (!Backend::Initialize("RmlUiWindow", width, height, true)) { LOGE << "Failed to init backend for RmlUi"; return; } - // Install the custom interfaces constructed by the backend before initializing RmlUi. Rml::SetSystemInterface(Backend::GetSystemInterface()); Rml::SetRenderInterface(Backend::GetRenderInterface()); - // RmlUi initialisation. Rml::Initialise(); Rml::Log::Message(Rml::Log::LT_WARNING, "Test warning."); context = Rml::CreateContext("main", Rml::Vector2i(width, height)); - if (!context) - { + if (!context) { Rml::Shutdown(); Backend::Shutdown(); Shell::Shutdown(); @@ -162,15 +160,11 @@ jleGameEngine::startRmlUi() Rml::LoadFontFace("C:/dev/cgfx/cgfx/GameResources/LatoLatin-Italic.ttf"); Rml::LoadFontFace("C:/dev/cgfx/cgfx/GameResources/LatoLatin-BoldItalic.ttf"); - if(auto doc = context->LoadDocument("assets/demo.rml")) - { + if (auto doc = context->LoadDocument("assets/demo.rml")) { doc->Show(); } Rml::Debugger::SetVisible(true); - - - } void @@ -184,6 +178,8 @@ jleGameEngine::start() mouse->setPixelatedScreenSize(initialScreenX, initialScreenY); mouse->setScreenSize(initialScreenX, initialScreenY); + luaEnvironment()->loadScript("ER:/scripts/engine.lua"); + startRmlUi(); _fullscreen_renderer = std::make_unique(); @@ -299,3 +295,9 @@ jleGameEngine::killRmlUi() Backend::Shutdown(); Shell::Shutdown(); } + +std::shared_ptr & +jleGameEngine::luaEnvironment() +{ + return _luaEnvironment; +} diff --git a/engine/jleGameEngine.h b/engine/jleGameEngine.h index c8b8c307..359b041f 100644 --- a/engine/jleGameEngine.h +++ b/engine/jleGameEngine.h @@ -4,6 +4,7 @@ #include "jleCore.h" #include "jleGame.h" +#include "jleLuaEnvironment.h" #include class jleFullscreenRendering; @@ -56,6 +57,8 @@ class jleGameEngine : public jleCore jleGame &gameRef(); + std::shared_ptr &luaEnvironment(); + static inline Rml::Context* context{}; private: @@ -85,6 +88,8 @@ class jleGameEngine : public jleCore std::unique_ptr _physics; + std::shared_ptr _luaEnvironment; + std::unique_ptr game; bool gameHalted = false; }; diff --git a/engine/jleLuaEnvironment.cpp b/engine/jleLuaEnvironment.cpp new file mode 100644 index 00000000..4d650e9e --- /dev/null +++ b/engine/jleLuaEnvironment.cpp @@ -0,0 +1,463 @@ +// Copyright (c) 2023. Johan Lind + +#include "jleLuaEnvironment.h" +#include "jleLuaScript.h" +#include "jleObject.h" +#include "jlePath.h" +#include "jleResourceRef.h" +#include + +jleLuaEnvironment::jleLuaEnvironment() +{ + _luaState = sol::state{}; + setupLua(_luaState); +} + +void +jleLuaEnvironment::setupLua(sol::state &lua) +{ + + lua.open_libraries(sol::lib::base, + sol::lib::math, + sol::lib::string, + sol::lib::coroutine, + sol::lib::package, + sol::lib::debug, + sol::lib::io, + sol::lib::table, + sol::lib::os); + + setupLuaGLM(lua); + + lua.set_function("loadScript", [&](const std::string path) { + loadScript(path.c_str()); + }); + + lua.new_usertype( + "jlePath", + sol::constructors(), + "prefix", + &jlePath::getPathPrefix, + "virtual", + &jlePath::getVirtualPathConst, + "real", + &jlePath::getRealPathConst, + "isEmpty", + &jlePath::isEmpty, + "fileEnding", + &jlePath::getFileEnding, + "fileName", + &jlePath::getFileNameNoEnding, + sol::meta_function::to_string, + &jlePath::getVirtualPathConst); + + lua.new_usertype("jleTransform", + "localPos", + &jleTransform::getLocalPosition, + "worldPos", + &jleTransform::getWorldPosition, + "setLocalPos", + &jleTransform::setLocalPosition, + "setWorldPos", + &jleTransform::setWorldPosition, + "worldMatrix", + &jleTransform::getWorldMatrix, + "localMatrix", + &jleTransform::getLocalMatrix); + + lua.new_usertype( + "jleObject", + "name", + &jleObject::_instanceName, + "transform", + &jleObject::getTransform, + "addComponent", + &jleObject::addComponentByName, + "duplicate", + [](jleObject &object) { return object.duplicate().get(); }, + "destroy", + &jleObject::destroyObject, + "pendingKill", + sol::readonly(&jleObject::_pendingKill), + "isStarted", + sol::readonly(&jleObject::_isStarted), + "instanceID", + sol::readonly(&jleObject::_instanceID), + "scene", + sol::readonly(&jleObject::_containedInScene)); + + lua.new_usertype("jleScene", + "name", + &jleScene::sceneName, + "spawnObject", + &jleScene::spawnObjectWithName, + "destroy", + &jleScene::destroyScene, + "objects", + &jleScene::sceneObjects); + + lua.set_function("LOGE", [](const std::string &s) { + if (!plog::get<0>() || !plog::get<0>()->checkSeverity(plog::error)) { + ; + } else + (*plog::get<0>()) += plog::Record(plog::error, "(Lua)", 0, "(Lua)", reinterpret_cast(0), 0).ref() + << s; + }); + + lua.set_function("LOGF", [](const std::string &s) { + if (!plog::get<0>() || !plog::get<0>()->checkSeverity(plog::fatal)) { + ; + } else + (*plog::get<0>()) += plog::Record(plog::fatal, "(Lua)", 0, "(Lua)", reinterpret_cast(0), 0).ref() + << s; + }); + + lua.set_function("LOGI", [](const std::string &s) { + if (!plog::get<0>() || !plog::get<0>()->checkSeverity(plog::info)) { + ; + } else + (*plog::get<0>()) += plog::Record(plog::info, "(Lua)", 0, "(Lua)", reinterpret_cast(0), 0).ref() + << s; + }); + lua.set_function("LOGW", [](const std::string &s) { + if (!plog::get<0>() || !plog::get<0>()->checkSeverity(plog::warning)) { + ; + } else + (*plog::get<0>()) += plog::Record(plog::warning, "(Lua)", 0, "(Lua)", reinterpret_cast(0), 0).ref() + << s; + }); + lua.set_function("LOGV", [](const std::string &s) { + if (!plog::get<0>() || !plog::get<0>()->checkSeverity(plog::verbose)) { + ; + } else + (*plog::get<0>()) += plog::Record(plog::verbose, "(Lua)", 0, "(Lua)", reinterpret_cast(0), 0).ref() + << s; + }); + + for (auto &c : jleTypeReflectionUtils::registeredComponentsRef()) { + auto instance = c.second(); + auto table = lua.create_table(c.first); + instance->registerLua(lua, table); + } +} + +void +jleLuaEnvironment::setupLuaGLM(sol::state &lua) +{ + auto multOverloadsVec2 = + sol::overload([](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 * v2; }, + [](const glm::vec2 &v1, float f) -> glm::vec2 { return v1 * f; }, + [](float f, const glm::vec2 &v1) -> glm::vec2 { return f * v1; }); + + auto divOverloadsVec2 = sol::overload([](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 / v2; }, + [](const glm::vec2 &v1, float f) -> glm::vec2 { return v1 / f; }, + [](float f, const glm::vec2 &v1) -> glm::vec2 { return f / v1; }); + + auto addOverloadsVec2 = + sol::overload([](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 + v2; }); + + auto subtractOverloadsVec2 = + sol::overload([](const glm::vec2 &v1, const glm::vec2 &v2) -> glm::vec2 { return v1 - v2; }); + + auto toStrOverloadsVec2 = sol::overload( + [](const glm::vec2 &v1) -> std::string { return std::to_string(v1.x) + ", " + std::to_string(v1.y); }); + + auto multOverloadsVec3 = + sol::overload([](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 * v2; }, + [](const glm::vec3 &v1, float f) -> glm::vec3 { return v1 * f; }, + [](float f, const glm::vec3 &v1) -> glm::vec3 { return f * v1; }); + + auto divOverloadsVec3 = sol::overload([](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 / v2; }, + [](const glm::vec3 &v1, float f) -> glm::vec3 { return v1 / f; }, + [](float f, const glm::vec3 &v1) -> glm::vec3 { return f / v1; }); + + auto addOverloadsVec3 = + sol::overload([](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 + v2; }); + + auto subtractOverloadsVec3 = + sol::overload([](const glm::vec3 &v1, const glm::vec3 &v2) -> glm::vec3 { return v1 - v2; }); + + auto toStrOverloadsVec3 = sol::overload([](const glm::vec3 &v1) -> std::string { + return std::to_string(v1.x) + ", " + std::to_string(v1.y) + ", " + std::to_string(v1.z); + }); + + auto multOverloadsVec4 = + sol::overload([](const glm::vec4 &v1, const glm::vec4 &v2) -> glm::vec4 { return v1 * v2; }, + [](const glm::vec4 &v1, float f) -> glm::vec4 { return v1 * f; }, + [](float f, const glm::vec4 &v1) -> glm::vec4 { return f * v1; }); + + auto divOverloadsVec4 = sol::overload([](const glm::vec4 &v1, const glm::vec4 &v2) -> glm::vec4 { return v1 / v2; }, + [](const glm::vec4 &v1, float f) -> glm::vec4 { return v1 / f; }, + [](float f, const glm::vec4 &v1) -> glm::vec4 { return f / v1; }); + + auto addOverloadsVec4 = + sol::overload([](const glm::vec4 &v1, const glm::vec4 &v2) -> glm::vec4 { return v1 + v2; }); + + auto subtractOverloadsVec4 = + sol::overload([](const glm::vec4 &v1, const glm::vec4 &v2) -> glm::vec4 { return v1 - v2; }); + + auto toStrOverloadsVec4 = sol::overload([](const glm::vec4 &v1) -> std::string { + return std::to_string(v1.x) + ", " + std::to_string(v1.y) + ", " + std::to_string(v1.z) + ", " + + std::to_string(v1.w); + }); + + auto vec2 = lua.new_usertype( + "vec2", + sol::constructors(), + "x", + &glm::vec2::x, + "y", + &glm::vec2::y, + "length", + [&](glm::vec2 &v) { return glm::length(v); }, + sol::meta_function::multiplication, + multOverloadsVec2, + sol::meta_function::division, + divOverloadsVec2, + sol::meta_function::addition, + addOverloadsVec2, + sol::meta_function::subtraction, + subtractOverloadsVec2, + sol::meta_function::to_string, + toStrOverloadsVec2); + + auto vec3 = lua.new_usertype( + "vec3", + sol::constructors(), + "x", + &glm::vec3::x, + "y", + &glm::vec3::y, + "z", + &glm::vec3::z, + "length", + [&](glm::vec3 &v) { return glm::length(v); }, + sol::meta_function::multiplication, + multOverloadsVec3, + sol::meta_function::division, + divOverloadsVec3, + sol::meta_function::addition, + addOverloadsVec3, + sol::meta_function::subtraction, + subtractOverloadsVec3, + sol::meta_function::to_string, + toStrOverloadsVec3); + + auto vec4 = lua.new_usertype( + "vec4", + sol::constructors(), + "x", + &glm::vec4::x, + "y", + &glm::vec4::y, + "z", + &glm::vec4::z, + "w", + &glm::vec4::w, + "length", + [&](glm::vec4 &v) { return glm::length(v); }, + sol::meta_function::multiplication, + multOverloadsVec4, + sol::meta_function::division, + divOverloadsVec4, + sol::meta_function::addition, + addOverloadsVec4, + sol::meta_function::subtraction, + subtractOverloadsVec4, + sol::meta_function::to_string, + toStrOverloadsVec4); + + vec2.set_function("mix", [](glm::vec2 &v1, glm::vec2 &v2, float a) { return glm::mix(v1, v2, a); }); + vec3.set_function("mix", [](glm::vec3 &v1, glm::vec3 &v2, float a) { return glm::mix(v1, v2, a); }); + vec4.set_function("mix", [](glm::vec4 &v1, glm::vec4 &v2, float a) { return glm::mix(v1, v2, a); }); + + auto toStrOverloadsMat2 = sol::overload([](const glm::mat2 &m) -> std::string { + return "mat2=\n[" + std::to_string(m[0].x) + ", " + std::to_string(m[0].y) + +"]\n" + "[" + + std::to_string(m[1].x) + ", " + std::to_string(m[1].y) + "]"; + }); + + auto multOverloadsMat2 = + sol::overload([](const glm::mat2 &m1, const glm::mat2 &m2) -> glm::mat2 { return m1 * m2; }, + [](const glm::mat2 &m1, float f) -> glm::mat2 { return m1 * f; }, + [](float f, const glm::mat2 &m1) -> glm::mat2 { return f * m1; }); + + auto addOverloadsMat2 = sol::overload([](const glm::mat2 &m1, const glm::mat2 &m2) -> glm::mat2 { return m1 + m2; }, + [](const glm::mat2 &m1, float f) -> glm::mat2 { return m1 + f; }, + [](float f, const glm::mat2 &m1) -> glm::mat2 { return f + m1; }); + + auto subtractOverloadsMat2 = + sol::overload([](const glm::mat2 &m1, const glm::mat2 &m2) -> glm::mat2 { return m1 - m2; }, + [](const glm::mat2 &m1, float f) -> glm::mat2 { return m1 - f; }, + [](float f, const glm::mat2 &m1) -> glm::mat2 { return f - m1; }); + + auto divOverloadsMat2 = sol::overload([](const glm::mat2 &m1, const glm::mat2 &m2) -> glm::mat2 { return m1 / m2; }, + [](const glm::mat2 &m1, float f) -> glm::mat2 { return m1 / f; }, + [](float f, const glm::mat2 &m1) -> glm::mat2 { return f / m1; }); + + auto mat2 = lua.new_usertype( + "mat2", + sol::constructors(), + sol::meta_function::to_string, + toStrOverloadsMat2, + sol::meta_function::multiplication, + multOverloadsMat2, + sol::meta_function::addition, + addOverloadsMat2, + sol::meta_function::subtraction, + subtractOverloadsMat2, + sol::meta_function::division, + divOverloadsMat2, + "get", + [&](glm::mat2 &m, int index) { + if (index < 0 || index > 1) { + LOGW << "(Lua) Index out of bounds trying to get vec4 from mat4"; + return glm::vec2{}; + } + return glm::vec2{m[index]}; + }, + "set", + [&](glm::mat2 &m, int index, const glm::vec2 &v) { + if (index < 0 || index > 1) { + LOGW << "(Lua) Index out of bounds trying to set vec4 on mat4"; + return; + } + m[index] = v; + }); + + auto toStrOverloadsMat3 = sol::overload([](const glm::mat3 &m) -> std::string { + return "mat3=\n[" + std::to_string(m[0].x) + ", " + std::to_string(m[0].y) + ", " + std::to_string(m[0].z) + + +"]\n" + "[" + std::to_string(m[1].x) + ", " + std::to_string(m[1].y) + ", " + std::to_string(m[1].z) + + "]\n" + "[" + std::to_string(m[2].x) + ", " + std::to_string(m[2].y) + ", " + std::to_string(m[2].z) + + "]"; + }); + + auto multOverloadsMat3 = + sol::overload([](const glm::mat3 &m1, const glm::mat3 &m2) -> glm::mat3 { return m1 * m2; }, + [](const glm::mat3 &m1, float f) -> glm::mat3 { return m1 * f; }, + [](float f, const glm::mat3 &m1) -> glm::mat3 { return f * m1; }); + + auto addOverloadsMat3 = sol::overload([](const glm::mat3 &m1, const glm::mat3 &m2) -> glm::mat3 { return m1 + m2; }, + [](const glm::mat3 &m1, float f) -> glm::mat3 { return m1 + f; }, + [](float f, const glm::mat3 &m1) -> glm::mat3 { return f + m1; }); + + auto subtractOverloadsMat3 = + sol::overload([](const glm::mat3 &m1, const glm::mat3 &m2) -> glm::mat3 { return m1 - m2; }, + [](const glm::mat3 &m1, float f) -> glm::mat3 { return m1 - f; }, + [](float f, const glm::mat3 &m1) -> glm::mat3 { return f - m1; }); + + auto divOverloadsMat3 = sol::overload([](const glm::mat3 &m1, const glm::mat3 &m2) -> glm::mat3 { return m1 / m2; }, + [](const glm::mat3 &m1, float f) -> glm::mat3 { return m1 / f; }, + [](float f, const glm::mat3 &m1) -> glm::mat3 { return f / m1; }); + + auto mat3 = lua.new_usertype( + "mat3", + sol::constructors(), + sol::meta_function::to_string, + toStrOverloadsMat3, + sol::meta_function::multiplication, + multOverloadsMat3, + sol::meta_function::addition, + addOverloadsMat3, + sol::meta_function::subtraction, + subtractOverloadsMat3, + sol::meta_function::division, + divOverloadsMat3, + "get", + [&](glm::mat3 &m, int index) { + if (index < 0 || index > 2) { + LOGW << "(Lua) Index out of bounds trying to get vec4 from mat4"; + return glm::vec3{}; + } + return glm::vec3{m[index]}; + }, + "set", + [&](glm::mat3 &m, int index, const glm::vec3 &v) { + if (index < 0 || index > 2) { + LOGW << "(Lua) Index out of bounds trying to set vec4 on mat4"; + return; + } + m[index] = v; + }); + + auto toStrOverloadsMat4 = sol::overload([](const glm::mat4 &m) -> std::string { + return "mat4=\n[" + std::to_string(m[0].x) + ", " + std::to_string(m[0].y) + ", " + std::to_string(m[0].z) + + ", " + std::to_string(m[0].w) + "]\n" + "[" + std::to_string(m[1].x) + ", " + std::to_string(m[1].y) + + ", " + std::to_string(m[1].z) + ", " + std::to_string(m[1].w) + "]\n" + "[" + std::to_string(m[2].x) + + ", " + std::to_string(m[2].y) + ", " + std::to_string(m[2].z) + ", " + std::to_string(m[2].w) + "]\n" + + "[" + std::to_string(m[3].x) + ", " + std::to_string(m[3].y) + ", " + std::to_string(m[3].z) + ", " + + std::to_string(m[3].w) + "]"; + }); + + auto multOverloadsMat4 = + sol::overload([](const glm::mat4 &m1, const glm::mat4 &m2) -> glm::mat4 { return m1 * m2; }, + [](const glm::mat4 &m1, float f) -> glm::mat4 { return m1 * f; }, + [](float f, const glm::mat4 &m1) -> glm::mat4 { return f * m1; }); + + auto addOverloadsMat4 = sol::overload([](const glm::mat4 &m1, const glm::mat4 &m2) -> glm::mat4 { return m1 + m2; }, + [](const glm::mat4 &m1, float f) -> glm::mat4 { return m1 + f; }, + [](float f, const glm::mat4 &m1) -> glm::mat4 { return f + m1; }); + + auto subtractOverloadsMat4 = + sol::overload([](const glm::mat4 &m1, const glm::mat4 &m2) -> glm::mat4 { return m1 - m2; }, + [](const glm::mat4 &m1, float f) -> glm::mat4 { return m1 - f; }, + [](float f, const glm::mat4 &m1) -> glm::mat4 { return f - m1; }); + + auto divOverloadsMat4 = sol::overload([](const glm::mat4 &m1, const glm::mat4 &m2) -> glm::mat4 { return m1 / m2; }, + [](const glm::mat4 &m1, float f) -> glm::mat4 { return m1 / f; }, + [](float f, const glm::mat4 &m1) -> glm::mat4 { return f / m1; }); + + auto mat4 = lua.new_usertype( + "mat4", + sol::constructors(), + sol::meta_function::to_string, + toStrOverloadsMat4, + sol::meta_function::multiplication, + multOverloadsMat4, + sol::meta_function::addition, + addOverloadsMat4, + sol::meta_function::subtraction, + subtractOverloadsMat4, + sol::meta_function::division, + divOverloadsMat4, + "get", + [&](glm::mat4 &m, int index) { + if (index < 0 || index > 3) { + LOGW << "(Lua) Index out of bounds trying to get vec4 from mat4"; + return glm::vec4{}; + } + return glm::vec4{m[index]}; + }, + "set", + [&](glm::mat4 &m, int index, const glm::vec4 &v) { + if (index < 0 || index > 3) { + LOGW << "(Lua) Index out of bounds trying to set vec4 on mat4"; + return; + } + m[index] = v; + }); + + mat2.set_function("inverse", [](const glm::mat2 &m) { return glm::inverse(m); }); + mat3.set_function("inverse", [](const glm::mat3 &m) { return glm::inverse(m); }); + mat4.set_function("inverse", [](const glm::mat4 &m) { return glm::inverse(m); }); + + mat2.set_function("transpose", [](const glm::mat2 &m) { return glm::transpose(m); }); + mat3.set_function("transpose", [](const glm::mat3 &m) { return glm::transpose(m); }); + mat4.set_function("transpose", [](const glm::mat4 &m) { return glm::transpose(m); }); + + mat4.set_function("translate", [](const glm::mat4 &m, glm::vec3 &v) { return glm::translate(m, v); }); + mat4.set_function("scale", [](const glm::mat4 &m, glm::vec3 &v) { return glm::scale(m, v); }); + mat4.set_function("rotate", [](const glm::mat4 &m, float a, glm::vec3 &v) { return glm::rotate(m, a, v); }); +} + +sol::state & +jleLuaEnvironment::getState() +{ + return _luaState; +} + +void +jleLuaEnvironment::loadScript(const jlePath &path) +{ + // Loads script and it will be placed in resource holder + auto script = jleResourceRef(path); +} diff --git a/engine/jleLuaEnvironment.h b/engine/jleLuaEnvironment.h new file mode 100644 index 00000000..3ce1b67f --- /dev/null +++ b/engine/jleLuaEnvironment.h @@ -0,0 +1,29 @@ +// Copyright (c) 2023. Johan Lind + +#pragma once + +#include "jlePath.h" + +#define SOL_ALL_SAFETIES_ON 1 +#include + +class jleLuaScript; + +class jleLuaEnvironment +{ +public: + + jleLuaEnvironment(); + + void setupLua(sol::state& lua); + + void setupLuaGLM(sol::state& lua); + + void loadScript(const jlePath& path); + + [[nodiscard]] sol::state& getState(); + +private: + std::vector> _loadedScripts; + sol::state _luaState; +}; diff --git a/engine/jleLuaScript.cpp b/engine/jleLuaScript.cpp index 41e5f7f8..bdfacb36 100644 --- a/engine/jleLuaScript.cpp +++ b/engine/jleLuaScript.cpp @@ -17,141 +17,22 @@ jleLuaScript::loadFromFile(const jlePath &path) _sourceCode = buffer.str(); _luaScriptName = path.getFileNameNoEnding(); + _luaEnvironment = gEngine->luaEnvironment(); loadScript(); return jleLoadFromFileSuccessCode::SUCCESS; } void -jleLuaScript::saveToFile() -{ - std::ofstream save{filepath}; - save << _sourceCode; -} - -std::shared_ptr & -jleLuaScript::setupLua(sol::table &self, jleObject *ownerObject) -{ - loadScript(); - - if (!faultyState) { - auto result = _setupLua(); - if (result.valid()) { - self = result; - self["object"] = ownerObject; - for (auto &c : ownerObject->customComponents()) { - c->registerSelfLua(self); - } - } else { - sol::error err = result; - LOGE << "Failed starting script: " << err.what(); - faultyState = true; - } - } - return _currentGameLua; -} - -void -jleLuaScript::startLua(sol::table &self) -{ - if (faultyState) { - return; - } - auto result = _startLua(self); - if (!result.valid()) { - sol::error err = result; - LOGE << "Failed starting script: " << err.what(); - faultyState = true; - } -} - -void -jleLuaScript::updateLua(sol::table &self, float dt) +jleLuaScript::loadScript() { - if (faultyState) { - return; - } - - auto result = _updateLua(self, dt); - if (!result.valid()) { - sol::error err = result; - LOGE << "Failed updating script: " << err.what(); - } + _luaEnvironment->getState().script(_sourceCode); } void -jleLuaScript::onDestroyLua(sol::table &self) +jleLuaScript::saveToFile() { - if (faultyState) { - return; - } - auto result = _onDestroyLua(self); - if (!result.valid()) { - sol::error err = result; - LOGE << "Failed destroying script: " << err.what(); - } + std::ofstream save{filepath}; + save << _sourceCode; } -void -jleLuaScript::loadScript() -{ - if (gEngine->isGameKilled()) { - return; - } - - auto gameLua = gEngine->gameRef().lua(); - - if (_currentGameLua != gameLua) { - _setupLua = {}; - _startLua = {}; - _updateLua = {}; - _onDestroyLua = {}; - _currentGameLua = gameLua; - } - - auto &lua = *_currentGameLua; - - try { - lua.script(_sourceCode); - - auto setup = lua[_luaScriptName]["setup"]; - auto start = lua[_luaScriptName]["start"]; - auto update = lua[_luaScriptName]["update"]; - auto onDestroy = lua[_luaScriptName]["onDestroy"]; - - if (!setup.valid() || !setup.is()) { - LOGE << "Expected " + _luaScriptName + ".setup function was not found!"; - faultyState = true; - return; - } - - if (!start.valid() || !start.is()) { - LOGE << "Expected " + _luaScriptName + ".start function was not found!"; - faultyState = true; - return; - } - - if (!update.valid() || !update.is()) { - LOGE << "Expected " + _luaScriptName + ".update function was not found!"; - faultyState = true; - return; - } - - if (!onDestroy.valid() || !onDestroy.is()) { - LOGE << "Expected " + _luaScriptName + ".onDestroy function was not found!"; - faultyState = true; - return; - } - - _setupLua = setup; - _startLua = start; - _updateLua = update; - _onDestroyLua = onDestroy; - - faultyState = false; - - } catch (std::exception &e) { - LOGE << "Loading script failed: " << e.what(); - faultyState = true; - } -} diff --git a/engine/jleLuaScript.h b/engine/jleLuaScript.h index afcb54e0..66a52ed1 100644 --- a/engine/jleLuaScript.h +++ b/engine/jleLuaScript.h @@ -17,33 +17,18 @@ class jleLuaScript : public jleResourceInterface, public std::enable_shared_from jleLoadFromFileSuccessCode loadFromFile(const jlePath &path) override; - void saveToFile() override; - - std::shared_ptr &setupLua(sol::table &self, jleObject* ownerObject); - - void startLua(sol::table &self); - - void updateLua(sol::table &self, float dt); - - void onDestroyLua(sol::table &self); - -private: - void loadScript(); + virtual void loadScript(); - std::shared_ptr _currentGameLua{}; - - sol::protected_function _setupLua; - sol::protected_function _startLua; - sol::protected_function _updateLua; - sol::protected_function _onDestroyLua; + void saveToFile() override; - std::string _sourceCode; +protected: std::string _luaScriptName; - + std::string _sourceCode; + std::shared_ptr _luaEnvironment; bool faultyState = true; }; CEREAL_REGISTER_TYPE(jleLuaScript) CEREAL_REGISTER_POLYMORPHIC_RELATION(jleResourceInterface, jleLuaScript) -#endif // JLELUASCRIPT_H +#endif // JLE_LUASCRIPT_H diff --git a/engine/jleLuaScriptComponent.cpp b/engine/jleLuaScriptComponent.cpp new file mode 100644 index 00000000..716ac7e2 --- /dev/null +++ b/engine/jleLuaScriptComponent.cpp @@ -0,0 +1,116 @@ +// Copyright (c) 2023. Johan Lind + +#include "jleLuaScriptComponent.h" + +void +jleLuaScriptComponent::setupLua(sol::table &self, jleObject *ownerObject) +{ + loadScript(); + + if (!faultyState) { + auto result = _setupLua(); + if (result.valid()) { + self = result; + self["object"] = ownerObject; + for (auto &c : ownerObject->customComponents()) { + c->registerSelfLua(self); + } + } else { + sol::error err = result; + LOGE << "Failed starting script: " << err.what(); + faultyState = true; + } + } +} + +void +jleLuaScriptComponent::startLua(sol::table &self) +{ + if (faultyState) { + return; + } + auto result = _startLua(self); + if (!result.valid()) { + sol::error err = result; + LOGE << "Failed starting script: " << err.what(); + faultyState = true; + } +} +void +jleLuaScriptComponent::updateLua(sol::table &self, float dt) +{ + if (faultyState) { + return; + } + + auto result = _updateLua(self, dt); + if (!result.valid()) { + sol::error err = result; + LOGE << "Failed updating script: " << err.what(); + } +} +void +jleLuaScriptComponent::onDestroyLua(sol::table &self) +{ + if (faultyState) { + return; + } + auto result = _onDestroyLua(self); + if (!result.valid()) { + sol::error err = result; + LOGE << "Failed destroying script: " << err.what(); + } +} +void +jleLuaScriptComponent::loadScript() +{ + if (gEngine->isGameKilled()) { + return; + } + + auto &lua = _luaEnvironment->getState(); + + try { + lua.script(_sourceCode); + + auto setup = lua[_luaScriptName]["setup"]; + auto start = lua[_luaScriptName]["start"]; + auto update = lua[_luaScriptName]["update"]; + auto onDestroy = lua[_luaScriptName]["onDestroy"]; + + if (!setup.valid() || !setup.is()) { + LOGE << "Expected " + _luaScriptName + ".setup function was not found!"; + faultyState = true; + return; + } + + if (!start.valid() || !start.is()) { + LOGE << "Expected " + _luaScriptName + ".start function was not found!"; + faultyState = true; + return; + } + + if (!update.valid() || !update.is()) { + LOGE << "Expected " + _luaScriptName + ".update function was not found!"; + faultyState = true; + return; + } + + if (!onDestroy.valid() || !onDestroy.is()) { + LOGE << "Expected " + _luaScriptName + ".onDestroy function was not found!"; + faultyState = true; + return; + } + + _setupLua = setup; + _startLua = start; + _updateLua = update; + _onDestroyLua = onDestroy; + + faultyState = false; + + } catch (std::exception &e) { + LOGE << "Loading script failed: " << e.what(); + faultyState = true; + } +} diff --git a/engine/jleLuaScriptComponent.h b/engine/jleLuaScriptComponent.h new file mode 100644 index 00000000..5ddcd952 --- /dev/null +++ b/engine/jleLuaScriptComponent.h @@ -0,0 +1,31 @@ +// Copyright (c) 2023. Johan Lind + +#ifndef JLE_LUASCRIPTCOMPONENT_H +#define JLE_LUASCRIPTCOMPONENT_H + +#include "jleLuaScript.h" +class jleLuaScriptComponent : public jleLuaScript, public std::enable_shared_from_this +{ +public: + JLE_REGISTER_RESOURCE_TYPE(jleLuaScriptComponent, lua); + + void setupLua(sol::table &self, jleObject *ownerObject); + + void loadScript() override; + + void startLua(sol::table &self); + void updateLua(sol::table &self, float dt); + void onDestroyLua(sol::table &self); + +private: + sol::protected_function _setupLua; + sol::protected_function _startLua; + sol::protected_function _updateLua; + sol::protected_function _onDestroyLua; + +}; + +CEREAL_REGISTER_TYPE(jleLuaScriptComponent) +CEREAL_REGISTER_POLYMORPHIC_RELATION(jleLuaScript, jleLuaScriptComponent) + +#endif // JLE_LUASCRIPTCOMPONENT_H diff --git a/engine/jleObject.h b/engine/jleObject.h index c01b3ee1..c22e4977 100644 --- a/engine/jleObject.h +++ b/engine/jleObject.h @@ -147,6 +147,7 @@ class jleObject : public jleSerializedResource, public std::enable_shared_from_t protected: friend class jleGame; + friend class jleLuaEnvironment; std::vector> _components{}; jleTransform _transform; diff --git a/engine/jlePath.cpp b/engine/jlePath.cpp index 897dec4c..49df1a89 100644 --- a/engine/jlePath.cpp +++ b/engine/jlePath.cpp @@ -20,6 +20,8 @@ jlePath::jlePath(const std::string &path, bool virtualPath) } } +jlePath::jlePath(const char *virtualPath) : jlePath(std::string{virtualPath}, true) {} + jlePath::jlePath(const std::string &virtualPath) : jlePath(virtualPath, true) {} std::string @@ -230,4 +232,3 @@ jlePath::getVirtualPathConst() const { return getVirtualPath(); } - diff --git a/engine/jlePath.h b/engine/jlePath.h index eae9db70..fd1be9b0 100644 --- a/engine/jlePath.h +++ b/engine/jlePath.h @@ -30,6 +30,8 @@ class jlePath _virtualPath = value; } + jlePath(const char* virtualPath); + explicit jlePath(const std::string &virtualPath); explicit jlePath(const std::string &path, bool virtualPath);