Compare commits

..

No commits in common. "e81041fa2ba546e88e2186d42b373013a08c57a0" and "fba1465991e06e773c60efa7aae3967773383ff2" have entirely different histories.

25 changed files with 395 additions and 1315 deletions

View File

@ -15,19 +15,19 @@ Collapsed=0
[Window][Inspector] [Window][Inspector]
Pos=890,19 Pos=890,19
Size=390,292 Size=390,505
Collapsed=0 Collapsed=0
DockId=0x0000000B,0 DockId=0x00000005,0
[Window][Scene Tree] [Window][Scene Tree]
Pos=0,19 Pos=0,19
Size=376,366 Size=263,701
Collapsed=0 Collapsed=0
DockId=0x00000009,0 DockId=0x00000001,0
[Window][Viewport] [Window][Viewport]
Pos=378,19 Pos=265,19
Size=510,218 Size=623,329
Collapsed=0 Collapsed=0
DockId=0x00000007,0 DockId=0x00000007,0
@ -42,10 +42,10 @@ Collapsed=0
DockId=0x00000006,0 DockId=0x00000006,0
[Window][Console] [Window][Console]
Pos=0,387 Pos=265,350
Size=376,333 Size=623,370
Collapsed=0 Collapsed=0
DockId=0x0000000A,0 DockId=0x00000008,0
[Window][Tilemap Editor] [Window][Tilemap Editor]
Pos=265,19 Pos=265,19
@ -53,48 +53,14 @@ Size=1263,674
Collapsed=0 Collapsed=0
DockId=0x00000007,1 DockId=0x00000007,1
[Window][Profiler]
Pos=378,239
Size=510,481
Collapsed=0
DockId=0x00000008,0
[Window][Profiler Timeline]
Pos=265,69
Size=623,651
Collapsed=0
DockId=0x00000008,1
[Window][Profiler (Unity Style)]
Pos=265,430
Size=623,290
Collapsed=0
DockId=0x00000008,1
[Window][Profiler Timeline View]
Pos=265,526
Size=1263,651
Collapsed=0
DockId=0x00000008,1
[Window][Color Correction]
Pos=890,313
Size=390,211
Collapsed=0
DockId=0x0000000C,0
[Docking][Data] [Docking][Data]
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X
DockNode ID=0x00000003 Parent=0x11111111 SizeRef=888,1158 Split=X DockNode ID=0x00000003 Parent=0x11111111 SizeRef=888,1158 Split=X
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=376,701 Split=Y Selected=0x12EF0F59 DockNode ID=0x00000001 Parent=0x00000003 SizeRef=263,701 HiddenTabBar=1 Selected=0x12EF0F59
DockNode ID=0x00000009 Parent=0x00000001 SizeRef=376,605 HiddenTabBar=1 Selected=0x12EF0F59 DockNode ID=0x00000002 Parent=0x00000003 SizeRef=623,701 Split=Y Selected=0xC450F867
DockNode ID=0x0000000A Parent=0x00000001 SizeRef=376,551 HiddenTabBar=1 Selected=0xEA83D666 DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,329 CentralNode=1 Selected=0xC450F867
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1150,701 Split=Y Selected=0xC450F867 DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,370 Selected=0xEA83D666
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,675 CentralNode=1 Selected=0xC450F867
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,481 Selected=0x9B5D3198
DockNode ID=0x00000004 Parent=0x11111111 SizeRef=390,1158 Split=Y Selected=0x36DC96AB DockNode ID=0x00000004 Parent=0x11111111 SizeRef=390,1158 Split=Y Selected=0x36DC96AB
DockNode ID=0x00000005 Parent=0x00000004 SizeRef=407,835 Split=Y Selected=0x36DC96AB DockNode ID=0x00000005 Parent=0x00000004 SizeRef=407,835 HiddenTabBar=1 Selected=0x36DC96AB
DockNode ID=0x0000000B Parent=0x00000005 SizeRef=390,483 Selected=0x36DC96AB
DockNode ID=0x0000000C Parent=0x00000005 SizeRef=390,350 Selected=0xA873C17F
DockNode ID=0x00000006 Parent=0x00000004 SizeRef=407,321 HiddenTabBar=1 Selected=0x3FC1A724 DockNode ID=0x00000006 Parent=0x00000004 SizeRef=407,321 HiddenTabBar=1 Selected=0x3FC1A724

View File

@ -39,7 +39,6 @@ cxx: g++
cxxflags: cxxflags:
- -std=c++20 - -std=c++20
- -Wall - -Wall
- -g
# Auto-detect libraries and headers # Auto-detect libraries and headers
auto_libs: auto_libs:

View File

@ -1,10 +1 @@
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Engine.cpp -o src\build\Engine.o [LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\CameraComponent.o src\build\Components\LightComponent.o src\build\Components\ScriptComponent.o src\build\Components\SpriteComponent.o src\build\Components\TextComonent.o src\build\Components\TilemapComponent.o src\build\Entitys\Object.o src\build\utils\EngineConfig.o src\build\utils\ExceptionHandler.o src\build\utils\FileDialog.o src\build\utils\GameObjectsList.o src\build\utils\Logging.o src\build\utils\Shader.o src\build\utils\UID.o src\build\utils\utils.o src\build\imgui\imgui.o src\build\imgui\imgui_demo.o src\build\imgui\imgui_draw.o src\build\imgui\imgui_impl_glfw.o src\build\imgui\imgui_impl_opengl3.o src\build\imgui\imgui_tables.o src\build\imgui\imgui_widgets.o src\build\lapi.o src\build\lauxlib.o src\build\lbaselib.o src\build\lcode.o src\build\lcorolib.o src\build\lctype.o src\build\ldblib.o src\build\ldebug.o src\build\ldo.o src\build\ldump.o src\build\lfunc.o src\build\lgc.o src\build\linit.o src\build\liolib.o src\build\llex.o src\build\lmathlib.o src\build\lmem.o src\build\loadlib.o src\build\lobject.o src\build\lopcodes.o src\build\loslib.o src\build\lparser.o src\build\lstate.o src\build\lstring.o src\build\lstrlib.o src\build\ltable.o src\build\ltablib.o src\build\ltm.o src\build\lua.o src\build\luac.o src\build\lundump.o src\build\lutf8lib.o src\build\lvm.o src\build\lzio.o -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\main.cpp -o src\build\main.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Renderer.cpp -o src\build\Renderer.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Components\CameraComponent.cpp -o src\build\Components\CameraComponent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Components\LightComponent.cpp -o src\build\Components\LightComponent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Components\ScriptComponent.cpp -o src\build\Components\ScriptComponent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Components\SpriteComponent.cpp -o src\build\Components\SpriteComponent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Components\TextComonent.cpp -o src\build\Components\TextComonent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Components\TilemapComponent.cpp -o src\build\Components\TilemapComponent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Entitys\Object.cpp -o src\build\Entitys\Object.o

View File

@ -1,16 +0,0 @@
Engine.DebugLua(true)
local function sleep (a)
local sec = tonumber(os.clock() + a);
while (os.clock() < sec) do
end
end
function OnInit()
end
function OnUpdate(dt)
sleep(0.001)
end

View File

@ -1,13 +1,12 @@
engine_version: 0.1.0 engine_version: 0.1.0
scene_name: lighting_test_2 scene_name: lighting_test_2
scene_hash: 8f8260f09292105727f7f8afe890565a9feeaa92a1ca6d7fa55790a5019c67d7 scene_hash: a0ae96d593e1990a6f3944184fd6595738629af0dcb2d4cdd83011a91aaa738c
format_version: 1 format_version: 1
objects: objects:
- name: Tiles - name: Tiles
uid: f5e01f7892874a67b662633650b41dbd uid: f5e01f7892874a67b662633650b41dbd
id: 3 id: 3
position: [0, 0] position: [0, 0]
rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: [] components: []
@ -16,7 +15,6 @@ objects:
uid: 7dc3bbf8affb4844ae3801f03857b904 uid: 7dc3bbf8affb4844ae3801f03857b904
id: 4 id: 4
position: [0, 0] position: [0, 0]
rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
@ -29,7 +27,6 @@ objects:
uid: 13d8988343354e3c8a1f51c03ed40cda uid: 13d8988343354e3c8a1f51c03ed40cda
id: 5 id: 5
position: [1024, 0] position: [1024, 0]
rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
@ -42,7 +39,6 @@ objects:
uid: cff28abe7e3b455ab9b756acc84cd2d7 uid: cff28abe7e3b455ab9b756acc84cd2d7
id: 6 id: 6
position: [0, 1024] position: [0, 1024]
rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
@ -55,7 +51,6 @@ objects:
uid: 98967eb30e5b429b992766d8062b7c17 uid: 98967eb30e5b429b992766d8062b7c17
id: 7 id: 7
position: [1024, 1024] position: [1024, 1024]
rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
@ -67,8 +62,7 @@ objects:
- name: Logo - name: Logo
uid: c4ce6f16dfb347b0ae0ac67f5881b243 uid: c4ce6f16dfb347b0ae0ac67f5881b243
id: 8 id: 8
position: [2104, 56] position: [2048, 0]
rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
@ -80,8 +74,7 @@ objects:
- name: Carbooon Fobar - name: Carbooon Fobar
uid: 5ea269572751401da6d86519d3513b7d uid: 5ea269572751401da6d86519d3513b7d
id: 9 id: 9
position: [2048, 3070] position: [2559.30005, 1562]
rotation: 0
layer: 1 layer: 1
visable: true visable: true
components: components:
@ -93,8 +86,7 @@ objects:
- name: Mud - name: Mud
uid: a36b71937ba349bd8e6414f75be9ee16 uid: a36b71937ba349bd8e6414f75be9ee16
id: 10 id: 10
position: [0, 3070] position: [0, 2561.80005]
rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
@ -107,7 +99,6 @@ objects:
uid: 051b338a725a4076ad53ad8fa00c5f4e uid: 051b338a725a4076ad53ad8fa00c5f4e
id: 12 id: 12
position: [-556, 951] position: [-556, 951]
rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: [] components: []
@ -116,7 +107,6 @@ objects:
uid: 6afde2dd47aa4557b6afb1a607c99dc8 uid: 6afde2dd47aa4557b6afb1a607c99dc8
id: 13 id: 13
position: [512, 1024] position: [512, 1024]
rotation: 0
layer: 2 layer: 2
visable: true visable: true
components: components:
@ -138,7 +128,6 @@ objects:
uid: 0f950d76d24b4dc18f54cab2c3aaaf9a uid: 0f950d76d24b4dc18f54cab2c3aaaf9a
id: 14 id: 14
position: [1024, 512] position: [1024, 512]
rotation: 0
layer: 2 layer: 2
visable: true visable: true
components: components:
@ -160,7 +149,6 @@ objects:
uid: 09f722f51c7c4b0f98de3a0a16d127c4 uid: 09f722f51c7c4b0f98de3a0a16d127c4
id: 15 id: 15
position: [250, 250] position: [250, 250]
rotation: 0
layer: 2 layer: 2
visable: true visable: true
components: components:
@ -182,7 +170,6 @@ objects:
uid: d4fb425522d84a8cbbd7d1415bcd93df uid: d4fb425522d84a8cbbd7d1415bcd93df
id: 16 id: 16
position: [500, 500] position: [500, 500]
rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:
@ -200,7 +187,6 @@ objects:
uid: 895c655f3dda4aec9f2a354c1276c53e uid: 895c655f3dda4aec9f2a354c1276c53e
id: 14 id: 14
position: [0, 0] position: [0, 0]
rotation: 0
layer: 0 layer: 0
visable: true visable: true
components: components:

View File

@ -6,11 +6,6 @@ out vec4 FragColor;
uniform sampler2D uTex; uniform sampler2D uTex;
uniform sampler2D uNormalMap; uniform sampler2D uNormalMap;
uniform float uRotation;
uniform float uBrightness;
uniform float uSaturation;
uniform float uGamma;
#define MAX_LIGHTS 512 #define MAX_LIGHTS 512
@ -22,22 +17,16 @@ uniform float uLightRadius[MAX_LIGHTS];
void main() void main()
{ {
// Rotate UV 90° clockwise vec4 texColor = texture(uTex, vUV);
vec2 rotatedUV = vec2(vUV.y, 1.0 - vUV.x);
vec4 texColor = texture(uTex, rotatedUV);
if (texColor.a < 0.1) if (texColor.a < 0.1)
discard; discard;
vec3 n = texture(uNormalMap, rotatedUV).rgb * 2.0 - 1.0; // unpack normal map and convert from [0,1] to [-1,1]
vec3 n = texture(uNormalMap, vUV).rgb * 2.0 - 1.0;
// invert the green channel for OpenGL
n.y = -n.y; n.y = -n.y;
float c = cos(uRotation);
float s = sin(uRotation);
mat2 rot = mat2(c, -s, s, c);
n.xy = rot * n.xy;
vec3 normal = normalize(n); vec3 normal = normalize(n);
vec3 finalLight = vec3(0.0); vec3 finalLight = vec3(0.0);
for (int i = 0; i < uLightCount; ++i) for (int i = 0; i < uLightCount; ++i)
@ -48,8 +37,9 @@ void main()
if (dist < uLightRadius[i]) if (dist < uLightRadius[i])
{ {
vec2 lightDir2D = normalize(lightVec); vec2 lightDir2D = normalize(lightVec);
vec3 lightDir = normalize(vec3(lightDir2D, 1.0)); vec3 lightDir = normalize(vec3(lightDir2D, 1.0)); // pseudo-3D
float attenuation = smoothstep(uLightRadius[i], 0.0, dist);
float attenuation = 1.0 - dist / uLightRadius[i];
float diff = max(dot(normal, lightDir), 0.0); float diff = max(dot(normal, lightDir), 0.0);
vec3 light = uLightColor[i] * diff * attenuation * uLightIntensity[i]; vec3 light = uLightColor[i] * diff * attenuation * uLightIntensity[i];
finalLight += light; finalLight += light;
@ -57,15 +47,5 @@ void main()
} }
vec3 result = texColor.rgb * finalLight; vec3 result = texColor.rgb * finalLight;
result *= uBrightness;
float gray = dot(result, vec3(0.299, 0.587, 0.114));
result = mix(vec3(gray), result, uSaturation);
result = pow(result, vec3(1.0 / uGamma));
result = clamp(result, 0.0, 1.0);
FragColor = vec4(result, texColor.a); FragColor = vec4(result, texColor.a);
} }

View File

@ -1,7 +1,7 @@
#version 330 core #version 430 core
layout (location = 0) in vec2 aPos; layout(location = 0) in vec2 aPos;
layout (location = 1) in vec2 aUV; layout(location = 1) in vec2 aUV;
out vec2 vUV; out vec2 vUV;
out vec2 vFragScreenPos; out vec2 vFragScreenPos;
@ -9,22 +9,17 @@ out vec2 vFragScreenPos;
uniform vec2 uPos; uniform vec2 uPos;
uniform vec2 uSize; uniform vec2 uSize;
uniform vec2 uScreen; uniform vec2 uScreen;
uniform float uRotation;//r
void main() void main()
{ {
vec2 centered = aPos - vec2(0.5);
float s = cos(uRotation);
float c = sin(uRotation);
mat2 rot = mat2(c, -s, s, c);
vec2 rotated = rot * (centered * uSize);
vec2 finalPos = uPos + rotated;
vUV = aUV; vUV = aUV;
vFragScreenPos = finalPos;
vec2 ndc = finalPos / uScreen * 2.0 - 1.0; vec2 worldPos = uPos + aPos * uSize;
gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0); // Y-flip
vFragScreenPos = worldPos;
vec2 ndc = (worldPos / uScreen) * 2.0 - 1.0;
ndc.y *= -1.0;
gl_Position = vec4(ndc, 0.0, 1.0);
} }

