Updated Lighting and compont.

This commit is contained in:
OusmBlueNinja 2025-04-13 12:23:52 -05:00
parent 4dfd637972
commit 4ba7e8f888
19 changed files with 693 additions and 172 deletions

View File

@ -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 C:/msys64/mingw64/include/yaml-cpp/yaml.h:10,
from src\src\Components/Component.h:5, from src\src\Entitys/Object.h:7,
from src\src\Components/SpriteComponent.h:3, from src\src\Engine.cpp:2:
from src\src\Renderer.cpp:2:
C:/msys64/mingw64/include/yaml-cpp/dll.h:22:65: note: '#pragma message: Defining YAML_CPP_API for DLL import' 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" ) 22 | # pragma message( "Defining YAML_CPP_API for DLL import" )
| ^ | ^
src\src\Engine.cpp: In function 'void DrawInspectorUI(std::shared_ptr<Object>)':
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 [TIME] Build duration: 6.67s
[ERROR] Runtime crash
Command 'src\build\app.exe' returned non-zero exit status 1.

View File

@ -15,9 +15,9 @@ Collapsed=0
[Window][Inspector] [Window][Inspector]
Pos=873,19 Pos=873,19
Size=407,701 Size=407,505
Collapsed=0 Collapsed=0
DockId=0x00000004,0 DockId=0x00000005,0
[Window][Scene Tree] [Window][Scene Tree]
Pos=0,19 Pos=0,19
@ -27,19 +27,34 @@ DockId=0x00000001,0
[Window][Viewport] [Window][Viewport]
Pos=265,19 Pos=265,19
Size=606,701 Size=606,412
Collapsed=0 Collapsed=0
DockId=0x00000002,0 DockId=0x00000007,0
[Window][##MainMenuBar] [Window][##MainMenuBar]
Pos=0,0
Size=1280,19 Size=1280,19
Collapsed=0 Collapsed=0
[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] [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=1511,1158 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=0x00000001 Parent=0x00000003 SizeRef=263,701 HiddenTabBar=1 Selected=0x12EF0F59
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1246,701 CentralNode=1 Selected=0xC450F867 DockNode ID=0x00000002 Parent=0x00000003 SizeRef=1246,701 Split=Y Selected=0xC450F867
DockNode ID=0x00000004 Parent=0x11111111 SizeRef=407,1158 HiddenTabBar=1 Selected=0x36DC96AB 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

View File

@ -1,16 +1,17 @@
engine_version: 0.1.0 engine_version: 0.1.0
scene_name: test scene_name: test
scene_hash: b3488ddfbb343e554cb1782c1b79598e15545d752cfec63be97f90c8d422aaf5 scene_hash: beb59668150f92192118ae530ea3d931789cec7c937e2620b25516e0f88ac8a7
format_version: 1 format_version: 1
objects: objects:
- name: Sprite Object - name: Sprite Object
position: [438, 0] position: [0, 0]
layer: 0 layer: 0
components: components:
- type: CameraComponent - type: CameraComponent
fov: 45 fov: 45
aspect: 1.76999998 aspect: 1.76999998
zoom: 1 zoom: 1
primary: true
- type: SpriteComponent - type: SpriteComponent
texture: C:\Users\spenc\OneDrive\Pictures\49555.jpg texture: C:\Users\spenc\OneDrive\Pictures\49555.jpg
normalMap: "" normalMap: ""
@ -39,3 +40,17 @@ objects:
texture: C:\Users\spenc\OneDrive\Pictures\49555.jpg texture: C:\Users\spenc\OneDrive\Pictures\49555.jpg
normalMap: "" normalMap: ""
children: [] 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: []

View File

@ -1,9 +1,46 @@
#version 330 core #version 330 core
in vec2 vUV; in vec2 vUV;
in vec2 vFragScreenPos;
out vec4 FragColor; out vec4 FragColor;
uniform sampler2D uTex; uniform sampler2D uTex;
uniform sampler2D uNormalMap;
void main() { uniform int uLightCount;
FragColor = texture(uTex, vUV); 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);
} }

View File

