diff --git a/imgui.ini b/imgui.ini index a5f7bf4..287ef1a 100644 --- a/imgui.ini +++ b/imgui.ini @@ -27,7 +27,7 @@ DockId=0x00000001,0 [Window][Viewport] Pos=265,19 -Size=1263,674 +Size=1263,786 Collapsed=0 DockId=0x00000007,0 @@ -42,8 +42,8 @@ Collapsed=0 DockId=0x00000006,0 [Window][Console] -Pos=265,695 -Size=1263,482 +Pos=265,807 +Size=1263,370 Collapsed=0 DockId=0x00000008,0 @@ -58,8 +58,8 @@ DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1920,1158 Split=X DockNode ID=0x00000003 Parent=0x11111111 SizeRef=888,1158 Split=X DockNode ID=0x00000001 Parent=0x00000003 SizeRef=263,701 HiddenTabBar=1 Selected=0x12EF0F59 DockNode ID=0x00000002 Parent=0x00000003 SizeRef=623,701 Split=Y Selected=0xC450F867 - DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,674 CentralNode=1 Selected=0x36D5F628 - DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,482 Selected=0xEA83D666 + DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,329 CentralNode=1 Selected=0xC450F867 + DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,370 Selected=0xEA83D666 DockNode ID=0x00000004 Parent=0x11111111 SizeRef=390,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/remake/build.log b/remake/build.log index c8c354d..d897fca 100644 --- a/remake/build.log +++ b/remake/build.log @@ -1,3 +1,3 @@ -[COMPILE] g++ -std=c++20 -Wall -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\utils\Logging.cpp -o src\build\utils\Logging.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\SpriteComponent.o src\build\Components\TilemapComponent.o src\build\Entitys\Object.o src\build\utils\EngineConfig.o src\build\utils\FileDialog.o src\build\utils\Logging.o src\build\utils\Shader.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 -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto +[COMPILE] g++ -std=c++20 -Wall -Isrc/include -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 +[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\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\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 -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto [RUN] Executed app.exe successfully. diff --git a/src/assets/icons/error.png b/src/assets/icons/error.png new file mode 100644 index 0000000..031b0aa Binary files /dev/null and b/src/assets/icons/error.png differ diff --git a/src/assets/icons/lightbulb-on-10.png b/src/assets/icons/lightbulb-on-10.png new file mode 100644 index 0000000..5367091 Binary files /dev/null and b/src/assets/icons/lightbulb-on-10.png differ diff --git a/src/assets/scenes/lighting_test_2.cene b/src/assets/scenes/lighting_test_2.cene new file mode 100644 index 0000000..3f26606 --- /dev/null +++ b/src/assets/scenes/lighting_test_2.cene @@ -0,0 +1,160 @@ +engine_version: 0.1.0 +scene_name: lighting_test_2 +scene_hash: 0d3581851da4c35a61a9f3eb409408b8ca1d440c1a1ff97cc4ac73d2ef0682a2 +format_version: 1 +objects: + - name: Tiles + uid: f5e01f7892874a67b662633650b41dbd + id: 3 + position: [0, 0] + layer: 0 + components: [] + children: + - name: Bark + uid: 7dc3bbf8affb4844ae3801f03857b904 + id: 4 + position: [0, 0] + layer: 0 + components: + - type: SpriteComponent + texture: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_diff_1k.png + normalMap: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_nor_gl_1k.png + renderType: Lit + children: [] + - name: Planks + uid: 13d8988343354e3c8a1f51c03ed40cda + id: 5 + position: [1024, 0] + layer: 0 + components: + - type: SpriteComponent + texture: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_diff_1k.png + normalMap: C:\Users\spenc\OneDrive\Pictures\textures\wood_floor_worn_nor_gl_1k.png + renderType: Lit + children: [] + - name: Rocks + uid: cff28abe7e3b455ab9b756acc84cd2d7 + id: 6 + position: [0, 1024] + layer: 0 + components: + - type: SpriteComponent + texture: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_diff_1k.png + normalMap: C:\Users\spenc\OneDrive\Pictures\textures\ganges_river_pebbles_nor_gl_1k.png + renderType: Lit + children: [] + - name: Metal + uid: 98967eb30e5b429b992766d8062b7c17 + id: 7 + position: [1024, 1025] + layer: 0 + components: + - type: SpriteComponent + texture: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_diff_1k.png + normalMap: C:\Users\spenc\OneDrive\Pictures\textures\metal_plate_nor_gl_1k.png + renderType: Lit + children: [] + - name: Logo + uid: c4ce6f16dfb347b0ae0ac67f5881b243 + id: 8 + position: [2048, 0] + layer: 0 + components: + - type: SpriteComponent + texture: C:\Users\spenc\OneDrive\Pictures\blue_logo.png + normalMap: C:\Users\spenc\OneDrive\Pictures\textures\images.jpg + renderType: Lit + children: [] + - name: Carbooon Fobar + uid: 5ea269572751401da6d86519d3513b7d + id: 9 + position: [2567, 1545] + layer: 1 + components: + - type: SpriteComponent + texture: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_albedo.png + normalMap: C:\Users\spenc\OneDrive\Pictures\textures\carbon-fiber-smooth-bl\carbon-fiber-smooth-bl\carbon-fiber_smooth_normal-ogl.png + renderType: Lit + children: [] + - name: Mud + uid: a36b71937ba349bd8e6414f75be9ee16 + id: 10 + position: [0, 2578] + layer: 0 + components: + - type: SpriteComponent + texture: C:\Users\spenc\OneDrive\Pictures\textures\mud-bl\mud-bl\mud_albedo.png + normalMap: C:\Users\spenc\OneDrive\Pictures\textures\mud-bl\mud-bl\mud_normal-ogl.png + renderType: Lit + children: [] + - name: Lights + uid: 051b338a725a4076ad53ad8fa00c5f4e + id: 12 + position: [-556, 951] + layer: 0 + components: [] + children: + - name: Red + uid: 6afde2dd47aa4557b6afb1a607c99dc8 + id: 13 + position: [1, 0] + layer: 0 + components: + - type: LightComponent + color: + - 1 + - 0 + - 0 + intensity: 2 + radius: 1000 + falloff: 0.100000001 + type: 0 + children: [] + - name: Green + uid: 0f950d76d24b4dc18f54cab2c3aaaf9a + id: 14 + position: [500, 0] + layer: 0 + components: + - type: LightComponent + color: + - 0 + - 1 + - 0 + intensity: 2 + radius: 1000 + falloff: 1 + type: 0 + children: [] + - name: Blue + uid: 09f722f51c7c4b0f98de3a0a16d127c4 + id: 15 + position: [250, 250] + layer: 0 + components: + - type: LightComponent + color: + - 0 + - 0 + - 1 + intensity: 2 + radius: 1000 + falloff: 1 + type: 0 + children: [] + - name: Ambient light + uid: d4fb425522d84a8cbbd7d1415bcd93df + id: 16 + position: [500, 500] + layer: 0 + components: + - type: LightComponent + color: + - 1 + - 1 + - 1 + intensity: 1 + radius: 1000000 + falloff: 1 + type: 0 + children: [] \ No newline at end of file diff --git a/src/src/Components/Component.h b/src/src/Components/Component.h index 2e31662..7574c23 100644 --- a/src/src/Components/Component.h +++ b/src/src/Components/Component.h @@ -3,6 +3,8 @@ #include #include #include +#include "../utils/ExceptionHandler.h" + class Object; @@ -21,4 +23,5 @@ public: protected: Object* owner; + }; diff --git a/src/src/Components/ScriptComponent.cpp b/src/src/Components/ScriptComponent.cpp new file mode 100644 index 0000000..c27cf4e --- /dev/null +++ b/src/src/Components/ScriptComponent.cpp @@ -0,0 +1,38 @@ +#include "ScriptComponent.h" +#include "../utils/Logging.h" +#include "../utils/ExceptionHandler.h" + +ScriptComponent::ScriptComponent(Object* owner) + : Component(owner) {} + +void ScriptComponent::SetScriptPath(const std::string& path) { + scriptPath = path; +} + +const std::string& ScriptComponent::GetScriptPath() const { + return scriptPath; +} + +void ScriptComponent::Save(YAML::Emitter& out) const { + out << YAML::BeginMap; + out << YAML::Key << "type" << YAML::Value << "ScriptComponent"; + out << YAML::Key << "scriptPath" << YAML::Value << scriptPath; + out << YAML::EndMap; +} + +void ScriptComponent::Load(const YAML::Node& node) { + try { + if (!node["scriptPath"]) { + RecoverableError("Missing 'scriptPath' in ScriptComponent", Create::Exceptions::MissingField).Handle(); + return; + } + if (!node["scriptPath"].IsScalar()) { + RecoverableError("'scriptPath' must be a string", Create::Exceptions::InvalidFormat).Handle(); + return; + } + + scriptPath = node["scriptPath"].as(); + } catch (const YAML::Exception& e) { + RecoverableError("Failed to load ScriptComponent: " + std::string(e.what()), Create::Exceptions::ComponentLoad).Handle(); + } +} diff --git a/src/src/Components/ScriptComponent.h b/src/src/Components/ScriptComponent.h new file mode 100644 index 0000000..338bcd2 --- /dev/null +++ b/src/src/Components/ScriptComponent.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Component.h" +#include +#include + +class ScriptComponent : public Component { +public: + ScriptComponent(Object* owner); + + void SetScriptPath(const std::string& path); + const std::string& GetScriptPath() const; + + virtual std::string GetName() const override { return "ScriptComponent"; } + + virtual void Save(YAML::Emitter& out) const override; + virtual void Load(const YAML::Node& node) override; + +private: + std::string scriptPath; +}; diff --git a/src/src/Components/SpriteComponent.cpp b/src/src/Components/SpriteComponent.cpp index 0243792..6b5d37f 100644 --- a/src/src/Components/SpriteComponent.cpp +++ b/src/src/Components/SpriteComponent.cpp @@ -45,7 +45,7 @@ unsigned int SpriteComponent::LoadTexture(const std::string& path, bool updateSi if (!data) { Logger::LogError("Failed to load image: '%s': %s", path.c_str(), stbi_failure_reason()); - textureCache.erase(it); // clean up placeholder + textureCache.erase(it); return 0; } @@ -130,14 +130,50 @@ void SpriteComponent::Save(YAML::Emitter &out) const out << YAML::Key << "type" << YAML::Value << "SpriteComponent"; out << YAML::Key << "texture" << YAML::Value << texturePath; out << YAML::Key << "normalMap" << YAML::Value << normalMapPath; + out << YAML::Key << "renderType" << YAML::Value << (renderType == RenderType::Lit ? "Lit" : "Unlit"); out << YAML::EndMap; } -void SpriteComponent::Load(const YAML::Node &node) -{ - if (node["texture"] && !node["texture"].as().empty()) - SetTexture(node["texture"].as()); - if (node["normalMap"] && !node["normalMap"].as().empty()) - SetNormalMap(node["normalMap"].as()); +void SpriteComponent::Load(const YAML::Node& node) +{ + try { + if (!node["texture"]) + { + RecoverableError("Missing 'texture' key in SpriteComponent YAML node", Create::Exceptions::MissingField).Handle(); + } + else if (!node["texture"].IsScalar()) + { + RecoverableError("'texture' field must be a string", Create::Exceptions::InvalidFormat).Handle(); + } + else if (!node["texture"].as().empty()) + { + SetTexture(node["texture"].as()); + } + + if (!node["normalMap"]) + { + RecoverableError("Missing 'normalMap' key in SpriteComponent YAML node", Create::Exceptions::MissingField).Handle(); + } + else if (!node["normalMap"].IsScalar()) + { + RecoverableError("'normalMap' field must be a string", Create::Exceptions::InvalidFormat).Handle(); + } + else if (!node["normalMap"].as().empty()) + { + SetNormalMap(node["normalMap"].as()); + } + + if (node["renderType"] && node["renderType"].IsScalar()) { + std::string typeStr = node["renderType"].as(); + if (typeStr == "Lit") renderType = RenderType::Lit; + else if (typeStr == "Unlit") renderType = RenderType::Unlit; + else + RecoverableError("Invalid 'renderType' value in SpriteComponent: " + typeStr, Create::Exceptions::InvalidFormat).Handle(); + } + + } catch (const YAML::Exception& e) { + RecoverableError("YAML parsing error in SpriteComponent::Load: " + std::string(e.what()), + Create::Exceptions::ComponentLoad).Handle(); + } } diff --git a/src/src/Components/SpriteComponent.h b/src/src/Components/SpriteComponent.h index f974e05..d534622 100644 --- a/src/src/Components/SpriteComponent.h +++ b/src/src/Components/SpriteComponent.h @@ -4,9 +4,16 @@ #include #include + + class SpriteComponent : public Component { public: SpriteComponent(Object* owner); + + enum class RenderType { + Unlit, + Lit + }; void SetTexture(const std::string& path); @@ -20,7 +27,8 @@ public: bool HasTexture(); - + RenderType GetRenderType() const { return renderType; } + void SetRenderType(RenderType type) { renderType = type; } virtual glm::vec2 GetSize() const { return size; } @@ -35,8 +43,11 @@ private: glm::vec2 size = { 64, 64 }; std::string texturePath; std::string normalMapPath; + RenderType renderType = RenderType::Lit; unsigned int textureID = 0; unsigned int normalMapID = 0; bool texture_loaded = false; unsigned int LoadTexture(const std::string& path, bool updateSize); + + }; diff --git a/src/src/Components/TextComonent.cpp b/src/src/Components/TextComonent.cpp new file mode 100644 index 0000000..e4fafea --- /dev/null +++ b/src/src/Components/TextComonent.cpp @@ -0,0 +1,50 @@ +#include "TextComponent.h" +#include +#include +#include + +TextComponent::TextComponent(Object* owner) + : Component(owner), text("") {} + +TextComponent::TextComponent(Object* owner, std::string initialText) + : Component(owner), text(std::move(initialText)) {} + +std::string TextComponent::GetName() const { + return "TextComponent"; +} + +void TextComponent::Save(YAML::Emitter& out) const { + out << YAML::BeginMap; + out << YAML::Key << "component" << YAML::Value << GetName(); + out << YAML::Key << "text" << YAML::Value << text; + out << YAML::EndMap; +} + + +void TextComponent::Load(const YAML::Node& node) { + if (!node["text"]) { + text = ""; + RecoverableError("'text' key missing in YAML", Create::Exceptions::MissingField).Handle(); + return; + } + + try { + text = node["text"].as(); + } catch (const YAML::BadConversion& e) { + RecoverableError("Invalid 'text' format: " + std::string(e.what()), Create::Exceptions::InvalidFormat).Handle(); + return; + } +} + + +const std::string& TextComponent::GetText() const { + return text; +} + +void TextComponent::SetText(const std::string& newText) { + text = newText; +} + +void TextComponent::SetText(std::string&& newText) { + text = std::move(newText); +} \ No newline at end of file diff --git a/src/src/Components/TextComponent.h b/src/src/Components/TextComponent.h new file mode 100644 index 0000000..894c632 --- /dev/null +++ b/src/src/Components/TextComponent.h @@ -0,0 +1,23 @@ +#pragma once + +#include "Component.h" // Base class definition +#include + + + +class TextComponent : public Component { +public: + TextComponent(Object* owner); + TextComponent(Object* owner, std::string initialText); + + std::string GetName() const override; + void Save(YAML::Emitter& out) const override; + void Load(const YAML::Node& node) override; + + const std::string& GetText() const; + void SetText(const std::string& newText); + void SetText(std::string&& newText); + +private: + std::string text; +}; \ No newline at end of file diff --git a/src/src/Engine.cpp b/src/src/Engine.cpp index 444df75..43fa793 100644 --- a/src/src/Engine.cpp +++ b/src/src/Engine.cpp @@ -9,6 +9,8 @@ #include "utils/FileDialog.h" #include "utils/Logging.h" +#include "utils/EngineConfig.h" + #include #include #include @@ -147,6 +149,11 @@ void DrawInspectorUI(std::shared_ptr selected) ImGui::InputInt("Layer", &selected->layer); + ImGui::Text("ID:%d", selected->uid.id); + ImGui::Text("UID:%s", selected->uid.uuid.c_str()); + + + ImGui::SeparatorText("Add Components"); if (ImGui::Button("Add SpriteComponent")) @@ -170,13 +177,20 @@ void DrawInspectorUI(std::shared_ptr selected) selected->AddComponent(); } - // Sprite UI... if (auto sprite = selected->GetComponent()) { ImGui::SeparatorText("Sprite Component"); - std::string tex = sprite->GetTexturePath(); - std::string norm = sprite->GetNormalMapPath(); + const char *renderTypes[] = {"Unlit", "Lit"}; + SpriteComponent::RenderType currentType = sprite->GetRenderType(); + int currentTypeIndex = static_cast(currentType); + + if (ImGui::Combo("Render Type", ¤tTypeIndex, renderTypes, IM_ARRAYSIZE(renderTypes))) + { + sprite->SetRenderType(static_cast(currentTypeIndex)); + } + + std::string tex = sprite->GetTexturePath(); ImGui::Text("Texture: %s", tex.c_str()); if (ImGui::Button("Load Texture")) { @@ -185,6 +199,7 @@ void DrawInspectorUI(std::shared_ptr selected) sprite->SetTexture(path); } + std::string norm = sprite->GetNormalMapPath(); ImGui::Text("Normal Map: %s", norm.c_str()); if (ImGui::Button("Load Normal Map")) { @@ -193,6 +208,9 @@ void DrawInspectorUI(std::shared_ptr selected) sprite->SetNormalMap(path); } + glm::vec2 size = sprite->GetSize(); + ImGui::Text("Size: %.0f x %.0f", size.x, size.y); + if (ImGui::Button("Remove SpriteComponent")) selected->RemoveComponent(); } @@ -313,16 +331,15 @@ void Engine::Run() if (ImGui::BeginPopupContextWindow("SceneTreeContext", ImGuiPopupFlags_MouseButtonRight)) { - if (ImGui::MenuItem("Create New Object")) + if (ImGui::MenuItem("Create New")) { auto obj = std::make_shared("NewObject"); - obj->AddComponent(); objects.push_back(obj); selected = obj; ImGui::OpenPopup("RenameObject"); } ImGui::Separator(); - if (ImGui::MenuItem("Create New Sprite Object")) + if (ImGui::MenuItem("Create New Sprite")) { auto obj = std::make_shared("NewSprite"); obj->AddComponent(); @@ -330,6 +347,14 @@ void Engine::Run() selected = obj; ImGui::OpenPopup("RenameObject"); } + if (ImGui::MenuItem("Create New Light")) + { + auto obj = std::make_shared("NewSprite"); + obj->AddComponent(); + objects.push_back(obj); + selected = obj; + ImGui::OpenPopup("RenameObject"); + } ImGui::EndPopup(); } @@ -488,7 +513,6 @@ void Engine::Run() } pendingDeletion.clear(); } - } void Engine::DrawObjectNode(const std::shared_ptr &obj) @@ -497,7 +521,7 @@ void Engine::DrawObjectNode(const std::shared_ptr &obj) ImGuiTreeNodeFlags_SpanAvailWidth | (obj == selected ? ImGuiTreeNodeFlags_Selected : 0); - bool open = ImGui::TreeNodeEx((void *)(intptr_t)obj->id, flags, "%s", obj->GetName().c_str()); + bool open = ImGui::TreeNodeEx((void *)(intptr_t)obj->uid.id, flags, "%s", obj->GetName().c_str()); if (ImGui::IsItemClicked()) selected = obj; @@ -561,26 +585,28 @@ void Engine::SaveScene(const std::string &path) YAML::Emitter out; YAML::Emitter sceneData; + // Serialize object list only sceneData << YAML::BeginSeq; for (const auto &obj : objects) obj->Save(sceneData); sceneData << YAML::EndSeq; - std::string sceneString = sceneData.c_str(); + // Hash the serialized object data + std::string objectData = sceneData.c_str(); unsigned char hash[SHA256_DIGEST_LENGTH]; - SHA256(reinterpret_cast(sceneString.c_str()), sceneString.size(), hash); + SHA256(reinterpret_cast(objectData.c_str()), objectData.size(), hash); std::ostringstream hashHex; for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) hashHex << std::hex << std::setw(2) << std::setfill('0') << static_cast(hash[i]); - // Output full file + // Build final full YAML output out << YAML::BeginMap; - out << YAML::Key << "engine_version" << YAML::Value << "0.1.0"; + out << YAML::Key << "engine_version" << YAML::Value << g_engineConfig.version; out << YAML::Key << "scene_name" << YAML::Value << std::filesystem::path(path).stem().string(); out << YAML::Key << "scene_hash" << YAML::Value << hashHex.str(); out << YAML::Key << "format_version" << YAML::Value << 1; - out << YAML::Key << "objects" << YAML::Value << YAML::Load(sceneString); + out << YAML::Key << "objects" << YAML::Value << YAML::Load(objectData); out << YAML::EndMap; std::ofstream file(path); @@ -614,7 +640,6 @@ void Engine::LoadScene(const std::string &path) Logger::LogDebug("[LoadScene] Verifying Scene"); - if (!root["engine_version"] || !root["format_version"] || !root["scene_name"]) { Logger::LogError("[LoadScene] Missing required metadata!"); @@ -633,7 +658,7 @@ void Engine::LoadScene(const std::string &path) } Logger::LogDebug("[LoadScene] Reseting Scene."); - + objects.clear(); Logger::LogDebug("[LoadScene] Recreting Objects"); @@ -644,7 +669,6 @@ void Engine::LoadScene(const std::string &path) auto obj = std::make_shared("[DefaultObject]"); obj->Load(node); objects.push_back(obj); - } Logger::LogInfo("[LoadScene] Loaded scene: %s", root["scene_name"].as().c_str()); diff --git a/src/src/Engine.h b/src/src/Engine.h index c04ffe6..64a8477 100644 --- a/src/src/Engine.h +++ b/src/src/Engine.h @@ -21,6 +21,7 @@ private: 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 fd81daa..0100dbc 100644 --- a/src/src/Entitys/Object.cpp +++ b/src/src/Entitys/Object.cpp @@ -1,112 +1,156 @@ #include "Object.h" - #include "../Components/Component.h" #include "../Components/SpriteComponent.h" #include "../Components/CameraComponent.h" #include "../Components/LightComponent.h" #include "../Components/TilemapComponent.h" - +#include "../Components/TextComponent.h" #include "../utils/Logging.h" - - +#include "../utils/UID.h" #include -static int nextID = 0; - -Object::Object(const std::string& name) - : name(name), localPosition(0.0f, 0.0f), id(nextID++) {} +Object::Object(const std::string &name) + : name(name), localPosition(0.0f, 0.0f), uid() {} Object::~Object() {} -void Object::SetParent(Object* newParent) { +void Object::SetParent(Object *newParent) +{ if (parent) parent->RemoveChild(this); parent = newParent; } -void Object::AddChild(std::shared_ptr child) { +void Object::AddChild(std::shared_ptr child) +{ child->SetParent(this); children.push_back(child); } -void Object::RemoveChild(Object* child) { +void Object::RemoveChild(Object *child) +{ children.erase(std::remove_if(children.begin(), children.end(), - [child](const std::shared_ptr& obj) { - return obj.get() == child; - }), children.end()); + [child](const std::shared_ptr &obj) + { + return obj.get() == child; + }), + children.end()); } -glm::vec2 Object::GetLocalPosition() const { +glm::vec2 Object::GetLocalPosition() const +{ return localPosition; } -void Object::SetLocalPosition(glm::vec2 pos) { +void Object::SetLocalPosition(glm::vec2 pos) +{ localPosition = pos; } -glm::vec2 Object::GetWorldPosition() const { +glm::vec2 Object::GetWorldPosition() const +{ if (parent) return parent->GetWorldPosition() + localPosition; return localPosition; } -const std::string& Object::GetName() const { return name; } -void Object::SetName(const std::string& n) { name = n; } -std::vector>& Object::GetChildren() { return children; } -Object* Object::GetParent() const { return parent; } +const std::string &Object::GetName() const { return name; } +void Object::SetName(const std::string &n) { name = n; } +std::vector> &Object::GetChildren() { return children; } +Object *Object::GetParent() const { return parent; } + +void Object::Save(YAML::Emitter &out) const +{ + Logger::LogVerbose("[LoadScene] Saving Object: [%s, %d]", name.c_str(), uid.id); + -void Object::Save(YAML::Emitter& out) const { out << YAML::BeginMap; out << YAML::Key << "name" << YAML::Value << name; + out << YAML::Key << "uid" << YAML::Value << uid.uuid; + out << YAML::Key << "id" << YAML::Value << uid.id; out << YAML::Key << "position" << YAML::Value << YAML::Flow << YAML::BeginSeq << localPosition.x << localPosition.y << YAML::EndSeq; out << YAML::Key << "layer" << YAML::Value << layer; + out << YAML::Key << "components" << YAML::Value << YAML::BeginSeq; - for (const auto& comp : components) + for (const auto &comp : components) + { + Logger::LogVerbose("[LoadScene] Saving Component: %s", comp->GetName().c_str()); comp->Save(out); + } out << YAML::EndSeq; + out << YAML::Key << "children" << YAML::Value << YAML::BeginSeq; - for (const auto& child : children) + for (const auto &child : children) child->Save(out); out << YAML::EndSeq; + out << YAML::EndMap; } -void Object::Load(const YAML::Node& node) { +void Object::Load(const YAML::Node &node) +{ name = node["name"].as(); - + + if (node["uid"]) + uid.uuid = node["uid"].as(); + else + uid.uuid = GenerateUUID(); + + if (node["id"]) + uid.id = node["id"].as(); + auto pos = node["position"]; - if (pos && pos.IsSequence() && pos.size() == 2) { + if (pos && pos.IsSequence() && pos.size() == 2) + { localPosition.x = pos[0].as(); localPosition.y = pos[1].as(); } + if (node["layer"]) layer = node["layer"].as(); - Logger::LogVerbose("[LoadScene] Loading Object: [%s, (%f,%f), %d]", name.c_str(), localPosition.x, localPosition.y, layer); - + Logger::LogVerbose("[LoadScene] Loading Object: [%s, %d]", name.c_str(), uid.id); - if (node["components"]) { - for (const auto& compNode : node["components"]) { + if (node["components"]) + { + for (const auto &compNode : node["components"]) + { std::string type = compNode["type"].as(); - if (type == "SpriteComponent") { + Logger::LogVerbose("[LoadScene] Createing Component: %s", type.c_str()); + + if (type == "SpriteComponent") + { auto comp = AddComponent(); comp->Load(compNode); - } else if (type == "CameraComponent") { + } + else if (type == "CameraComponent") + { auto comp = AddComponent(); comp->Load(compNode); - } else if (type == "LightComponent") { + } + else if (type == "LightComponent") + { auto comp = AddComponent(); comp->Load(compNode); - } else if (type == "TilemapComponent") { + } + else if (type == "TilemapComponent") + { auto comp = AddComponent(); comp->Load(compNode); } + else if (type == "TextComponent") + { + auto comp = AddComponent(); + comp->Load(compNode); + } } } - if (node["children"]) { - for (const auto& childNode : node["children"]) { + if (node["children"]) + { + for (const auto &childNode : node["children"]) + { auto child = std::make_shared("Child"); child->Load(childNode); AddChild(child); diff --git a/src/src/Entitys/Object.h b/src/src/Entitys/Object.h index b61314e..f32b5af 100644 --- a/src/src/Entitys/Object.h +++ b/src/src/Entitys/Object.h @@ -5,6 +5,7 @@ #include #include #include +#include "../utils/UID.h" class Component; @@ -26,19 +27,14 @@ public: void RemoveChild(Object* child); std::vector>& GetChildren(); - template - std::shared_ptr GetComponent() const; - - template - std::shared_ptr AddComponent(); - - template - void RemoveComponent(); + template std::shared_ptr GetComponent() const; + template std::shared_ptr AddComponent(); + template void RemoveComponent(); void Save(YAML::Emitter& out) const; void Load(const YAML::Node& node); - int id = 0; + UID uid; int layer = 0; private: diff --git a/src/src/Renderer.cpp b/src/src/Renderer.cpp index 3cdcd51..7af2a83 100644 --- a/src/src/Renderer.cpp +++ b/src/src/Renderer.cpp @@ -28,15 +28,14 @@ std::vector Renderer::s_Lights; static Shader tilemapShader; - -void Renderer::InitQuad() { +void Renderer::InitQuad() +{ float vertices[] = { // pos // uv 0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 1.f, 0.f, 1.f, 1.f, 1.f, 1.f, - 0.f, 1.f, 0.f, 1.f - }; + 0.f, 1.f, 0.f, 1.f}; glGenVertexArrays(1, &quadVAO); glBindVertexArray(quadVAO); @@ -46,14 +45,15 @@ void Renderer::InitQuad() { glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glEnableVertexAttribArray(0); // position - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0); glEnableVertexAttribArray(1); // UV - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)(2 * sizeof(float))); glBindVertexArray(0); } -void Renderer::Init() { +void Renderer::Init() +{ glGenFramebuffers(1, &fbo); glBindFramebuffer(GL_FRAMEBUFFER, fbo); @@ -82,7 +82,7 @@ void Renderer::Init() { unlitShader.LoadFromFile("src/assets/shaders/unlit.vert", "src/assets/shaders/unlit.frag"); // 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); glBindTexture(GL_TEXTURE_2D, defaultNormalMap); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, flatNormal); @@ -92,8 +92,10 @@ void Renderer::Init() { s_DrawCalls = 0; } -void Renderer::Resize(int w, int h) { - if (w == width && h == height) return; +void Renderer::Resize(int w, int h) +{ + if (w == width && h == height) + return; width = w; height = h; @@ -105,7 +107,8 @@ void Renderer::Resize(int w, int h) { glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); } -void Renderer::Begin() { +void Renderer::Begin() +{ glBindFramebuffer(GL_FRAMEBUFFER, fbo); glViewport(0, 0, width, height); glEnable(GL_BLEND); @@ -116,30 +119,37 @@ void Renderer::Begin() { ClearLights(); } -void Renderer::End() { +void Renderer::End() +{ glBindFramebuffer(GL_FRAMEBUFFER, 0); } -void Renderer::ClearLights() { +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; +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::DrawTilemap(TilemapComponent* tilemap, const glm::vec2& worldPos, float zoom, const glm::vec2& cameraPos) { - if (!tilemap || tilemap->GetAtlasPath().empty()) return; +void Renderer::DrawTilemap(TilemapComponent *tilemap, const glm::vec2 &worldPos, float zoom, const glm::vec2 &cameraPos) +{ + if (!tilemap || tilemap->GetAtlasPath().empty()) + return; glm::ivec2 grid = tilemap->GetGridSize(); glm::ivec2 tileSize = tilemap->GetTileSize(); int cols = tilemap->GetAtlasCols(); int rows = tilemap->GetAtlasRows(); - const std::string& atlasPath = tilemap->GetAtlasPath(); + const std::string &atlasPath = tilemap->GetAtlasPath(); GLuint atlasTex = LoadTextureIfNeeded(atlasPath); - if (atlasTex == 0) return; + if (atlasTex == 0) + return; tilemapShader.Use(); tilemapShader.SetVec2("uScreen", glm::vec2(width, height)); @@ -149,10 +159,13 @@ void Renderer::DrawTilemap(TilemapComponent* tilemap, const glm::vec2& worldPos, glBindVertexArray(quadVAO); - for (int y = 0; y < grid.y; ++y) { - for (int x = 0; x < grid.x; ++x) { + for (int y = 0; y < grid.y; ++y) + { + for (int x = 0; x < grid.x; ++x) + { int index = tilemap->GetTile(x, y); - if (index < 0 || index >= cols * rows) continue; + if (index < 0 || index >= cols * rows) + continue; int atlasX = index % cols; int atlasY = index / cols; @@ -177,74 +190,68 @@ void Renderer::DrawTilemap(TilemapComponent* tilemap, const glm::vec2& worldPos, glBindVertexArray(0); } - - -void Renderer::DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float zoom, glm::vec2& CameraPos) { - if (!sprite->HasTexture()) { - Logger::LogWarning("Tried to draw sprite with no texture"); +void Renderer::DrawSprite(SpriteComponent *sprite, const glm::vec2 &pos, float zoom, glm::vec2 &CameraPos) +{ + if (!sprite->HasTexture()) + { + static bool warned = false; + if (!warned) + { + Logger::LogWarning("Tried to draw sprite with no texture"); + warned = true; + } return; } - // Choose the shader based on engine configuration - if (g_engineConfig.lighting_enabled) { - spriteShader.Use(); - } else { - unlitShader.Use(); + Shader *shader = &unlitShader; + bool useLighting = false; + if (g_engineConfig.lighting_enabled && sprite->GetRenderType() == SpriteComponent::RenderType::Lit) + { + shader = &spriteShader; + useLighting = true; } + shader->Use(); glm::vec2 size = sprite->GetSize(); glm::vec2 screenPos = (pos - CameraPos) * zoom + glm::vec2(width, height) * 0.5f - (size * zoom * 0.5f); - // Set common uniforms - if (g_engineConfig.lighting_enabled) { - spriteShader.SetVec2("uPos", screenPos); - spriteShader.SetVec2("uSize", size * zoom); - spriteShader.SetVec2("uScreen", glm::vec2(width, height)); + shader->SetVec2("uPos", screenPos); + shader->SetVec2("uSize", size * zoom); + shader->SetVec2("uScreen", glm::vec2(width, height)); + shader->SetInt("uTex", 0); - 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); - } - } else { - // Unlit shader uniforms - unlitShader.SetVec2("uPos", screenPos); - unlitShader.SetVec2("uSize", size * zoom); - unlitShader.SetVec2("uScreen", glm::vec2(width, height)); - } - - // Bind the diffuse texture (common to both shaders) - if (g_engineConfig.lighting_enabled) { - spriteShader.SetInt("uTex", 0); - } else { - unlitShader.SetInt("uTex", 0); - } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, sprite->GetTextureID()); - if (g_engineConfig.lighting_enabled) { - spriteShader.SetInt("uNormalMap", 1); - glActiveTexture(GL_TEXTURE1); - if (sprite->GetNormalMapID()) { - glBindTexture(GL_TEXTURE_2D, sprite->GetNormalMapID()); - } else { - glBindTexture(GL_TEXTURE_2D, defaultNormalMap); + if (useLighting) + { + shader->SetInt("uLightCount", static_cast(s_Lights.size())); + for (size_t i = 0; i < s_Lights.size(); ++i) + { + shader->SetVec2(("uLightPos[" + std::to_string(i) + "]").c_str(), s_Lights[i].screenPos); + shader->SetVec3(("uLightColor[" + std::to_string(i) + "]").c_str(), s_Lights[i].color); + shader->SetFloat(("uLightIntensity[" + std::to_string(i) + "]").c_str(), s_Lights[i].intensity); + shader->SetFloat(("uLightRadius[" + std::to_string(i) + "]").c_str(), s_Lights[i].radius); } + + shader->SetInt("uNormalMap", 1); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, sprite->GetNormalMapID() ? sprite->GetNormalMapID() : defaultNormalMap); } - + glBindVertexArray(quadVAO); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glBindVertexArray(0); s_DrawCalls++; } -int Renderer::GetDrawCallCount() { +int Renderer::GetDrawCallCount() +{ return s_DrawCalls; } -void Renderer::DrawEditorGrid(const glm::vec2& cameraPos, float zoom) { +void Renderer::DrawEditorGrid(const glm::vec2 &cameraPos, float zoom) +{ glUseProgram(0); glColor4f(0.5f, 0.5f, 0.5f, 0.25f); glLineWidth(1.0f); @@ -254,32 +261,36 @@ void Renderer::DrawEditorGrid(const glm::vec2& cameraPos, float zoom) { float viewWidth = width / zoom; float viewHeight = height / zoom; - float left = cameraPos.x - viewWidth / 2; - float right = cameraPos.x + viewWidth / 2; + float left = cameraPos.x - viewWidth / 2; + float right = cameraPos.x + viewWidth / 2; float bottom = cameraPos.y + viewHeight / 2; - float top = cameraPos.y - viewHeight / 2; + float top = cameraPos.y - viewHeight / 2; int minX = static_cast(std::floor(left / spacing)) * spacing; int maxX = static_cast(std::ceil(right / spacing)) * spacing; int minY = static_cast(std::floor(top / spacing)) * spacing; int maxY = static_cast(std::ceil(bottom / spacing)) * spacing; - for (int x = minX; x <= maxX; x += spacing) { + for (int x = minX; x <= maxX; x += spacing) + { glVertex2f((float)x, top); glVertex2f((float)x, bottom); } - for (int y = minY; y <= maxY; y += spacing) { + for (int y = minY; y <= maxY; y += spacing) + { glVertex2f(left, (float)y); glVertex2f(right, (float)y); } glEnd(); } -GLuint Renderer::GetRenderTexture() { +GLuint Renderer::GetRenderTexture() +{ return textureColorBuffer; } -glm::ivec2 Renderer::GetSize() { - return { width, height }; +glm::ivec2 Renderer::GetSize() +{ + return {width, height}; } diff --git a/src/src/utils/ExceptionHandler.cpp b/src/src/utils/ExceptionHandler.cpp new file mode 100644 index 0000000..1b6675e --- /dev/null +++ b/src/src/utils/ExceptionHandler.cpp @@ -0,0 +1,31 @@ +#include "ExceptionHandler.h" +#include "Logging.h" +#include + + + +const char* Create::Exceptions::ExceptionToString(Create::Exceptions::Type type) { + switch (type) { + case Create::Exceptions::None: return "None"; + case Create::Exceptions::ComponentLoad: return "ComponentLoad"; + case Create::Exceptions::MissingField: return "MissingField"; + case Create::Exceptions::InvalidFormat: return "InvalidFormat"; + case Create::Exceptions::SystemFailure: return "SystemFailure"; + case Create::Exceptions::AssetMissing: return "AssetMissing"; + case Create::Exceptions::FileIO: return "FileIO"; + case Create::Exceptions::RuntimeLogic: return "RuntimeLogic"; + default: return "Unknown"; + } +} + +RecoverableError::RecoverableError(const std::string& msg, Create::Exceptions::Type type) + : message(msg), type(type) {} + +void RecoverableError::Handle() const { + Logger::LogWarning("[Recoverable][%s] %s", ExceptionToString(type), message.c_str()); +} + +FatalError::FatalError(const std::string& msg, Create::Exceptions::Type type) { + Logger::LogError("[Fatal][%s] %s", ExceptionToString(type), msg.c_str()); + std::exit(1); +} diff --git a/src/src/utils/ExceptionHandler.h b/src/src/utils/ExceptionHandler.h new file mode 100644 index 0000000..f70fb13 --- /dev/null +++ b/src/src/utils/ExceptionHandler.h @@ -0,0 +1,32 @@ +#pragma once +#include + +namespace Create::Exceptions { + enum Type { + None, + ComponentLoad, + MissingField, + InvalidFormat, + SystemFailure, + AssetMissing, + FileIO, + RuntimeLogic + }; + + const char* ExceptionToString(Type type); +} + +class RecoverableError { +public: + RecoverableError(const std::string& msg, Create::Exceptions::Type type = Create::Exceptions::None); + void Handle() const; + +private: + std::string message; + Create::Exceptions::Type type; +}; + +class FatalError { +public: + FatalError(const std::string& msg, Create::Exceptions::Type type = Create::Exceptions::None); +}; diff --git a/src/src/utils/UID.cpp b/src/src/utils/UID.cpp new file mode 100644 index 0000000..8f4dce9 --- /dev/null +++ b/src/src/utils/UID.cpp @@ -0,0 +1,31 @@ +#include "UID.h" +#include +#include +#include + +static int nextID = 0; + +std::string GenerateUUID() { + + std::ostringstream ss; + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dis(0, 15); + std::uniform_int_distribution dis2(8, 11); + + for (int i = 0; i < 32; i++) { + if (i == 12) + ss << 4; + else if (i == 16) + ss << dis2(gen); + else + ss << std::hex << dis(gen); + } + return ss.str(); +} + +UID::UID() + : id(nextID++), uuid(GenerateUUID()) {} + +UID::UID(int id, const std::string& uuid) + : id(id), uuid(uuid) {} diff --git a/src/src/utils/UID.h b/src/src/utils/UID.h new file mode 100644 index 0000000..92c37c2 --- /dev/null +++ b/src/src/utils/UID.h @@ -0,0 +1,12 @@ +#pragma once +#include +std::string GenerateUUID(); + +struct UID { + int id = 0; + std::string uuid; + + UID(); + UID(int id, const std::string& uuid); + +};