View File

@ -1,15 +1,10 @@
#version 330 core #version 430 core
in vec2 vUV; in vec2 vUV;
out vec4 FragColor; out vec4 FragColor;
uniform sampler2D uTex; uniform sampler2D uTex;
void main() {
void main() vec4 color = texture(uTex, vUV);
{
vec2 rotatedUV = vec2(vUV.y, 1.0 - vUV.x);
vec4 color = texture(uTex, rotatedUV);
if (color.a < 0.01) if (color.a < 0.01)
discard; discard;

View File

@ -1,28 +1,13 @@
#version 330 core #version 430 core
layout (location = 0) in vec2 aPos; layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aUV; layout (location = 1) in vec2 aUV;
out vec2 vUV; out vec2 vUV;
out vec2 vFragScreenPos;
uniform vec2 uPos; uniform vec2 uPos;
uniform vec2 uSize; uniform vec2 uSize;
uniform vec2 uScreen; uniform vec2 uScreen;
uniform float uRotation; // radians void main() {
vec2 worldPos = aPos * uSize + uPos;
void main()
{
vec2 centered = aPos - vec2(0.5);
float s = cos(uRotation);
float c = sin(uRotation);
mat2 rot = mat2(c, -s, s, c);
vec2 rotated = rot * (centered * uSize);
vec2 finalPos = uPos + rotated;
vFragScreenPos = finalPos;
vUV = aUV; vUV = aUV;
vec2 ndc = (worldPos / uScreen) * 2.0 - 1.0;
vec2 ndc = finalPos / uScreen * 2.0 - 1.0; gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0);
gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0); // Y flip for OpenGL
} }

View File

@ -17,7 +17,6 @@ public:
void SetOwner(Object* o) { owner = o; } void SetOwner(Object* o) { owner = o; }
virtual std::string GetName() const = 0; virtual std::string GetName() const = 0;
virtual void Save(YAML::Emitter& out) const = 0; virtual void Save(YAML::Emitter& out) const = 0;
virtual void Load(const YAML::Node& node) = 0; virtual void Load(const YAML::Node& node) = 0;

View File