@ -1,16 +1,25 @@
#version 330 core #version 330 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 vFragScreenPos;
uniform vec2 uPos; uniform vec2 uPos;
uniform vec2 uSize; uniform vec2 uSize;
uniform vec2 uScreen; uniform vec2 uScreen;
out vec2 vUV; void main()
{
vUV = aUV;
void main() { vec2 worldPos = uPos + aPos * uSize;
vec2 scaled = aPos * uSize + uPos;
vec2 ndc = scaled / uScreen * 2.0 - 1.0; vFragScreenPos = worldPos;
gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0);
vUV = vec2(aUV.x, 1.0 - aUV.y); vec2 ndc = (worldPos / uScreen) * 2.0 - 1.0;
ndc.y *= -1.0;
gl_Position = vec4(ndc, 0.0, 1.0);
} }

View File

@ -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

View File

@ -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<float>{ 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<std::vector<float>>();
if (vec.size() == 3)
m_Color = glm::vec3(vec[0], vec[1], vec[2]);
}
if (node["intensity"]) m_Intensity = node["intensity"].as<float>();
if (node["radius"]) m_Radius = node["radius"].as<float>();
if (node["falloff"]) m_Falloff = node["falloff"].as<float>();
if (node["light_type"])m_type = node["light_type"].as<int>();
}

View File

@ -0,0 +1,41 @@
#pragma once
#include "Component.h"
#include <glm/glm.hpp>
#include <yaml-cpp/yaml.h>
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;
};

View File

@ -3,15 +3,22 @@
#include <stb_image.h> #include <stb_image.h>
#include <GL/glew.h> #include <GL/glew.h>
#include <iostream> #include <iostream>
#include "../utils/Logging.h"
#include "../utils/utils.h"
SpriteComponent::SpriteComponent(Object* owner) : Component(owner) {} SpriteComponent::SpriteComponent(Object* owner) : Component(owner) {}
unsigned int SpriteComponent::LoadTexture(const std::string& path) { unsigned int SpriteComponent::LoadTexture(const std::string& path) {
int w, h, channels; 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); unsigned char* data = stbi_load(path.c_str(), &w, &h, &channels, 4);
if (!data) { 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; return 0;
} }
@ -30,18 +37,29 @@ unsigned int SpriteComponent::LoadTexture(const std::string& path) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data); stbi_image_free(data);
texture_loaded = true;
Logger::LogDebug("Loaded Asset: %s, %d", filename.c_str(), id);
textureID = id;
return id; return id;
} }
bool SpriteComponent::HasTexture()
{
return texture_loaded;
}
void SpriteComponent::SetTexture(const std::string& path) { void SpriteComponent::SetTexture(const std::string& path) {
if (path.empty()) return;
texturePath = path; texturePath = path;
textureID = LoadTexture(path); LoadTexture(path);
} }
void SpriteComponent::SetNormalMap(const std::string& path) { void SpriteComponent::SetNormalMap(const std::string& path) {
if (path.empty()) return;
normalMapPath = path; normalMapPath = path;
normalMapID = LoadTexture(path); LoadTexture(path);
} }
unsigned int SpriteComponent::GetTextureID() const { unsigned int SpriteComponent::GetTextureID() const {
@ -69,6 +87,10 @@ void SpriteComponent::Save(YAML::Emitter& out) const {
} }
void SpriteComponent::Load(const YAML::Node& node) { void SpriteComponent::Load(const YAML::Node& node) {
if (node["texture"]) SetTexture(node["texture"].as<std::string>()); if (node["texture"] && !node["texture"].as<std::string>().empty())
if (node["normalMap"]) SetNormalMap(node["normalMap"].as<std::string>()); SetTexture(node["texture"].as<std::string>());
if (node["normalMap"] && !node["normalMap"].as<std::string>().empty())
SetNormalMap(node["normalMap"].as<std::string>());
} }

View File

@ -18,6 +18,10 @@ public:
std::string GetTexturePath() const; std::string GetTexturePath() const;
std::string GetNormalMapPath() const; std::string GetNormalMapPath() const;
bool HasTexture();
virtual glm::vec2 GetSize() const { return size; } virtual glm::vec2 GetSize() const { return size; }
virtual std::string GetName() const override { return "SpriteComponent"; } virtual std::string GetName() const override { return "SpriteComponent"; }
@ -33,6 +37,6 @@ private:
std::string normalMapPath; std::string normalMapPath;
unsigned int textureID = 0; unsigned int textureID = 0;
unsigned int normalMapID = 0; unsigned int normalMapID = 0;
bool texture_loaded = false;
unsigned int LoadTexture(const std::string& path); unsigned int LoadTexture(const std::string& path);
}; };

