Optimsed OBJ Loader from ~60 seconds to ~3
This commit is contained in:
parent
9d653be08c
commit
20635140fe
@ -22,8 +22,20 @@ local transform = nil
|
||||
|
||||
local TAU = Math.constants.TAU
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function OnInit()
|
||||
local startTime = os.clock()
|
||||
|
||||
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 })
|
||||
|
||||
|
||||
@ -61,14 +73,16 @@ function OnInit()
|
||||
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)
|
||||
|
44
imgui.ini
44
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
|
||||
@ -129,13 +129,11 @@ 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=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=749,1142 Split=X
|
||||
DockNode ID=0x00000015 Parent=0x00000014 SizeRef=371,1142 Split=X
|
||||
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
|
||||
@ -149,8 +147,10 @@ DockSpace ID=0x14621557 Window=0x3DA2F1DE Pos=8,50 Size=1904,1
|
||||
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=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
|
||||
|
@ -8,11 +8,8 @@
|
||||
// External pointer to LoggerWindow (Assuming it's defined globally)
|
||||
extern LoggerWindow *g_LoggerWindow;
|
||||
|
||||
|
||||
|
||||
const std::string ScriptComponent::name = "ScriptComponent";
|
||||
|
||||
|
||||
ScriptComponent::ScriptComponent()
|
||||
: ScriptPath("assets/scripts/script.lua"), m_LastErrorMessage("")
|
||||
{
|
||||
@ -55,7 +52,6 @@ void ScriptComponent::Deserialize(const YAML::Node& node)
|
||||
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<std::string, LuaManager::LuaExposedVariant> ScriptComponent::GetExposedVariables()
|
||||
{
|
||||
return m_LuaManager.GetExposedVariables();
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <yaml-cpp/yaml.h>
|
||||
#include "Windows/LoggerWindow.h"
|
||||
#include "Engine/LuaAPI.h" // Include the LuaManager class
|
||||
#include <unordered_map>
|
||||
|
||||
class ScriptComponent : public Component
|
||||
{
|
||||
@ -16,7 +17,6 @@ public:
|
||||
|
||||
std::string ScriptPath; // Path to the Lua script
|
||||
|
||||
|
||||
// Component interface implementation
|
||||
virtual const std::string &GetName() const override;
|
||||
static const std::string &GetStaticName();
|
||||
@ -28,10 +28,10 @@ public:
|
||||
bool Initialize();
|
||||
virtual void Update(float deltaTime);
|
||||
|
||||
|
||||
void Init();
|
||||
|
||||
|
||||
void UpdateVariable(const std::string &name, const LuaManager::LuaExposedVariant &value);
|
||||
std::unordered_map<std::string, LuaManager::LuaExposedVariant> GetExposedVariables();
|
||||
|
||||
private:
|
||||
LuaManager m_LuaManager; // Instance of LuaManager
|
||||
@ -42,5 +42,4 @@ private:
|
||||
ScriptComponent &operator=(const ScriptComponent &) = delete;
|
||||
|
||||
static const std::string name;
|
||||
|
||||
};
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
@ -207,15 +201,31 @@ GLuint LoadTexture(const std::string &path, const std::string &directory)
|
||||
return textureID;
|
||||
}
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
// Custom hash function for Vertex
|
||||
struct VertexHash
|
||||
{
|
||||
std::size_t operator()(const Vertex &v) const
|
||||
{
|
||||
std::size_t h1 = std::hash<float>{}(v.position[0]);
|
||||
std::size_t h2 = std::hash<float>{}(v.position[1]);
|
||||
std::size_t h3 = std::hash<float>{}(v.position[2]);
|
||||
std::size_t h4 = std::hash<float>{}(v.texCoord[0]);
|
||||
std::size_t h5 = std::hash<float>{}(v.texCoord[1]);
|
||||
std::size_t h6 = std::hash<float>{}(v.normal[0]);
|
||||
std::size_t h7 = std::hash<float>{}(v.normal[1]);
|
||||
std::size_t h8 = std::hash<float>{}(v.normal[2]);
|
||||
return h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^ h7 ^ h8;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Hash map for deduplication
|
||||
std::unordered_map<Vertex, unsigned int, VertexHash> 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<float> temp_texCoords;
|
||||
std::vector<float> 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<char **>(&ptr), 10);
|
||||
|
||||
if (*ptr == '/')
|
||||
{
|
||||
// Format: f v1 v2 v3
|
||||
vIdx = std::stoi(vertexStr);
|
||||
++ptr; // Skip the first '/'
|
||||
if (*ptr != '/')
|
||||
{
|
||||
// Parse texture index (tIdx)
|
||||
tIdx = std::strtol(ptr, const_cast<char **>(&ptr), 10);
|
||||
}
|
||||
else if (secondSlash == std::string::npos)
|
||||
if (*ptr == '/')
|
||||
{
|
||||
// Format: f v1/vt1 v2/vt2 v3/vt3
|
||||
vIdx = std::stoi(vertexStr.substr(0, firstSlash));
|
||||
tIdx = std::stoi(vertexStr.substr(firstSlash + 1));
|
||||
++ptr; // Skip the second '/'
|
||||
// Parse normal index (nIdx)
|
||||
nIdx = std::strtol(ptr, const_cast<char **>(&ptr), 10);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
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<unsigned int>(std::distance(currentSubmesh.vertices.begin(), it));
|
||||
return it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int newIndex = static_cast<unsigned int>(currentSubmesh.vertices.size());
|
||||
currentSubmesh.vertices.push_back(vertex);
|
||||
return static_cast<unsigned int>(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<std::string, std::vector<Texture>> 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<std::chrono::duration<double>>(end - start).count());
|
||||
|
||||
DEBUG_PRINT("[AssetManager] Loaded model with %lld submeshes.", model->submeshes.size());
|
||||
|
||||
|
||||
return model;
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ extern LoggerWindow *g_LoggerWindow;
|
||||
extern std::vector<std::unique_ptr<GameObject>> g_GameObjects;
|
||||
|
||||
std::string LuaManager::m_ScriptName = "LUA_UNDEFINED";
|
||||
std::unordered_map<std::string, LuaManager::LuaExposedVariant> 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,209 +155,123 @@ bool LuaManager::Initialize(const std::string &scriptPath)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Implementation of GetGlobalVariables
|
||||
std::vector<LuaManager::LuaGlobalVariant> LuaManager::GetGlobalVariables()
|
||||
{
|
||||
std::vector<LuaManager::LuaGlobalVariant> globals;
|
||||
std::unordered_map<std::string, LuaManager::LuaExposedVariant> 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>(ImVec4(1.0f, 0.0f, 0.0f, 1.0f)));
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_PRINT("LuaManager: Lua state is not initialized.");
|
||||
}
|
||||
return globals;
|
||||
}
|
||||
|
||||
// Push the global table onto the stack
|
||||
#if LUA_VERSION_NUM >= 502
|
||||
lua_pushglobaltable(m_LuaState);
|
||||
#else
|
||||
lua_pushvalue(m_LuaState, LUA_GLOBALSINDEX);
|
||||
#endif
|
||||
|
||||
// Start iterating with a nil key
|
||||
lua_pushnil(m_LuaState); // First key
|
||||
|
||||
// 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)
|
||||
{
|
||||
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<int>(intVal));
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_Number numVal = lua_tonumber(m_LuaState, -1);
|
||||
// Store as float (you might choose double instead)
|
||||
globals.emplace_back(static_cast<float>(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<float>(numVal));
|
||||
}
|
||||
#endif
|
||||
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
|
||||
break;
|
||||
}
|
||||
|
||||
// Pop the value, keep the key for the next iteration
|
||||
lua_pop(m_LuaState, 1);
|
||||
}
|
||||
|
||||
// Pop the global table from the stack
|
||||
lua_pop(m_LuaState, 1);
|
||||
|
||||
return globals;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
// Update the variable in the map
|
||||
m_ExposedVariables[name] = value;
|
||||
|
||||
// Start iterating with a nil key
|
||||
lua_pushnil(m_LuaState); // First key
|
||||
// Push the variable to the Lua global environment
|
||||
lua_pushglobaltable(m_LuaState); // Push the global table
|
||||
|
||||
std::cout << "Engine Variables:" << std::endl;
|
||||
// Push the variable name
|
||||
lua_pushstring(m_LuaState, name.c_str());
|
||||
|
||||
// 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);
|
||||
// Push the new value based on its type
|
||||
if (std::holds_alternative<int>(value)) {
|
||||
lua_pushinteger(m_LuaState, std::get<int>(value));
|
||||
} else if (std::holds_alternative<float>(value)) {
|
||||
lua_pushnumber(m_LuaState, std::get<float>(value));
|
||||
} else if (std::holds_alternative<std::string>(value)) {
|
||||
lua_pushstring(m_LuaState, std::get<std::string>(value).c_str());
|
||||
} else if (std::holds_alternative<bool>(value)) {
|
||||
lua_pushboolean(m_LuaState, std::get<bool>(value));
|
||||
} else {
|
||||
// For non-string keys, skip
|
||||
lua_pop(m_LuaState, 1); // Remove value, keep key for next iteration
|
||||
continue;
|
||||
lua_pop(m_LuaState, 1); // Clean up stack
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the type of the value
|
||||
int valueType = lua_type(m_LuaState, -1);
|
||||
// Set the variable in the Lua global environment
|
||||
lua_settable(m_LuaState, -3);
|
||||
|
||||
// Print the key and value based on type
|
||||
std::cout << key << " = ";
|
||||
// Clean up stack
|
||||
lua_pop(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);
|
||||
std::cout << intVal;
|
||||
if (lua_isinteger(L, 2)) {
|
||||
varValue = static_cast<int>(lua_tointeger(L, 2));
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
lua_Number numVal = lua_tonumber(m_LuaState, -1);
|
||||
std::cout << numVal;
|
||||
varValue = static_cast<float>(lua_tonumber(L, 2));
|
||||
}
|
||||
break;
|
||||
|
||||
case LUA_TSTRING:
|
||||
{
|
||||
const char* str = lua_tostring(m_LuaState, -1);
|
||||
if (str) {
|
||||
std::cout << "\"" << str << "\"";
|
||||
} else {
|
||||
std::cout << "nil";
|
||||
}
|
||||
}
|
||||
varValue = std::string(lua_tostring(L, 2));
|
||||
break;
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
{
|
||||
int boolVal = lua_toboolean(m_LuaState, -1);
|
||||
std::cout << (boolVal ? "true" : "false");
|
||||
}
|
||||
varValue = static_cast<bool>(lua_toboolean(L, 2));
|
||||
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;
|
||||
luaL_error(L, "Unsupported variable type for Expose");
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
// Store the variable in the static m_ExposedVariables map
|
||||
m_ExposedVariables[varName] = varValue;
|
||||
|
||||
// Pop the value, keep the key for the next iteration
|
||||
lua_pop(m_LuaState, 1);
|
||||
// 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<int>(varValue)) {
|
||||
lua_pushinteger(L, std::get<int>(varValue));
|
||||
} else if (std::holds_alternative<float>(varValue)) {
|
||||
lua_pushnumber(L, std::get<float>(varValue));
|
||||
} else if (std::holds_alternative<std::string>(varValue)) {
|
||||
lua_pushstring(L, std::get<std::string>(varValue).c_str());
|
||||
} else if (std::holds_alternative<bool>(varValue)) {
|
||||
lua_pushboolean(L, std::get<bool>(varValue));
|
||||
} else {
|
||||
lua_pop(L, 1); // Clean up stack
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Pop the _T_Engine_Variables table from the stack
|
||||
lua_pop(m_LuaState, 1);
|
||||
// Set the variable in Lua global environment
|
||||
lua_settable(L, -3);
|
||||
|
||||
// Clean up stack
|
||||
lua_pop(L, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Update function called every frame
|
||||
void LuaManager::Update(float deltaTime)
|
||||
{
|
||||
|
@ -14,6 +14,7 @@ extern "C"
|
||||
#include <string>
|
||||
#include <optional>
|
||||
#include <variant>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
// Forward declarations to avoid circular dependencies
|
||||
@ -59,10 +60,14 @@ public:
|
||||
|
||||
void CallLuaFunction(std::string functionName);
|
||||
|
||||
using LuaGlobalVariant = std::variant<int, float, std::string>;
|
||||
using LuaExposedVariant = std::variant<int, float, std::string, bool>;
|
||||
|
||||
|
||||
|
||||
// Retrieve exposed variables
|
||||
std::unordered_map<std::string, LuaExposedVariant> GetExposedVariables();
|
||||
void UpdateVariable(const std::string& name, const LuaExposedVariant& value);
|
||||
|
||||
std::vector<LuaGlobalVariant> GetGlobalVariables();
|
||||
void PrintEngineVariables();
|
||||
|
||||
private:
|
||||
// Lua state
|
||||
@ -72,6 +77,9 @@ private:
|
||||
|
||||
lua_State *m_LuaState;
|
||||
|
||||
static std::unordered_map<std::string, LuaExposedVariant> 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);
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
@ -558,7 +558,6 @@ void InspectorWindow::Show()
|
||||
// Optionally, trigger reloading the mesh if the path changes
|
||||
// Example:
|
||||
std::shared_ptr<Model> model = g_AssetManager->loadAsset<Model>(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<std::string, LuaExposedVariant>
|
||||
auto exposedVariables = script->GetExposedVariables();
|
||||
|
||||
for (const auto &[name, value] : exposedVariables)
|
||||
{
|
||||
ImGui::Text("%s:", name.c_str());
|
||||
|
||||
if (std::holds_alternative<int>(value))
|
||||
{
|
||||
int intValue = std::get<int>(value);
|
||||
if (ImGui::InputInt(name.c_str(), &intValue))
|
||||
{
|
||||
script->UpdateVariable(name, intValue);
|
||||
}
|
||||
}
|
||||
else if (std::holds_alternative<float>(value))
|
||||
{
|
||||
float floatValue = std::get<float>(value);
|
||||
if (ImGui::InputFloat(name.c_str(), &floatValue))
|
||||
{
|
||||
script->UpdateVariable(name, floatValue);
|
||||
}
|
||||
}
|
||||
else if (std::holds_alternative<std::string>(value))
|
||||
{
|
||||
const std::string &strValue = std::get<std::string>(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<bool>(value))
|
||||
{
|
||||
bool boolValue = std::get<bool>(value);
|
||||
if (ImGui::Checkbox(name.c_str(), &boolValue))
|
||||
{
|
||||
script->UpdateVariable(name, boolValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::TextDisabled("Unsupported Type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user