@ -10,114 +10,78 @@
#include "../Components/TextComponent.h" #include "../Components/TextComponent.h"
#include "../Components/TilemapComponent.h" #include "../Components/TilemapComponent.h"
#include "../utils/Profiler.h"
#include <lua.hpp> #include <lua.hpp>
#include <memory> #include <memory>
#include <cstring> #include <cstring>
static bool luaDebugEnabled = false; static bool luaDebugEnabled = false;
static bool old_state = false;
struct LuaObjectWrapper struct LuaObjectWrapper {
{ Object* obj;
Object *obj;
}; };
#define LUA_OBJECT_MT "LuaObjectMeta" #define LUA_OBJECT_MT "LuaObjectMeta"
struct LuaVector2 struct LuaVector2 {
{
float x, y; float x, y;
}; };
#define LUA_VECTOR2_MT "LuaVector2Meta" #define LUA_VECTOR2_MT "LuaVector2Meta"
ScriptComponent::ScriptComponent(Object *owner) : Component(owner), L(nullptr) {} ScriptComponent::ScriptComponent(Object* owner) : Component(owner), L(nullptr) {}
ScriptComponent::~ScriptComponent() ScriptComponent::~ScriptComponent() { if (L) lua_close(L); }
{
if (L)
lua_close(L);
}
void ScriptComponent::SetScriptPath(const std::string &path) void ScriptComponent::SetScriptPath(const std::string& path) {
{
scriptPath = path; scriptPath = path;
ReloadScript(); ReloadScript();
} }
const std::string &ScriptComponent::GetScriptPath() const { return scriptPath; } const std::string& ScriptComponent::GetScriptPath() const { return scriptPath; }
// Logging bindings // Logging bindings
static int Lua_LogInfo(lua_State *L) static int Lua_LogInfo(lua_State* L) {
{
Logger::LogInfo("[Lua] %s", lua_tostring(L, 1)); Logger::LogInfo("[Lua] %s", lua_tostring(L, 1));
return 0; return 0;
} }
static int Lua_LogError(lua_State *L) static int Lua_LogError(lua_State* L) {
{
Logger::LogError("[Lua] %s", lua_tostring(L, 1)); Logger::LogError("[Lua] %s", lua_tostring(L, 1));
return 0; return 0;
} }
static int Lua_LogDebug(lua_State *L) static int Lua_LogDebug(lua_State* L) {
{
Logger::LogDebug("[Lua] %s", lua_tostring(L, 1)); Logger::LogDebug("[Lua] %s", lua_tostring(L, 1));
return 0; return 0;
} }
static int Lua_DebugLua(lua_State *L) static int Lua_DebugLua(lua_State* L) {
{
luaDebugEnabled = lua_toboolean(L, 1); luaDebugEnabled = lua_toboolean(L, 1);
if (old_state != luaDebugEnabled) Logger::LogInfo("[Lua] DebugLua = %s", luaDebugEnabled ? "true" : "false");
{
Logger::LogInfo("[Lua] DebugLua(%s)", luaDebugEnabled ? "true" : "false");
}
old_state = luaDebugEnabled;
return 0; return 0;
} }
// Component resolver // Component resolver
static Component *GetComponentByName(Object *obj, const std::string &type) static Component* GetComponentByName(Object* obj, const std::string& type) {
{ if (type == "SpriteComponent") return obj->GetComponent<SpriteComponent>().get();
PROFILE_SCOPE("LUA_GetComponentByName"); if (type == "CameraComponent") return obj->GetComponent<CameraComponent>().get();
if (type == "LightComponent") return obj->GetComponent<LightComponent>().get();
if (type == "SpriteComponent") if (type == "TilemapComponent") return obj->GetComponent<TilemapComponent>().get();
return obj->GetComponent<SpriteComponent>().get(); if (type == "TextComponent") return obj->GetComponent<TextComponent>().get();
if (type == "CameraComponent") if (type == "ScriptComponent") return obj->GetComponent<ScriptComponent>().get();
return obj->GetComponent<CameraComponent>().get();
if (type == "LightComponent")
return obj->GetComponent<LightComponent>().get();
if (type == "TilemapComponent")
return obj->GetComponent<TilemapComponent>().get();
if (type == "TextComponent")
return obj->GetComponent<TextComponent>().get();
if (type == "ScriptComponent")
return obj->GetComponent<ScriptComponent>().get();
return nullptr; return nullptr;
} }
// Object:GetComponent("Type") // Object:GetComponent("Type")
static int Lua_Object_GetComponent(lua_State *L) static int Lua_Object_GetComponent(lua_State* L) {
{ auto* wrapper = (LuaObjectWrapper*)luaL_checkudata(L, 1, LUA_OBJECT_MT);
PROFILE_SCOPE("Lua_Object_GetComponent"); const char* type = luaL_checkstring(L, 2);
auto *wrapper = (LuaObjectWrapper *)luaL_checkudata(L, 1, LUA_OBJECT_MT); Component* comp = GetComponentByName(wrapper->obj, type);
const char *type = luaL_checkstring(L, 2); if (comp) lua_pushlightuserdata(L, comp);
else lua_pushnil(L);
Component *comp = GetComponentByName(wrapper->obj, type);
if (comp)
lua_pushlightuserdata(L, comp);
else
lua_pushnil(L);
return 1; return 1;
} }
// Object:GetPosition() // Object:GetPosition()
static int Lua_Object_GetPosition(lua_State *L) static int Lua_Object_GetPosition(lua_State* L) {
{ auto* wrapper = (LuaObjectWrapper*)luaL_checkudata(L, 1, LUA_OBJECT_MT);
PROFILE_SCOPE("Lua_Object_GetPosition");
auto *wrapper = (LuaObjectWrapper *)luaL_checkudata(L, 1, LUA_OBJECT_MT);
glm::vec2 pos = wrapper->obj->GetLocalPosition(); glm::vec2 pos = wrapper->obj->GetLocalPosition();
LuaVector2 *vec = (LuaVector2 *)lua_newuserdata(L, sizeof(LuaVector2)); LuaVector2* vec = (LuaVector2*)lua_newuserdata(L, sizeof(LuaVector2));
vec->x = pos.x; vec->x = pos.x;
vec->y = pos.y; vec->y = pos.y;
luaL_getmetatable(L, LUA_VECTOR2_MT); luaL_getmetatable(L, LUA_VECTOR2_MT);
@ -126,37 +90,27 @@ static int Lua_Object_GetPosition(lua_State *L)
} }
// Object:SetPosition(Vector2) // Object:SetPosition(Vector2)
static int Lua_Object_SetPosition(lua_State *L) static int Lua_Object_SetPosition(lua_State* L) {
{ auto* wrapper = (LuaObjectWrapper*)luaL_checkudata(L, 1, LUA_OBJECT_MT);
PROFILE_SCOPE("Lua_Object_SetPosition"); auto* vec = (LuaVector2*)luaL_checkudata(L, 2, LUA_VECTOR2_MT);
wrapper->obj->SetLocalPosition({ vec->x, vec->y });
auto *wrapper = (LuaObjectWrapper *)luaL_checkudata(L, 1, LUA_OBJECT_MT);
auto *vec = (LuaVector2 *)luaL_checkudata(L, 2, LUA_VECTOR2_MT);
wrapper->obj->SetLocalPosition({vec->x, vec->y});
return 0; return 0;
} }
// __index for Object // __index for Object
static int Lua_Object_Index(lua_State *L) static int Lua_Object_Index(lua_State* L) {
{ const char* key = luaL_checkstring(L, 2);
PROFILE_SCOPE("Lua_Object_Index");
const char *key = luaL_checkstring(L, 2);
lua_getfield(L, lua_upvalueindex(1), key); lua_getfield(L, lua_upvalueindex(1), key);
return 1; return 1;
} }
void RegisterObjectType(lua_State *L) void RegisterObjectType(lua_State* L) {
{
luaL_newmetatable(L, LUA_OBJECT_MT); luaL_newmetatable(L, LUA_OBJECT_MT);
lua_newtable(L); // method table lua_newtable(L); // method table
lua_pushcfunction(L, Lua_Object_GetComponent); lua_pushcfunction(L, Lua_Object_GetComponent); lua_setfield(L, -2, "GetComponent");
lua_setfield(L, -2, "GetComponent"); lua_pushcfunction(L, Lua_Object_GetPosition); lua_setfield(L, -2, "GetPosition");
lua_pushcfunction(L, Lua_Object_GetPosition); lua_pushcfunction(L, Lua_Object_SetPosition); lua_setfield(L, -2, "SetPosition");
lua_setfield(L, -2, "GetPosition");
lua_pushcfunction(L, Lua_Object_SetPosition);
lua_setfield(L, -2, "SetPosition");
lua_pushcclosure(L, Lua_Object_Index, 1); lua_pushcclosure(L, Lua_Object_Index, 1);
lua_setfield(L, -2, "__index"); lua_setfield(L, -2, "__index");
@ -164,25 +118,19 @@ void RegisterObjectType(lua_State *L)
lua_pop(L, 1); lua_pop(L, 1);
} }
static void PushObject(lua_State *L, Object *obj) static void PushObject(lua_State* L, Object* obj) {
{ auto* wrapper = (LuaObjectWrapper*)lua_newuserdata(L, sizeof(LuaObjectWrapper));
auto *wrapper = (LuaObjectWrapper *)lua_newuserdata(L, sizeof(LuaObjectWrapper));
wrapper->obj = obj; wrapper->obj = obj;
luaL_getmetatable(L, LUA_OBJECT_MT); luaL_getmetatable(L, LUA_OBJECT_MT);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
} }
// Engine.GetObjectByTag(name) // Engine.GetObjectByTag(name)
static int Lua_GetObjectByTag(lua_State *L) static int Lua_GetObjectByTag(lua_State* L) {
{ const char* name = luaL_checkstring(L, 1);
PROFILE_SCOPE("Lua_GetObjectByTag"); for (const auto& obj : objects) {
const char *name = luaL_checkstring(L, 1);
for (const auto &obj : objects)
{
auto found = FindByTagRecursive(obj, name); auto found = FindByTagRecursive(obj, name);
if (found) if (found) {
{
PushObject(L, found.get()); PushObject(L, found.get());
return 1; return 1;
} }
@ -192,86 +140,57 @@ static int Lua_GetObjectByTag(lua_State *L)
} }
// Vector2(x, y) // Vector2(x, y)
static int Lua_Vector2_New(lua_State *L) static int Lua_Vector2_New(lua_State* L) {
{ LuaVector2* vec = (LuaVector2*)lua_newuserdata(L, sizeof(LuaVector2));
PROFILE_SCOPE("Lua_Vector2_New"); vec->x = (float)luaL_optnumber(L, 1, 0);
vec->y = (float)luaL_optnumber(L, 2, 0);
LuaVector2 *vec = static_cast<LuaVector2 *>(lua_newuserdata(L, sizeof(LuaVector2))); luaL_getmetatable(L, LUA_VECTOR2_MT);
lua_setmetatable(L, -2);
int nargs = lua_gettop(L);
vec->x = nargs >= 1 ? (float)lua_tonumber(L, 1) : 0.0f;
vec->y = nargs >= 2 ? (float)lua_tonumber(L, 2) : 0.0f;
luaL_setmetatable(L, LUA_VECTOR2_MT);
return 1; return 1;
} }
static int Lua_Vector2_Index(lua_State *L) static int Lua_Vector2_Index(lua_State* L) {
{ auto* vec = (LuaVector2*)luaL_checkudata(L, 1, LUA_VECTOR2_MT);
PROFILE_SCOPE("Lua_Vector2_Index"); const char* key = luaL_checkstring(L, 2);
if (strcmp(key, "x") == 0) lua_pushnumber(L, vec->x);
auto *vec = (LuaVector2 *)luaL_checkudata(L, 1, LUA_VECTOR2_MT); else if (strcmp(key, "y") == 0) lua_pushnumber(L, vec->y);
const char *key = luaL_checkstring(L, 2); else lua_pushnil(L);
if (strcmp(key, "x") == 0)
lua_pushnumber(L, vec->x);
else if (strcmp(key, "y") == 0)
lua_pushnumber(L, vec->y);
else
lua_pushnil(L);
return 1; return 1;
} }
static int Lua_Vector2_NewIndex(lua_State *L) static int Lua_Vector2_NewIndex(lua_State* L) {
{ auto* vec = (LuaVector2*)luaL_checkudata(L, 1, LUA_VECTOR2_MT);
PROFILE_SCOPE("Lua_Vector2_NewIndex"); const char* key = luaL_checkstring(L, 2);
auto *vec = (LuaVector2 *)luaL_checkudata(L, 1, LUA_VECTOR2_MT);
const char *key = luaL_checkstring(L, 2);
float value = (float)luaL_checknumber(L, 3); float value = (float)luaL_checknumber(L, 3);
if (strcmp(key, "x") == 0) if (strcmp(key, "x") == 0) vec->x = value;
vec->x = value; else if (strcmp(key, "y") == 0) vec->y = value;
else if (strcmp(key, "y") == 0)
vec->y = value;
return 0; return 0;
} }
void RegisterVector2Type(lua_State *L) void RegisterVector2Type(lua_State* L) {
{
luaL_newmetatable(L, LUA_VECTOR2_MT); luaL_newmetatable(L, LUA_VECTOR2_MT);
lua_pushcfunction(L, Lua_Vector2_Index); lua_pushcfunction(L, Lua_Vector2_Index); lua_setfield(L, -2, "__index");
lua_setfield(L, -2, "__index"); lua_pushcfunction(L, Lua_Vector2_NewIndex); lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, Lua_Vector2_NewIndex);
lua_setfield(L, -2, "__newindex");
lua_pop(L, 1); lua_pop(L, 1);
lua_pushcfunction(L, Lua_Vector2_New); lua_pushcfunction(L, Lua_Vector2_New);
lua_setglobal(L, "Vector2"); lua_setglobal(L, "Vector2");
} }
void ScriptComponent::RegisterEngineBindings() void ScriptComponent::RegisterEngineBindings() {
{
lua_newtable(L); lua_newtable(L);
lua_pushcfunction(L, Lua_LogInfo); lua_pushcfunction(L, Lua_LogInfo); lua_setfield(L, -2, "LogInfo");
lua_setfield(L, -2, "LogInfo"); lua_pushcfunction(L, Lua_LogError); lua_setfield(L, -2, "LogError");
lua_pushcfunction(L, Lua_LogError); lua_pushcfunction(L, Lua_LogDebug); lua_setfield(L, -2, "LogDebug");
lua_setfield(L, -2, "LogError"); lua_pushcfunction(L, Lua_GetObjectByTag); lua_setfield(L, -2, "GetObjectByTag");
lua_pushcfunction(L, Lua_LogDebug); lua_pushcfunction(L, Lua_DebugLua); lua_setfield(L, -2, "DebugLua");
lua_setfield(L, -2, "LogDebug");
lua_pushcfunction(L, Lua_GetObjectByTag);
lua_setfield(L, -2, "GetObjectByTag");
lua_pushcfunction(L, Lua_DebugLua);
lua_setfield(L, -2, "DebugLua");
lua_setglobal(L, "Engine"); lua_setglobal(L, "Engine");
} }
void ScriptComponent::ReloadScript() void ScriptComponent::ReloadScript() {
{ if (scriptPath.empty()) return;
if (scriptPath.empty())
return;
if (L) if (L) lua_close(L);
lua_close(L);
L = luaL_newstate(); L = luaL_newstate();
luaL_openlibs(L); luaL_openlibs(L);
@ -279,79 +198,54 @@ void ScriptComponent::ReloadScript()
RegisterVector2Type(L); RegisterVector2Type(L);
RegisterEngineBindings(); RegisterEngineBindings();
Logger::LogVerbose("[Lua] Loading Script from file."); if (luaL_dofile(L, scriptPath.c_str())) {
if (luaL_dofile(L, scriptPath.c_str()))
{
Logger::LogError("[Lua] %s", lua_tostring(L, -1)); Logger::LogError("[Lua] %s", lua_tostring(L, -1));
RecoverableError("Failed to load Lua script: " + scriptPath, Create::Exceptions::ComponentLoad).Handle(); RecoverableError("Failed to load Lua script: " + scriptPath, Create::Exceptions::ComponentLoad).Handle();
return; return;
} }
if (luaDebugEnabled)
{
Logger::LogVerbose("[Lua][call] OnInit()");
}
lua_getglobal(L, "OnInit"); lua_getglobal(L, "OnInit");
if (lua_isfunction(L, -1)) if (lua_isfunction(L, -1)) {
{ if (lua_pcall(L, 0, 0, 0) != LUA_OK) {
if (lua_pcall(L, 0, 0, 0) != LUA_OK)
{
Logger::LogError("[Lua] %s", lua_tostring(L, -1)); Logger::LogError("[Lua] %s", lua_tostring(L, -1));
RecoverableError("OnInit failed: " + scriptPath, Create::Exceptions::ComponentLoad).Handle(); RecoverableError("OnInit failed: " + scriptPath, Create::Exceptions::ComponentLoad).Handle();
} }
} } else {
else
{
lua_pop(L, 1); lua_pop(L, 1);
} }
} }
void ScriptComponent::OnUpdate(float dt) void ScriptComponent::OnUpdate(float dt) {
{ if (!L) return;
PROFILE_SCOPE("ScriptComponent::OnUpdate");
if (!L)
return;
lua_getglobal(L, "OnUpdate"); lua_getglobal(L, "OnUpdate");
if (lua_isfunction(L, -1)) if (lua_isfunction(L, -1)) {
{
lua_pushnumber(L, dt); lua_pushnumber(L, dt);
if (lua_pcall(L, 1, 0, 0) != LUA_OK) if (lua_pcall(L, 1, 0, 0) != LUA_OK) {
{
Logger::LogError("[Lua] %s", lua_tostring(L, -1)); Logger::LogError("[Lua] %s", lua_tostring(L, -1));
RecoverableError("OnUpdate failed in: " + scriptPath, Create::Exceptions::ComponentLoad).Handle(); RecoverableError("OnUpdate failed in: " + scriptPath, Create::Exceptions::ComponentLoad).Handle();
} }
} } else {
else
{
lua_pop(L, 1); lua_pop(L, 1);
} }
} }
void ScriptComponent::Save(YAML::Emitter &out) const void ScriptComponent::Save(YAML::Emitter& out) const {
{
out << YAML::BeginMap; out << YAML::BeginMap;
out << YAML::Key << "type" << YAML::Value << "ScriptComponent"; out << YAML::Key << "type" << YAML::Value << "ScriptComponent";
out << YAML::Key << "scriptPath" << YAML::Value << scriptPath; out << YAML::Key << "scriptPath" << YAML::Value << scriptPath;
out << YAML::EndMap; out << YAML::EndMap;
} }
void ScriptComponent::Load(const YAML::Node &node) void ScriptComponent::Load(const YAML::Node& node) {
{ try {
try if (!node["scriptPath"]) {
{
if (!node["scriptPath"])
{
RecoverableError("Missing 'scriptPath' in ScriptComponent", Create::Exceptions::MissingField).Handle(); RecoverableError("Missing 'scriptPath' in ScriptComponent", Create::Exceptions::MissingField).Handle();
return; return;
} }
scriptPath = node["scriptPath"].as<std::string>(); scriptPath = node["scriptPath"].as<std::string>();
ReloadScript(); ReloadScript();
} } catch (const YAML::Exception& e) {
catch (const YAML::Exception &e)
{
RecoverableError("YAML error in ScriptComponent::Load: " + std::string(e.what()), Create::Exceptions::ComponentLoad).Handle(); RecoverableError("YAML error in ScriptComponent::Load: " + std::string(e.what()), Create::Exceptions::ComponentLoad).Handle();
} }
} }

View File

@ -8,8 +8,6 @@
#include "../utils/utils.h" #include "../utils/utils.h"
struct ImageCacheEntry { struct ImageCacheEntry {
unsigned int textureID; unsigned int textureID;
glm::vec2 size; glm::vec2 size;

View File

@ -12,7 +12,6 @@
#include "utils/EngineConfig.h" #include "utils/EngineConfig.h"
#include "utils/GameObjectsList.h" #include "utils/GameObjectsList.h"
#include "utils/Profiler.h"
#include <GL/glew.h> #include <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
@ -25,10 +24,6 @@
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <vector> #include <vector>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <format>
#include <memory> #include <memory>
#include <filesystem> #include <filesystem>
#include <iostream> #include <iostream>
@ -45,15 +40,14 @@ static glm::vec2 cameraPos = {0, 0};
static float cameraZoom = 1.0f; static float cameraZoom = 1.0f;
static ImVec2 lastMousePos = {}; static ImVec2 lastMousePos = {};
float g_fps = 0.0f;
static const std::string tempScenePath = "__tmp_scene.yaml"; static const std::string tempScenePath = "__tmp_scene.yaml";
static float g_fps = 0.0f;
GLFWwindow *window = nullptr; GLFWwindow *window = nullptr;
Engine::Engine() Engine::Engine()
{ {
Init(); Init();
} }
@ -62,251 +56,46 @@ Engine::~Engine()
Shutdown(); Shutdown();
} }
void DrawProfilerTimelineBars(const ProfileNode &node,
int depth,
float baseOffsetX,
float frameDuration,
ImVec2 origin)
{
constexpr float rowHeight = 24.0f;
constexpr float textPadding = 5.0f;
// compute bar rect
float startRel = node.visualStartMs / frameDuration;
float durRel = node.visualDurationMs / frameDuration;
float x = origin.x + startRel * baseOffsetX;
float width = std::fmax(1.0f, durRel * baseOffsetX);
float y = origin.y + depth * rowHeight;
ImVec2 barMin(x, y);
ImVec2 barMax(x + width, y + rowHeight - 4.0f);
// draw the bar
size_t hash = std::hash<std::string>{}(node.name);
ImU32 color = ImColor::HSV((hash % 1000) / 1000.0f, 0.6f, 0.85f);
ImDrawList *draw = ImGui::GetWindowDrawList();
draw->AddRectFilled(barMin, barMax, color, 3.0f);
draw->AddRect(barMin, barMax, IM_COL32_BLACK, 3.0f);
// how much room we have for text
float availW = width - textPadding * 2;
const char *textToDraw = nullptr;
// 1) try the short "XX.XX ms"
char timeBuf[16];
int tn = std::snprintf(timeBuf, sizeof(timeBuf), "%.2f ms", node.visualDurationMs);
if (tn > 0)
{
ImVec2 sz = ImGui::CalcTextSize(timeBuf);
if (sz.x <= availW)
{
textToDraw = timeBuf;
}
}
// 2) only if the short fits, see if full fits
if (textToDraw == timeBuf)
{
char fullBuf[64];
int fn = std::snprintf(fullBuf, sizeof(fullBuf),
"%s (%.2f ms)",
node.name.c_str(),
node.visualDurationMs);
if (fn > 0)
{
ImVec2 fsz = ImGui::CalcTextSize(fullBuf);
if (fsz.x <= availW)
{
textToDraw = fullBuf;
}
}
}
// 3) draw if we decided on something
if (textToDraw)
{
draw->AddText(
ImVec2(barMin.x + textPadding,
barMin.y),
IM_COL32_WHITE,
textToDraw);
}
// tooltip
ImVec2 mouse = ImGui::GetMousePos();
if (mouse.x >= barMin.x && mouse.x <= barMax.x &&
mouse.y >= barMin.y && mouse.y <= barMax.y)
{
ImGui::SetTooltip(
"%s\nCurrent: %.3f ms\nSmoothed: %.3f ms",
node.name.c_str(),
node.durationMs,
node.visualDurationMs);
}
// recurse
for (auto &child : node.children)
DrawProfilerTimelineBars(child,
depth + 1,
baseOffsetX,
frameDuration,
origin);
}
static ProfileNode GetAveragedFrameCopy(const ProfileNode &src)
{
ProfileNode averaged = src;
averaged.visualStartMs = src.startMs;
averaged.visualDurationMs = src.durationMs;
averaged.children.clear();
for (const auto &child : src.children)
averaged.children.push_back(GetAveragedFrameCopy(child));
return averaged;
}
void ShowProfilerTimeline()
{
static ProfileNode cachedAveragedFrame;
static double lastUpdateTime = 0.0;
static double updateInterval = 0.25;
static bool freezeView = false;
const double now = ImGui::GetTime();
const ProfileNode *latest = profiler.GetLatestFrame();
ImGui::Begin("Profiler", nullptr, ImGuiWindowFlags_NoScrollbar);
// --- Controls ---
if (g_engineConfig.settings.profile_enabled)
{
ImGui::Checkbox("Freeze View", &freezeView);
ImGui::SameLine();
ImGui::SetNextItemWidth(100);
float interval = static_cast<float>(updateInterval);
if (ImGui::DragFloat("Update Interval", &interval, 0.05f, 0.05f, 5.0f))
updateInterval = interval;
updateInterval = std::clamp(updateInterval, 0.05, 5.0);
if (!freezeView && latest && (now - lastUpdateTime) >= updateInterval)
{
cachedAveragedFrame = GetAveragedFrameCopy(*latest);
lastUpdateTime = now;
}
if (cachedAveragedFrame.durationMs <= 0.0f)
{
ImGui::Text("Waiting for profiler data...");
ImGui::End();
return;
}
const float rowHeight = 24.0f;
const float timelineHeight = 400.0f;
float frameDuration = cachedAveragedFrame.visualDurationMs;
float timelineWidth = ImGui::GetContentRegionAvail().x * 0.95f;
ImGui::BeginChild("TimelineScroll", ImVec2(0, timelineHeight));
ImVec2 origin = ImGui::GetCursorScreenPos();
DrawProfilerTimelineBars(cachedAveragedFrame, 0, timelineWidth, frameDuration, origin);
ImGui::Dummy(ImVec2(timelineWidth, 32 * rowHeight));
ImGui::EndChild();
ImGui::Text("Frame Duration (Avg): %.2f ms | View Update Rate: %.2fs", frameDuration, updateInterval);
}
else
{
ImGui::Text("Profiling Disabled.");
}
ImGui::End();
}
void Engine::ShowDebugOverlay(float deltaTime) void Engine::ShowDebugOverlay(float deltaTime)
{ {
// === Performance Window ===
static std::vector<float> fpsHistory; static std::vector<float> fpsHistory;
static const int maxFpsHistory = 100; static const int maxHistory = 100;
static float fpsTimer = 0.0f; static float timer = 0;
float fps = 1.0f / deltaTime; float fps = 1.0f / deltaTime;
g_fps = fps; g_fps = fps;
if (fpsHistory.size() >= maxFpsHistory) if (fpsHistory.size() >= maxHistory)
fpsHistory.erase(fpsHistory.begin()); fpsHistory.erase(fpsHistory.begin());
if (fpsTimer >= 0.05f) if (timer >= 0.05)
{ {
fpsTimer = 0; timer = 0;
fpsHistory.push_back(fps); fpsHistory.push_back(fps);
} }
fpsTimer += deltaTime; timer += deltaTime;
ImGui::Begin("Performance Info", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_AlwaysAutoResize); ImGui::Begin("Performance Info", nullptr,
ImGuiWindowFlags_NoDecoration);
ImGui::TextColored(ImVec4(0.3f, 1.0f, 0.3f, 1.0f), "Performance"); ImGui::TextColored(ImVec4(0.3f, 1.0f, 0.3f, 1.0f), "Performance");
ImGui::Separator(); ImGui::Separator();
ImGui::Text("FPS: %.1f", fps); ImGui::Text("FPS: %.1f", fps);
ImGui::Text("Delta Time: %.4f s", deltaTime); ImGui::Text("Delta Time: %.4f s", deltaTime);
ImGui::Text("Frame Time: %.2f ms", deltaTime * 1000.0f); ImGui::Text("Frame Time: %.2f ms", deltaTime * 1000.0f);
ImGui::PlotLines("##FPS", fpsHistory.data(), fpsHistory.size(), 0, "FPS History", 0.0f, 144.0f, ImVec2(-1, 50));
if (!fpsHistory.empty())
{
float maxFps = *std::max_element(fpsHistory.begin(), fpsHistory.end());
maxFps = std::max(maxFps * 1.1f, 60.0f);
ImGui::PlotLines("##FPS", fpsHistory.data(), fpsHistory.size(), 0, "FPS History",
0.0f, maxFps, ImVec2(-1, 50));
}
else
{
ImGui::Text("FPS data unavailable");
}
ImGui::Spacing(); ImGui::Spacing();
ImGui::TextColored(ImVec4(0.4f, 0.7f, 1.0f, 1.0f), "Renderer"); ImGui::TextColored(ImVec4(0.4f, 0.7f, 1.0f, 1.0f), "Renderer");
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Draw Calls: %d", Renderer::GetDrawCallCount()); ImGui::Text("Draw Calls: %d", Renderer::GetDrawCallCount());
ImGui::Text("Lua OnUpdate Calls: %d", m_OnUpdateCalls); ImGui::Text("Scene Lights: %d/%d", Renderer::GetLightsCount(), g_engineConfig.gl_maxLight);
ImGui::Text("Scene Lights: %d / %d", Renderer::GetLightsCount(), g_engineConfig.gl_maxLight);
ImGui::Text("Reserved Draws: %d", m_Reserved_draws); ImGui::Text("Reserved Draws: %d", m_Reserved_draws);
ImGui::Text("Camera Zoom: %.2f", cameraZoom);
ImGui::Text("Camera Pos: (%.1f, %.1f)", cameraPos.x, cameraPos.y); ImGui::Text("Camera Zoom: %.2f", cameraZoom);
ImGui::Text("Camera Pos: (%.1f, %.1f)", cameraPos.x, cameraPos.y);
ImGui::End(); ImGui::End();
} }
void ShowColorCorrectionWindow()
{
PROFILE_ENGINE_SCOPE("Engine::ShowColorCorrectionWindow");
ColorCorrection* cc = Renderer::GetColorCorrection();
if (!cc)
return;
ImGui::Begin("Color Correction");
bool changed = false;
changed |= ImGui::SliderFloat("Brightness", &cc->brightness, 0.0f, 2.0f, "%.2f");
changed |= ImGui::SliderFloat("Saturation", &cc->saturation, 0.0f, 2.0f, "%.2f");
changed |= ImGui::SliderFloat("Gamma", &cc->gamma, 0.1f, 4.0f, "%.2f");
ImGui::Spacing();
if (ImGui::Button("Reset to Default"))
{
*cc = ColorCorrection();
}
ImGui::SameLine();
ImGui::End();
}
void Engine::Init() void Engine::Init()
{ {
glfwInit(); glfwInit();
@ -319,8 +108,6 @@ void Engine::Init()
glfwSwapInterval(0); // No VSync glfwSwapInterval(0); // No VSync
glewInit(); glewInit();
g_engineConfig.LoadFromFile();
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
ImGuiIO &io = ImGui::GetIO(); ImGuiIO &io = ImGui::GetIO();
@ -336,16 +123,10 @@ void Engine::Init()
objects.push_back(obj); objects.push_back(obj);
selected = obj; selected = obj;
Logger::LogVerbose("Resverving Objects");
m_toDraw.reserve(1024);
m_scriptUpdates.reserve(256);
m_collectStack.reserve(1024);
Logger::LogInfo("Initialized Engine"); Logger::LogInfo("Initialized Engine");
} }
void DrawInspectorUI(std::shared_ptr<Object> selected) void DrawInspectorUI(std::shared_ptr<Object> selected)
{ {
PROFILE_ENGINE_SCOPE("Engine::DrawInspectorUI");
ImGui::Begin("Inspector"); ImGui::Begin("Inspector");
if (!selected) if (!selected)
@ -386,10 +167,6 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
if (ImGui::DragFloat2("Position", &pos.x, 0.1f)) if (ImGui::DragFloat2("Position", &pos.x, 0.1f))
selected->SetLocalPosition(pos); selected->SetLocalPosition(pos);
float rotation = selected->GetLocalRotation();
if (ImGui::DragFloat("Rotation", &rotation, 1.0f))
selected->SetLocalRotation(rotation);
int layer = selected->layer; int layer = selected->layer;
if (ImGui::InputInt("Layer", &layer)) if (ImGui::InputInt("Layer", &layer))
selected->layer = layer; selected->layer = layer;
@ -565,109 +342,24 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
} }
} }
// Add this method to Engine:
void Engine::collectObjects(bool playing, const glm::vec2 &camPos, float camZoom)
{
m_toDraw.clear();
m_scriptUpdates.clear();
m_collectStack.clear();
for (auto &root : objects)
if (!root->GetParent())
m_collectStack.push_back(root);
while (!m_collectStack.empty())
{
auto obj = m_collectStack.back();
m_collectStack.pop_back();
if (!obj->GetVisable())
continue;
m_toDraw.push_back(obj.get());
if (auto light = obj->GetComponent<LightComponent>())
{
glm::vec2 world = obj->GetWorldPosition();
glm::vec2 screen = (world - camPos) * camZoom + glm::vec2(Renderer::GetSize()) * 0.5f;
Renderer::AddLight(screen,
light->GetColor(),
light->GetIntensity(),
light->GetRadius() * camZoom);
}
if (playing)
{
if (auto script = obj->GetComponent<ScriptComponent>())
m_scriptUpdates.push_back(script.get());
}
for (auto &child : obj->GetChildren())
m_collectStack.push_back(child);
}
}
void Engine::Run() void Engine::Run()
{ {
while (!glfwWindowShouldClose(window)) while (!glfwWindowShouldClose(window))
{ {
if (g_engineConfig.settings.profile_editor)
{
profiler.BeginFrame();
}
profiler.BeginEngineSection("glfwPollEvents");
glfwPollEvents(); glfwPollEvents();
profiler.EndEngineSection();
profiler.BeginEngineSection("NewFrame");
profiler.BeginEngineSection("ImGui_ImplOpenGL3_NewFrame");
ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplOpenGL3_NewFrame();
profiler.EndEngineSection();
profiler.BeginEngineSection("ImGui_ImplGlfw_NewFrame");
ImGui_ImplGlfw_NewFrame(); ImGui_ImplGlfw_NewFrame();
profiler.EndEngineSection();
profiler.BeginEngineSection("ImGui::NewFrame");
ImGui::NewFrame(); ImGui::NewFrame();
profiler.EndEngineSection();
profiler.BeginEngineSection("ImGui::DockSpaceOverViewport");
ImGui::DockSpaceOverViewport(ImGui::GetMainViewport()->ID); ImGui::DockSpaceOverViewport(ImGui::GetMainViewport()->ID);
profiler.EndEngineSection();
profiler.BeginEngineSection("glfwGetTime");
float currentTime = glfwGetTime(); float currentTime = glfwGetTime();
static float lastTime = currentTime; static float lastTime = currentTime;
float deltaTime = currentTime - lastTime; float deltaTime = currentTime - lastTime;
lastTime = currentTime; lastTime = currentTime;
profiler.EndEngineSection();
profiler.EndEngineSection();
profiler.BeginEngineSection("Engine::ShowDebugOverlay");
ShowDebugOverlay(deltaTime); ShowDebugOverlay(deltaTime);
profiler.EndEngineSection();
profiler.BeginEngineSection("Logger::Draw");
Logger::Draw(); Logger::Draw();
profiler.EndEngineSection();
profiler.BeginEngineSection("BeginMainMenuBar");
if (ImGui::BeginMainMenuBar()) if (ImGui::BeginMainMenuBar())
{ {
@ -677,12 +369,12 @@ void Engine::Run()
if (!playing) if (!playing)
{ {
Logger::LogVerbose("[RestoreScene] Saving original scene"); Logger::LogVerbose("[RestoreScene] Saving original scene");
SaveState(); SaveScene(tempScenePath);
} }
else else
{ {
Logger::LogVerbose("[RestoreScene] Reloading original scene"); Logger::LogVerbose("[RestoreScene] Reloading original scene");
LoadState(); LoadScene(tempScenePath);
} }
selected = nullptr; selected = nullptr;
playing = !playing; playing = !playing;
@ -710,24 +402,9 @@ void Engine::Run()
if (ImGui::BeginMenu("Options")) if (ImGui::BeginMenu("Options"))
{ {
// simple checkbox never closes the menu when you click it
if (ImGui::BeginMenu("Settings")) ImGui::Checkbox("Enable Lighting", &g_engineConfig.lighting_enabled);
{ ImGui::Checkbox("Enable Gizmos", &g_engineConfig.settings.draw_gizmos);
ImGui::Checkbox("Enable Lighting", &g_engineConfig.settings.lighting_enabled);
ImGui::Checkbox("Enable Gizmos", &g_engineConfig.settings.draw_gizmos);
ImGui::Checkbox("Profiling", &g_engineConfig.settings.profile_enabled);
if (g_engineConfig.settings.profile_enabled)
{
ImGui::Checkbox("Profile Engine", &g_engineConfig.settings.profile_editor);
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Windows"))
{
ImGui::Checkbox("Color Correction", &g_engineConfig.settings.show_color_correction_window);
ImGui::EndMenu();
}
ImGui::EndMenu(); ImGui::EndMenu();
} }
@ -749,53 +426,44 @@ void Engine::Run()
ImGui::EndMainMenuBar(); ImGui::EndMainMenuBar();
} }
profiler.EndEngineSection();
if (g_engineConfig.settings.show_color_correction_window)
ShowColorCorrectionWindow();
ImGui::Begin("Scene Tree");
if (ImGui::BeginPopupContextWindow("SceneTreeContext", ImGuiPopupFlags_MouseButtonRight))
{ {
PROFILE_ENGINE_SCOPE("Engine::DrawSceneTree"); if (ImGui::MenuItem("Create New"))
ImGui::Begin("Scene Tree");
if (ImGui::BeginPopupContextWindow("SceneTreeContext", ImGuiPopupFlags_MouseButtonRight))
{ {
if (ImGui::MenuItem("Create New")) auto obj = std::make_shared<Object>("NewObject");
{ objects.push_back(obj);
auto obj = std::make_shared<Object>("NewObject"); selected = obj;
objects.push_back(obj); ImGui::OpenPopup("RenameObject");
selected = obj;
ImGui::OpenPopup("RenameObject");
}
ImGui::Separator();
if (ImGui::MenuItem("Create New Sprite"))
{
auto obj = std::make_shared<Object>("NewSprite");
obj->AddComponent<SpriteComponent>();
objects.push_back(obj);
selected = obj;
ImGui::OpenPopup("RenameObject");
}
if (ImGui::MenuItem("Create New Light"))
{
auto obj = std::make_shared<Object>("NewSprite");
obj->AddComponent<LightComponent>();
objects.push_back(obj);
selected = obj;
ImGui::OpenPopup("RenameObject");
}
ImGui::EndPopup();
} }
ImGui::Separator();
for (auto &obj : objects) if (ImGui::MenuItem("Create New Sprite"))
if (!obj->GetParent()) // Only draw root nodes {
DrawObjectNode(obj); auto obj = std::make_shared<Object>("NewSprite");
obj->AddComponent<SpriteComponent>();
ImGui::End(); objects.push_back(obj);
selected = obj;
ImGui::OpenPopup("RenameObject");
}
if (ImGui::MenuItem("Create New Light"))
{
auto obj = std::make_shared<Object>("NewSprite");
obj->AddComponent<LightComponent>();
objects.push_back(obj);
selected = obj;
ImGui::OpenPopup("RenameObject");
}
ImGui::EndPopup();
} }
for (auto &obj : objects)
if (!obj->GetParent()) // Only draw root nodes
DrawObjectNode(obj);
ImGui::End();
DrawInspectorUI(selected); DrawInspectorUI(selected);
// Viewport // Viewport
@ -838,92 +506,95 @@ void Engine::Run()
} }
} }
// Resize
profiler.BeginEngineSection("Renderer::Resize");
Renderer::Resize((int)size.x, (int)size.y); Renderer::Resize((int)size.x, (int)size.y);
profiler.EndEngineSection();
// Begin
profiler.BeginEngineSection("Renderer::Begin");
Renderer::Begin(); Renderer::Begin();
profiler.EndEngineSection();
// Reserve (no profiling) std::vector<std::shared_ptr<Object>> toDraw;
m_toDraw.reserve(m_Reserved_draws); std::vector<ScriptComponent *> scriptUpdates;
m_Reserved_draws = 0;
toDraw.reserve(m_Reserved_draws);
m_Reserved_draws = 0; // Reset
// Draw Editor Grid
profiler.BeginEngineSection("Draw Editor Grid");
Renderer::DrawEditorGrid(cameraPos, cameraZoom); Renderer::DrawEditorGrid(cameraPos, cameraZoom);
profiler.EndEngineSection();
// Clear temporary arrays // clear arrays each frame…
m_toDraw.clear(); toDraw.clear();
m_scriptUpdates.clear(); scriptUpdates.clear();
m_Reserved_draws = 0; m_Reserved_draws = 0;
// Collect Objects // recursive collector now skips invisible objects (and their children)
profiler.BeginEngineSection("Collect Objects"); std::function<void(const std::shared_ptr<Object> &)> collect =
collectObjects(playing, cameraPos, cameraZoom); [&](const std::shared_ptr<Object> &obj)
profiler.EndEngineSection();
// Sort Objects
profiler.BeginEngineSection("Sort Objects");
if (m_toDraw.size() > 1)
{ {
std::sort(m_toDraw.begin(), m_toDraw.end(), // if this object isnt visible, skip it and its children
[](auto const &a, auto const &b) if (!obj->GetVisable())
{ return;
if (a->layer != b->layer)
return a->layer < b->layer;
return a->GetWorldPosition().y < b->GetWorldPosition().y;
});
}
profiler.EndEngineSection();
if (!g_engineConfig.settings.profile_editor) // still visible → collect for drawing
profiler.BeginFrame(); toDraw.push_back(obj);
m_Reserved_draws += 1;
m_OnUpdateCalls = 0; // Collect lights
if (auto light = obj->GetComponent<LightComponent>())
profiler.BeginSection("Script Updates");
for (auto *script : m_scriptUpdates)
{
profiler.BeginSection("Script: " + script->GetOwner()->GetName());
script->OnUpdate(deltaTime);
m_OnUpdateCalls++;
profiler.EndSection();
}
profiler.EndSection();
profiler.BeginSection("Render");
for (auto *obj : m_toDraw)
{
if (auto spritePtr = obj->GetComponent<SpriteComponent>())
{ {
profiler.BeginSection("Draw Sprite: " + obj->GetName()); glm::vec2 world = obj->GetWorldPosition();
Renderer::DrawSprite(spritePtr.get(), glm::vec2 screen = (world - cameraPos) * cameraZoom + glm::vec2(Renderer::GetSize().x * 0.5f,
obj->GetWorldPosition(), Renderer::GetSize().y * 0.5f);
cameraZoom, Renderer::AddLight(screen,
cameraPos); light->GetColor(),
profiler.EndSection(); light->GetIntensity(),
light->GetRadius() * cameraZoom);
Renderer::DrawGizmoCircle(
world,
light->GetRadius(),
64, // segments
light->GetColor(), // circle color
cameraPos,
cameraZoom);
}
// Collect scripts
if (playing)
{
if (auto script = obj->GetComponent<ScriptComponent>())
scriptUpdates.push_back(script.get());
}
// recurse into children
for (const auto &child : obj->GetChildren())
collect(child);
};
// Traverse only root objects
for (const auto &obj : objects)
if (!obj->GetParent())
collect(obj);
// Sort drawables by layer then Y
std::sort(toDraw.begin(), toDraw.end(), [](auto const &a, auto const &b)
{
if (a->layer != b->layer)
return a->layer < b->layer;
return a->GetWorldPosition().y < b->GetWorldPosition().y; });
// Run script updates
for (auto *script : scriptUpdates)
script->OnUpdate(deltaTime);
// Draw all sprites
for (const auto &obj : toDraw)
{
if (auto sprite = obj->GetComponent<SpriteComponent>())
{
glm::vec2 worldPos = obj->GetWorldPosition();
Renderer::DrawSprite(sprite.get(), worldPos, cameraZoom, cameraPos);
} }
} }
profiler.EndSection();
// Finish frame profiling
if (!g_engineConfig.settings.profile_editor)
profiler.EndFrame();
// End renderer
profiler.BeginEngineSection("Renderer::End");
Renderer::End(); Renderer::End();
profiler.EndEngineSection();
// Display render target texture
GLuint texID = Renderer::GetRenderTexture(); GLuint texID = Renderer::GetRenderTexture();
ImGui::Image((ImTextureID)(uintptr_t)texID, size, ImVec2(0, 1), ImVec2(1, 0)); ImGui::Image((ImTextureID)(uintptr_t)texID, size, ImVec2(0, 1), ImVec2(1, 0));
ImGui::End(); ImGui::End();
if (ImGui::BeginPopup("RenameObject")) if (ImGui::BeginPopup("RenameObject"))
@ -956,13 +627,7 @@ void Engine::Run()
ImGui::EndPopup(); ImGui::EndPopup();
} }
if (g_engineConfig.settings.profile_editor)
{
profiler.EndFrame(); // Finish frame
}
// ImGui render // ImGui render
ShowProfilerTimeline();
ImGui::Render(); ImGui::Render();
int w, h; int w, h;
glfwGetFramebufferSize(window, &w, &h); glfwGetFramebufferSize(window, &w, &h);
@ -991,8 +656,6 @@ void Engine::Run()
void Engine::DrawObjectNode(const std::shared_ptr<Object> &obj) void Engine::DrawObjectNode(const std::shared_ptr<Object> &obj)
{ {
PROFILE_ENGINE_SCOPE("Engine::DrawObjectNode");
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow |
ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanAvailWidth |
(obj == selected ? ImGuiTreeNodeFlags_Selected : 0); (obj == selected ? ImGuiTreeNodeFlags_Selected : 0);
@ -1150,53 +813,8 @@ void Engine::LoadScene(const std::string &path)
Logger::LogInfo("[LoadScene] Loaded scene: %s", root["scene_name"].as<std::string>().c_str()); Logger::LogInfo("[LoadScene] Loaded scene: %s", root["scene_name"].as<std::string>().c_str());
} }
void Engine::LoadState()
{
if (savedStateYAML.empty())
{
Logger::LogWarning("[LoadState] No scene state in memory.");
return;
}
YAML::Node objectArray;
try
{
objectArray = YAML::Load(savedStateYAML);
}
catch (const std::exception &e)
{
Logger::LogError("[LoadState] Failed to parse saved scene: %s", e.what());
return;
}
objects.clear();
for (const auto &node : objectArray)
{
auto obj = std::make_shared<Object>("[DefaultObject]");
obj->Load(node);
objects.push_back(obj);
}
Logger::LogVerbose("[LoadState] Scene restored");
}
void Engine::SaveState()
{
YAML::Emitter sceneData;
sceneData << YAML::BeginSeq;
for (const auto &obj : objects)
obj->Save(sceneData);
sceneData << YAML::EndSeq;
savedStateYAML = sceneData.c_str();
Logger::LogVerbose("[SaveState] Scene serialized (%zu bytes)", savedStateYAML.size());
}
void Engine::Shutdown() void Engine::Shutdown()
{ {
g_engineConfig.SaveToFile();
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown(); ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext(); ImGui::DestroyContext();
@ -1204,5 +822,4 @@ void Engine::Shutdown()
glfwTerminate(); glfwTerminate();
std::filesystem::remove(tempScenePath); std::filesystem::remove(tempScenePath);
} }

