Updated Lighting and stuff, error handling

This commit is contained in:
OusmBlueNinja 2025-04-17 17:07:39 -05:00
parent 0f43490f64
commit ab4a94dc68
21 changed files with 676 additions and 152 deletions

View File

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

View File

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

BIN
src/assets/icons/error.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -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: []

View File

@ -3,6 +3,8 @@
#include <string>
#include <memory>
#include <yaml-cpp/yaml.h>
#include "../utils/ExceptionHandler.h"
class Object;
@ -21,4 +23,5 @@ public:
protected:
Object* owner;
};

View File

@ -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<std::string>();
} catch (const YAML::Exception& e) {
RecoverableError("Failed to load ScriptComponent: " + std::string(e.what()), Create::Exceptions::ComponentLoad).Handle();
}
}

View File

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

View File

@ -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<std::string>().empty())
SetTexture(node["texture"].as<std::string>());
if (node["normalMap"] && !node["normalMap"].as<std::string>().empty())
SetNormalMap(node["normalMap"].as<std::string>());
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<std::string>().empty())
{
SetTexture(node["texture"].as<std::string>());
}
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<std::string>().empty())
{
SetNormalMap(node["normalMap"].as<std::string>());
}
if (node["renderType"] && node["renderType"].IsScalar()) {
std::string typeStr = node["renderType"].as<std::string>();
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();
}
}

View File

@ -4,10 +4,17 @@
#include <string>
#include <glm/glm.hpp>
class SpriteComponent : public Component {
public:
SpriteComponent(Object* owner);
enum class RenderType {
Unlit,
Lit
};
void SetTexture(const std::string& path);
void SetNormalMap(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);
};

View File

@ -0,0 +1,50 @@
#include "TextComponent.h"
#include <yaml-cpp/yaml.h>
#include <stdexcept>
#include <utility>
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<std::string>();
} 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);
}

View File

@ -0,0 +1,23 @@
#pragma once
#include "Component.h" // Base class definition
#include <string>
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;
};

View File