View File

@ -3,8 +3,10 @@
#include "Renderer.h" #include "Renderer.h"
#include "components/SpriteComponent.h" #include "components/SpriteComponent.h"
#include "components/CameraComponent.h" #include "components/CameraComponent.h"
#include "components/LightComponent.h"
#include "utils/FileDialog.h" #include "utils/FileDialog.h"
#include "utils/Logging.h"
#include <GL/glew.h> #include <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
@ -21,7 +23,6 @@
#include <filesystem> #include <filesystem>
#include <iostream> #include <iostream>
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h> #include <windows.h>
#include <commdlg.h> #include <commdlg.h>
#include <openssl/sha.h> #include <openssl/sha.h>
@ -32,7 +33,6 @@ static bool playing = false;
static glm::vec2 cameraPos = {0, 0}; static glm::vec2 cameraPos = {0, 0};
static float cameraZoom = 1.0f; static float cameraZoom = 1.0f;
static bool isDragging = false;
static ImVec2 lastMousePos = {}; static ImVec2 lastMousePos = {};
GLFWwindow *window = nullptr; GLFWwindow *window = nullptr;
@ -47,6 +47,43 @@ Engine::~Engine()
Shutdown(); Shutdown();
} }
void Engine::ShowDebugOverlay(float deltaTime)
{
static std::vector<float> 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() void Engine::Init()
{ {
glfwInit(); glfwInit();
@ -54,9 +91,9 @@ void Engine::Init()
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 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); glfwMakeContextCurrent(window);
glfwSwapInterval(1); glfwSwapInterval(0); // No VSync
glewInit(); glewInit();
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
@ -66,13 +103,137 @@ void Engine::Init()
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
ImGui_ImplGlfw_InitForOpenGL(window, true); ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 330"); ImGui_ImplOpenGL3_Init("#version 330");
m_Reserved_draws = 0;
Renderer::Init(); Renderer::Init();
auto obj = std::make_shared<Object>("Sprite Object"); auto obj = std::make_shared<Object>("Hello, Create");
objects.push_back(obj); objects.push_back(obj);
selected = obj; selected = obj;
Logger::LogInfo("Initialized Engine");
} }
void DrawInspectorUI(std::shared_ptr<Object> 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<Object> 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<SpriteComponent>())
selected->AddComponent<SpriteComponent>();
}
if (ImGui::Button("Add CameraComponent"))
{
if (!selected->GetComponent<CameraComponent>())
selected->AddComponent<CameraComponent>();
}
if (ImGui::Button("Add LightComponent"))
{
if (!selected->GetComponent<LightComponent>())
selected->AddComponent<LightComponent>();
}
// Sprite UI...
if (auto sprite = selected->GetComponent<SpriteComponent>())
{
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<SpriteComponent>();
}
// Camera UI...
if (auto cam = selected->GetComponent<CameraComponent>())
{
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<CameraComponent>();
}
// Light UI...
if (auto light = selected->GetComponent<LightComponent>())
{
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<LightComponent>();
}
ImGui::End();
}
void Engine::Run() void Engine::Run()
{ {
@ -85,6 +246,14 @@ void Engine::Run()
ImGui::NewFrame(); ImGui::NewFrame();
ImGui::DockSpaceOverViewport(ImGui::GetMainViewport()->ID); 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::BeginMainMenuBar())
{ {
if (ImGui::Button(playing ? "Stop" : "Play")) if (ImGui::Button(playing ? "Stop" : "Play"))
@ -141,93 +310,7 @@ void Engine::Run()
ImGui::End(); ImGui::End();
ImGui::Begin("Inspector"); DrawInspectorUI(selected);
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<SpriteComponent>())
selected->AddComponent<SpriteComponent>();
}
// Add CameraComponent
if (ImGui::Button("Add CameraComponent"))
{
if (!selected->GetComponent<CameraComponent>())
selected->AddComponent<CameraComponent>();
}
// Show SpriteComponent UI
if (auto sprite = selected->GetComponent<SpriteComponent>())
{
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<SpriteComponent>();
}
}
// Show CameraComponent UI
if (auto cam = selected->GetComponent<CameraComponent>())
{
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<CameraComponent>();
}
}
}
else
{
ImGui::Text("No object selected.");
}
ImGui::End();
// Viewport // Viewport
ImGui::Begin("Viewport", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); ImGui::Begin("Viewport", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
@ -270,16 +353,28 @@ void Engine::Run()
} }
Renderer::Resize((int)size.x, (int)size.y); Renderer::Resize((int)size.x, (int)size.y);
Renderer::Begin(); // assumes orthographic matrix is set up here Renderer::Begin();
std::vector<std::shared_ptr<Object>> toDraw; std::vector<std::shared_ptr<Object>> toDraw;
Renderer::DrawEditorGrid(cameraPos, cameraZoom); toDraw.reserve(m_Reserved_draws);
m_Reserved_draws = 0; // Reset
Renderer::DrawEditorGrid(cameraPos, cameraZoom);
std::function<void(const std::shared_ptr<Object> &)> collect = [&](const std::shared_ptr<Object> &obj) std::function<void(const std::shared_ptr<Object> &)> collect = [&](const std::shared_ptr<Object> &obj)
{ {
toDraw.push_back(obj); toDraw.push_back(obj);
m_Reserved_draws += 1;
if (auto light = obj->GetComponent<LightComponent>())
{
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()) for (const auto &child : obj->GetChildren())
collect(child); collect(child);
}; };
@ -289,7 +384,11 @@ void Engine::Run()
collect(obj); collect(obj);
std::sort(toDraw.begin(), toDraw.end(), [](const auto &a, const auto &b) 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) 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"]) if (!root["engine_version"] || !root["format_version"] || !root["scene_name"])
{ {
std::cerr << "[LoadScene] Missing required metadata!\n"; Logger::LogError("[LoadScene] Missing required metadata!");
return; return;
} }
if (root["engine_version"].as<std::string>() != "0.1.0") if (root["engine_version"].as<std::string>() != "0.1.0")
{ {
std::cerr << "[LoadScene] Version mismatch! Expected 0.1.0, got " << root["engine_version"].as<std::string>() << "\n"; Logger::LogError("[LoadScene] Version mismatch! Expected 0.1.0, got %s", root["engine_version"].as<std::string>().c_str());
return; return;
} }
if (!VerifySceneHash(root)) 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(); objects.clear();
@ -501,7 +600,7 @@ void Engine::LoadScene(const std::string &path)
objects.push_back(obj); objects.push_back(obj);
} }
std::cout << "[LoadScene] Loaded scene: " << root["scene_name"].as<std::string>() << "\n"; Logger::LogInfo("[LoadScene] Loaded scene: %s", root["scene_name"].as<std::string>().c_str());
} }
void Engine::Shutdown() void Engine::Shutdown()