View File

@ -1,40 +1,30 @@
#pragma once #pragma once
#include <memory> #include <memory>
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <vector> // ← for std::vector<>
#include <glm/vec2.hpp> // ← for glm::vec2
class Object; class Object;
class ScriptComponent;
class Engine class Engine {
{
public: public:
Engine(); Engine();
~Engine(); ~Engine();
void Run(); void Run();
std::shared_ptr<Object> GetObjectByTag(const std::string &tag); std::shared_ptr<Object> GetObjectByTag(const std::string &tag);
private: private:
void Init(); void Init();
void Shutdown(); void Shutdown();
void DrawObjectNode(const std::shared_ptr<Object> &obj); void DrawObjectNode(const std::shared_ptr<Object>& obj); // make sure this matches Engine.cpp
void SaveScene(const std::string &path); void SaveScene(const std::string& path);
void LoadScene(const std::string &path); void LoadScene(const std::string& path);
void ShowDebugOverlay(float deltaTime); void ShowDebugOverlay(float deltaTime);
void collectObjects(bool playing, const glm::vec2& camPos, float camZoom);
void SaveState(); int m_Reserved_draws;
void LoadState();
int m_Reserved_draws;
std::vector<Object *> m_toDraw;
std::vector<ScriptComponent *> m_scriptUpdates;
int m_OnUpdateCalls;
std::vector<std::shared_ptr<Object>> m_collectStack;
}; };