@ -9,6 +9,8 @@
#include "utils/FileDialog.h"
#include "utils/Logging.h"
#include "utils/EngineConfig.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <imgui.h>
@ -147,6 +149,11 @@ void DrawInspectorUI(std::shared_ptr<Object> 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<Object> selected)
selected->AddComponent<TilemapComponent>();
}
// Sprite UI...
if (auto sprite = selected->GetComponent<SpriteComponent>())
{
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<int>(currentType);
if (ImGui::Combo("Render Type", &currentTypeIndex, renderTypes, IM_ARRAYSIZE(renderTypes)))
{
sprite->SetRenderType(static_cast<SpriteComponent::RenderType>(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<Object> 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<Object> 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<SpriteComponent>();
}
@ -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<Object>("NewObject");
obj->AddComponent<SpriteComponent>();
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<Object>("NewSprite");
obj->AddComponent<SpriteComponent>();
@ -330,6 +347,14 @@ void Engine::Run()
selected = obj;
ImGui::OpenPopup("RenameObject");
}
if (ImGui::MenuItem("Create New Light"))
{
auto obj = std::make_shared<Object>("NewSprite");
obj->AddComponent<LightComponent>();
objects.push_back(obj);
selected = obj;
ImGui::OpenPopup("RenameObject");
}
ImGui::EndPopup();
}
@ -488,7 +513,6 @@ void Engine::Run()
}
pendingDeletion.clear();
}
}
void Engine::DrawObjectNode(const std::shared_ptr<Object> &obj)
@ -497,7 +521,7 @@ void Engine::DrawObjectNode(const std::shared_ptr<Object> &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<const unsigned char *>(sceneString.c_str()), sceneString.size(), hash);
SHA256(reinterpret_cast<const unsigned char *>(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<int>(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!");
@ -644,7 +669,6 @@ void Engine::LoadScene(const std::string &path)
auto obj = std::make_shared<Object>("[DefaultObject]");
obj->Load(node);
objects.push_back(obj);
}
Logger::LogInfo("[LoadScene] Loaded scene: %s", root["scene_name"].as<std::string>().c_str());

View File

@ -23,5 +23,6 @@ private:
void ShowDebugOverlay(float deltaTime);
int m_Reserved_draws;
};

View File

@ -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 <algorithm>
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<Object> child) {
void Object::AddChild(std::shared_ptr<Object> 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<Object>& obj) {
return obj.get() == child;
}), children.end());
[child](const std::shared_ptr<Object> &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<std::shared_ptr<Object>>& 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<std::shared_ptr<Object>> &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<std::string>();
if (node["uid"])
uid.uuid = node["uid"].as<std::string>();
else
uid.uuid = GenerateUUID();
if (node["id"])
uid.id = node["id"].as<int>();
auto pos = node["position"];
if (pos && pos.IsSequence() && pos.size() == 2) {
if (pos && pos.IsSequence() && pos.size() == 2)
{
localPosition.x = pos[0].as<float>();
localPosition.y = pos[1].as<float>();
}
if (node["layer"])
layer = node["layer"].as<int>();
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<std::string>();
if (type == "SpriteComponent") {
Logger::LogVerbose("[LoadScene] Createing Component: %s", type.c_str());
if (type == "SpriteComponent")
{
auto comp = AddComponent<SpriteComponent>();
comp->Load(compNode);
} else if (type == "CameraComponent") {
}
else if (type == "CameraComponent")
{
auto comp = AddComponent<CameraComponent>();
comp->Load(compNode);
} else if (type == "LightComponent") {
}
else if (type == "LightComponent")
{
auto comp = AddComponent<LightComponent>();
comp->Load(compNode);
} else if (type == "TilemapComponent") {
}
else if (type == "TilemapComponent")
{
auto comp = AddComponent<TilemapComponent>();
comp->Load(compNode);
}
else if (type == "TextComponent")
{
auto comp = AddComponent<TextComponent>();
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<Object>("Child");
child->Load(childNode);
AddChild(child);

View File

@ -5,6 +5,7 @@
#include <memory>
#include <glm/glm.hpp>
#include <yaml-cpp/yaml.h>
#include "../utils/UID.h"
class Component;
@ -26,19 +27,14 @@ public:
void RemoveChild(Object* child);
std::vector<std::shared_ptr<Object>>& GetChildren();
template<typename T>
std::shared_ptr<T> GetComponent() const;
template<typename T>
std::shared_ptr<T> AddComponent();
template<typename T>
void RemoveComponent();
template<typename T> std::shared_ptr<T> GetComponent() const;
template<typename T> std::shared_ptr<T> AddComponent();
template<typename T> void RemoveComponent();
void Save(YAML::Emitter& out) const;
void Load(const YAML::Node& node);
int id = 0;
UID uid;
int layer = 0;
private:

View File

@ -28,15 +28,14 @@ std::vector<Light> 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,61 +190,53 @@ 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<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);
}
} 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<int>(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);
@ -240,11 +245,13 @@ void Renderer::DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float z
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<int>(std::floor(left / spacing)) * spacing;
int maxX = static_cast<int>(std::ceil(right / spacing)) * spacing;
int minY = static_cast<int>(std::floor(top / spacing)) * spacing;
int maxY = static_cast<int>(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};
}

View File

@ -0,0 +1,31 @@
#include "ExceptionHandler.h"
#include "Logging.h"
#include <cstdlib>
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);
}

View File

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

31
src/src/utils/UID.cpp Normal file
View File

@ -0,0 +1,31 @@
#include "UID.h"
#include <random>
#include <sstream>
#include <iomanip>
static int nextID = 0;
std::string GenerateUUID() {
std::ostringstream ss;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dis(0, 15);
std::uniform_int_distribution<int> 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) {}

12
src/src/utils/UID.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <string>
std::string GenerateUUID();
struct UID {
int id = 0;
std::string uuid;
UID();
UID(int id, const std::string& uuid);
};