View File

@ -20,5 +20,8 @@ private:
void DrawObjectNode(const std::shared_ptr<Object>& obj); // make sure this matches Engine.cpp 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);
int m_Reserved_draws;
}; };

View File

@ -1,7 +1,10 @@
#include "Object.h" #include "Object.h"
#include "../Components/Component.h" #include "../Components/Component.h"
#include "../Components/SpriteComponent.h" #include "../Components/SpriteComponent.h"
#include "../Components/CameraComponent.h" #include "../Components/CameraComponent.h"
#include "../Components/LightComponent.h"
#include <algorithm> #include <algorithm>
@ -84,6 +87,9 @@ void Object::Load(const YAML::Node& node) {
} else if (type == "CameraComponent") { } else if (type == "CameraComponent") {
auto comp = AddComponent<CameraComponent>(); auto comp = AddComponent<CameraComponent>();
comp->Load(compNode); comp->Load(compNode);
} else if (type == "LightComponent") {
auto comp = AddComponent<LightComponent>();
comp->Load(compNode);
} }
} }
} }

View File

@ -1,6 +1,8 @@
#include "Renderer.h" #include "Renderer.h"
#include "Components/SpriteComponent.h" #include "Components/SpriteComponent.h"
#include "utils/Shader.h" #include "utils/Shader.h"
#include "utils/Logging.h"
#include <GL/glew.h> #include <GL/glew.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
@ -15,6 +17,12 @@ GLuint Renderer::quadVAO = 0;
GLuint Renderer::quadVBO = 0; GLuint Renderer::quadVBO = 0;
int Renderer::width = 1280; int Renderer::width = 1280;
int Renderer::height = 720; int Renderer::height = 720;
int Renderer::s_DrawCalls = 0;
std::vector<Light> Renderer::s_Lights;
void Renderer::InitQuad() { void Renderer::InitQuad() {
float vertices[] = { float vertices[] = {
@ -64,6 +72,8 @@ void Renderer::Init() {
InitQuad(); InitQuad();
spriteShader.LoadFromFile("src/assets/shaders/sprite.vert", "src/assets/shaders/sprite.frag"); spriteShader.LoadFromFile("src/assets/shaders/sprite.vert", "src/assets/shaders/sprite.frag");
s_DrawCalls = 0;
} }
void Renderer::Resize(int w, int h) { void Renderer::Resize(int w, int h) {
@ -86,6 +96,8 @@ void Renderer::Begin() {
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
s_DrawCalls = 0;
ClearLights();
} }
void Renderer::End() { 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) { 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(); spriteShader.Use();
glm::vec2 size = sprite->GetSize(); 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("uPos", screenPos);
spriteShader.SetVec2("uSize", size * zoom); spriteShader.SetVec2("uSize", size * zoom);
spriteShader.SetVec2("uScreen", glm::vec2(width, height)); spriteShader.SetVec2("uScreen", glm::vec2(width, height));
spriteShader.SetInt("uLightCount", static_cast<int>(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("uTex", 0);
spriteShader.SetInt("uNormalMap", 1);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, sprite->GetTextureID()); glBindTexture(GL_TEXTURE_2D, sprite->GetTextureID());
if (sprite->GetNormalMapID()) {
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, sprite->GetNormalMapID());
}
glBindVertexArray(quadVAO); glBindVertexArray(quadVAO);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glBindVertexArray(0); glBindVertexArray(0);
s_DrawCalls++;
}
int Renderer::GetDrawCallCount()
{
return s_DrawCalls;
} }

View File

@ -1,9 +1,18 @@
#pragma once #pragma once
#include <GL/glew.h> #include <GL/glew.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <vector>
class SpriteComponent; class SpriteComponent;
struct Light {
glm::vec2 screenPos;
glm::vec3 color;
float intensity;
float radius;
};
class Renderer { class Renderer {
public: public:
static void Init(); static void Init();
@ -11,14 +20,18 @@ public:
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 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 void DrawEditorGrid(const glm::vec2& cameraPos, float zoom);
static GLuint GetRenderTexture(); static GLuint GetRenderTexture();
static glm::ivec2 GetSize(); static glm::ivec2 GetSize();
static int GetDrawCallCount();
private: private:
static std::vector<Light> s_Lights;
static GLuint fbo, textureColorBuffer, rbo; static GLuint fbo, textureColorBuffer, rbo;
static int width, height; static int width, height;
static int s_DrawCalls;
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);

141
src/src/utils/Logging.cpp Normal file
View File

@ -0,0 +1,141 @@
#include "Logging.h"
#include <imgui.h>
#include <cstdarg>
#include <cstdio>
#include <iostream>
std::vector<Logger::LogMessage> 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();
}

43
src/src/utils/Logging.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include <string>
#include <vector>
#include <ostream>
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<LogMessage> 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);
};

14
src/src/utils/utils.cpp Normal file
View File

@ -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;
}

4
src/src/utils/utils.h Normal file
View File

@ -0,0 +1,4 @@
#include <string>
#include <algorithm>
std::string GetFilenameFromPath(const std::string& path);