View File

@ -13,7 +13,7 @@
#include <algorithm> #include <algorithm>
Object::Object(const std::string &name) Object::Object(const std::string &name)
: name(name), localPosition(0.0f, 0.0f), localRotationDeg(0.0f), uid(), visable(true) {} : name(name), localPosition(0.0f, 0.0f), uid() {}
Object::~Object() {} Object::~Object() {}
@ -45,41 +45,6 @@ glm::vec2 Object::GetLocalPosition() const
return localPosition; return localPosition;
} }
void Object::SetLocalPosition(glm::vec2 pos)
{
localPosition = pos;
}
glm::vec2 Object::GetWorldPosition() const
{
if (parent)
{
float parentRotation = glm::radians(parent->GetWorldRotation());
glm::vec2 rotated = glm::rotate(localPosition, parentRotation);
return parent->GetWorldPosition() + rotated;
}
return localPosition;
}
float Object::GetLocalRotation() const
{
return localRotationDeg;
}
void Object::SetLocalRotation(float deg)
{
localRotationDeg = deg;
}
float Object::GetWorldRotation() const
{
if (parent)
return parent->GetWorldRotation() + localRotationDeg;
return localRotationDeg;
}
bool Object::GetVisable() const bool Object::GetVisable() const
{ {
return visable; return visable;
@ -90,6 +55,19 @@ void Object::SetVisable(bool state)
visable = state; visable = state;
} }
void Object::SetLocalPosition(glm::vec2 pos)
{
localPosition = pos;
}
glm::vec2 Object::GetWorldPosition() const
{
if (parent)
return parent->GetWorldPosition() + localPosition;
return localPosition;
}
const std::string &Object::GetName() const { return name; } const std::string &Object::GetName() const { return name; }
void Object::SetName(const std::string &n) { name = n; } void Object::SetName(const std::string &n) { name = n; }
std::vector<std::shared_ptr<Object>> &Object::GetChildren() { return children; } std::vector<std::shared_ptr<Object>> &Object::GetChildren() { return children; }
@ -99,15 +77,16 @@ void Object::Save(YAML::Emitter &out) const
{ {
Logger::LogVerbose("[LoadScene] Saving Object: [%s, %d]", name.c_str(), uid.id); Logger::LogVerbose("[LoadScene] Saving Object: [%s, %d]", name.c_str(), uid.id);
out << YAML::BeginMap; out << YAML::BeginMap;
out << YAML::Key << "name" << YAML::Value << name; out << YAML::Key << "name" << YAML::Value << name;
out << YAML::Key << "uid" << YAML::Value << uid.uuid; out << YAML::Key << "uid" << YAML::Value << uid.uuid;
out << YAML::Key << "id" << YAML::Value << uid.id; out << YAML::Key << "id" << YAML::Value << uid.id;
out << YAML::Key << "position" << YAML::Flow << YAML::BeginSeq << localPosition.x << localPosition.y << YAML::EndSeq; out << YAML::Key << "position" << YAML::Value << YAML::Flow << YAML::BeginSeq << localPosition.x << localPosition.y << YAML::EndSeq;
out << YAML::Key << "rotation" << YAML::Value << localRotationDeg;
out << YAML::Key << "layer" << YAML::Value << layer; out << YAML::Key << "layer" << YAML::Value << layer;
out << YAML::Key << "visable" << YAML::Value << visable; out << YAML::Key << "visable" << YAML::Value << visable;
out << YAML::Key << "components" << YAML::Value << YAML::BeginSeq; out << YAML::Key << "components" << YAML::Value << YAML::BeginSeq;
for (const auto &comp : components) for (const auto &comp : components)
{ {
@ -127,36 +106,71 @@ void Object::Save(YAML::Emitter &out) const
void Object::Load(const YAML::Node &node) void Object::Load(const YAML::Node &node)
{ {
name = node["name"].as<std::string>(); name = node["name"].as<std::string>();
uid.uuid = node["uid"] ? node["uid"].as<std::string>() : GenerateUUID();
uid.id = node["id"] ? node["id"].as<int>() : 0; if (node["uid"])
uid.uuid = node["uid"].as<std::string>();
else
uid.uuid = GenerateUUID();
if (node["id"])
uid.id = node["id"].as<int>();
auto pos = node["position"]; auto pos = node["position"];
if (pos && pos.IsSequence() && pos.size() == 2) if (pos && pos.IsSequence() && pos.size() == 2)
localPosition = {pos[0].as<float>(), pos[1].as<float>()}; {
localPosition.x = pos[0].as<float>();
localPosition.y = pos[1].as<float>();
}
localRotationDeg = node["rotation"] ? node["rotation"].as<float>() : 0.0f; if (node["layer"])
layer = node["layer"] ? node["layer"].as<int>() : 0; layer = node["layer"].as<int>();
visable = node["visable"] ? node["visable"].as<bool>() : true;
if (node["visable"])
visable = node["visable"].as<bool>();
Logger::LogVerbose("[LoadScene] Loading Object: [%s, %d]", name.c_str(), uid.id); Logger::LogVerbose("[LoadScene] Loading Object: [%s, %d]", name.c_str(), uid.id);
components.clear();
if (node["components"]) if (node["components"])
{ {
for (const auto &compNode : node["components"]) for (const auto &compNode : node["components"])
{ {
std::string type = compNode["type"].as<std::string>(); std::string type = compNode["type"].as<std::string>();
Logger::LogVerbose("[LoadScene] Createing Component: %s", type.c_str());
if (type == "SpriteComponent") AddComponent<SpriteComponent>()->Load(compNode); if (type == "SpriteComponent")
else if (type == "CameraComponent") AddComponent<CameraComponent>()->Load(compNode); {
else if (type == "LightComponent") AddComponent<LightComponent>()->Load(compNode); auto comp = AddComponent<SpriteComponent>();
else if (type == "TilemapComponent") AddComponent<TilemapComponent>()->Load(compNode); comp->Load(compNode);
else if (type == "TextComponent") AddComponent<TextComponent>()->Load(compNode); }
else if (type == "ScriptComponent") AddComponent<ScriptComponent>()->Load(compNode); else if (type == "CameraComponent")
{
auto comp = AddComponent<CameraComponent>();
comp->Load(compNode);
}
else if (type == "LightComponent")
{
auto comp = AddComponent<LightComponent>();
comp->Load(compNode);
}
else if (type == "TilemapComponent")
{
auto comp = AddComponent<TilemapComponent>();
comp->Load(compNode);
}
else if (type == "TextComponent")
{
auto comp = AddComponent<TextComponent>();
comp->Load(compNode);
}
else if (type == "ScriptComponent")
{
auto comp = AddComponent<ScriptComponent>();
comp->Load(compNode);
}
} }
} }
children.clear();
if (node["children"]) if (node["children"])
{ {
for (const auto &childNode : node["children"]) for (const auto &childNode : node["children"])
@ -166,4 +180,4 @@ void Object::Load(const YAML::Node &node)
AddChild(child); AddChild(child);
} }
} }
} }

View File

@ -3,10 +3,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <memory> #include <memory>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtx/rotate_vector.hpp>
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
#include "../utils/UID.h" #include "../utils/UID.h"
@ -25,10 +22,6 @@ public:
void SetLocalPosition(glm::vec2 pos); void SetLocalPosition(glm::vec2 pos);
glm::vec2 GetWorldPosition() const; glm::vec2 GetWorldPosition() const;
float GetLocalRotation() const;
void SetLocalRotation(float deg);
float GetWorldRotation() const;
void SetParent(Object *parent); void SetParent(Object *parent);
Object *GetParent() const; Object *GetParent() const;
void AddChild(std::shared_ptr<Object> child); void AddChild(std::shared_ptr<Object> child);
@ -38,6 +31,7 @@ public:
bool GetVisable() const; bool GetVisable() const;
void SetVisable(bool state); void SetVisable(bool state);
template <typename T> template <typename T>
std::shared_ptr<T> GetComponent() const; std::shared_ptr<T> GetComponent() const;
template <typename T> template <typename T>
@ -52,10 +46,9 @@ public:
int layer = 0; int layer = 0;
private: private:
bool visable = true; bool visable;
std::string name; std::string name;
glm::vec2 localPosition{0.0f}; glm::vec2 localPosition;
float localRotationDeg = 0.0f; // Rotation in degrees
Object *parent = nullptr; Object *parent = nullptr;
std::vector<std::shared_ptr<Object>> children; std::vector<std::shared_ptr<Object>> children;
std::vector<std::shared_ptr<Component>> components; std::vector<std::shared_ptr<Component>> components;
@ -65,8 +58,10 @@ template <typename T>
std::shared_ptr<T> Object::GetComponent() const std::shared_ptr<T> Object::GetComponent() const
{ {
for (const auto &comp : components) for (const auto &comp : components)
{
if (auto casted = std::dynamic_pointer_cast<T>(comp)) if (auto casted = std::dynamic_pointer_cast<T>(comp))
return casted; return casted;
}
return nullptr; return nullptr;
} }
@ -77,7 +72,7 @@ std::shared_ptr<T> Object::AddComponent()
if (existing) if (existing)
return existing; return existing;
auto component = std::make_shared<T>(this); std::shared_ptr<T> component = std::make_shared<T>(this);
components.push_back(component); components.push_back(component);
return component; return component;
} }

