diff --git a/assets/scripts/BouncingItem.lua b/assets/scripts/BouncingItem.lua index d691dc8..f8eb045 100644 --- a/assets/scripts/BouncingItem.lua +++ b/assets/scripts/BouncingItem.lua @@ -12,9 +12,9 @@ local rotationSpeed = 25 -- Degrees per second for spinning local new_rotation = 0 -- Variables for bobbing effect -local initial_position = {x = 0, y = 0, z = 0} -- To store the gun's initial position -local bobAmplitude = 5 -- Amplitude of the bobbing (units) -local bobFrequency = 0.5 -- Frequency of the bobbing (oscillations per second) +local initial_position = { x = 0, y = 0, z = 0 } -- To store the gun's initial position +local bobAmplitude = 5 -- Amplitude of the bobbing (units) +local bobFrequency = 0.5 -- Frequency of the bobbing (oscillations per second) -- Reference to the Gun GameObject and its Transform component local gun = nil @@ -22,9 +22,21 @@ local transform = nil local TAU = Math.constants.TAU + + + + function OnInit() local startTime = os.clock() - Engine.Log("Init START", {1.0,1.0,1.0,1.0}) + + Engine.Expose("GameObjectName", GameObjectName) + Engine.Expose("new_rotation", new_rotation) + Engine.Expose("elapsedTime", elapsedTime) + Engine.Expose("bobAmplitude", bobAmplitude) + Engine.Expose("bobFrequency", bobFrequency) + + + Engine.Log("Init START", { 1.0, 1.0, 1.0, 1.0 }) @@ -34,41 +46,43 @@ function OnInit() transform = gun:GetComponent("Transform") if transform then local pos = transform:GetPosition() - initial_position = {x = pos.x, y = pos.y, z = pos.z} - Engine.Log("Gun found and initial position updated.", {1, 1, 1, 1}) + initial_position = { x = pos.x, y = pos.y, z = pos.z } + Engine.Log("Gun found and initial position updated.", { 1, 1, 1, 1 }) else - Engine.Log("Transform component not found on Gun.", {1, 1, 0, 1}) + Engine.Log("Transform component not found on Gun.", { 1, 1, 0, 1 }) return end else - Engine.Log("Gun GameObject still not found.", {1, 1, 0, 1}) + Engine.Log("Gun GameObject still not found.", { 1, 1, 0, 1 }) return end elseif not transform then transform = gun:GetComponent("Transform") if transform then local pos = transform:GetPosition() - initial_position = {x = pos.x, y = pos.y, z = pos.z} - Engine.Log("Transform component found and initial position updated.", {1, 1, 1, 1}) + initial_position = { x = pos.x, y = pos.y, z = pos.z } + Engine.Log("Transform component found and initial position updated.", { 1, 1, 1, 1 }) else - Engine.Log("Transform component still not found on Gun.", {1, 1, 0, 1}) + Engine.Log("Transform component still not found on Gun.", { 1, 1, 0, 1 }) return end end - Engine.Log("Init OK", {0.0,1.0,0.0,1.0}) + Engine.Log("Init OK", { 0.0, 1.0, 0.0, 1.0 }) + - local endTime = os.clock() - Engine.Log(string.format("Time to load: %f", endTime-startTime)) - - - + Engine.Log(string.format("Time to load: %fms", (endTime - startTime)*1000)) end -- Update function called every frame function OnUpdate(deltaTime) + Engine.Expose("GameObjectName", GameObjectName) + Engine.Expose("new_rotation", new_rotation) + Engine.Expose("elapsedTime", elapsedTime) + Engine.Expose("bobAmplitude", bobAmplitude) + Engine.Expose("bobFrequency", bobFrequency) -- Ensure that the Gun and its Transform component are valid if not gun then gun = Engine.GetGameObjectByTag(GameObjectName) @@ -76,10 +90,10 @@ function OnUpdate(deltaTime) transform = gun:GetComponent("Transform") if transform then local pos = transform:GetPosition() - initial_position = {x = pos.x, y = pos.y, z = pos.z} - Engine.Log("Gun found and initial position updated.", {1, 1, 1, 1}) + initial_position = { x = pos.x, y = pos.y, z = pos.z } + Engine.Log("Gun found and initial position updated.", { 1, 1, 1, 1 }) else - Engine.Log("Transform component not found on Gun.", {1, 1, 0, 1}) + Engine.Log("Transform component not found on Gun.", { 1, 1, 0, 1 }) return end else @@ -89,8 +103,8 @@ function OnUpdate(deltaTime) transform = gun:GetComponent("Transform") if transform then local pos = transform:GetPosition() - initial_position = {x = pos.x, y = pos.y, z = pos.z} - Engine.Log("Transform component found and initial position updated.", {1, 1, 1, 1}) + initial_position = { x = pos.x, y = pos.y, z = pos.z } + Engine.Log("Transform component found and initial position updated.", { 1, 1, 1, 1 }) else return end @@ -110,9 +124,9 @@ function OnUpdate(deltaTime) -- Define the new rotation (spinning around the Y-axis) local rotation = { - x = 0, -- Preserving existing rotation on X-axis + x = 0, -- Preserving existing rotation on X-axis y = new_rotation, -- Updated rotation on Y-axis for spinning - z = 0 -- Preserving existing rotation on Z-axis + z = 0 -- Preserving existing rotation on Z-axis } -- Apply the new rotation to the Transform component @@ -124,9 +138,9 @@ function OnUpdate(deltaTime) -- Define the new position by adding the bobbing offset to the initial Y position local new_position = { - x = initial_position.x, -- No change on X-axis + x = initial_position.x, -- No change on X-axis y = initial_position.y + bobOffset, -- Bouncing up and down on Y-axis - z = initial_position.z -- No change on Z-axis + z = initial_position.z -- No change on Z-axis } -- Apply the new position to the Transform component diff --git a/imgui.ini b/imgui.ini index d6f2c02..080ebd5 100644 --- a/imgui.ini +++ b/imgui.ini @@ -74,28 +74,28 @@ Collapsed=0 DockId=0x00000016,0 [Window][Editor##EditorWindow] -Pos=523,27 -Size=1011,764 +Pos=332,27 +Size=1202,776 Collapsed=0 DockId=0x00000017,0 [Window][Performance##performance] Pos=8,761 -Size=513,408 +Size=322,408 Collapsed=0 DockId=0x0000001C,0 [Window][Logger##logger] -Pos=8,395 -Size=513,364 +Pos=332,805 +Size=1202,364 Collapsed=0 -DockId=0x0000001A,0 +DockId=0x00000019,0 [Window][Lua Text Editor##LuaEditor] -Pos=523,793 -Size=1011,376 +Pos=8,27 +Size=322,732 Collapsed=0 -DockId=0x00000018,0 +DockId=0x0000001B,0 [Window][Scene Window@SceneWindow] Pos=8,27 @@ -105,9 +105,9 @@ DockId=0x0000000F,0 [Window][Scene Window##SceneWindow] Pos=8,27 -Size=513,366 +Size=322,732 Collapsed=0 -DockId=0x00000019,0 +DockId=0x0000001B,0 [Window][Game Objects] Pos=182,27 @@ -116,10 +116,10 @@ Collapsed=0 DockId=0x00000011,0 [Window][Profiler] -Pos=523,793 -Size=1011,376 +Pos=935,805 +Size=599,364 Collapsed=0 -DockId=0x00000018,1 +DockId=0x0000001A,0 [Table][0xE9E836E4,4] Column 0 Weight=1.2999 @@ -128,34 +128,34 @@ Column 2 Weight=0.6474 Column 3 Weight=1.0088 [Docking][Data] -DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,50 Size=1904,1142 Split=X Selected=0xF7365A5A - DockNode ID=0x00000013 Parent=0x14621557 SizeRef=513,1142 Split=Y Selected=0x818D04BB - DockNode ID=0x0000001B Parent=0x00000013 SizeRef=264,456 Split=Y Selected=0x1D5D92B6 - DockNode ID=0x00000019 Parent=0x0000001B SizeRef=264,366 HiddenTabBar=1 Selected=0x1D5D92B6 - DockNode ID=0x0000001A Parent=0x0000001B SizeRef=264,364 HiddenTabBar=1 Selected=0x1C0788A1 - DockNode ID=0x0000001C Parent=0x00000013 SizeRef=264,254 HiddenTabBar=1 Selected=0x818D04BB - DockNode ID=0x00000014 Parent=0x14621557 SizeRef=749,1142 Split=X - DockNode ID=0x00000015 Parent=0x00000014 SizeRef=371,1142 Split=X - DockNode ID=0x00000011 Parent=0x00000015 SizeRef=265,1142 Selected=0x1D5D92B6 - DockNode ID=0x00000012 Parent=0x00000015 SizeRef=1259,1142 Split=X - DockNode ID=0x00000009 Parent=0x00000012 SizeRef=364,1142 Split=Y Selected=0x3DC5AC3F - DockNode ID=0x00000005 Parent=0x00000009 SizeRef=364,745 Split=Y Selected=0x3DC5AC3F - DockNode ID=0x0000000B Parent=0x00000005 SizeRef=364,452 HiddenTabBar=1 Selected=0x3DC5AC3F - DockNode ID=0x0000000C Parent=0x00000005 SizeRef=364,291 Selected=0xAE3C694A - DockNode ID=0x00000006 Parent=0x00000009 SizeRef=364,395 HiddenTabBar=1 Selected=0x726D8899 - DockNode ID=0x0000000A Parent=0x00000012 SizeRef=1538,1142 Split=X - DockNode ID=0x00000007 Parent=0x0000000A SizeRef=357,1142 Selected=0x7737E8B2 - DockNode ID=0x00000008 Parent=0x0000000A SizeRef=1545,1142 Split=X - DockNode ID=0x00000001 Parent=0x00000008 SizeRef=1202,1142 Split=Y Selected=0xDF0EC458 - DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1202,849 Split=Y Selected=0xDF0EC458 - DockNode ID=0x0000000D Parent=0x00000003 SizeRef=1202,571 Split=Y Selected=0xDFF75B3F - DockNode ID=0x00000017 Parent=0x0000000D SizeRef=1303,764 CentralNode=1 HiddenTabBar=1 Selected=0xDFF75B3F - DockNode ID=0x00000018 Parent=0x0000000D SizeRef=1303,376 Selected=0x9B5D3198 - DockNode ID=0x0000000E Parent=0x00000003 SizeRef=1202,569 Selected=0xE98146C5 - DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1202,291 Selected=0x9DD4E196 - DockNode ID=0x00000002 Parent=0x00000008 SizeRef=334,1142 HiddenTabBar=1 Selected=0x36DC96AB - DockNode ID=0x00000016 Parent=0x00000014 SizeRef=376,1142 HiddenTabBar=1 Selected=0x8D0E8380 -DockSpace ID=0xC6145A92 Pos=8,27 Size=1904,1142 Split=X - DockNode ID=0x0000000F Parent=0xC6145A92 SizeRef=301,1142 Selected=0xA8433A03 - DockNode ID=0x00000010 Parent=0xC6145A92 SizeRef=1601,1142 CentralNode=1 +DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,50 Size=1904,1142 Split=X Selected=0xF7365A5A + DockNode ID=0x00000013 Parent=0x14621557 SizeRef=322,1142 Split=Y Selected=0x818D04BB + DockNode ID=0x0000001B Parent=0x00000013 SizeRef=264,456 HiddenTabBar=1 Selected=0x1D5D92B6 + DockNode ID=0x0000001C Parent=0x00000013 SizeRef=264,254 HiddenTabBar=1 Selected=0x818D04BB + DockNode ID=0x00000014 Parent=0x14621557 SizeRef=1580,1142 Split=X + DockNode ID=0x00000015 Parent=0x00000014 SizeRef=1202,1142 Split=X + DockNode ID=0x00000011 Parent=0x00000015 SizeRef=265,1142 Selected=0x1D5D92B6 + DockNode ID=0x00000012 Parent=0x00000015 SizeRef=1259,1142 Split=X + DockNode ID=0x00000009 Parent=0x00000012 SizeRef=364,1142 Split=Y Selected=0x3DC5AC3F + DockNode ID=0x00000005 Parent=0x00000009 SizeRef=364,745 Split=Y Selected=0x3DC5AC3F + DockNode ID=0x0000000B Parent=0x00000005 SizeRef=364,452 HiddenTabBar=1 Selected=0x3DC5AC3F + DockNode ID=0x0000000C Parent=0x00000005 SizeRef=364,291 Selected=0xAE3C694A + DockNode ID=0x00000006 Parent=0x00000009 SizeRef=364,395 HiddenTabBar=1 Selected=0x726D8899 + DockNode ID=0x0000000A Parent=0x00000012 SizeRef=1538,1142 Split=X + DockNode ID=0x00000007 Parent=0x0000000A SizeRef=357,1142 Selected=0x7737E8B2 + DockNode ID=0x00000008 Parent=0x0000000A SizeRef=1545,1142 Split=X + DockNode ID=0x00000001 Parent=0x00000008 SizeRef=1202,1142 Split=Y Selected=0xDF0EC458 + DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1202,849 Split=Y Selected=0xDF0EC458 + DockNode ID=0x0000000D Parent=0x00000003 SizeRef=1202,571 Split=Y Selected=0xDFF75B3F + DockNode ID=0x00000017 Parent=0x0000000D SizeRef=1202,776 CentralNode=1 Selected=0xDFF75B3F + DockNode ID=0x00000018 Parent=0x0000000D SizeRef=1202,364 Split=X Selected=0x1C0788A1 + DockNode ID=0x00000019 Parent=0x00000018 SizeRef=601,364 Selected=0x1C0788A1 + DockNode ID=0x0000001A Parent=0x00000018 SizeRef=599,364 Selected=0x9B5D3198 + DockNode ID=0x0000000E Parent=0x00000003 SizeRef=1202,569 Selected=0xE98146C5 + DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1202,291 Selected=0x9DD4E196 + DockNode ID=0x00000002 Parent=0x00000008 SizeRef=334,1142 HiddenTabBar=1 Selected=0x36DC96AB + DockNode ID=0x00000016 Parent=0x00000014 SizeRef=376,1142 HiddenTabBar=1 Selected=0x8D0E8380 +DockSpace ID=0xC6145A92 Pos=8,27 Size=1904,1142 Split=X + DockNode ID=0x0000000F Parent=0xC6145A92 SizeRef=301,1142 Selected=0xA8433A03 + DockNode ID=0x00000010 Parent=0xC6145A92 SizeRef=1601,1142 CentralNode=1 diff --git a/src/Componenets/ScriptComponent.cpp b/src/Componenets/ScriptComponent.cpp index 74333ab..b84a96d 100644 --- a/src/Componenets/ScriptComponent.cpp +++ b/src/Componenets/ScriptComponent.cpp @@ -6,13 +6,10 @@ #include "gcml.h" // External pointer to LoggerWindow (Assuming it's defined globally) -extern LoggerWindow* g_LoggerWindow; - - +extern LoggerWindow *g_LoggerWindow; const std::string ScriptComponent::name = "ScriptComponent"; - ScriptComponent::ScriptComponent() : ScriptPath("assets/scripts/script.lua"), m_LastErrorMessage("") { @@ -45,17 +42,16 @@ YAML::Node ScriptComponent::Serialize() return node; } -void ScriptComponent::Deserialize(const YAML::Node& node) +void ScriptComponent::Deserialize(const YAML::Node &node) { if (node["ScriptPath"]) { ScriptPath = node["ScriptPath"].as(); - } - + } + DEBUG_PRINT("Script Path: %s", ScriptPath.c_str()); Initialize(); - } bool ScriptComponent::Initialize() @@ -80,8 +76,6 @@ bool ScriptComponent::Initialize() return false; } - m_LuaManager.PrintEngineVariables(); - return true; } @@ -91,9 +85,18 @@ void ScriptComponent::Update(float deltaTime) m_LuaManager.Update(deltaTime); } - void ScriptComponent::Init() { // Call the Update method of LuaManager m_LuaManager.CallLuaFunction("OnInit"); } + +void ScriptComponent::UpdateVariable(const std::string &name, const LuaManager::LuaExposedVariant &value) +{ + m_LuaManager.UpdateVariable(name, value); +} + +std::unordered_map ScriptComponent::GetExposedVariables() +{ + return m_LuaManager.GetExposedVariables(); +} diff --git a/src/Componenets/ScriptComponent.h b/src/Componenets/ScriptComponent.h index 521aaea..d426f70 100644 --- a/src/Componenets/ScriptComponent.h +++ b/src/Componenets/ScriptComponent.h @@ -7,6 +7,7 @@ #include #include "Windows/LoggerWindow.h" #include "Engine/LuaAPI.h" // Include the LuaManager class +#include class ScriptComponent : public Component { @@ -14,33 +15,31 @@ public: ScriptComponent(); virtual ~ScriptComponent(); - std::string ScriptPath; // Path to the Lua script - + std::string ScriptPath; // Path to the Lua script // Component interface implementation - virtual const std::string& GetName() const override; - static const std::string& GetStaticName(); + virtual const std::string &GetName() const override; + static const std::string &GetStaticName(); virtual YAML::Node Serialize() override; - virtual void Deserialize(const YAML::Node& node) override; + virtual void Deserialize(const YAML::Node &node) override; // Script management methods bool Initialize(); virtual void Update(float deltaTime); - void Init(); - + void UpdateVariable(const std::string &name, const LuaManager::LuaExposedVariant &value); + std::unordered_map GetExposedVariables(); private: - LuaManager m_LuaManager; // Instance of LuaManager - std::string m_LastErrorMessage; // To prevent duplicate error logs + LuaManager m_LuaManager; // Instance of LuaManager + std::string m_LastErrorMessage; // To prevent duplicate error logs // block copying - ScriptComponent(const ScriptComponent&) = delete; - ScriptComponent& operator=(const ScriptComponent&) = delete; + ScriptComponent(const ScriptComponent &) = delete; + ScriptComponent &operator=(const ScriptComponent &) = delete; static const std::string name; - }; diff --git a/src/Engine.cpp b/src/Engine.cpp index b3c5477..6c9e224 100644 --- a/src/Engine.cpp +++ b/src/Engine.cpp @@ -260,7 +260,7 @@ void MyEngine::Run() m_PerformanceWindow->Show(m_Fps, m_Ms); // FPS & ms m_LoggerWindow->Show(); // Logs m_SceneWindow->Show(); - m_luaEditor->Show(); + //m_luaEditor->Show(); if (m_showProfiler) { diff --git a/src/Engine/AssetManager.cpp b/src/Engine/AssetManager.cpp index edd2c74..d7fbe51 100644 --- a/src/Engine/AssetManager.cpp +++ b/src/Engine/AssetManager.cpp @@ -63,7 +63,7 @@ AssetManager::AssetVariant AssetManager::loadAssetFromDisk(AssetType type, const } case AssetType::SHADER: { - Shader* shaderPtr = LoadShaderFromList(path); // Returns Shader* + Shader *shaderPtr = LoadShaderFromList(path); // Returns Shader* if (shaderPtr != nullptr) { // It's essential to ensure that shaderPtr is dynamically allocated and not managed elsewhere @@ -76,7 +76,7 @@ AssetManager::AssetVariant AssetManager::loadAssetFromDisk(AssetType type, const } case AssetType::MODEL: { - Model* modelPtr = LoadModelFromList(path); // Returns Model* + Model *modelPtr = LoadModelFromList(path); // Returns Model* if (modelPtr != nullptr) { // It's essential to ensure that modelPtr is dynamically allocated and not managed elsewhere @@ -139,7 +139,7 @@ GLuint LoadTextureFromList(const std::string &path) return texID; } -Shader* LoadShaderFromList(const std::string &path) +Shader *LoadShaderFromList(const std::string &path) { // Build actual paths from the base path @@ -160,12 +160,6 @@ Shader* LoadShaderFromList(const std::string &path) return newShader; } - - - - - - GLuint LoadTexture(const std::string &path, const std::string &directory) { std::string fullPath = directory + path; @@ -173,7 +167,7 @@ GLuint LoadTexture(const std::string &path, const std::string &directory) unsigned char *data = stbi_load(fullPath.c_str(), &width, &height, &channels, 0); if (!data) { - DEBUG_PRINT("[AssetManager] failed to load texture: %s: %s", fullPath.c_str(),stbi_failure_reason()); + DEBUG_PRINT("[AssetManager] failed to load texture: %s: %s", fullPath.c_str(), stbi_failure_reason()); return 0; } @@ -190,15 +184,15 @@ GLuint LoadTexture(const std::string &path, const std::string &directory) GLuint textureID; glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); - + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data); glGenerateMipmap(GL_TEXTURE_2D); // Set texture parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glBindTexture(GL_TEXTURE_2D, 0); @@ -207,15 +201,31 @@ GLuint LoadTexture(const std::string &path, const std::string &directory) return textureID; } +#include - - - - - - -Model* LoadModelFromList(const std::string &path) +// Custom hash function for Vertex +struct VertexHash { + std::size_t operator()(const Vertex &v) const + { + std::size_t h1 = std::hash{}(v.position[0]); + std::size_t h2 = std::hash{}(v.position[1]); + std::size_t h3 = std::hash{}(v.position[2]); + std::size_t h4 = std::hash{}(v.texCoord[0]); + std::size_t h5 = std::hash{}(v.texCoord[1]); + std::size_t h6 = std::hash{}(v.normal[0]); + std::size_t h7 = std::hash{}(v.normal[1]); + std::size_t h8 = std::hash{}(v.normal[2]); + return h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^ h7 ^ h8; + } +}; + +// Hash map for deduplication +std::unordered_map vertexCache; + +Model *LoadModelFromList(const std::string &path) +{ + auto start = std::chrono::high_resolution_clock::now(); std::ifstream objFile(path); if (!objFile.is_open()) @@ -227,6 +237,10 @@ Model* LoadModelFromList(const std::string &path) std::vector temp_texCoords; std::vector temp_normals; + temp_positions.reserve(100000); + temp_texCoords.reserve(100000); + temp_normals.reserve(100000); + std::string directory; size_t lastSlash = path.find_last_of("/\\"); if (lastSlash != std::string::npos) @@ -234,7 +248,6 @@ Model* LoadModelFromList(const std::string &path) else directory = ""; - std::string currentMaterial = "default"; // Map material name to Submesh @@ -243,7 +256,14 @@ Model* LoadModelFromList(const std::string &path) std::string line; std::string mtlFileName; - while (std::getline(objFile, line)) + + // Read file into memory for faster line parsing + std::stringstream fileBuffer; + fileBuffer << objFile.rdbuf(); + objFile.close(); + DEBUG_PRINT("OBJ READ"); + + while (std::getline(fileBuffer, line)) { if (line.empty() || line[0] == '#') continue; // Skip empty lines and comments @@ -296,32 +316,25 @@ Model* LoadModelFromList(const std::string &path) while (iss >> vertexStr) { unsigned int vIdx = 0, tIdx = 0, nIdx = 0; - size_t firstSlash = vertexStr.find('/'); - size_t secondSlash = vertexStr.find('/', firstSlash + 1); + const char *ptr = vertexStr.c_str(); - if (firstSlash == std::string::npos) + // Parse vertex index (vIdx) + vIdx = std::strtol(ptr, const_cast(&ptr), 10); + + if (*ptr == '/') { - // Format: f v1 v2 v3 - vIdx = std::stoi(vertexStr); - } - else if (secondSlash == std::string::npos) - { - // Format: f v1/vt1 v2/vt2 v3/vt3 - vIdx = std::stoi(vertexStr.substr(0, firstSlash)); - tIdx = std::stoi(vertexStr.substr(firstSlash + 1)); - } - else if (secondSlash > firstSlash + 1) - { - // Format: f v1/vt1/vn1 v2/vt2/vn2 v3/vt3/vn3 - vIdx = std::stoi(vertexStr.substr(0, firstSlash)); - tIdx = std::stoi(vertexStr.substr(firstSlash + 1, secondSlash - firstSlash - 1)); - nIdx = std::stoi(vertexStr.substr(secondSlash + 1)); - } - else - { - // Format: f v1//vn1 v2//vn2 v3//vn3 - vIdx = std::stoi(vertexStr.substr(0, firstSlash)); - nIdx = std::stoi(vertexStr.substr(secondSlash + 1)); + ++ptr; // Skip the first '/' + if (*ptr != '/') + { + // Parse texture index (tIdx) + tIdx = std::strtol(ptr, const_cast(&ptr), 10); + } + if (*ptr == '/') + { + ++ptr; // Skip the second '/' + // Parse normal index (nIdx) + nIdx = std::strtol(ptr, const_cast(&ptr), 10); + } } faceVertices.emplace_back(vIdx, tIdx, nIdx); @@ -333,8 +346,10 @@ Model* LoadModelFromList(const std::string &path) // Current material's submesh Submesh ¤tSubmesh = materialToSubmesh[currentMaterial]; - auto addVertex = [&](unsigned int v, unsigned int t, unsigned int n) -> unsigned int { + auto addVertex = [&](unsigned int v, unsigned int t, unsigned int n) -> unsigned int + { Vertex vertex; + // OBJ indices are 1-based vertex.position[0] = temp_positions[(v - 1) * 3]; vertex.position[1] = temp_positions[(v - 1) * 3 + 1]; @@ -364,16 +379,18 @@ Model* LoadModelFromList(const std::string &path) vertex.normal[2] = 0.0f; } - // Check if the vertex already exists in the submesh - auto it = std::find(currentSubmesh.vertices.begin(), currentSubmesh.vertices.end(), vertex); - if (it != currentSubmesh.vertices.end()) + // Use the hash map to check for duplicates + auto it = vertexCache.find(vertex); + if (it != vertexCache.end()) { - return static_cast(std::distance(currentSubmesh.vertices.begin(), it)); + return it->second; } else { + unsigned int newIndex = static_cast(currentSubmesh.vertices.size()); currentSubmesh.vertices.push_back(vertex); - return static_cast(currentSubmesh.vertices.size() - 1); + vertexCache[vertex] = newIndex; + return newIndex; } }; @@ -388,7 +405,10 @@ Model* LoadModelFromList(const std::string &path) } } - objFile.close(); + temp_positions.shrink_to_fit(); + temp_texCoords.shrink_to_fit(); + temp_normals.shrink_to_fit(); + DEBUG_PRINT("MTL READ"); // Load MTL file if specified std::unordered_map> materialTexturesMap; @@ -476,6 +496,8 @@ Model* LoadModelFromList(const std::string &path) { } + DEBUG_PRINT("MTL SUBASSIGN"); + // Assign textures to submeshes based on their material for (auto &pair : materialToSubmesh) { @@ -504,13 +526,18 @@ Model* LoadModelFromList(const std::string &path) Model *model = new Model(); // Move submeshes to the model + DEBUG_PRINT("SUB MIGRATE"); + for (auto &pair : materialToSubmesh) { model->submeshes.emplace_back(std::move(pair.second)); } + // Code to analyze + auto end = std::chrono::high_resolution_clock::now(); + g_LoggerWindow->AddLog("Loaded Mesh in %.6f seconds", + std::chrono::duration_cast>(end - start).count()); DEBUG_PRINT("[AssetManager] Loaded model with %lld submeshes.", model->submeshes.size()); - return model; } diff --git a/src/Engine/LuaAPI.cpp b/src/Engine/LuaAPI.cpp index 328aa0c..f192927 100644 --- a/src/Engine/LuaAPI.cpp +++ b/src/Engine/LuaAPI.cpp @@ -25,6 +25,8 @@ extern LoggerWindow *g_LoggerWindow; extern std::vector> g_GameObjects; std::string LuaManager::m_ScriptName = "LUA_UNDEFINED"; +std::unordered_map LuaManager::m_ExposedVariables; + // Constructor LuaManager::LuaManager() @@ -92,6 +94,9 @@ bool LuaManager::Initialize(const std::string &scriptPath) lua_pushcfunction(m_LuaState, Lua_Engine_Log); lua_setfield(m_LuaState, -2, "Log"); + lua_pushcfunction(m_LuaState, Lua_Engine_Expose); + lua_setfield(m_LuaState, -2, "Expose"); + // Add the ScriptName binding lua_pushcfunction(m_LuaState, Lua_Engine_ScriptName); lua_setfield(m_LuaState, -2, "ScriptName"); @@ -150,208 +155,122 @@ bool LuaManager::Initialize(const std::string &scriptPath) return true; } -// Implementation of GetGlobalVariables -std::vector LuaManager::GetGlobalVariables() -{ - std::vector globals; +std::unordered_map LuaManager::GetExposedVariables() { + return m_ExposedVariables; +} + + +void LuaManager::UpdateVariable(const std::string &name, const LuaManager::LuaExposedVariant &value) { if (!m_LuaState) - { - // Handle error: Lua state not initialized - if (g_LoggerWindow) - { - g_LoggerWindow->AddLog("LuaManager: Lua state is not initialized.", - std::optional(ImVec4(1.0f, 0.0f, 0.0f, 1.0f))); - } - else - { - DEBUG_PRINT("LuaManager: Lua state is not initialized."); - } - return globals; + return; + + // Update the variable in the map + m_ExposedVariables[name] = value; + + // Push the variable to the Lua global environment + lua_pushglobaltable(m_LuaState); // Push the global table + + // Push the variable name + lua_pushstring(m_LuaState, name.c_str()); + + // Push the new value based on its type + if (std::holds_alternative(value)) { + lua_pushinteger(m_LuaState, std::get(value)); + } else if (std::holds_alternative(value)) { + lua_pushnumber(m_LuaState, std::get(value)); + } else if (std::holds_alternative(value)) { + lua_pushstring(m_LuaState, std::get(value).c_str()); + } else if (std::holds_alternative(value)) { + lua_pushboolean(m_LuaState, std::get(value)); + } else { + lua_pop(m_LuaState, 1); // Clean up stack + return; } - // Push the global table onto the stack -#if LUA_VERSION_NUM >= 502 - lua_pushglobaltable(m_LuaState); -#else - lua_pushvalue(m_LuaState, LUA_GLOBALSINDEX); -#endif + // Set the variable in the Lua global environment + lua_settable(m_LuaState, -3); - // Start iterating with a nil key - lua_pushnil(m_LuaState); // First key + // Clean up stack + lua_pop(m_LuaState, 1); +} - // Iterate over the global table - while (lua_next(m_LuaState, -2) != 0) - { - // Stack now contains key at -2 and value at -1 - // Get the type of the value - int valueType = lua_type(m_LuaState, -1); - switch (valueType) - { + +int LuaManager::Lua_Engine_Expose(lua_State* L) { + // Check that at least two arguments are passed: name and value + if (lua_gettop(L) < 2) { + luaL_error(L, "Expose function requires at least two arguments: name and value"); + return 0; + } + + // First argument: variable name (string) + if (!lua_isstring(L, 1)) { + luaL_error(L, "First argument to Expose must be a string (variable name)"); + return 0; + } + + const char* varName = lua_tostring(L, 1); + + // Second argument: variable value (supports int, float, string, bool) + LuaExposedVariant varValue; + int type = lua_type(L, 2); + + switch (type) { case LUA_TNUMBER: #if LUA_VERSION_NUM >= 503 - if (lua_isinteger(m_LuaState, -1)) - { - lua_Integer intVal = lua_tointeger(m_LuaState, -1); - // Assuming you want to store as int - globals.emplace_back(static_cast(intVal)); - } - else - { - lua_Number numVal = lua_tonumber(m_LuaState, -1); - // Store as float (you might choose double instead) - globals.emplace_back(static_cast(numVal)); - } -#else - { - lua_Number numVal = lua_tonumber(m_LuaState, -1); - // Lua 5.2 and earlier use double for all numbers - // Decide how to store: here, stored as float - globals.emplace_back(static_cast(numVal)); - } + if (lua_isinteger(L, 2)) { + varValue = static_cast(lua_tointeger(L, 2)); + } else #endif + { + varValue = static_cast(lua_tonumber(L, 2)); + } break; - case LUA_TSTRING: - { - size_t len = 0; - const char *str = lua_tolstring(m_LuaState, -1, &len); - if (str) - { - globals.emplace_back(std::string(str, len)); - } - } - break; - - // Optionally handle other types or skip them - // For example, you might skip tables, functions, booleans, etc. - default: - // Skip other types + varValue = std::string(lua_tostring(L, 2)); break; - } - - // Pop the value, keep the key for the next iteration - lua_pop(m_LuaState, 1); + case LUA_TBOOLEAN: + varValue = static_cast(lua_toboolean(L, 2)); + break; + default: + luaL_error(L, "Unsupported variable type for Expose"); + return 0; } - // Pop the global table from the stack - lua_pop(m_LuaState, 1); + // Store the variable in the static m_ExposedVariables map + m_ExposedVariables[varName] = varValue; - return globals; + // Push the variable to the Lua global environment + lua_pushglobaltable(L); + + lua_pushstring(L, varName); // Push the variable name + + // Push the value to Lua based on its type + if (std::holds_alternative(varValue)) { + lua_pushinteger(L, std::get(varValue)); + } else if (std::holds_alternative(varValue)) { + lua_pushnumber(L, std::get(varValue)); + } else if (std::holds_alternative(varValue)) { + lua_pushstring(L, std::get(varValue).c_str()); + } else if (std::holds_alternative(varValue)) { + lua_pushboolean(L, std::get(varValue)); + } else { + lua_pop(L, 1); // Clean up stack + return 0; + } + + // Set the variable in Lua global environment + lua_settable(L, -3); + + // Clean up stack + lua_pop(L, 1); + + return 0; } -// Implementation of PrintEngineVariables -void LuaManager::PrintEngineVariables() { - if (!m_LuaState) { - std::cerr << "LuaManager: Lua state is not initialized." << std::endl; - return; - } - // Push the _T_Engine_Variables table onto the stack - lua_getglobal(m_LuaState, "_T_Engine_Variables"); - if (!lua_istable(m_LuaState, -1)) { - std::cerr << "LuaManager: _T_Engine_Variables is not a table or does not exist." << std::endl; - lua_pop(m_LuaState, 1); // Remove non-table value - return; - } - - // Start iterating with a nil key - lua_pushnil(m_LuaState); // First key - - std::cout << "Engine Variables:" << std::endl; - - // Iterate over the _T_Engine_Variables table - while (lua_next(m_LuaState, -2) != 0) { - // Stack now contains key at -2 and value at -1 - - // Get the key - const char* key = nullptr; - if (lua_type(m_LuaState, -2) == LUA_TSTRING) { - key = lua_tostring(m_LuaState, -2); - } else { - // For non-string keys, skip - lua_pop(m_LuaState, 1); // Remove value, keep key for next iteration - continue; - } - - // Get the type of the value - int valueType = lua_type(m_LuaState, -1); - - // Print the key and value based on type - std::cout << key << " = "; - - switch (valueType) { - case LUA_TNUMBER: -#if LUA_VERSION_NUM >= 503 - if (lua_isinteger(m_LuaState, -1)) { - lua_Integer intVal = lua_tointeger(m_LuaState, -1); - std::cout << intVal; - } else -#endif - { - lua_Number numVal = lua_tonumber(m_LuaState, -1); - std::cout << numVal; - } - break; - - case LUA_TSTRING: - { - const char* str = lua_tostring(m_LuaState, -1); - if (str) { - std::cout << "\"" << str << "\""; - } else { - std::cout << "nil"; - } - } - break; - - case LUA_TBOOLEAN: - { - int boolVal = lua_toboolean(m_LuaState, -1); - std::cout << (boolVal ? "true" : "false"); - } - break; - - case LUA_TTABLE: - std::cout << "table"; - break; - - case LUA_TFUNCTION: - std::cout << "function"; - break; - - case LUA_TUSERDATA: - std::cout << "userdata"; - break; - - case LUA_TLIGHTUSERDATA: - std::cout << "lightuserdata"; - break; - - case LUA_TTHREAD: - std::cout << "thread"; - break; - - case LUA_TNIL: - std::cout << "nil"; - break; - - default: - std::cout << "unknown"; - break; - } - - std::cout << std::endl; - - // Pop the value, keep the key for the next iteration - lua_pop(m_LuaState, 1); - } - - // Pop the _T_Engine_Variables table from the stack - lua_pop(m_LuaState, 1); -} // Update function called every frame void LuaManager::Update(float deltaTime) diff --git a/src/Engine/LuaAPI.h b/src/Engine/LuaAPI.h index 52a12ae..290a668 100644 --- a/src/Engine/LuaAPI.h +++ b/src/Engine/LuaAPI.h @@ -14,6 +14,7 @@ extern "C" #include #include #include +#include #include // Forward declarations to avoid circular dependencies @@ -59,10 +60,14 @@ public: void CallLuaFunction(std::string functionName); - using LuaGlobalVariant = std::variant; + using LuaExposedVariant = std::variant; + + + + // Retrieve exposed variables + std::unordered_map GetExposedVariables(); + void UpdateVariable(const std::string& name, const LuaExposedVariant& value); - std::vector GetGlobalVariables(); - void PrintEngineVariables(); private: // Lua state @@ -72,6 +77,9 @@ private: lua_State *m_LuaState; + static std::unordered_map m_ExposedVariables; + + // Last error message to prevent duplicate logging std::string m_LastErrorMessage; void RegisterAllMetatables(); @@ -106,6 +114,9 @@ private: // Binding functions for Engine table static int Lua_Engine_Log(lua_State *L); static int Lua_Engine_ScriptName(lua_State *L); - static int Lua_Engine_GetGameObjectByTag(lua_State *L); + static int Lua_Engine_Expose(lua_State* L); + + + }; diff --git a/src/Windows/InspectorWindow.cpp b/src/Windows/InspectorWindow.cpp index 45007f5..5e61d06 100644 --- a/src/Windows/InspectorWindow.cpp +++ b/src/Windows/InspectorWindow.cpp @@ -558,7 +558,6 @@ void InspectorWindow::Show() // Optionally, trigger reloading the mesh if the path changes // Example: std::shared_ptr model = g_AssetManager->loadAsset(AssetType::MODEL, mesh->MeshPath.c_str()); - } // --- Submeshes Information --- @@ -636,41 +635,83 @@ void InspectorWindow::Show() if (script && g_SelectedObject) { - // Transform* transform = &g_SelectedObject->transform; - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); bool scriptOpen = ImGui::CollapsingHeader("Script##Main", ImGuiTreeNodeFlags_DefaultOpen); ImGui::PopStyleColor(); - // printf("%p\n", &transform); if (scriptOpen) { - // Define a maximum buffer size + // Define a maximum buffer size for script path const size_t BUFFER_SIZE = 256; - // Allocate a buffer and initialize it with the current string + // Allocate a buffer and initialize it with the current script path char buffer[BUFFER_SIZE]; strncpy(buffer, script->ScriptPath.c_str(), BUFFER_SIZE - 1); - buffer[BUFFER_SIZE - 1] = '\0'; // Ensure null-termination - // Render the InputText widget + // Render the InputText widget for editing the script path if (ImGui::InputText("Script Path", buffer, BUFFER_SIZE)) { - - // Update the string if user made changes - script->ScriptPath = buffer; + script->ScriptPath = buffer; // Update the script path if modified } + // Reload Script Button if (ImGui::Button("Reload Script")) { - if (script->Initialize()) { script->Init(); g_LoggerWindow->AddLog("Reloaded Script: %s", ImVec4(0.0f, 1.0f, 0.0f, 1.0f), script->ScriptPath.c_str()); } } + + // Assuming script->GetExposedVariables() returns std::unordered_map + auto exposedVariables = script->GetExposedVariables(); + + for (const auto &[name, value] : exposedVariables) + { + ImGui::Text("%s:", name.c_str()); + + if (std::holds_alternative(value)) + { + int intValue = std::get(value); + if (ImGui::InputInt(name.c_str(), &intValue)) + { + script->UpdateVariable(name, intValue); + } + } + else if (std::holds_alternative(value)) + { + float floatValue = std::get(value); + if (ImGui::InputFloat(name.c_str(), &floatValue)) + { + script->UpdateVariable(name, floatValue); + } + } + else if (std::holds_alternative(value)) + { + const std::string &strValue = std::get(value); + char buffer[256]; + strncpy(buffer, strValue.c_str(), sizeof(buffer)); + buffer[sizeof(buffer) - 1] = '\0'; // Ensure null termination + if (ImGui::InputText(name.c_str(), buffer, sizeof(buffer))) + { + script->UpdateVariable(name, std::string(buffer)); + } + } + else if (std::holds_alternative(value)) + { + bool boolValue = std::get(value); + if (ImGui::Checkbox(name.c_str(), &boolValue)) + { + script->UpdateVariable(name, boolValue); + } + } + else + { + ImGui::TextDisabled("Unsupported Type"); + } + } } } }