From 4ba7e8f88813ed95f89f2a202837180839afef4b Mon Sep 17 00:00:00 2001 From: OusmBlueNinja <89956790+OusmBlueNinja@users.noreply.github.com> Date: Sun, 13 Apr 2025 12:23:52 -0500 Subject: [PATCH] Updated Lighting and compont. --- build.log | 17 +- imgui.ini | 37 ++- src/assets/scenes/test.cene | 19 +- src/assets/shaders/sprite.frag | 43 +++- src/assets/shaders/sprite.vert | 21 +- src/build/imgui.ini | 31 --- src/src/Components/LightComponent.cpp | 32 +++ src/src/Components/LightComponent.h | 41 ++++ src/src/Components/SpriteComponent.cpp | 34 ++- src/src/Components/SpriteComponent.h | 6 +- src/src/Engine.cpp | 297 ++++++++++++++++--------- src/src/Engine.h | 5 +- src/src/Entitys/Object.cpp | 6 + src/src/Renderer.cpp | 59 ++++- src/src/Renderer.h | 15 +- src/src/utils/Logging.cpp | 141 ++++++++++++ src/src/utils/Logging.h | 43 ++++ src/src/utils/utils.cpp | 14 ++ src/src/utils/utils.h | 4 + 19 files changed, 693 insertions(+), 172 deletions(-) delete mode 100644 src/build/imgui.ini create mode 100644 src/src/Components/LightComponent.cpp create mode 100644 src/src/Components/LightComponent.h create mode 100644 src/src/utils/Logging.cpp create mode 100644 src/src/utils/Logging.h create mode 100644 src/src/utils/utils.cpp create mode 100644 src/src/utils/utils.h diff --git a/build.log b/build.log index ee42ce6..08c0d60 100644 --- a/build.log +++ b/build.log @@ -1,14 +1,15 @@ -[COMPILE] g++ -std=c++20 -Wall -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -MMD -MP -c src\src\Renderer.cpp -o src\build\src\Renderer.oIn file included from C:/msys64/mingw64/include/yaml-cpp/parser.h:13, +[COMPILE] g++ -std=c++20 -Wall -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -MMD -MP -c src\src\Engine.cpp -o src\build\src\Engine.oIn file included from C:/msys64/mingw64/include/yaml-cpp/parser.h:13, from C:/msys64/mingw64/include/yaml-cpp/yaml.h:10, - from src\src\Components/Component.h:5, - from src\src\Components/SpriteComponent.h:3, - from src\src\Renderer.cpp:2: + from src\src\Entitys/Object.h:7, + from src\src\Engine.cpp:2: C:/msys64/mingw64/include/yaml-cpp/dll.h:22:65: note: '#pragma message: Defining YAML_CPP_API for DLL import' 22 | # pragma message( "Defining YAML_CPP_API for DLL import" ) | ^ +src\src\Engine.cpp: In function 'void DrawInspectorUI(std::shared_ptr)': +src\src\Engine.cpp:219:13: warning: unused variable 'type' [-Wunused-variable] + 219 | int type = light->GetType(); + | ^~~~ -[LINK] g++ src\build\src\Engine.o src\build\src\main.o src\build\src\Renderer.o src\build\src\Components\CameraComponent.o src\build\src\Components\SpriteComponent.o src\build\src\Entitys\Object.o src\build\src\utils\FileDialog.o src\build\src\utils\Shader.o src\build\vendor\imgui\imgui.o src\build\vendor\imgui\imgui_demo.o src\build\vendor\imgui\imgui_draw.o src\build\vendor\imgui\imgui_impl_glfw.o src\build\vendor\imgui\imgui_impl_opengl3.o src\build\vendor\imgui\imgui_tables.o src\build\vendor\imgui\imgui_widgets.o -o src\build\app.exe -LC:/msys64/mingw64/lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto +[LINK] g++ src\build\src\Engine.o src\build\src\main.o src\build\src\Renderer.o src\build\src\Components\CameraComponent.o src\build\src\Components\LightComponent.o src\build\src\Components\SpriteComponent.o src\build\src\Entitys\Object.o src\build\src\utils\FileDialog.o src\build\src\utils\Logging.o src\build\src\utils\Shader.o src\build\src\utils\utils.o src\build\vendor\imgui\imgui.o src\build\vendor\imgui\imgui_demo.o src\build\vendor\imgui\imgui_draw.o src\build\vendor\imgui\imgui_impl_glfw.o src\build\vendor\imgui\imgui_impl_opengl3.o src\build\vendor\imgui\imgui_tables.o src\build\vendor\imgui\imgui_widgets.o -o src\build\app.exe -LC:/msys64/mingw64/lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto -[TIME] Build duration: 2.75s -[ERROR] Runtime crash -Command 'src\build\app.exe' returned non-zero exit status 1. +[TIME] Build duration: 6.67s diff --git a/imgui.ini b/imgui.ini index 586c710..2715f01 100644 --- a/imgui.ini +++ b/imgui.ini @@ -15,9 +15,9 @@ Collapsed=0 [Window][Inspector] Pos=873,19 -Size=407,701 +Size=407,505 Collapsed=0 -DockId=0x00000004,0 +DockId=0x00000005,0 [Window][Scene Tree] Pos=0,19 @@ -27,19 +27,34 @@ DockId=0x00000001,0 [Window][Viewport] Pos=265,19 -Size=606,701 +Size=606,412 Collapsed=0 -DockId=0x00000002,0 +DockId=0x00000007,0 [Window][##MainMenuBar] -Pos=0,0 Size=1280,19 Collapsed=0 -[Docking][Data] -DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X - DockNode ID=0x00000003 Parent=0x11111111 SizeRef=1511,1158 Split=X - DockNode ID=0x00000001 Parent=0x00000003 SizeRef=263,701 HiddenTabBar=1 Selected=0x12EF0F59 - DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1246,701 CentralNode=1 Selected=0xC450F867 - DockNode ID=0x00000004 Parent=0x11111111 SizeRef=407,1158 HiddenTabBar=1 Selected=0x36DC96AB +[Window][Performance Info] +Pos=873,526 +Size=407,194 +Collapsed=0 +DockId=0x00000006,0 + +[Window][Console] +Pos=265,433 +Size=606,287 +Collapsed=0 +DockId=0x00000008,0 + +[Docking][Data] +DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X + DockNode ID=0x00000003 Parent=0x11111111 SizeRef=1511,1158 Split=X + DockNode ID=0x00000001 Parent=0x00000003 SizeRef=263,701 HiddenTabBar=1 Selected=0x12EF0F59 + DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1246,701 Split=Y Selected=0xC450F867 + DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,869 CentralNode=1 Selected=0xC450F867 + DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,287 Selected=0xEA83D666 + DockNode ID=0x00000004 Parent=0x11111111 SizeRef=407,1158 Split=Y Selected=0x36DC96AB + DockNode ID=0x00000005 Parent=0x00000004 SizeRef=407,835 HiddenTabBar=1 Selected=0x36DC96AB + DockNode ID=0x00000006 Parent=0x00000004 SizeRef=407,321 HiddenTabBar=1 Selected=0x3FC1A724 diff --git a/src/assets/scenes/test.cene b/src/assets/scenes/test.cene index 7262a71..f42b900 100644 --- a/src/assets/scenes/test.cene +++ b/src/assets/scenes/test.cene @@ -1,16 +1,17 @@ engine_version: 0.1.0 scene_name: test -scene_hash: b3488ddfbb343e554cb1782c1b79598e15545d752cfec63be97f90c8d422aaf5 +scene_hash: beb59668150f92192118ae530ea3d931789cec7c937e2620b25516e0f88ac8a7 format_version: 1 objects: - name: Sprite Object - position: [438, 0] + position: [0, 0] layer: 0 components: - type: CameraComponent fov: 45 aspect: 1.76999998 zoom: 1 + primary: true - type: SpriteComponent texture: C:\Users\spenc\OneDrive\Pictures\49555.jpg normalMap: "" @@ -38,4 +39,18 @@ objects: - type: SpriteComponent texture: C:\Users\spenc\OneDrive\Pictures\49555.jpg normalMap: "" + children: [] + - name: Light + position: [-5000, -5000] + layer: 1 + components: + - type: LightComponent + color: + - 1 + - 1 + - 1 + intensity: 10 + radius: 100000000 + falloff: 0.100000001 + type: 0 children: [] \ No newline at end of file diff --git a/src/assets/shaders/sprite.frag b/src/assets/shaders/sprite.frag index dd9876f..3ad1636 100644 --- a/src/assets/shaders/sprite.frag +++ b/src/assets/shaders/sprite.frag @@ -1,9 +1,46 @@ #version 330 core + in vec2 vUV; +in vec2 vFragScreenPos; out vec4 FragColor; uniform sampler2D uTex; +uniform sampler2D uNormalMap; -void main() { - FragColor = texture(uTex, vUV); -} \ No newline at end of file +uniform int uLightCount; +uniform vec2 uLightPos[8]; +uniform vec3 uLightColor[8]; +uniform float uLightIntensity[8]; +uniform float uLightRadius[8]; + +void main() +{ + vec4 texColor = texture(uTex, vUV); + if (texColor.a < 0.1) + discard; + + vec3 normal = texture(uNormalMap, vUV).rgb * 2.0 - 1.0; + normal = normalize(normal); + + vec3 finalLight = vec3(0.0); + + for (int i = 0; i < uLightCount; ++i) + { + vec2 lightVec = uLightPos[i] - vFragScreenPos; + float dist = length(lightVec); + + if (dist < uLightRadius[i]) + { + vec2 lightDir2D = normalize(lightVec); + vec3 lightDir = normalize(vec3(lightDir2D, 1.0)); // pseudo-3D + + float attenuation = 1.0 - dist / uLightRadius[i]; + float diff = max(dot(normal, lightDir), 0.0); + vec3 light = uLightColor[i] * diff * attenuation * uLightIntensity[i]; + finalLight += light; + } + } + + vec3 result = texColor.rgb * finalLight; + FragColor = vec4(result, texColor.a); +} diff --git a/src/assets/shaders/sprite.vert b/src/assets/shaders/sprite.vert index c4bf1e3..6add211 100644 --- a/src/assets/shaders/sprite.vert +++ b/src/assets/shaders/sprite.vert @@ -1,16 +1,25 @@ #version 330 core + layout(location = 0) in vec2 aPos; layout(location = 1) in vec2 aUV; +out vec2 vUV; +out vec2 vFragScreenPos; + uniform vec2 uPos; uniform vec2 uSize; uniform vec2 uScreen; -out vec2 vUV; +void main() +{ + vUV = aUV; -void main() { - vec2 scaled = aPos * uSize + uPos; - vec2 ndc = scaled / uScreen * 2.0 - 1.0; - gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0); - vUV = vec2(aUV.x, 1.0 - aUV.y); + vec2 worldPos = uPos + aPos * uSize; + + vFragScreenPos = worldPos; + + vec2 ndc = (worldPos / uScreen) * 2.0 - 1.0; + ndc.y *= -1.0; + + gl_Position = vec4(ndc, 0.0, 1.0); } diff --git a/src/build/imgui.ini b/src/build/imgui.ini deleted file mode 100644 index b58bc05..0000000 --- a/src/build/imgui.ini +++ /dev/null @@ -1,31 +0,0 @@ -[Window][WindowOverViewport_11111111] -Pos=0,19 -Size=1280,701 -Collapsed=0 - -[Window][Debug##Default] -Pos=60,60 -Size=400,400 -Collapsed=0 - -[Window][Scene Tree] -Pos=60,60 -Size=128,48 -Collapsed=0 - -[Window][Inspector] -Pos=1123,19 -Size=157,701 -Collapsed=0 -DockId=0x00000002,0 - -[Window][Viewport] -Pos=60,60 -Size=32,35 -Collapsed=0 - -[Docking][Data] -DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X - DockNode ID=0x00000001 Parent=0x11111111 SizeRef=1121,701 CentralNode=1 - DockNode ID=0x00000002 Parent=0x11111111 SizeRef=157,701 Selected=0x36DC96AB - diff --git a/src/src/Components/LightComponent.cpp b/src/src/Components/LightComponent.cpp new file mode 100644 index 0000000..1c063e1 --- /dev/null +++ b/src/src/Components/LightComponent.cpp @@ -0,0 +1,32 @@ +#include "LightComponent.h" + +LightComponent::LightComponent(Object* owner) + : Component(owner) {} + +void LightComponent::Save(YAML::Emitter& out) const +{ + out << YAML::BeginMap; + out << YAML::Key << "type" << YAML::Value << "LightComponent"; + out << YAML::Key << "color" << YAML::Value << std::vector{ m_Color.r, m_Color.g, m_Color.b }; + out << YAML::Key << "intensity" << YAML::Value << m_Intensity; + out << YAML::Key << "radius" << YAML::Value << m_Radius; + out << YAML::Key << "falloff" << YAML::Value << m_Falloff; + out << YAML::Key << "type" << YAML::Value << m_type; + + out << YAML::EndMap; +} + +void LightComponent::Load(const YAML::Node& node) +{ + if (node["color"]) + { + auto vec = node["color"].as>(); + if (vec.size() == 3) + m_Color = glm::vec3(vec[0], vec[1], vec[2]); + } + if (node["intensity"]) m_Intensity = node["intensity"].as(); + if (node["radius"]) m_Radius = node["radius"].as(); + if (node["falloff"]) m_Falloff = node["falloff"].as(); + if (node["light_type"])m_type = node["light_type"].as(); + +} diff --git a/src/src/Components/LightComponent.h b/src/src/Components/LightComponent.h new file mode 100644 index 0000000..e33df6f --- /dev/null +++ b/src/src/Components/LightComponent.h @@ -0,0 +1,41 @@ +#pragma once +#include "Component.h" +#include +#include + + + +class LightComponent : public Component +{ +public: + + + + LightComponent(Object* owner); + + std::string GetName() const override { return "LightComponent"; } + + void Save(YAML::Emitter& out) const override; + void Load(const YAML::Node& node) override; + + void SetColor(const glm::vec3& color) { m_Color = color; } + void SetIntensity(float intensity) { m_Intensity = intensity; } + void SetRadius(float radius) { m_Radius = radius; } + void SetFalloff(float falloff) { m_Falloff = falloff; } + void SetType(int type) { m_type = type; } + + + glm::vec3 GetColor() const { return m_Color; } + float GetIntensity() const { return m_Intensity; } + float GetRadius() const { return m_Radius; } + float GetFalloff() const { return m_Falloff; } + int GetType() const { return m_type; } + + +private: + glm::vec3 m_Color {1.0f, 1.0f, 1.0f}; + float m_Intensity = 1.0f; + float m_Radius = 300.0f; + float m_Falloff = 1.0f; + int m_type = 0; +}; diff --git a/src/src/Components/SpriteComponent.cpp b/src/src/Components/SpriteComponent.cpp index 7bf722b..f391e4f 100644 --- a/src/src/Components/SpriteComponent.cpp +++ b/src/src/Components/SpriteComponent.cpp @@ -3,15 +3,22 @@ #include #include #include +#include "../utils/Logging.h" +#include "../utils/utils.h" + SpriteComponent::SpriteComponent(Object* owner) : Component(owner) {} unsigned int SpriteComponent::LoadTexture(const std::string& path) { int w, h, channels; - stbi_set_flip_vertically_on_load(1); + std::string filename = GetFilenameFromPath(path); + stbi_set_flip_vertically_on_load(false); + unsigned char* data = stbi_load(path.c_str(), &w, &h, &channels, 4); if (!data) { - std::cerr << "Failed to load image: " << path << "\nReason: " << stbi_failure_reason() << std::endl; + Logger::LogError("Failed to load asset: '%s': %s", filename.c_str(), stbi_failure_reason()); + + texture_loaded = false; return 0; } @@ -30,18 +37,29 @@ unsigned int SpriteComponent::LoadTexture(const std::string& path) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); stbi_image_free(data); + texture_loaded = true; + Logger::LogDebug("Loaded Asset: %s, %d", filename.c_str(), id); + textureID = id; return id; } +bool SpriteComponent::HasTexture() +{ + return texture_loaded; +} + void SpriteComponent::SetTexture(const std::string& path) { + if (path.empty()) return; texturePath = path; - textureID = LoadTexture(path); + LoadTexture(path); } + void SpriteComponent::SetNormalMap(const std::string& path) { + if (path.empty()) return; normalMapPath = path; - normalMapID = LoadTexture(path); + LoadTexture(path); } unsigned int SpriteComponent::GetTextureID() const { @@ -69,6 +87,10 @@ void SpriteComponent::Save(YAML::Emitter& out) const { } void SpriteComponent::Load(const YAML::Node& node) { - if (node["texture"]) SetTexture(node["texture"].as()); - if (node["normalMap"]) SetNormalMap(node["normalMap"].as()); + if (node["texture"] && !node["texture"].as().empty()) + SetTexture(node["texture"].as()); + + if (node["normalMap"] && !node["normalMap"].as().empty()) + SetNormalMap(node["normalMap"].as()); } + diff --git a/src/src/Components/SpriteComponent.h b/src/src/Components/SpriteComponent.h index c2ef79d..fdfee8b 100644 --- a/src/src/Components/SpriteComponent.h +++ b/src/src/Components/SpriteComponent.h @@ -18,6 +18,10 @@ public: std::string GetTexturePath() const; std::string GetNormalMapPath() const; + bool HasTexture(); + + + virtual glm::vec2 GetSize() const { return size; } virtual std::string GetName() const override { return "SpriteComponent"; } @@ -33,6 +37,6 @@ private: std::string normalMapPath; unsigned int textureID = 0; unsigned int normalMapID = 0; - + bool texture_loaded = false; unsigned int LoadTexture(const std::string& path); }; diff --git a/src/src/Engine.cpp b/src/src/Engine.cpp index ea39510..680396f 100644 --- a/src/src/Engine.cpp +++ b/src/src/Engine.cpp @@ -3,8 +3,10 @@ #include "Renderer.h" #include "components/SpriteComponent.h" #include "components/CameraComponent.h" +#include "components/LightComponent.h" #include "utils/FileDialog.h" +#include "utils/Logging.h" #include #include @@ -21,7 +23,6 @@ #include #include #define WIN32_LEAN_AND_MEAN -#define NOMINMAX #include #include #include @@ -32,7 +33,6 @@ static bool playing = false; static glm::vec2 cameraPos = {0, 0}; static float cameraZoom = 1.0f; -static bool isDragging = false; static ImVec2 lastMousePos = {}; GLFWwindow *window = nullptr; @@ -47,6 +47,43 @@ Engine::~Engine() Shutdown(); } +void Engine::ShowDebugOverlay(float deltaTime) +{ + static std::vector fpsHistory; + static const int maxHistory = 100; + static float timer = 0; + float fps = 1.0f / deltaTime; + if (fpsHistory.size() >= maxHistory) + fpsHistory.erase(fpsHistory.begin()); + if (timer >= 0.05) + { + timer = 0; + fpsHistory.push_back(fps); + } + timer += deltaTime; + + ImGui::Begin("Performance Info", nullptr, + ImGuiWindowFlags_NoDecoration); + + ImGui::TextColored(ImVec4(0.3f, 1.0f, 0.3f, 1.0f), "Performance"); + ImGui::Separator(); + ImGui::Text("FPS: %.1f", fps); + ImGui::Text("Delta Time: %.4f s", deltaTime); + 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)); + + ImGui::Spacing(); + ImGui::TextColored(ImVec4(0.4f, 0.7f, 1.0f, 1.0f), "Renderer"); + ImGui::Separator(); + ImGui::Text("Draw Calls: %d", Renderer::GetDrawCallCount()); + 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::End(); +} + void Engine::Init() { glfwInit(); @@ -54,9 +91,9 @@ void Engine::Init() glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - window = glfwCreateWindow(1280, 720, "2D Editor", nullptr, nullptr); + window = glfwCreateWindow(1280, 720, "Create Editor", nullptr, nullptr); glfwMakeContextCurrent(window); - glfwSwapInterval(1); + glfwSwapInterval(0); // No VSync glewInit(); IMGUI_CHECKVERSION(); @@ -66,13 +103,137 @@ void Engine::Init() ImGui::StyleColorsDark(); ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplOpenGL3_Init("#version 330"); + m_Reserved_draws = 0; Renderer::Init(); - auto obj = std::make_shared("Sprite Object"); + auto obj = std::make_shared("Hello, Create"); + objects.push_back(obj); selected = obj; + Logger::LogInfo("Initialized Engine"); } +void DrawInspectorUI(std::shared_ptr selected) +{ + ImGui::Begin("Inspector"); + + if (!selected) + { + ImGui::Text("No object selected."); + ImGui::End(); + return; + } + + // Static buffer and last-selected tracking + static char nameBuffer[128] = ""; + static std::shared_ptr lastSelected = nullptr; + + // If a new object is selected, refresh buffer + if (selected != lastSelected) + { + strncpy(nameBuffer, selected->GetName().c_str(), sizeof(nameBuffer)); + nameBuffer[sizeof(nameBuffer) - 1] = '\0'; // null terminate + lastSelected = selected; + } + + if (ImGui::InputText("Name", nameBuffer, sizeof(nameBuffer))) + selected->SetName(nameBuffer); + + glm::vec2 pos = selected->GetLocalPosition(); + if (ImGui::DragFloat2("Position", &pos.x)) + selected->SetLocalPosition(pos); + + ImGui::InputInt("Layer", &selected->layer); + + ImGui::SeparatorText("Add Components"); + + if (ImGui::Button("Add SpriteComponent")) + { + if (!selected->GetComponent()) + selected->AddComponent(); + } + if (ImGui::Button("Add CameraComponent")) + { + if (!selected->GetComponent()) + selected->AddComponent(); + } + if (ImGui::Button("Add LightComponent")) + { + if (!selected->GetComponent()) + selected->AddComponent(); + } + + // Sprite UI... + if (auto sprite = selected->GetComponent()) + { + ImGui::SeparatorText("Sprite Component"); + std::string tex = sprite->GetTexturePath(); + std::string norm = sprite->GetNormalMapPath(); + + ImGui::Text("Texture: %s", tex.c_str()); + if (ImGui::Button("Load Texture")) + { + auto path = OpenFileDialog(FileDialogType::Images); + if (!path.empty()) + sprite->SetTexture(path); + } + + ImGui::Text("Normal Map: %s", norm.c_str()); + if (ImGui::Button("Load Normal Map")) + { + auto path = OpenFileDialog(FileDialogType::Images); + if (!path.empty()) + sprite->SetNormalMap(path); + } + + if (ImGui::Button("Remove SpriteComponent")) + selected->RemoveComponent(); + } + + // Camera UI... + if (auto cam = selected->GetComponent()) + { + ImGui::SeparatorText("Camera Component"); + + float fov = cam->GetFOV(); + float aspect = cam->GetAspect(); + float zoom = cam->GetZoom(); + + if (ImGui::DragFloat("FOV", &fov, 0.1f, 1.0f, 179.0f)) cam->SetFOV(fov); + if (ImGui::DragFloat("Aspect", &aspect, 0.01f, 0.1f, 5.0f)) cam->SetAspect(aspect); + if (ImGui::DragFloat("Zoom", &zoom, 0.1f, 0.1f, 10.0f)) cam->SetZoom(zoom); + + if (ImGui::Button("Remove CameraComponent")) + selected->RemoveComponent(); + } + + // Light UI... + if (auto light = selected->GetComponent()) + { + ImGui::SeparatorText("Light Component"); + + glm::vec3 color = light->GetColor(); + float intensity = light->GetIntensity(); + float radius = light->GetRadius(); + float falloff = light->GetFalloff(); + int type = light->GetType(); + + if (ImGui::ColorEdit3("Color", &color.x)) light->SetColor(color); + if (ImGui::DragFloat("Intensity", &intensity, 0.05f, 0.0f, 10.0f)) light->SetIntensity(intensity); + if (ImGui::DragFloat("Radius", &radius, 1.0f, 10.0f, 1000.0f)) light->SetRadius(radius); + if (ImGui::DragFloat("Falloff", &falloff, 0.05f, 0.1f, 5.0f)) light->SetFalloff(falloff); + + //const char* types[] = { "Point", "Directional" }; + //if (ImGui::Combo("Type", &type, types, IM_ARRAYSIZE(types))) + // light->SetType(type); + + if (ImGui::Button("Remove LightComponent")) + selected->RemoveComponent(); + } + + ImGui::End(); +} + void Engine::Run() { @@ -85,6 +246,14 @@ void Engine::Run() ImGui::NewFrame(); ImGui::DockSpaceOverViewport(ImGui::GetMainViewport()->ID); + float currentTime = glfwGetTime(); + static float lastTime = currentTime; + float deltaTime = currentTime - lastTime; + lastTime = currentTime; + + ShowDebugOverlay(deltaTime); + Logger::Draw(); + if (ImGui::BeginMainMenuBar()) { if (ImGui::Button(playing ? "Stop" : "Play")) @@ -141,93 +310,7 @@ void Engine::Run() ImGui::End(); - ImGui::Begin("Inspector"); - if (selected) - { - char buffer[128]; - strcpy(buffer, selected->GetName().c_str()); - if (ImGui::InputText("Name", buffer, sizeof(buffer))) - selected->SetName(buffer); - - glm::vec2 pos = selected->GetLocalPosition(); - if (ImGui::DragFloat2("Position", &pos.x)) - selected->SetLocalPosition(pos); - - ImGui::InputInt("Layer", &selected->layer); - - // Add SpriteComponent - if (ImGui::Button("Add SpriteComponent")) - { - if (!selected->GetComponent()) - selected->AddComponent(); - } - - // Add CameraComponent - if (ImGui::Button("Add CameraComponent")) - { - if (!selected->GetComponent()) - selected->AddComponent(); - } - - // Show SpriteComponent UI - if (auto sprite = selected->GetComponent()) - { - ImGui::Separator(); - ImGui::Text("Sprite Component"); - - std::string tex = sprite->GetTexturePath(); - std::string norm = sprite->GetNormalMapPath(); - - ImGui::Text("Texture: %s", tex.c_str()); - if (ImGui::Button("Load Texture")) - { - auto path = OpenFileDialog(FileDialogType::Images); - if (!path.empty()) - sprite->SetTexture(path); - } - - ImGui::Text("Normal Map: %s", norm.c_str()); - if (ImGui::Button("Load Normal Map")) - { - auto path = OpenFileDialog(FileDialogType::Images); - if (!path.empty()) - sprite->SetNormalMap(path); - } - - if (ImGui::Button("Remove SpriteComponent")) - { - selected->RemoveComponent(); - } - } - - // Show CameraComponent UI - if (auto cam = selected->GetComponent()) - { - ImGui::Separator(); - ImGui::Text("Camera Component"); - - float fov = cam->GetFOV(); - float aspect = cam->GetAspect(); - float zoom = cam->GetZoom(); - - if (ImGui::DragFloat("FOV", &fov, 0.1f, 1.0f, 179.0f)) - cam->SetFOV(fov); - if (ImGui::DragFloat("Aspect", &aspect, 0.01f, 0.1f, 5.0f)) - cam->SetAspect(aspect); - if (ImGui::DragFloat("Zoom", &zoom, 0.1f, 0.1f, 10.0f)) - cam->SetZoom(zoom); - - if (ImGui::Button("Remove CameraComponent")) - { - selected->RemoveComponent(); - } - } - } - else - { - ImGui::Text("No object selected."); - } - ImGui::End(); + DrawInspectorUI(selected); // Viewport ImGui::Begin("Viewport", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); @@ -270,16 +353,28 @@ void Engine::Run() } Renderer::Resize((int)size.x, (int)size.y); - Renderer::Begin(); // assumes orthographic matrix is set up here + Renderer::Begin(); std::vector> toDraw; - Renderer::DrawEditorGrid(cameraPos, cameraZoom); + toDraw.reserve(m_Reserved_draws); + m_Reserved_draws = 0; // Reset + Renderer::DrawEditorGrid(cameraPos, cameraZoom); std::function &)> collect = [&](const std::shared_ptr &obj) { toDraw.push_back(obj); + m_Reserved_draws += 1; + + if (auto light = obj->GetComponent()) + { + glm::vec2 world = obj->GetWorldPosition(); + glm::vec2 screen = (world - cameraPos) * cameraZoom + glm::vec2(Renderer::GetSize().x * 0.5f, Renderer::GetSize().y * 0.5f); + + Renderer::AddLight(screen, light->GetColor(), light->GetIntensity(), light->GetRadius() * cameraZoom); + } + for (const auto &child : obj->GetChildren()) collect(child); }; @@ -289,7 +384,11 @@ void Engine::Run() collect(obj); std::sort(toDraw.begin(), toDraw.end(), [](const auto &a, const auto &b) - { return a->layer < b->layer; }); + { + if (a->layer != b->layer) + return a->layer < b->layer; + + return a->GetWorldPosition().y < b->GetWorldPosition().y; }); for (const auto &obj : toDraw) { @@ -477,19 +576,19 @@ void Engine::LoadScene(const std::string &path) if (!root["engine_version"] || !root["format_version"] || !root["scene_name"]) { - std::cerr << "[LoadScene] Missing required metadata!\n"; + Logger::LogError("[LoadScene] Missing required metadata!"); return; } if (root["engine_version"].as() != "0.1.0") { - std::cerr << "[LoadScene] Version mismatch! Expected 0.1.0, got " << root["engine_version"].as() << "\n"; + Logger::LogError("[LoadScene] Version mismatch! Expected 0.1.0, got %s", root["engine_version"].as().c_str()); return; } if (!VerifySceneHash(root)) { - std::cerr << "[LoadScene] Scene hash does not match! File may be corrupted or tampered.\n"; + Logger::LogWarning("[LoadScene] Scene hash does not match! File may be corrupted or tampered."); } objects.clear(); @@ -501,7 +600,7 @@ void Engine::LoadScene(const std::string &path) objects.push_back(obj); } - std::cout << "[LoadScene] Loaded scene: " << root["scene_name"].as() << "\n"; + Logger::LogInfo("[LoadScene] Loaded scene: %s", root["scene_name"].as().c_str()); } void Engine::Shutdown() diff --git a/src/src/Engine.h b/src/src/Engine.h index b57aade..c04ffe6 100644 --- a/src/src/Engine.h +++ b/src/src/Engine.h @@ -20,5 +20,8 @@ private: void DrawObjectNode(const std::shared_ptr& obj); // make sure this matches Engine.cpp void SaveScene(const std::string& path); void LoadScene(const std::string& path); - + void ShowDebugOverlay(float deltaTime); + + + int m_Reserved_draws; }; diff --git a/src/src/Entitys/Object.cpp b/src/src/Entitys/Object.cpp index 7ac1314..971daa3 100644 --- a/src/src/Entitys/Object.cpp +++ b/src/src/Entitys/Object.cpp @@ -1,7 +1,10 @@ #include "Object.h" + #include "../Components/Component.h" #include "../Components/SpriteComponent.h" #include "../Components/CameraComponent.h" +#include "../Components/LightComponent.h" + #include @@ -84,6 +87,9 @@ void Object::Load(const YAML::Node& node) { } else if (type == "CameraComponent") { auto comp = AddComponent(); comp->Load(compNode); + } else if (type == "LightComponent") { + auto comp = AddComponent(); + comp->Load(compNode); } } } diff --git a/src/src/Renderer.cpp b/src/src/Renderer.cpp index 46d63d8..d6e66fb 100644 --- a/src/src/Renderer.cpp +++ b/src/src/Renderer.cpp @@ -1,6 +1,8 @@ #include "Renderer.h" #include "Components/SpriteComponent.h" #include "utils/Shader.h" +#include "utils/Logging.h" + #include #include @@ -15,6 +17,12 @@ GLuint Renderer::quadVAO = 0; GLuint Renderer::quadVBO = 0; int Renderer::width = 1280; int Renderer::height = 720; +int Renderer::s_DrawCalls = 0; +std::vector Renderer::s_Lights; + + + + void Renderer::InitQuad() { float vertices[] = { @@ -64,6 +72,8 @@ void Renderer::Init() { InitQuad(); spriteShader.LoadFromFile("src/assets/shaders/sprite.vert", "src/assets/shaders/sprite.frag"); + + s_DrawCalls = 0; } void Renderer::Resize(int w, int h) { @@ -86,6 +96,8 @@ void Renderer::Begin() { 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() { @@ -108,25 +120,66 @@ void Renderer::End() { //} +void Renderer::ClearLights() { + s_Lights.clear(); +} + + + +void Renderer::AddLight(const glm::vec2& screenPos, const glm::vec3& color, float intensity, float radius) { + if (s_Lights.size() >= 8) return; + s_Lights.push_back({screenPos, color, intensity, radius}); +} void Renderer::DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float zoom, glm::vec2& CameraPos) { - if (!sprite || sprite->GetTextureID() == 0) return; + if (!sprite->HasTexture()) { + Logger::LogWarning("Tried to draw sprite with no texture"); + return; + } spriteShader.Use(); + glm::vec2 size = sprite->GetSize(); - glm::vec2 screenPos = (pos - CameraPos) * zoom + glm::vec2(size.x / 2, size.y / 2); + glm::vec2 screenPos = (pos - CameraPos) * zoom + glm::vec2(width, height) * 0.5f - (size * zoom * 0.5f); + spriteShader.SetVec2("uPos", screenPos); - spriteShader.SetVec2("uSize", size*zoom); + spriteShader.SetVec2("uSize", size * zoom); spriteShader.SetVec2("uScreen", glm::vec2(width, height)); + + spriteShader.SetInt("uLightCount", static_cast(s_Lights.size())); + for (size_t i = 0; i < s_Lights.size(); ++i) { + spriteShader.SetVec2(("uLightPos[" + std::to_string(i) + "]").c_str(), s_Lights[i].screenPos); + spriteShader.SetVec3(("uLightColor[" + std::to_string(i) + "]").c_str(), s_Lights[i].color); + spriteShader.SetFloat(("uLightIntensity[" + std::to_string(i) + "]").c_str(), s_Lights[i].intensity); + spriteShader.SetFloat(("uLightRadius[" + std::to_string(i) + "]").c_str(), s_Lights[i].radius); + } + spriteShader.SetInt("uTex", 0); + spriteShader.SetInt("uNormalMap", 1); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, sprite->GetTextureID()); + if (sprite->GetNormalMapID()) { + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, sprite->GetNormalMapID()); + } + glBindVertexArray(quadVAO); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glBindVertexArray(0); + s_DrawCalls++; +} + + + + + + +int Renderer::GetDrawCallCount() +{ + return s_DrawCalls; } diff --git a/src/src/Renderer.h b/src/src/Renderer.h index 3d0d0e8..2cbc271 100644 --- a/src/src/Renderer.h +++ b/src/src/Renderer.h @@ -1,9 +1,18 @@ #pragma once #include #include +#include + class SpriteComponent; +struct Light { + glm::vec2 screenPos; + glm::vec3 color; + float intensity; + float radius; +}; + class Renderer { public: static void Init(); @@ -11,14 +20,18 @@ public: static void Begin(); static void End(); static void DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float zoom, glm::vec2& CameraPos); + static void AddLight(const glm::vec2& screenPos, const glm::vec3& color, float intensity, float radius); + static void ClearLights(); static void DrawEditorGrid(const glm::vec2& cameraPos, float zoom); static GLuint GetRenderTexture(); static glm::ivec2 GetSize(); + static int GetDrawCallCount(); private: + static std::vector s_Lights; static GLuint fbo, textureColorBuffer, rbo; static int width, height; - + static int s_DrawCalls; static GLuint shader, quadVAO, quadVBO; static void InitQuad(); static GLuint LoadShader(const char* vertexSrc, const char* fragmentSrc); diff --git a/src/src/utils/Logging.cpp b/src/src/utils/Logging.cpp new file mode 100644 index 0000000..499b94c --- /dev/null +++ b/src/src/utils/Logging.cpp @@ -0,0 +1,141 @@ +#include "Logging.h" +#include +#include +#include +#include + +std::vector Logger::s_Messages; +bool Logger::s_AutoScroll = true; +bool Logger::s_ShowInfo = true; +bool Logger::s_ShowWarning = true; +bool Logger::s_ShowError = true; +bool Logger::s_ShowDebug = true; + +const char* Logger::ToString(Level level) +{ + switch (level) + { + case Info: return "Info"; + case Warning: return "Warning"; + case Error: return "Error"; + case Debug: return "Debug"; + default: return "Unknown"; + } +} + +const char* Logger::GetAnsiColor(Level level) +{ + switch (level) + { + case Info: return "\033[0;37m"; // Gray + case Warning: return "\033[1;33m"; // Yellow + case Error: return "\033[1;31m"; // Red + case Debug: return "\033[1;36m"; // Cyan + default: return "\033[0m"; + } +} + +void Logger::Log(Level level, const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + LogVA(level, fmt, args); + va_end(args); +} + +void Logger::LogVA(Level level, const char* fmt, va_list args) +{ + char buffer[1024]; + vsnprintf(buffer, sizeof(buffer), fmt, args); + s_Messages.push_back({ buffer, level }); + + std::cout << GetAnsiColor(level) + << "[Logger][" << ToString(level) << "] " + << buffer << "\033[0m" << std::endl; +} + + +void Logger::LogInfo(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + LogVA(Info, fmt, args); + va_end(args); +} + +void Logger::LogWarning(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + LogVA(Warning, fmt, args); + va_end(args); +} + +void Logger::LogError(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + LogVA(Error, fmt, args); + va_end(args); +} + +void Logger::LogDebug(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + LogVA(Debug, fmt, args); + va_end(args); +} + +void Logger::Clear() +{ + s_Messages.clear(); +} + +void Logger::Draw(const char* title) +{ + ImGui::Begin(title); + + if (ImGui::Button("Clear")) Clear(); + ImGui::SameLine(); ImGui::Checkbox("Auto-scroll", &s_AutoScroll); + ImGui::Separator(); + + ImGui::Checkbox("Info", &s_ShowInfo); ImGui::SameLine(); + ImGui::Checkbox("Warning", &s_ShowWarning); ImGui::SameLine(); + ImGui::Checkbox("Error", &s_ShowError); ImGui::SameLine(); + ImGui::Checkbox("Debug", &s_ShowDebug); + ImGui::Separator(); + + ImGui::BeginChild("LogMessages"); + + for (const auto& msg : s_Messages) + { + if ((msg.level == Info && !s_ShowInfo) || + (msg.level == Warning && !s_ShowWarning) || + (msg.level == Error && !s_ShowError) || + (msg.level == Debug && !s_ShowDebug)) + { + continue; + } + + ImVec4 color; + switch (msg.level) + { + case Info: color = ImVec4(0.8f, 0.8f, 0.8f, 1.0f); break; + case Warning: color = ImVec4(1.0f, 0.85f, 0.3f, 1.0f); break; + case Error: color = ImVec4(1.0f, 0.3f, 0.3f, 1.0f); break; + case Debug: color = ImVec4(0.3f, 0.9f, 1.0f, 1.0f); break; + default: color = ImVec4(1, 1, 1, 1); break; + } + + ImGui::PushStyleColor(ImGuiCol_Text, color); + ImGui::Text("[%s] %s", ToString(msg.level), msg.text.c_str()); + ImGui::PopStyleColor(); + } + + if (s_AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) + ImGui::SetScrollHereY(1.0f); + + ImGui::EndChild(); + ImGui::End(); +} diff --git a/src/src/utils/Logging.h b/src/src/utils/Logging.h new file mode 100644 index 0000000..b17f624 --- /dev/null +++ b/src/src/utils/Logging.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include +#include + +class Logger +{ +public: + enum Level + { + Info, + Warning, + Error, + Debug + }; + static void Log(Level level, const char* fmt, ...); + static void LogVA(Level level, const char* fmt, va_list args); + + static void LogInfo(const char* fmt, ...); + static void LogWarning(const char* fmt, ...); + static void LogError(const char* fmt, ...); + static void LogDebug(const char* fmt, ...); + + static void Clear(); + static void Draw(const char* title = "Console"); + +private: + struct LogMessage + { + std::string text; + Level level; + }; + + static std::vector s_Messages; + static bool s_AutoScroll; + static bool s_ShowInfo; + static bool s_ShowWarning; + static bool s_ShowError; + static bool s_ShowDebug; + + static const char* ToString(Level level); + static const char* GetAnsiColor(Level level); +}; diff --git a/src/src/utils/utils.cpp b/src/src/utils/utils.cpp new file mode 100644 index 0000000..050b012 --- /dev/null +++ b/src/src/utils/utils.cpp @@ -0,0 +1,14 @@ +#include "utils.h" + +std::string GetFilenameFromPath(const std::string& path) +{ + // Find the last slash or backslash + size_t lastSlash = path.find_last_of("/\\"); + std::string filename = (lastSlash == std::string::npos) ? path : path.substr(lastSlash + 1); + + // Strip trailing slashes (if any) + while (!filename.empty() && (filename.back() == '/' || filename.back() == '\\')) + filename.pop_back(); + + return filename; +} diff --git a/src/src/utils/utils.h b/src/src/utils/utils.h new file mode 100644 index 0000000..b44a32e --- /dev/null +++ b/src/src/utils/utils.h @@ -0,0 +1,4 @@ +#include +#include + +std::string GetFilenameFromPath(const std::string& path);