View File

@ -4,8 +4,6 @@
#include "utils/Logging.h" #include "utils/Logging.h"
#include "utils/EngineConfig.h" #include "utils/EngineConfig.h"
#include "utils/utils.h" #include "utils/utils.h"
#include "utils/Profiler.h"
#include "Entitys/Object.h"
#include "stb_image.h" #include "stb_image.h"
@ -27,8 +25,6 @@ int Renderer::width = 1280;
int Renderer::height = 720; int Renderer::height = 720;
int Renderer::s_DrawCalls = 0; int Renderer::s_DrawCalls = 0;
int Renderer::s_LightsCount = 0; int Renderer::s_LightsCount = 0;
std::unique_ptr<ColorCorrection> Renderer::s_ColorCorrection = nullptr;
std::vector<Light> Renderer::s_Lights; std::vector<Light> Renderer::s_Lights;
@ -87,9 +83,6 @@ void Renderer::Init()
// Load unlit shader // Load unlit shader
unlitShader.LoadFromFile("src/assets/shaders/unlit.vert", "src/assets/shaders/unlit.frag"); unlitShader.LoadFromFile("src/assets/shaders/unlit.vert", "src/assets/shaders/unlit.frag");
SetColorCorrection(std::make_unique<ColorCorrection>());
// Create a 1x1 flat normal map (RGB: 128,128,255) // Create a 1x1 flat normal map (RGB: 128,128,255)
unsigned char flatNormal[3] = {128, 128, 255}; unsigned char flatNormal[3] = {128, 128, 255};
glGenTextures(1, &defaultNormalMap); glGenTextures(1, &defaultNormalMap);
@ -103,7 +96,6 @@ void Renderer::Init()
void Renderer::Resize(int w, int h) void Renderer::Resize(int w, int h)
{ {
if (w == width && h == height) if (w == width && h == height)
return; return;
width = w; width = w;
@ -119,26 +111,14 @@ void Renderer::Resize(int w, int h)
void Renderer::Begin() void Renderer::Begin()
{ {
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
{ glViewport(0, 0, width, height);
PROFILE_ENGINE_SCOPE("glBindFramebuffer"); glEnable(GL_BLEND);
glBindFramebuffer(GL_FRAMEBUFFER, fbo); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
} glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
{ glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, width, height); s_DrawCalls = 0;
glEnable(GL_BLEND); ClearLights();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
{
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
{
s_DrawCalls = 0;
ClearLights();
}
} }
void Renderer::End() void Renderer::End()
@ -148,16 +128,12 @@ void Renderer::End()
void Renderer::ClearLights() void Renderer::ClearLights()
{ {
PROFILE_ENGINE_SCOPE("Renderer::ClearLights");
s_Lights.clear(); s_Lights.clear();
s_LightsCount = 0; s_LightsCount = 0;
} }
void Renderer::AddLight(const glm::vec2 &screenPos, const glm::vec3 &color, float intensity, float radius) void Renderer::AddLight(const glm::vec2 &screenPos, const glm::vec3 &color, float intensity, float radius)
{ {
PROFILE_ENGINE_SCOPE("Engine::AddLight");
if (s_Lights.size() >= g_engineConfig.gl_maxLight) if (s_Lights.size() >= g_engineConfig.gl_maxLight)
return; return;
s_Lights.push_back({screenPos, color, intensity, radius}); s_Lights.push_back({screenPos, color, intensity, radius});
@ -166,8 +142,6 @@ void Renderer::AddLight(const glm::vec2 &screenPos, const glm::vec3 &color, floa
void Renderer::DrawTilemap(TilemapComponent *tilemap, const glm::vec2 &worldPos, float zoom, const glm::vec2 &cameraPos) void Renderer::DrawTilemap(TilemapComponent *tilemap, const glm::vec2 &worldPos, float zoom, const glm::vec2 &cameraPos)
{ {
PROFILE_ENGINE_SCOPE("Renderer::DrawTilemap");
if (!tilemap || tilemap->GetAtlasPath().empty()) if (!tilemap || tilemap->GetAtlasPath().empty())
return; return;
@ -235,32 +209,26 @@ void Renderer::DrawSprite(SpriteComponent *sprite, const glm::vec2 &pos, float z
Shader *shader = &unlitShader; Shader *shader = &unlitShader;
bool useLighting = false; bool useLighting = false;
if (g_engineConfig.settings.lighting_enabled && sprite->GetRenderType() == SpriteComponent::RenderType::Lit) if (g_engineConfig.lighting_enabled && sprite->GetRenderType() == SpriteComponent::RenderType::Lit)
{ {
shader = &spriteShader; shader = &spriteShader;
useLighting = true; useLighting = true;
} }
shader->Use(); shader->Use();
glm::vec2 size = sprite->GetSize(); glm::vec2 size = sprite->GetSize();
glm::vec2 screenPos = (pos - CameraPos) * zoom + glm::vec2(width, height) * 0.5f - (size * zoom * 0.5f); glm::vec2 screenPos = (pos - CameraPos) * zoom + glm::vec2(width, height) * 0.5f - (size * zoom * 0.5f);
float rotationDeg = sprite->GetOwner()->GetWorldRotation();
shader->SetVec2("uPos", screenPos); shader->SetVec2("uPos", screenPos);
shader->SetVec2("uSize", size * zoom); shader->SetVec2("uSize", size * zoom);
shader->SetVec2("uScreen", glm::vec2(width, height)); shader->SetVec2("uScreen", glm::vec2(width, height));
shader->SetFloat("uRotation", glm::radians(rotationDeg));
shader->SetInt("uTex", 0); shader->SetInt("uTex", 0);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, sprite->GetTextureID()); glBindTexture(GL_TEXTURE_2D, sprite->GetTextureID());
if (useLighting) if (useLighting)
{ {
s_ColorCorrection->Upload(*shader);
shader->SetInt("uLightCount", static_cast<int>(s_Lights.size())); shader->SetInt("uLightCount", static_cast<int>(s_Lights.size()));
for (size_t i = 0; i < s_Lights.size(); ++i) for (size_t i = 0; i < s_Lights.size(); ++i)
{ {
@ -401,12 +369,4 @@ GLuint Renderer::GetRenderTexture()
glm::ivec2 Renderer::GetSize() glm::ivec2 Renderer::GetSize()
{ {
return {width, height}; return {width, height};
}
void Renderer::SetColorCorrection(std::unique_ptr<ColorCorrection> correction)
{
s_ColorCorrection = std::move(correction);
}
ColorCorrection *Renderer::GetColorCorrection()
{
return s_ColorCorrection.get();
} }

View File

@ -6,61 +6,63 @@
#include "Components/TilemapComponent.h" #include "Components/TilemapComponent.h"
#include "Components/SpriteComponent.h" #include "Components/SpriteComponent.h"
#include "utils/EngineConfig.h" #include "utils/EngineConfig.h"
#include "utils/Shader.h"
#include "utils/Profiler.h"
struct Light {
struct ColorCorrection {
float brightness = 1.0f;
float saturation = 1.0f;
float gamma = 1.0f;
void Upload(Shader& shader) const {
shader.SetFloat("uBrightness", brightness);
shader.SetFloat("uSaturation", saturation);
shader.SetFloat("uGamma", gamma);
}
};
struct Light
{
glm::vec2 screenPos; glm::vec2 screenPos;
glm::vec3 color; glm::vec3 color;
float intensity; float intensity;
float radius; float radius;
}; };
class Renderer class Renderer {
{
public: public:
static void Init(); static void Init();
static void Resize(int w, int h); static void Resize(int w, int h);
static void Begin(); static void Begin();
static void End(); static void End();
static void DrawSprite(SpriteComponent *sprite, const glm::vec2 &pos, float zoom, glm::vec2 &CameraPos); static void DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float zoom, glm::vec2& CameraPos);
static void DrawTilemap(TilemapComponent *tilemap, const glm::vec2 &worldPos, float zoom, const glm::vec2 &cameraPos); static void DrawTilemap(TilemapComponent* tilemap, const glm::vec2& worldPos, float zoom, const glm::vec2& cameraPos);
static void AddLight(const glm::vec2 &screenPos, const glm::vec3 &color, float intensity, float radius); static void AddLight(const glm::vec2& screenPos, const glm::vec3& color, float intensity, float radius);
static void ClearLights(); static void ClearLights();
static void DrawEditorGrid(const glm::vec2 &cameraPos, float zoom); static void DrawEditorGrid(const glm::vec2& cameraPos, float zoom);
static void DrawGizmoLine(const glm::vec2 &worldStart, const glm::vec2 &worldEnd, const glm::vec3 &color, const glm::vec2 &cameraPos, float zoom); // —— New gizmo functions ——
static void DrawGizmoRect(const glm::vec2 &worldPos, const glm::vec2 &size, const glm::vec3 &color, const glm::vec2 &cameraPos, float zoom); // Draws a colored line between two worldspace points.
static void DrawGizmoCircle(const glm::vec2 &worldCenter, float radius, int segments, const glm::vec3 &color, const glm::vec2 &cameraPos, float zoom); static void DrawGizmoLine(
const glm::vec2& worldStart,
const glm::vec2& worldEnd,
const glm::vec3& color,
const glm::vec2& cameraPos,
float zoom
);
// Draws a colored axisaligned rectangle in world space.
static void DrawGizmoRect(
const glm::vec2& worldPos,
const glm::vec2& size,
const glm::vec3& color,
const glm::vec2& cameraPos,
float zoom
);
// Draws a colored circle (approximated by segments) in world space.
static void DrawGizmoCircle(
const glm::vec2& worldCenter,
float radius,
int segments,
const glm::vec3& color,
const glm::vec2& cameraPos,
float zoom
);
static GLuint GetRenderTexture(); static GLuint GetRenderTexture();
static glm::ivec2 GetSize(); static glm::ivec2 GetSize();
static int GetDrawCallCount(); static int GetDrawCallCount();
static int GetLightsCount(); static int GetLightsCount();
static void SetColorCorrection(std::unique_ptr<ColorCorrection> correction);
static ColorCorrection *GetColorCorrection();
private: private:
static std::vector<Light> s_Lights; static std::vector<Light> s_Lights;
static GLuint fbo, textureColorBuffer, rbo; static GLuint fbo, textureColorBuffer, rbo;
@ -71,7 +73,5 @@ private:
static GLuint shader, quadVAO, quadVBO; static GLuint shader, quadVAO, quadVBO;
static void InitQuad(); static void InitQuad();
static GLuint LoadShader(const char *vertexSrc, const char *fragmentSrc); static GLuint LoadShader(const char* vertexSrc, const char* fragmentSrc);
static std::unique_ptr<ColorCorrection> s_ColorCorrection;
}; };

View File

@ -1,71 +1,14 @@
// EngineConfig.cpp
#include "EngineConfig.h" #include "EngineConfig.h"
#include <yaml-cpp/yaml.h>
#include <filesystem>
#include <fstream>
#include <Windows.h>
#include <shlobj.h> // SHGetFolderPathA
#include "Logging.h"
EngineConfig g_engineConfig{ EngineConfig g_engineConfig {
.lighting_enabled = true,
.version = "0.1.0", .version = "0.1.0",
.gl_version = "430", .gl_version = "430",
.gl_maxLight = 512, .gl_maxLight = 512,
.settings = { .settings{
.draw_gizmos = true, .draw_gizmos = true,
.profile_editor = false, },
.profile_enabled = true,
.show_color_correction_window = false,
.lighting_enabled = true
}
}; };
static std::filesystem::path GetUserSettingsPath() {
char userPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0, userPath))) {
std::filesystem::path path = std::filesystem::path(userPath) / ".CreateEngine" / ".user_settings.yaml";
std::filesystem::create_directories(path.parent_path());
Logger::LogVerbose("Settings Path: %s", path.string().c_str());
return path;
}
return {};
}
void EngineConfig::SaveToFile() {
Logger::LogVerbose("Saving User Settings");
YAML::Emitter out;
out << YAML::BeginMap;
out << YAML::Key << "draw_gizmos" << YAML::Value << settings.draw_gizmos;
out << YAML::Key << "profile_editor" << YAML::Value << settings.profile_editor;
out << YAML::Key << "profile_enabled" << YAML::Value << settings.profile_enabled;
out << YAML::Key << "show_color_correction_window" << YAML::Value << settings.show_color_correction_window;
out << YAML::Key << "lighting_enabled" << YAML::Value << settings.lighting_enabled;
out << YAML::EndMap;
std::ofstream fout(GetUserSettingsPath());
fout << out.c_str();
}
void EngineConfig::LoadFromFile() {
Logger::LogVerbose("Loading User Settings");
auto path = GetUserSettingsPath();
if (!std::filesystem::exists(path)) return;
YAML::Node root = YAML::LoadFile(path.string());
if (root["draw_gizmos"])
settings.draw_gizmos = root["draw_gizmos"].as<bool>();
if (root["profile_editor"])
settings.profile_editor = root["profile_editor"].as<bool>();
if (root["profile_enabled"])
settings.profile_enabled = root["profile_enabled"].as<bool>();
if (root["show_color_correction_window"])
settings.show_color_correction_window = root["show_color_correction_window"].as<bool>();
if (root["lighting_enabled"])
settings.lighting_enabled = root["lighting_enabled"].as<bool>();
}

View File

@ -1,23 +1,17 @@
#pragma once #pragma once
#include <string> #include <string>
struct UserSettings { struct UserSettings{
bool draw_gizmos; bool draw_gizmos;
bool profile_editor;
bool profile_enabled;
bool show_color_correction_window;
bool lighting_enabled;
}; };
struct EngineConfig { struct EngineConfig {
bool lighting_enabled;
std::string version; std::string version;
std::string gl_version; std::string gl_version;
int gl_maxLight; int gl_maxLight;
UserSettings settings; UserSettings settings;
void SaveToFile();
void LoadFromFile();
}; };
extern EngineConfig g_engineConfig; extern EngineConfig g_engineConfig;

View File

@ -2,8 +2,6 @@
#include "../utils/Logging.h" #include "../utils/Logging.h"
std::vector<std::shared_ptr<Object>> objects; std::vector<std::shared_ptr<Object>> objects;
std::string savedStateYAML;
std::shared_ptr<Object> FindByTagRecursive(const std::shared_ptr<Object>& obj, const std::string& tag) { std::shared_ptr<Object> FindByTagRecursive(const std::shared_ptr<Object>& obj, const std::string& tag) {
if (obj->GetName() == tag) if (obj->GetName() == tag)

View File

@ -5,6 +5,4 @@
#include "../Entitys/Object.h" #include "../Entitys/Object.h"
extern std::vector<std::shared_ptr<Object>> objects; extern std::vector<std::shared_ptr<Object>> objects;
extern std::string savedStateYAML;
std::shared_ptr<Object> FindByTagRecursive(const std::shared_ptr<Object>& obj, const std::string& tag); std::shared_ptr<Object> FindByTagRecursive(const std::shared_ptr<Object>& obj, const std::string& tag);

View File

@ -67,7 +67,7 @@ void Logger::LogVA(Level level, const char *fmt, va_list args)
std::cout << GetAnsiColor(level) std::cout << GetAnsiColor(level)
<< "[Logger][" << ToString(level) << "] " << "[Logger][" << ToString(level) << "] "
<< buffer << "\033[0m" << "\n"; << buffer << "\033[0m" << std::endl;
} }
void Logger::LogInfo(const char *fmt, ...) void Logger::LogInfo(const char *fmt, ...)

View File

@ -1,107 +0,0 @@
#include "Profiler.h"
#include <cmath>
extern float g_fps;
extern EngineConfig g_engineConfig;
inline double Lerp(double a, double b, double t) {
return a + (b - a) * t;
}
static void SmoothVisualDurations(ProfileNode& node, double blendFactor) {
node.visualStartMs = Lerp(node.visualStartMs, node.startMs, blendFactor);
node.visualDurationMs = Lerp(node.visualDurationMs, node.durationMs, blendFactor);
for (auto& child : node.children)
SmoothVisualDurations(child, blendFactor);
}
void HierarchicalProfiler::BeginFrame() {
if (!g_engineConfig.settings.profile_enabled)
return;
root.startMs = 0.0;
root.durationMs = 0.0;
root.visualStartMs = 0.0;
root.visualDurationMs = 0.0;
root.children.clear();
currentStack.clear();
sectionStartTimes.clear();
currentStack.reserve(ProfilesLastFrame);
sectionStartTimes.reserve(ProfilesLastFrame);
startTime = Clock::now();
currentStack.push_back(&root);
ProfilesLastFrame = 0;
}
void HierarchicalProfiler::BeginSection(const std::string& name) {
if (!g_engineConfig.settings.profile_enabled)
return;
auto now = Clock::now();
double timeSinceStart = std::chrono::duration<double, std::milli>(now - startTime).count();
ProfileNode& parent = *currentStack.back();
parent.children.emplace_back(name, timeSinceStart);
currentStack.push_back(&parent.children.back());
sectionStartTimes.push_back(now);
ProfilesLastFrame++;
}
void HierarchicalProfiler::EndSection() {
if (!g_engineConfig.settings.profile_enabled)
return;
if (currentStack.size() <= 1 || sectionStartTimes.empty())
return;
auto now = Clock::now();
ProfileNode& node = *currentStack.back();
double duration = std::chrono::duration<double, std::milli>(now - sectionStartTimes.back()).count();
node.durationMs = duration;
currentStack.pop_back();
sectionStartTimes.pop_back();
}
void HierarchicalProfiler::BeginEngineSection(const std::string& name) {
if (g_engineConfig.settings.profile_enabled && g_engineConfig.settings.profile_editor)
BeginSection(name);
}
void HierarchicalProfiler::EndEngineSection() {
if (g_engineConfig.settings.profile_enabled && g_engineConfig.settings.profile_editor)
EndSection();
}
void HierarchicalProfiler::EndFrame() {
if (!g_engineConfig.settings.profile_enabled)
return;
root.durationMs = std::chrono::duration<double, std::milli>(Clock::now() - startTime).count();
if (frameHistory.empty())
root.visualDurationMs = root.durationMs;
double blendFactor = 1.0 - std::pow(0.01, 1.0 / g_fps);
SmoothVisualDurations(root, blendFactor);
frameHistory.push_back(root);
if (frameHistory.size() > maxFrames)
frameHistory.erase(frameHistory.begin());
}
const std::vector<ProfileNode>& HierarchicalProfiler::GetFrames() const {
return frameHistory;
}
const ProfileNode* HierarchicalProfiler::GetLatestFrame() const {
return frameHistory.empty() ? nullptr : &frameHistory.back();
}
HierarchicalProfiler profiler;

View File

@ -1,94 +0,0 @@
#pragma once
#include <string>
#include <vector>
#include <chrono>
#include "EngineConfig.h"
struct ProfileNode
{
std::string name;
double startMs = 0.0;
double durationMs = 0.0;
double visualStartMs = 0.0;
double visualDurationMs = 0.0;
std::vector<ProfileNode> children;
ProfileNode() = default;
ProfileNode(const std::string &n, double start)
: name(n), startMs(start)
{
children.reserve(8);
}
};
class HierarchicalProfiler
{
public:
void BeginFrame();
void EndFrame();
void BeginSection(const std::string &name);
void EndSection();
void BeginEngineSection(const std::string &name);
void EndEngineSection();
const std::vector<ProfileNode> &GetFrames() const;
const ProfileNode *GetLatestFrame() const;
private:
using Clock = std::chrono::high_resolution_clock;
Clock::time_point startTime;
std::vector<Clock::time_point> sectionStartTimes;
std::vector<ProfileNode *> currentStack;
ProfileNode root{"Frame", 0.0};
std::vector<ProfileNode> frameHistory;
static constexpr size_t maxFrames = 30;
size_t ProfilesLastFrame = 128;
};
extern HierarchicalProfiler profiler;
// RAII Scoped Profiling (Zero-overhead when disabled)
struct ScopedProfile
{
ScopedProfile(const std::string &name)
{
if (g_engineConfig.settings.profile_enabled)
profiler.BeginSection(name);
}
~ScopedProfile()
{
if (g_engineConfig.settings.profile_enabled)
profiler.EndSection();
}
};
struct ScopedEngineProfile
{
ScopedEngineProfile(const std::string &name)
{
if (g_engineConfig.settings.profile_enabled && g_engineConfig.settings.profile_editor)
profiler.BeginSection(name);
}
~ScopedEngineProfile()
{
if (g_engineConfig.settings.profile_enabled && g_engineConfig.settings.profile_editor)
profiler.EndSection();
}
};
#define CONCAT_IMPL(a, b) a##b
#define CONCAT(a, b) CONCAT_IMPL(a, b)
#define PROFILE_SCOPE(label) \
ScopedProfile CONCAT(_scopedProfile_, __LINE__)(label)
#define PROFILE_ENGINE_SCOPE(label) \
ScopedEngineProfile CONCAT(_scopedEngineProfile_, __LINE__)(label)