From 17b7908b86d05286fea86bba5d38d24c6192c04f Mon Sep 17 00:00:00 2001 From: Daynlight Date: Sat, 22 Aug 2026 22:13:16 +0100 Subject: [PATCH 01/13] First tests for ResourceController --- .../Core/DataSerializer/MeshSerialization.cpp | 4 +- Engine/Utils/Utils/Resource/Resource.hpp | 2 +- .../Utils/Utils/Resource/ResourceController.h | 51 ++++- .../Utils/Resource/ResourceController.hpp | 140 +++++++++--- Tests/CMakeLists.txt | 9 +- .../Utils/Resource/ResourceController.cpp | 207 ++++++++++++++++++ 6 files changed, 360 insertions(+), 53 deletions(-) create mode 100644 Tests/Unit/Utils/Resource/ResourceController.cpp diff --git a/Engine/Core/Core/DataSerializer/MeshSerialization.cpp b/Engine/Core/Core/DataSerializer/MeshSerialization.cpp index 6fed058..4ecd83d 100644 --- a/Engine/Core/Core/DataSerializer/MeshSerialization.cpp +++ b/Engine/Core/Core/DataSerializer/MeshSerialization.cpp @@ -110,11 +110,11 @@ void Engine::MeshSerialization::saveAll(Engine::Utils::ResourceController> meshes_to_save; - for (const auto& pair : meshes.getIDs()) + for (const auto& pair : meshes.getNameToID()) meshes_to_save.push_back(pair); for (const auto& [mesh_name, mesh_id] : meshes_to_save) - save(mesh_name, meshes[mesh_id]); + save(mesh_name, meshes.getResource(mesh_id)); Engine::Utils::Logger::get().info("MeshSerialization", "All meshes have been saved"); }; diff --git a/Engine/Utils/Utils/Resource/Resource.hpp b/Engine/Utils/Utils/Resource/Resource.hpp index 510ad44..9d535e4 100644 --- a/Engine/Utils/Utils/Resource/Resource.hpp +++ b/Engine/Utils/Utils/Resource/Resource.hpp @@ -70,7 +70,7 @@ T* Engine::Utils::Resource::get(){ valid = validate(); if(!valid) return nullptr; - return &((*controller)[id]); + return nullptr; }; diff --git a/Engine/Utils/Utils/Resource/ResourceController.h b/Engine/Utils/Utils/Resource/ResourceController.h index 82e285a..483d6e1 100644 --- a/Engine/Utils/Utils/Resource/ResourceController.h +++ b/Engine/Utils/Utils/Resource/ResourceController.h @@ -18,37 +18,64 @@ namespace Engine::Utils { template class ResourceController { +// ========================== // +// ========== Data ========== // +// ========================== // +// ================= // +// ====== Core ===== // +// ================= // private: std::vector data; std::unordered_map name_to_id; std::vector id_to_name; unsigned int version = 0; + + +// ========================== // +// ======== Functions ======= // +// ========================== // +// ================== // +// == Constructors == // +// ================== // public: +// core ResourceController(); ~ResourceController(); - - T& operator[](unsigned int index); - - const T& operator[](unsigned int index) const; - - static constexpr unsigned int INVALID_ID = -1; - unsigned int getID(const std::string& name); +// copy + ResourceController(const ResourceController& second) noexcept; + ResourceController& operator=(const ResourceController& second) noexcept; +// move + ResourceController(ResourceController&& second) noexcept; + ResourceController& operator=(ResourceController&& second) noexcept; + +// ================== // +// == Data Control == // +// ================== // +public: + void emplace_back(const std::string& name, const T& record); + void emplace_back(const std::string& name, T&& record); void erase(const std::string& name); - unsigned int size() const; void clear(); - void emplace_back(const std::string& name, T&& mesh); - bool exists(const std::string& name) const; + T& getResource(unsigned int id); + +// ================== // +// ==== Data Info === // +// ================== // +public: +unsigned int getID(const std::string& name); +std::string getName(unsigned int id); +std::unordered_map getNameToID(); - std::unordered_map& getIDs(); + bool exists(const std::string& name) const; + unsigned int size() const; bool validateVersion(unsigned int version); unsigned int getLatestsVersion(); void compileAll(); - }; }; diff --git a/Engine/Utils/Utils/Resource/ResourceController.hpp b/Engine/Utils/Utils/Resource/ResourceController.hpp index 33e7b83..9be7f94 100644 --- a/Engine/Utils/Utils/Resource/ResourceController.hpp +++ b/Engine/Utils/Utils/Resource/ResourceController.hpp @@ -9,62 +9,82 @@ +// ================== // +// == Constructors == // +// ================== // +// core template -Engine::Utils::ResourceController::ResourceController() { -}; +Engine::Utils::ResourceController::ResourceController() {}; template -Engine::Utils::ResourceController::~ResourceController() { -}; +Engine::Utils::ResourceController::~ResourceController() {}; -template -T& Engine::Utils::ResourceController::operator[](unsigned int index) { - return data[index]; -}; +// copy +template +inline Engine::Utils::ResourceController::ResourceController(const ResourceController &second) noexcept + : data(second.data), + name_to_id(second.name_to_id), + id_to_name(second.id_to_name), + version(second.version) {}; -template -const T& Engine::Utils::ResourceController::operator[](unsigned int index) const { - return data[index]; +template +inline Engine::Utils::ResourceController &Engine::Utils::ResourceController::operator=(const ResourceController &second) noexcept { + if(this == &second) return *this; + + data = second.data; + name_to_id = second.name_to_id; + id_to_name = second.id_to_name; + version = second.version; + + return *this; }; -template -unsigned int Engine::Utils::ResourceController::getID(const std::string& name) { - auto it = name_to_id.find(name); - if (it == name_to_id.end()) { - return INVALID_ID; - }; - return it->second; -}; +// move +template +inline Engine::Utils::ResourceController::ResourceController(ResourceController &&second) noexcept + : data(std::move(second.data)), + name_to_id(std::move(second.name_to_id)), + id_to_name(std::move(second.id_to_name)), + version(std::move(second.version)) {}; +template +inline Engine::Utils::ResourceController &Engine::Utils::ResourceController::operator=(ResourceController &&second) noexcept { + if(this == &second) return *this; -template -bool Engine::Utils::ResourceController::exists(const std::string& name) const { - return name_to_id.find(name) != name_to_id.end(); + data = std::move(second.data); + name_to_id = std::move(second.name_to_id); + id_to_name = std::move(second.id_to_name); + version = std::move(second.version); + + return *this; }; +// ================== // +// == Data Control == // +// ================== // template -void Engine::Utils::ResourceController::emplace_back(const std::string& name, T&& mesh) { +void Engine::Utils::ResourceController::emplace_back(const std::string& name, const T& record) { version += 1; auto it = name_to_id.find(name); if (it != name_to_id.end()) { - data[it->second] = std::move(mesh); + data[it->second] = record; } else { unsigned int new_id = static_cast(data.size()); - data.emplace_back(std::move(mesh)); + data.emplace_back(record); name_to_id[name] = new_id; id_to_name.push_back(name); }; @@ -72,6 +92,23 @@ void Engine::Utils::ResourceController::emplace_back(const std::string& name, +template +void Engine::Utils::ResourceController::emplace_back(const std::string& name, T&& record) { + version += 1; + + auto it = name_to_id.find(name); + if (it != name_to_id.end()) { + data[it->second] = std::move(record); + } else { + unsigned int new_id = static_cast(data.size()); + + data.emplace_back(std::move(record)); + name_to_id[name] = new_id; + id_to_name.push_back(name); + }; +}; + + template void Engine::Utils::ResourceController::erase(const std::string& name) { @@ -97,28 +134,63 @@ void Engine::Utils::ResourceController::erase(const std::string& name) { +template +void Engine::Utils::ResourceController::clear(){ + version += 1; + data.clear(); + name_to_id.clear(); + id_to_name.clear(); +}; + + + +template +inline T &Engine::Utils::ResourceController::getResource(unsigned int id){ + return data[id]; +}; + + +// ================== // +// ==== Data Info === // +// ================== // template -unsigned int Engine::Utils::ResourceController::size() const{ - return data.size(); +unsigned int Engine::Utils::ResourceController::getID(const std::string& name) { + auto it = name_to_id.find(name); + if (it == name_to_id.end()) { + return -1; + }; + + return it->second; }; +template +inline std::string Engine::Utils::ResourceController::getName(unsigned int id){ + if(id >= id_to_name.size()) return ""; + return id_to_name[id]; +}; + + + +template +inline std::unordered_map Engine::Utils::ResourceController::getNameToID(){ + return name_to_id; +}; + + template -void Engine::Utils::ResourceController::clear(){ - version += 1; - data.clear(); - name_to_id.clear(); - id_to_name.clear(); +bool Engine::Utils::ResourceController::exists(const std::string& name) const { + return name_to_id.find(name) != name_to_id.end(); }; template -std::unordered_map& Engine::Utils::ResourceController::getIDs(){ - return name_to_id; +unsigned int Engine::Utils::ResourceController::size() const{ + return data.size(); }; diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 0d8a852..5120f99 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -8,10 +8,11 @@ cmake_minimum_required(VERSION 3.15) set(tests_src - Unit/Core/Camera/Camera.cpp - Unit/Core/Camera/CameraController.cpp - Unit/Utils/utils.cpp - Unit/Utils/utilsProd.cpp + # Unit/Core/Camera/Camera.cpp + # Unit/Core/Camera/CameraController.cpp + # Unit/Utils/utils.cpp + # Unit/Utils/utilsProd.cpp + Unit/Utils/Resource/ResourceController.cpp ) add_executable(unit_tests ${tests_src}) diff --git a/Tests/Unit/Utils/Resource/ResourceController.cpp b/Tests/Unit/Utils/Resource/ResourceController.cpp new file mode 100644 index 0000000..efb4997 --- /dev/null +++ b/Tests/Unit/Utils/Resource/ResourceController.cpp @@ -0,0 +1,207 @@ +// Engine +// Copyright 2026 Daynlight +// Licensed under the GNU General, Version 3.0. +// See LICENSE file for details. + + + +#include +#include +#include + +#define private public +#define protected public + +#include "Utils/Resource/Resource.h" +#include "Utils/Resource/ResourceController.h" + +#undef private +#undef protected + + + +class TestingRes{ +public: + std::string str = ""; + int val_i = 0; + float val_f = 0.0f; + +public: + TestingRes() = default; + TestingRes(const TestingRes& second) noexcept + : str(second.str), + val_i(second.val_i), + val_f(second.val_f) {}; + + TestingRes& operator=(const TestingRes& second) noexcept { + if(this == &second) return *this; + + str = second.str; + val_i = second.val_i; + val_f = second.val_f; + + return *this; + }; + + TestingRes(TestingRes&& second) noexcept + : str(std::move(second.str)), + val_i(std::move(second.val_i)), + val_f(std::move(second.val_f)) {}; + + TestingRes& operator=(TestingRes&& second) noexcept { + if(this == &second) return *this; + + str = std::move(second.str); + val_i = std::move(second.val_i); + val_f = std::move(second.val_f); + + return *this; + }; + + bool operator==(const TestingRes& second) const { + if(str != second.str) return false; + if(val_i != second.val_i) return false; + if(val_f != second.val_f) return false; + return true; + }; +}; + + + +// ================== // +// == Constructors == // +// ================== // +TEST(ResourceControllerDefaultConstructor, HandlesInitialization){ +}; + +TEST(ResourceControllerCopyConstructor, HandlesInitialization){ +}; + +TEST(ResourceControllerCopyAssignConstructor, HandlesInitialization){ +}; + +TEST(ResourceControllerMoveConstructor, HandlesInitialization){ +}; + +TEST(ResourceControllerMoveAssignConstructor, HandlesInitialization){ +}; + + + +// ================== // +// == Data Control == // +// ================== // +TEST(ResourceControllerEmplaceViaMoveEraseClear, HandlesInitialization){ + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + + TestingRes test_res2 = TestingRes(); + test_res2.str = "Hello World"; + std::string test_res_name2 = "Hello World"; + + TestingRes test_res3 = TestingRes(); + test_res3.str = "Hello Big World"; + std::string test_res_name3 = "Hello Big World"; + + Engine::Utils::ResourceController controller; + controller.emplace_back(test_res_name, std::move(test_res)); + controller.emplace_back(test_res_name2, std::move(test_res2)); + controller.emplace_back(test_res_name3, std::move(test_res3)); + + EXPECT_EQ(controller.size(), 3); + EXPECT_TRUE(controller.exists(test_res_name)); + EXPECT_TRUE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); + + controller.erase(test_res_name); + EXPECT_EQ(controller.size(), 2); + EXPECT_FALSE(controller.exists(test_res_name)); + EXPECT_TRUE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); + + controller.clear(); + EXPECT_EQ(controller.size(), 0); + EXPECT_FALSE(controller.exists(test_res_name)); + EXPECT_FALSE(controller.exists(test_res_name2)); + EXPECT_FALSE(controller.exists(test_res_name3)); +}; + +TEST(ResourceControllerEmplaceViaCopyEraseClear, HandlesInitialization){ + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + + TestingRes test_res2 = TestingRes(); + test_res2.str = "Hello World"; + std::string test_res_name2 = "Hello World"; + + TestingRes test_res3 = TestingRes(); + test_res3.str = "Hello Big World"; + std::string test_res_name3 = "Hello Big World"; + + Engine::Utils::ResourceController controller; + controller.emplace_back(test_res_name, test_res); + controller.emplace_back(test_res_name2, test_res2); + controller.emplace_back(test_res_name3, test_res3); + + EXPECT_EQ(controller.size(), 3); + EXPECT_TRUE(controller.exists(test_res_name)); + EXPECT_TRUE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); + + controller.erase(test_res_name); + EXPECT_EQ(controller.size(), 2); + EXPECT_FALSE(controller.exists(test_res_name)); + EXPECT_TRUE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); + + controller.clear(); + EXPECT_EQ(controller.size(), 0); + EXPECT_FALSE(controller.exists(test_res_name)); + EXPECT_FALSE(controller.exists(test_res_name2)); + EXPECT_FALSE(controller.exists(test_res_name3)); +}; + +TEST(ResourceControllerEmplaceGetResource, HandlesInitialization){ + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + + TestingRes test_res2 = TestingRes(); + test_res2.str = "Hello World"; + std::string test_res_name2 = "Hello World"; + + TestingRes test_res3 = TestingRes(); + test_res3.str = "Hello Big World"; + std::string test_res_name3 = "Hello Big World"; + + Engine::Utils::ResourceController controller; + controller.emplace_back(test_res_name, test_res); + controller.emplace_back(test_res_name2, test_res2); + controller.emplace_back(test_res_name3, test_res3); + + EXPECT_EQ(controller.size(), 3); + EXPECT_TRUE(controller.exists(test_res_name)); + EXPECT_TRUE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); + + TestingRes test_res_return = controller.getResource(controller.getID(test_res_name)); + EXPECT_TRUE(test_res_return == test_res); + + TestingRes test_res_return2 = controller.getResource(controller.getID(test_res_name2)); + EXPECT_TRUE(test_res_return2 == test_res2); + + TestingRes test_res_return3 = controller.getResource(controller.getID(test_res_name3)); + EXPECT_TRUE(test_res_return3 == test_res3); +}; + +// emplace two the same +// erase twice the same +// erase not existing one +// random amount elements clear +// getResource + getID with erasing element before +// getResource out of bound +// integration with Resource + +// getID not existing name \ No newline at end of file From 3d033139218617ded13ac6df444c3563619f3fc1 Mon Sep 17 00:00:00 2001 From: Daynlight Date: Sun, 23 Aug 2026 01:04:07 +0100 Subject: [PATCH 02/13] ResourceController DataControl tests --- .../Utils/Utils/Resource/ResourceController.h | 7 +- .../Utils/Resource/ResourceController.hpp | 10 + .../Utils/Resource/ResourceController.cpp | 190 +++++++++++++++++- 3 files changed, 196 insertions(+), 11 deletions(-) diff --git a/Engine/Utils/Utils/Resource/ResourceController.h b/Engine/Utils/Utils/Resource/ResourceController.h index 483d6e1..9b71142 100644 --- a/Engine/Utils/Utils/Resource/ResourceController.h +++ b/Engine/Utils/Utils/Resource/ResourceController.h @@ -65,9 +65,10 @@ class ResourceController { // ==== Data Info === // // ================== // public: -unsigned int getID(const std::string& name); -std::string getName(unsigned int id); -std::unordered_map getNameToID(); + unsigned int getID(const std::string& name); + bool isIDValid(unsigned int id); + std::string getName(unsigned int id); + std::unordered_map getNameToID(); bool exists(const std::string& name) const; unsigned int size() const; diff --git a/Engine/Utils/Utils/Resource/ResourceController.hpp b/Engine/Utils/Utils/Resource/ResourceController.hpp index 9be7f94..4ca203c 100644 --- a/Engine/Utils/Utils/Resource/ResourceController.hpp +++ b/Engine/Utils/Utils/Resource/ResourceController.hpp @@ -146,6 +146,8 @@ void Engine::Utils::ResourceController::clear(){ template inline T &Engine::Utils::ResourceController::getResource(unsigned int id){ + if(id >= data.size()) + throw std::runtime_error("id is out of bound! [check it before]"); return data[id]; }; @@ -166,6 +168,14 @@ unsigned int Engine::Utils::ResourceController::getID(const std::string& name +template +inline bool Engine::Utils::ResourceController::isIDValid(unsigned int id){ + if(id == -1) return false; + return data.size() > id; +}; + + + template inline std::string Engine::Utils::ResourceController::getName(unsigned int id){ if(id >= id_to_name.size()) return ""; diff --git a/Tests/Unit/Utils/Resource/ResourceController.cpp b/Tests/Unit/Utils/Resource/ResourceController.cpp index efb4997..19563cb 100644 --- a/Tests/Unit/Utils/Resource/ResourceController.cpp +++ b/Tests/Unit/Utils/Resource/ResourceController.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #define private public #define protected public @@ -196,12 +197,185 @@ TEST(ResourceControllerEmplaceGetResource, HandlesInitialization){ EXPECT_TRUE(test_res_return3 == test_res3); }; -// emplace two the same -// erase twice the same -// erase not existing one -// random amount elements clear -// getResource + getID with erasing element before -// getResource out of bound -// integration with Resource +TEST(ResourceControllerTwiceEmplace, HandlesInitialization){ + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + + TestingRes test_res2 = TestingRes(); + test_res2.str = "Hello World"; + + TestingRes test_res3 = TestingRes(); + test_res3.str = "Hello Big World"; + + Engine::Utils::ResourceController controller; + controller.emplace_back(test_res_name, test_res); + + EXPECT_EQ(controller.size(), 1); + EXPECT_TRUE(controller.exists(test_res_name)); + + TestingRes test_res_return = controller.getResource(controller.getID(test_res_name)); + EXPECT_TRUE(test_res_return == test_res); + EXPECT_EQ(controller.size(), 1); + EXPECT_TRUE(controller.exists(test_res_name)); + + controller.emplace_back(test_res_name, test_res2); + TestingRes test_res_return2 = controller.getResource(controller.getID(test_res_name)); + EXPECT_TRUE(test_res_return2 == test_res2); + EXPECT_EQ(controller.size(), 1); + EXPECT_TRUE(controller.exists(test_res_name)); + + controller.emplace_back(test_res_name, test_res3); + TestingRes test_res_return3 = controller.getResource(controller.getID(test_res_name)); + EXPECT_TRUE(test_res_return3 == test_res3); + EXPECT_EQ(controller.size(), 1); + EXPECT_TRUE(controller.exists(test_res_name)); +}; + +TEST(ResourceControllerEraseMultipleTimes, HandlesInitialization){ + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + + TestingRes test_res2 = TestingRes(); + test_res2.str = "Hello World"; + std::string test_res_name2 = "Hello World"; + + TestingRes test_res3 = TestingRes(); + test_res3.str = "Hello Big World"; + std::string test_res_name3 = "Hello Big World"; + + Engine::Utils::ResourceController controller; + controller.emplace_back(test_res_name, test_res); + controller.emplace_back(test_res_name2, test_res2); + controller.emplace_back(test_res_name3, test_res3); + + EXPECT_EQ(controller.size(), 3); + EXPECT_TRUE(controller.exists(test_res_name)); + EXPECT_TRUE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); + + controller.erase(test_res_name); + EXPECT_EQ(controller.size(), 2); + EXPECT_FALSE(controller.exists(test_res_name)); + EXPECT_TRUE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); + + controller.erase(test_res_name); + EXPECT_EQ(controller.size(), 2); + EXPECT_FALSE(controller.exists(test_res_name)); + EXPECT_TRUE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); + + controller.erase(test_res_name2); + EXPECT_EQ(controller.size(), 1); + EXPECT_FALSE(controller.exists(test_res_name)); + EXPECT_FALSE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); + + controller.erase(test_res_name); + EXPECT_EQ(controller.size(), 1); + EXPECT_FALSE(controller.exists(test_res_name)); + EXPECT_FALSE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); + + controller.erase("empty"); + EXPECT_EQ(controller.size(), 1); + EXPECT_FALSE(controller.exists(test_res_name)); + EXPECT_FALSE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); + + controller.erase(test_res_name); + EXPECT_EQ(controller.size(), 1); + EXPECT_FALSE(controller.exists(test_res_name)); + EXPECT_FALSE(controller.exists(test_res_name2)); + EXPECT_TRUE(controller.exists(test_res_name3)); +}; + +TEST(ResourceControllerEraseMultipleItems, HandlesInitialization){ + const unsigned int seed = 1231231; + const unsigned int random_tests_min = 25; + const unsigned int random_tests_max = 100; + const float random_element_f_min = -200.0f; + const float random_element_f_max = 200.0f; + const int random_element_i_min = -200; + const int random_element_i_max = 200; + + std::mt19937 gen_f(seed); + std::uniform_real_distribution dist_f(random_element_f_min, random_element_f_max); + + std::mt19937 gen_i(seed); + std::uniform_int_distribution dist_i(random_element_i_min, random_element_i_max); + + std::mt19937 gen_tests(seed); + std::uniform_int_distribution dist_tests(random_tests_min, random_tests_max); + + Engine::Utils::ResourceController controller; + std::vector tests = {}; + + unsigned int random_tests = dist_tests(gen_tests); + for(unsigned int i = 0; i < random_tests; i++){ + TestingRes test = TestingRes(); + float rand_f = dist_f(gen_f); + int rand_i = dist_i(gen_i); + test.val_f = rand_f; + test.val_i = rand_i; + tests.emplace_back(test); + std::string name = std::to_string(i); + controller.emplace_back(name, test); + }; + + EXPECT_EQ(controller.size(), tests.size()); + + for(unsigned int i = 0; i < random_tests; i++){ + std::string name = std::to_string(i); + TestingRes test = controller.getResource(controller.getID(name)); + EXPECT_TRUE(test == tests[i]); + }; + + std::mt19937 gen_rm_tests(seed); + std::uniform_int_distribution dist_rm_tests(0, tests.size()); + + unsigned int random_remove = dist_rm_tests(gen_rm_tests); + for(unsigned int i = 0; i < random_remove; i++){ + std::string name = std::to_string(i); + controller.erase(name); + }; + + EXPECT_EQ(controller.size(), tests.size() - random_remove); + + controller.clear(); + + EXPECT_EQ(controller.size(), 0); +}; + +TEST(ResourceControllerEmplaceGetResourceIncorrectID, HandlesInitialization){ + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + + Engine::Utils::ResourceController controller; + controller.emplace_back(test_res_name, test_res); + + EXPECT_EQ(controller.size(), 1); + EXPECT_TRUE(controller.exists(test_res_name)); + + TestingRes test_res_return = controller.getResource(controller.getID(test_res_name)); + EXPECT_TRUE(test_res_return == test_res); + + unsigned int test_id = 1231; + EXPECT_THROW(controller.getResource(test_id), std::runtime_error); + EXPECT_FALSE(controller.isIDValid(test_id)); + EXPECT_FALSE(controller.isIDValid(-1)); + EXPECT_TRUE(controller.isIDValid(controller.getID(test_res_name))); +}; + + + +// ================== // +// ==== Data Info === // +// ================== // +// getID not existing name + -// getID not existing name \ No newline at end of file +// integration with Resource \ No newline at end of file From 550d1d559f3167ccc54881eff2fa5eb6fbf11d6f Mon Sep 17 00:00:00 2001 From: Daynlight Date: Sun, 23 Aug 2026 01:04:34 +0100 Subject: [PATCH 03/13] ResourceController DataControl tests --- Tests/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 5120f99..4fef082 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -8,10 +8,10 @@ cmake_minimum_required(VERSION 3.15) set(tests_src - # Unit/Core/Camera/Camera.cpp - # Unit/Core/Camera/CameraController.cpp - # Unit/Utils/utils.cpp - # Unit/Utils/utilsProd.cpp + Unit/Core/Camera/Camera.cpp + Unit/Core/Camera/CameraController.cpp + Unit/Utils/utils.cpp + Unit/Utils/utilsProd.cpp Unit/Utils/Resource/ResourceController.cpp ) From 504d70c2e5718816c226f18ed6dfa971285eee78 Mon Sep 17 00:00:00 2001 From: Daynlight Date: Sun, 23 Aug 2026 01:23:31 +0100 Subject: [PATCH 04/13] ResourceController Constructors tests --- .../Utils/Resource/ResourceController.cpp | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) diff --git a/Tests/Unit/Utils/Resource/ResourceController.cpp b/Tests/Unit/Utils/Resource/ResourceController.cpp index 19563cb..2746af1 100644 --- a/Tests/Unit/Utils/Resource/ResourceController.cpp +++ b/Tests/Unit/Utils/Resource/ResourceController.cpp @@ -73,18 +73,175 @@ class TestingRes{ // == Constructors == // // ================== // TEST(ResourceControllerDefaultConstructor, HandlesInitialization){ + Engine::Utils::ResourceController controller; + + EXPECT_EQ(controller.data.size(), 0); + EXPECT_EQ(controller.name_to_id.size(), 0); + EXPECT_EQ(controller.id_to_name.size(), 0); + EXPECT_EQ(controller.version, 0); + + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + controller.emplace_back(test_res_name, test_res); + + EXPECT_EQ(controller.data.size(), 1); + EXPECT_EQ(controller.name_to_id.size(), 1); + EXPECT_EQ(controller.id_to_name.size(), 1); + EXPECT_NE(controller.version, 0); }; TEST(ResourceControllerCopyConstructor, HandlesInitialization){ + Engine::Utils::ResourceController controller; + + EXPECT_EQ(controller.data.size(), 0); + EXPECT_EQ(controller.name_to_id.size(), 0); + EXPECT_EQ(controller.id_to_name.size(), 0); + EXPECT_EQ(controller.version, 0); + + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + controller.emplace_back(test_res_name, test_res); + + EXPECT_EQ(controller.data.size(), 1); + EXPECT_EQ(controller.name_to_id.size(), 1); + EXPECT_EQ(controller.id_to_name.size(), 1); + EXPECT_NE(controller.version, 0); + + Engine::Utils::ResourceController controller2(controller); + + EXPECT_EQ(controller2.data.size(), 1); + EXPECT_EQ(controller2.name_to_id.size(), 1); + EXPECT_EQ(controller2.id_to_name.size(), 1); + EXPECT_EQ(controller2.version, controller.version); + + TestingRes test_res2 = controller2.getResource(controller2.getID(test_res_name)); + EXPECT_TRUE(test_res2 == test_res); + }; TEST(ResourceControllerCopyAssignConstructor, HandlesInitialization){ + Engine::Utils::ResourceController controller; + + EXPECT_EQ(controller.data.size(), 0); + EXPECT_EQ(controller.name_to_id.size(), 0); + EXPECT_EQ(controller.id_to_name.size(), 0); + EXPECT_EQ(controller.version, 0); + + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + controller.emplace_back(test_res_name, test_res); + + EXPECT_EQ(controller.data.size(), 1); + EXPECT_EQ(controller.name_to_id.size(), 1); + EXPECT_EQ(controller.id_to_name.size(), 1); + EXPECT_NE(controller.version, 0); + + Engine::Utils::ResourceController controller2 = controller; + + EXPECT_EQ(controller2.data.size(), 1); + EXPECT_EQ(controller2.name_to_id.size(), 1); + EXPECT_EQ(controller2.id_to_name.size(), 1); + EXPECT_EQ(controller2.version, controller.version); + + TestingRes test_res2 = controller2.getResource(controller2.getID(test_res_name)); + EXPECT_TRUE(test_res2 == test_res); + + controller2 = controller2; + + EXPECT_EQ(controller2.data.size(), 1); + EXPECT_EQ(controller2.name_to_id.size(), 1); + EXPECT_EQ(controller2.id_to_name.size(), 1); + EXPECT_EQ(controller2.version, controller.version); + + TestingRes test_res3 = controller2.getResource(controller2.getID(test_res_name)); + EXPECT_TRUE(test_res3 == test_res); }; TEST(ResourceControllerMoveConstructor, HandlesInitialization){ + Engine::Utils::ResourceController controller; + + EXPECT_EQ(controller.data.size(), 0); + EXPECT_EQ(controller.name_to_id.size(), 0); + EXPECT_EQ(controller.id_to_name.size(), 0); + EXPECT_EQ(controller.version, 0); + + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + controller.emplace_back(test_res_name, test_res); + + EXPECT_EQ(controller.data.size(), 1); + EXPECT_EQ(controller.name_to_id.size(), 1); + EXPECT_EQ(controller.id_to_name.size(), 1); + EXPECT_NE(controller.version, 0); + + unsigned int version = controller.version; + + Engine::Utils::ResourceController controller2(std::move(controller)); + + EXPECT_EQ(controller2.data.size(), 1); + EXPECT_EQ(controller2.name_to_id.size(), 1); + EXPECT_EQ(controller2.id_to_name.size(), 1); + EXPECT_EQ(controller2.version, version); + + TestingRes test_res2 = controller2.getResource(controller2.getID(test_res_name)); + EXPECT_TRUE(test_res2 == test_res); + + EXPECT_EQ(controller.data.size(), 0); + EXPECT_EQ(controller.name_to_id.size(), 0); + EXPECT_EQ(controller.id_to_name.size(), 0); }; TEST(ResourceControllerMoveAssignConstructor, HandlesInitialization){ + Engine::Utils::ResourceController controller; + + EXPECT_EQ(controller.data.size(), 0); + EXPECT_EQ(controller.name_to_id.size(), 0); + EXPECT_EQ(controller.id_to_name.size(), 0); + EXPECT_EQ(controller.version, 0); + + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + controller.emplace_back(test_res_name, test_res); + + EXPECT_EQ(controller.data.size(), 1); + EXPECT_EQ(controller.name_to_id.size(), 1); + EXPECT_EQ(controller.id_to_name.size(), 1); + EXPECT_NE(controller.version, 0); + + unsigned int version = controller.version; + + Engine::Utils::ResourceController controller2 = std::move(controller); + + EXPECT_EQ(controller2.data.size(), 1); + EXPECT_EQ(controller2.name_to_id.size(), 1); + EXPECT_EQ(controller2.id_to_name.size(), 1); + EXPECT_EQ(controller2.version, version); + + TestingRes test_res2 = controller2.getResource(controller2.getID(test_res_name)); + EXPECT_TRUE(test_res2 == test_res); + + EXPECT_EQ(controller.data.size(), 0); + EXPECT_EQ(controller.name_to_id.size(), 0); + EXPECT_EQ(controller.id_to_name.size(), 0); + + controller2 = std::move(controller2); + + EXPECT_EQ(controller2.data.size(), 1); + EXPECT_EQ(controller2.name_to_id.size(), 1); + EXPECT_EQ(controller2.id_to_name.size(), 1); + EXPECT_EQ(controller2.version, version); + + TestingRes test_res3 = controller2.getResource(controller2.getID(test_res_name)); + EXPECT_TRUE(test_res3 == test_res); + + EXPECT_EQ(controller.data.size(), 0); + EXPECT_EQ(controller.name_to_id.size(), 0); + EXPECT_EQ(controller.id_to_name.size(), 0); }; From 3345be4e53b9074db7280bde2f49629209e6be86 Mon Sep 17 00:00:00 2001 From: Daynlight Date: Sun, 23 Aug 2026 13:36:33 +0100 Subject: [PATCH 05/13] ResourceController DataInfo Tests --- .../Utils/Resource/ResourceController.cpp | 137 +++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/Tests/Unit/Utils/Resource/ResourceController.cpp b/Tests/Unit/Utils/Resource/ResourceController.cpp index 2746af1..2501fbd 100644 --- a/Tests/Unit/Utils/Resource/ResourceController.cpp +++ b/Tests/Unit/Utils/Resource/ResourceController.cpp @@ -532,7 +532,142 @@ TEST(ResourceControllerEmplaceGetResourceIncorrectID, HandlesInitialization){ // ================== // // ==== Data Info === // // ================== // -// getID not existing name +TEST(ResourceControllerGetID, HandlesInitialization){ + TestingRes test_res = TestingRes(); + test_res.str = "Hello"; + std::string test_res_name = "Hello"; + + Engine::Utils::ResourceController controller; + controller.emplace_back(test_res_name, test_res); + + EXPECT_EQ(controller.size(), 1); + EXPECT_TRUE(controller.exists(test_res_name)); + + unsigned int test_id = controller.getID(test_res_name); + std::string test_name = controller.getName(test_id); + std::unordered_map namt_to_id = controller.getNameToID(); + EXPECT_LT(test_id, controller.size()); + EXPECT_LT(test_id, controller.data.size()); + EXPECT_TRUE(controller.isIDValid(test_id)); + EXPECT_EQ(test_name, test_res_name); + bool found = false; + for(auto& el : namt_to_id){ + if(el.first == test_res_name && el.second == test_id) { + found = true; + break; + }; + }; + EXPECT_TRUE(found); + + test_id = 1231; + test_name = controller.getName(test_id); + namt_to_id = controller.getNameToID(); + EXPECT_GE(test_id, controller.size()); + EXPECT_GE(test_id, controller.data.size()); + EXPECT_FALSE(controller.isIDValid(test_id)); + EXPECT_NE(test_name, test_res_name); + found = false; + for(auto& el : namt_to_id){ + if(el.first == test_res_name && el.second == test_id) { + found = true; + break; + }; + }; + EXPECT_FALSE(found); +}; + +TEST(ResourceControllerGetNameToID, HandlesInitialization){ + const unsigned int seed = 1231231; + const unsigned int random_tests_min = 25; + const unsigned int random_tests_max = 100; + const float random_element_f_min = -200.0f; + const float random_element_f_max = 200.0f; + const int random_element_i_min = -200; + const int random_element_i_max = 200; + + std::mt19937 gen_f(seed); + std::uniform_real_distribution dist_f(random_element_f_min, random_element_f_max); + + std::mt19937 gen_i(seed); + std::uniform_int_distribution dist_i(random_element_i_min, random_element_i_max); + + std::mt19937 gen_tests(seed); + std::uniform_int_distribution dist_tests(random_tests_min, random_tests_max); + + Engine::Utils::ResourceController controller; + std::vector tests = {}; + + unsigned int random_tests = dist_tests(gen_tests); + + for(unsigned int i = 0; i < random_tests; i++){ + TestingRes test = TestingRes(); + float rand_f = dist_f(gen_f); + int rand_i = dist_i(gen_i); + test.val_f = rand_f; + test.val_i = rand_i; + tests.emplace_back(test); + std::string name = std::to_string(i); + controller.emplace_back(name, test); + }; + EXPECT_EQ(controller.size(), tests.size()); + + std::unordered_map name_to_id = controller.getNameToID(); + + for(unsigned int i = 0; i < random_tests; i++){ + std::string name = std::to_string(i); + + bool found = false; + for(auto& el : name_to_id){ + if(el.first == name) { + found = true; + break; + }; + }; + EXPECT_TRUE(found); + }; +}; + +TEST(ResourceControllerValidateVersion, HandlesInitialization){ + Engine::Utils::ResourceController controller; + unsigned int version = controller.getLatestsVersion(); + + TestingRes test = TestingRes(); + std::string testing_name = "1"; + controller.emplace_back(testing_name, test); + + EXPECT_FALSE(controller.validateVersion(version)); + EXPECT_NE(version, controller.getLatestsVersion()); + version = controller.validateVersion(version); + + test = TestingRes(); + testing_name = "1"; + controller.emplace_back(testing_name, test); + + EXPECT_FALSE(controller.validateVersion(version)); + EXPECT_NE(version, controller.getLatestsVersion()); + version = controller.validateVersion(version); + + test = TestingRes(); + testing_name = "234"; + controller.emplace_back(testing_name, test); + + EXPECT_FALSE(controller.validateVersion(version)); + EXPECT_NE(version, controller.getLatestsVersion()); + version = controller.validateVersion(version); + + testing_name = "234"; + controller.erase(testing_name); + + EXPECT_FALSE(controller.validateVersion(version)); + EXPECT_NE(version, controller.getLatestsVersion()); + version = controller.validateVersion(version); + + controller.clear(); + + EXPECT_FALSE(controller.validateVersion(version)); + EXPECT_NE(version, controller.getLatestsVersion()); + version = controller.validateVersion(version); +}; // integration with Resource \ No newline at end of file From 3a4618f0d35f787c76c09b145b58f0e401b55918 Mon Sep 17 00:00:00 2001 From: Daynlight Date: Sun, 23 Aug 2026 14:30:09 +0100 Subject: [PATCH 06/13] ResController all tests and markers + rm compielAll --- .../Core/DataSerializer/MeshSerialization.cpp | 7 ++- Engine/Utils/Utils/Resource/Resource.hpp | 1 + .../Utils/Utils/Resource/ResourceController.h | 32 +++++++------ .../Utils/Resource/ResourceController.hpp | 42 +++++++----------- .../Game/GameData/Assets/Meshes/Default.msh | Bin 575 -> 575 bytes .../GameData/Assets/Meshes/screen_quad.msh | Bin 195 -> 195 bytes Examples/Game/GameData/Resources.res | Bin 33 -> 33 bytes .../Utils/Resource/ResourceController.cpp | 30 ++++++------- 8 files changed, 53 insertions(+), 59 deletions(-) diff --git a/Engine/Core/Core/DataSerializer/MeshSerialization.cpp b/Engine/Core/Core/DataSerializer/MeshSerialization.cpp index 4ecd83d..7b64f50 100644 --- a/Engine/Core/Core/DataSerializer/MeshSerialization.cpp +++ b/Engine/Core/Core/DataSerializer/MeshSerialization.cpp @@ -114,7 +114,7 @@ void Engine::MeshSerialization::saveAll(Engine::Utils::ResourceControllercompile(); + }; Engine::Utils::Logger::get().info("MeshSerialization", "All meshes have been loaded"); } catch (const std::exception& e) { diff --git a/Engine/Utils/Utils/Resource/Resource.hpp b/Engine/Utils/Utils/Resource/Resource.hpp index 9d535e4..04e1762 100644 --- a/Engine/Utils/Utils/Resource/Resource.hpp +++ b/Engine/Utils/Utils/Resource/Resource.hpp @@ -66,6 +66,7 @@ Engine::Utils::Resource& Engine::Utils::Resource::operator=(Resource &&oth template T* Engine::Utils::Resource::get(){ // if(!valid) return nullptr; + return controller->getResource(controller->getID(name)); valid = validate(); if(!valid) return nullptr; diff --git a/Engine/Utils/Utils/Resource/ResourceController.h b/Engine/Utils/Utils/Resource/ResourceController.h index 9b71142..db4a95e 100644 --- a/Engine/Utils/Utils/Resource/ResourceController.h +++ b/Engine/Utils/Utils/Resource/ResourceController.h @@ -40,8 +40,8 @@ class ResourceController { // ================== // public: // core - ResourceController(); - ~ResourceController(); + ResourceController() noexcept; + ~ResourceController() noexcept; // copy ResourceController(const ResourceController& second) noexcept; ResourceController& operator=(const ResourceController& second) noexcept; @@ -53,30 +53,28 @@ class ResourceController { // == Data Control == // // ================== // public: - void emplace_back(const std::string& name, const T& record); - void emplace_back(const std::string& name, T&& record); + void emplace_back(const std::string& name, const T& record) noexcept; + void emplace_back(const std::string& name, T&& record) noexcept; - void erase(const std::string& name); - void clear(); + void erase(const std::string& name) noexcept; + void clear() noexcept; - T& getResource(unsigned int id); + T* getResource(unsigned int id) noexcept; // ================== // // ==== Data Info === // // ================== // public: - unsigned int getID(const std::string& name); - bool isIDValid(unsigned int id); - std::string getName(unsigned int id); - std::unordered_map getNameToID(); + unsigned int getID(const std::string& name) const noexcept; + bool isIDValid(unsigned int id) const noexcept; + std::string getName(unsigned int id) const noexcept; + std::unordered_map getNameToID() const noexcept; - bool exists(const std::string& name) const; - unsigned int size() const; + bool exists(const std::string& name) const noexcept; + unsigned int size() const noexcept; - bool validateVersion(unsigned int version); - unsigned int getLatestsVersion(); - - void compileAll(); + bool validateVersion(unsigned int version) const noexcept; + unsigned int getLatestsVersion() const noexcept; }; }; diff --git a/Engine/Utils/Utils/Resource/ResourceController.hpp b/Engine/Utils/Utils/Resource/ResourceController.hpp index 4ca203c..9dbc715 100644 --- a/Engine/Utils/Utils/Resource/ResourceController.hpp +++ b/Engine/Utils/Utils/Resource/ResourceController.hpp @@ -14,12 +14,12 @@ // ================== // // core template -Engine::Utils::ResourceController::ResourceController() {}; +Engine::Utils::ResourceController::ResourceController() noexcept {}; template -Engine::Utils::ResourceController::~ResourceController() {}; +Engine::Utils::ResourceController::~ResourceController() noexcept {}; @@ -75,7 +75,7 @@ inline Engine::Utils::ResourceController &Engine::Utils::ResourceController -void Engine::Utils::ResourceController::emplace_back(const std::string& name, const T& record) { +void Engine::Utils::ResourceController::emplace_back(const std::string& name, const T& record) noexcept { version += 1; auto it = name_to_id.find(name); @@ -93,7 +93,7 @@ void Engine::Utils::ResourceController::emplace_back(const std::string& name, template -void Engine::Utils::ResourceController::emplace_back(const std::string& name, T&& record) { +void Engine::Utils::ResourceController::emplace_back(const std::string& name, T&& record) noexcept { version += 1; auto it = name_to_id.find(name); @@ -111,7 +111,7 @@ void Engine::Utils::ResourceController::emplace_back(const std::string& name, template -void Engine::Utils::ResourceController::erase(const std::string& name) { +void Engine::Utils::ResourceController::erase(const std::string& name) noexcept { if (!exists(name)) return; version += 1; @@ -135,7 +135,7 @@ void Engine::Utils::ResourceController::erase(const std::string& name) { template -void Engine::Utils::ResourceController::clear(){ +void Engine::Utils::ResourceController::clear() noexcept { version += 1; data.clear(); name_to_id.clear(); @@ -145,10 +145,9 @@ void Engine::Utils::ResourceController::clear(){ template -inline T &Engine::Utils::ResourceController::getResource(unsigned int id){ - if(id >= data.size()) - throw std::runtime_error("id is out of bound! [check it before]"); - return data[id]; +inline T* Engine::Utils::ResourceController::getResource(unsigned int id) noexcept { + if(id >= data.size()) return nullptr; + return &data[id]; }; @@ -157,7 +156,7 @@ inline T &Engine::Utils::ResourceController::getResource(unsigned int id){ // ==== Data Info === // // ================== // template -unsigned int Engine::Utils::ResourceController::getID(const std::string& name) { +unsigned int Engine::Utils::ResourceController::getID(const std::string& name) const noexcept { auto it = name_to_id.find(name); if (it == name_to_id.end()) { return -1; @@ -169,7 +168,7 @@ unsigned int Engine::Utils::ResourceController::getID(const std::string& name template -inline bool Engine::Utils::ResourceController::isIDValid(unsigned int id){ +inline bool Engine::Utils::ResourceController::isIDValid(unsigned int id) const noexcept { if(id == -1) return false; return data.size() > id; }; @@ -177,7 +176,7 @@ inline bool Engine::Utils::ResourceController::isIDValid(unsigned int id){ template -inline std::string Engine::Utils::ResourceController::getName(unsigned int id){ +inline std::string Engine::Utils::ResourceController::getName(unsigned int id) const noexcept { if(id >= id_to_name.size()) return ""; return id_to_name[id]; }; @@ -185,41 +184,34 @@ inline std::string Engine::Utils::ResourceController::getName(unsigned int id template -inline std::unordered_map Engine::Utils::ResourceController::getNameToID(){ +inline std::unordered_map Engine::Utils::ResourceController::getNameToID() const noexcept { return name_to_id; }; template -bool Engine::Utils::ResourceController::exists(const std::string& name) const { +bool Engine::Utils::ResourceController::exists(const std::string& name) const noexcept { return name_to_id.find(name) != name_to_id.end(); }; template -unsigned int Engine::Utils::ResourceController::size() const{ +unsigned int Engine::Utils::ResourceController::size() const noexcept { return data.size(); }; template -bool Engine::Utils::ResourceController::validateVersion(unsigned int version){ +bool Engine::Utils::ResourceController::validateVersion(unsigned int version) const noexcept { return version == this->version; }; template -unsigned int Engine::Utils::ResourceController::getLatestsVersion(){ +unsigned int Engine::Utils::ResourceController::getLatestsVersion() const noexcept { return version; }; - - - -template -void Engine::Utils::ResourceController::compileAll(){ - for(T& rec : data) rec.compile(); -}; diff --git a/Examples/Game/GameData/Assets/Meshes/Default.msh b/Examples/Game/GameData/Assets/Meshes/Default.msh index 976fac070f13abbe17acd8301e21f3a74e8201a1..fa3567a64bc067453a76e5db929d522394a29f87 100644 GIT binary patch delta 34 scmV+-0Nww;1iu83uag4;Jd>vZTmb=*upN_10S}YV0R@v?0ZNgte9*-U-T(jq delta 20 ccmdnbvY%zb`pJhGYbLuh)=YdIGjY8Q0AKS7L;wH) diff --git a/Examples/Game/GameData/Assets/Meshes/screen_quad.msh b/Examples/Game/GameData/Assets/Meshes/screen_quad.msh index 8f71699d25d83dcd13f90eb1233129e5b0baf839..37d1898a7acd6cbf650781bf53e87b21a5378e31 100644 GIT binary patch delta 12 TcmX@ic$jg5^~83YiPk; Date: Sun, 23 Aug 2026 22:15:54 +0100 Subject: [PATCH 07/13] Resource Tests --- Engine/Core/Core/Objects/GameObject.cpp | 2 +- Engine/Utils/Utils/Resource/Resource.h | 45 +- Engine/Utils/Utils/Resource/Resource.hpp | 99 ++++- .../Utils/Utils/Resource/ResourceController.h | 3 - .../Game/GameData/Assets/Meshes/Default.msh | Bin 575 -> 575 bytes .../GameData/Assets/Meshes/screen_quad.msh | Bin 195 -> 195 bytes Examples/Game/GameData/Objects.obj | Bin 2001 -> 2001 bytes Examples/Game/GameData/Resources.res | Bin 33 -> 33 bytes Tests/CMakeLists.txt | 1 + Tests/Unit/Utils/Resource/Resource.cpp | 417 ++++++++++++++++++ .../Utils/Resource/ResourceController.cpp | 5 +- 11 files changed, 534 insertions(+), 38 deletions(-) create mode 100644 Tests/Unit/Utils/Resource/Resource.cpp diff --git a/Engine/Core/Core/Objects/GameObject.cpp b/Engine/Core/Core/Objects/GameObject.cpp index 3e5c2dc..7aee00b 100644 --- a/Engine/Core/Core/Objects/GameObject.cpp +++ b/Engine/Core/Core/Objects/GameObject.cpp @@ -206,7 +206,7 @@ void Engine::Core::GameObject::render(CW::Renderer::Renderer *renderer, Engine:: mesh_last = copy_game_object_data.mesh; }; - CW::Renderer::Mesh* mesh = this->mesh.get(); + CW::Renderer::Mesh* mesh = this->mesh.getResource(); if(!mesh) return; uniform["projection"]->set(render_camera.projection()); diff --git a/Engine/Utils/Utils/Resource/Resource.h b/Engine/Utils/Utils/Resource/Resource.h index dee201c..10c6149 100644 --- a/Engine/Utils/Utils/Resource/Resource.h +++ b/Engine/Utils/Utils/Resource/Resource.h @@ -19,27 +19,54 @@ namespace Engine::Utils { template class Resource { +// ========================== // +// ========== Data ========== // +// ========================== // private: std::string name = ""; ResourceController* controller = nullptr; unsigned int version = -1; unsigned int id = -1; - bool valid = 1; + + +// ========================== // +// ======== Functions ======= // +// ========================== // +// ================== // +// == Constructors == // +// ================== // public: - Resource() = default; - Resource(const std::string& name, ResourceController* controller); - ~Resource(); - Resource(const Resource& other); - Resource& operator=(const Resource& other); +// core + Resource() noexcept; + Resource(const std::string& name, ResourceController* controller) noexcept; + ~Resource() noexcept; + +// copy + Resource(const Resource& other) noexcept; + Resource& operator=(const Resource& other) noexcept; +// move Resource(Resource&& other) noexcept; Resource& operator=(Resource&& other) noexcept; - T* get(); - void setName(const std::string& name); +// ================== // +// == Data Control == // +// ================== // +public: + T* getResource() noexcept; + + std::string getName() const noexcept; + void setName(const std::string& name) noexcept; + bool nameIsValid() const noexcept; + + void setController(ResourceController* controller) noexcept; + ResourceController* getController() noexcept; +// ================ // +// == Validation == // +// ================ // private: - bool validate(); + bool validate() noexcept; }; }; diff --git a/Engine/Utils/Utils/Resource/Resource.hpp b/Engine/Utils/Utils/Resource/Resource.hpp index 04e1762..20957f3 100644 --- a/Engine/Utils/Utils/Resource/Resource.hpp +++ b/Engine/Utils/Utils/Resource/Resource.hpp @@ -9,87 +9,144 @@ +// ================== // +// == Constructors == // +// ================== // +// core template -Engine::Utils::Resource::Resource(const std::string& name, ResourceController* controller) +Engine::Utils::Resource::Resource() noexcept {}; + + + +template +Engine::Utils::Resource::Resource(const std::string& name, ResourceController* controller) noexcept :name(name), controller(controller) { - valid = validate(); + if(!this->controller) version = -1; + else version = this->controller->getLatestsVersion() - 1; }; template -Engine::Utils::Resource::~Resource() { +Engine::Utils::Resource::~Resource() noexcept { }; +// copy template -Engine::Utils::Resource::Resource(const Resource& other) - :name(other.name), controller(other.controller), version(other.version), id(other.id), valid(other.valid){ -}; +Engine::Utils::Resource::Resource(const Resource& other) noexcept + :name(other.name), + controller(other.controller), + version(other.version), + id(other.id) {}; template -Engine::Utils::Resource& Engine::Utils::Resource::operator=(const Resource &other){ +Engine::Utils::Resource& Engine::Utils::Resource::operator=(const Resource &other) noexcept { + if(this == &other) return *this; + name = other.name; controller = other.controller; version = other.version; id = other.id; - valid = other.valid; return *this; }; +// move template Engine::Utils::Resource::Resource(Resource &&other) noexcept - : name(std::move(other.name)), controller(std::move(other.controller)), version(std::move(other.version)), id(std::move(other.id)), valid(std::move(other.valid)){ + : name(std::move(other.name)), + controller(std::move(other.controller)), + version(std::move(other.version)), + id(std::move(other.id)) { + other.controller = nullptr; }; + template -Engine::Utils::Resource& Engine::Utils::Resource::operator=(Resource &&other) noexcept{ +Engine::Utils::Resource& Engine::Utils::Resource::operator=(Resource &&other) noexcept { + if(this == &other) return *this; + name = std::move(other.name); controller = std::move(other.controller); version = std::move(other.version); id = std::move(other.id); - valid = std::move(other.valid); + other.controller = nullptr; + return *this; }; +// ================== // +// == Data Control == // +// ================== // template -T* Engine::Utils::Resource::get(){ - // if(!valid) return nullptr; - return controller->getResource(controller->getID(name)); +T* Engine::Utils::Resource::getResource() noexcept { + if(!controller) return nullptr; - valid = validate(); + bool valid = validate(); if(!valid) return nullptr; - return nullptr; + return controller->getResource(id); +}; + + + +template +inline std::string Engine::Utils::Resource::getName() const noexcept { + return name; }; template -void Engine::Utils::Resource::setName(const std::string& name){ +inline void Engine::Utils::Resource::setName(const std::string& name) noexcept { this->name = name; - version = controller->getLatestsVersion() - 1; + if(!controller) version = -1; + else version = controller->getLatestsVersion() - 1; }; +template +inline bool Engine::Utils::Resource::nameIsValid() const noexcept { + if(!controller) return false; + return controller->exists(name); +}; + + + +template +inline void Engine::Utils::Resource::setController(Engine::Utils::ResourceController *controller) noexcept { + this->controller = controller; +}; + + + +template +inline Engine::Utils::ResourceController *Engine::Utils::Resource::getController() noexcept { + return controller; +}; + + + +// ================ // +// == Validation == // +// ================ // template -bool Engine::Utils::Resource::validate(){ +bool Engine::Utils::Resource::validate() noexcept { if(!controller) return 0; if(!controller->exists(name)) return 0; - if(!controller->validateVersion(version)){ id = controller->getID(name); version = controller->getLatestsVersion(); @@ -98,4 +155,4 @@ bool Engine::Utils::Resource::validate(){ if(id >= controller->size()) return 0; return 1; -}; \ No newline at end of file +}; diff --git a/Engine/Utils/Utils/Resource/ResourceController.h b/Engine/Utils/Utils/Resource/ResourceController.h index db4a95e..75b0e0e 100644 --- a/Engine/Utils/Utils/Resource/ResourceController.h +++ b/Engine/Utils/Utils/Resource/ResourceController.h @@ -21,9 +21,6 @@ class ResourceController { // ========================== // // ========== Data ========== // // ========================== // -// ================= // -// ====== Core ===== // -// ================= // private: std::vector data; std::unordered_map name_to_id; diff --git a/Examples/Game/GameData/Assets/Meshes/Default.msh b/Examples/Game/GameData/Assets/Meshes/Default.msh index fa3567a64bc067453a76e5db929d522394a29f87..976fac070f13abbe17acd8301e21f3a74e8201a1 100644 GIT binary patch delta 20 ccmdnbvY%zb`pJhGYbLuh)=YdIGjY8Q0AKS7L;wH) delta 34 scmV+-0Nww;1iu83uag4;Jd>vZTmb=*upN_10S}YV0R@v?0ZNgte9*-U-T(jq diff --git a/Examples/Game/GameData/Assets/Meshes/screen_quad.msh b/Examples/Game/GameData/Assets/Meshes/screen_quad.msh index 37d1898a7acd6cbf650781bf53e87b21a5378e31..8f71699d25d83dcd13f90eb1233129e5b0baf839 100644 GIT binary patch delta 12 TcmX@ic$jg5^~7?YiPkm%AWa0Y delta 12 TcmX@ic$jg5^~83YiPk;u>0_g@uj>+sy3X?xFicLPws5E&g5VJE&Gd0*xmS;LP zxr0%fiNRs=dUmo|5SHygDUrzmY+OJo s;mO=ATrjCtR*;nNrZEOpHP5=pWPmW@f1*(>t+`^~`0G*XG`2YX_ delta 156 zcmcb}f02KKFXQBFM$ySGjB=A37&#_CWs;tJk5OgvK1QX<3xHxBj0%(0nf6UCXR~Eu zaG0#ZybY>cX0i<{7hHJ=%XXl+@Z`75+>>uH3s25vL&&wVg5*Rd%LCN|<(M2CCf{XJ Y2HUcYZQ*2Jpf-OtIfSsn +#include +#include +#include + +#define private public +#define protected public + +#include "Utils/Resource/Resource.h" +#include "Utils/Resource/ResourceController.h" + +#undef private +#undef protected + + + +class TestingRes{ +public: + std::string str = ""; + int val_i = 0; + float val_f = 0.0f; + +public: + TestingRes() = default; + TestingRes(const TestingRes& second) noexcept + : str(second.str), + val_i(second.val_i), + val_f(second.val_f) {}; + + TestingRes& operator=(const TestingRes& second) noexcept { + if(this == &second) return *this; + + str = second.str; + val_i = second.val_i; + val_f = second.val_f; + + return *this; + }; + + TestingRes(TestingRes&& second) noexcept + : str(std::move(second.str)), + val_i(std::move(second.val_i)), + val_f(std::move(second.val_f)) {}; + + TestingRes& operator=(TestingRes&& second) noexcept { + if(this == &second) return *this; + + str = std::move(second.str); + val_i = std::move(second.val_i); + val_f = std::move(second.val_f); + + return *this; + }; + + bool operator==(const TestingRes& second) const { + if(str != second.str) return false; + if(val_i != second.val_i) return false; + if(val_f != second.val_f) return false; + return true; + }; +}; + + + +// ================== // +// == Constructors == // +// ================== // +TEST(ResourceDefaultConstructor, HandlesInitialization){ + Engine::Utils::Resource resource; + + EXPECT_EQ(resource.controller, nullptr); + EXPECT_EQ(resource.version, -1); + EXPECT_EQ(resource.id, -1); + EXPECT_EQ(resource.name, ""); + + TestingRes* testing_record = resource.getResource(); + + EXPECT_EQ(resource.controller, nullptr); + EXPECT_EQ(resource.version, -1); + EXPECT_EQ(resource.id, -1); + EXPECT_EQ(resource.name, ""); + EXPECT_EQ(testing_record, nullptr); + + Engine::Utils::ResourceController controller; + TestingRes record = TestingRes(); + std::string testing_str = "Hello"; + std::string testing_name = "Hello"; + record.str = testing_str; + controller.emplace_back(testing_name, record); + resource.setController(&controller); + + EXPECT_NE(resource.controller, nullptr); + EXPECT_EQ(resource.version, -1); + EXPECT_EQ(resource.id, -1); + EXPECT_EQ(resource.name, ""); + + resource.setName(testing_name); + + EXPECT_NE(resource.controller, nullptr); + EXPECT_EQ(resource.version, controller.getLatestsVersion() - 1); + EXPECT_EQ(resource.id, -1); + EXPECT_EQ(resource.name, testing_name); + EXPECT_TRUE(resource.nameIsValid()); + + testing_record = resource.getResource(); + + EXPECT_NE(resource.controller, nullptr); + EXPECT_EQ(resource.version, controller.getLatestsVersion()); + EXPECT_NE(resource.id, -1); + EXPECT_EQ(resource.name, testing_name); + EXPECT_TRUE(resource.nameIsValid()); + EXPECT_TRUE(*testing_record == record); +}; + +TEST(ResourceParamConstructor, HandlesInitialization){ + Engine::Utils::ResourceController controller; + TestingRes record = TestingRes(); + std::string testing_str = "Hello"; + std::string testing_name = "Hello"; + record.str = testing_str; + controller.emplace_back(testing_name, record); + + Engine::Utils::Resource resource(testing_name, &controller); + + EXPECT_NE(resource.controller, nullptr); + EXPECT_EQ(resource.version, controller.getLatestsVersion() - 1); + EXPECT_EQ(resource.id, -1); + EXPECT_EQ(resource.name, testing_name); + EXPECT_TRUE(resource.nameIsValid()); + + TestingRes* testing_record = resource.getResource(); + + EXPECT_NE(resource.controller, nullptr); + EXPECT_EQ(resource.version, controller.getLatestsVersion()); + EXPECT_NE(resource.id, -1); + EXPECT_EQ(resource.name, testing_name); + EXPECT_TRUE(resource.nameIsValid()); + EXPECT_TRUE(*testing_record == record); +}; + +TEST(ResourceCopyConstructor, HandlesInitialization){ + Engine::Utils::ResourceController controller; + TestingRes record = TestingRes(); + std::string testing_str = "Hello"; + std::string testing_name = "Hello"; + record.str = testing_str; + controller.emplace_back(testing_name, record); + + Engine::Utils::Resource resource(testing_name, &controller); + resource.getResource(); + + EXPECT_NE(resource.controller, nullptr); + EXPECT_EQ(resource.version, controller.getLatestsVersion()); + EXPECT_NE(resource.id, -1); + EXPECT_EQ(resource.name, testing_name); + EXPECT_TRUE(resource.nameIsValid()); + + Engine::Utils::Resource resource2(resource); + + EXPECT_EQ(resource.controller, resource2.controller); + EXPECT_EQ(resource.version, resource2.version); + EXPECT_EQ(resource.id, resource2.id); + EXPECT_EQ(resource.name, resource2.name); + EXPECT_TRUE(resource2.nameIsValid()); + + Engine::Utils::Resource resource3 = resource; + + EXPECT_EQ(resource.controller, resource3.controller); + EXPECT_EQ(resource.version, resource3.version); + EXPECT_EQ(resource.id, resource3.id); + EXPECT_EQ(resource.name, resource3.name); + EXPECT_TRUE(resource3.nameIsValid()); + + Engine::Utils::Resource resource4 = resource; + Engine::Utils::Resource* resource4_ptr = &resource4; + resource4 = resource4; + Engine::Utils::Resource* resource4_ptr2 = &resource4; + + EXPECT_EQ(resource4_ptr, resource4_ptr2); + EXPECT_EQ(resource.controller, resource4.controller); + EXPECT_EQ(resource.version, resource4.version); + EXPECT_EQ(resource.id, resource4.id); + EXPECT_EQ(resource.name, resource4.name); + EXPECT_TRUE(resource4.nameIsValid()); +}; + +TEST(ResourceMoveConstructor, HandlesInitialization) { + Engine::Utils::ResourceController controller; + TestingRes record = TestingRes(); + std::string testing_str = "Hello"; + std::string testing_name = "Hello"; + record.str = testing_str; + controller.emplace_back(testing_name, record); + + Engine::Utils::Resource resource(testing_name, &controller); + resource.getResource(); + + EXPECT_NE(resource.controller, nullptr); + EXPECT_EQ(resource.version, controller.getLatestsVersion()); + EXPECT_NE(resource.id, -1); + EXPECT_EQ(resource.name, testing_name); + EXPECT_TRUE(resource.nameIsValid()); + + auto expected_controller = resource.controller; + auto expected_version = resource.version; + auto expected_id = resource.id; + auto expected_name = resource.name; + + Engine::Utils::Resource resource2(std::move(resource)); + + EXPECT_EQ(expected_controller, resource2.controller); + EXPECT_EQ(expected_version, resource2.version); + EXPECT_EQ(expected_id, resource2.id); + EXPECT_EQ(expected_name, resource2.name); + EXPECT_TRUE(resource2.nameIsValid()); + EXPECT_EQ(resource.controller, nullptr); + + Engine::Utils::Resource resource_source(testing_name, &controller); + resource_source.getResource(); + + Engine::Utils::Resource resource3; + resource3 = std::move(resource_source); + + EXPECT_EQ(expected_controller, resource3.controller); + EXPECT_EQ(expected_version, resource3.version); + EXPECT_EQ(expected_id, resource3.id); + EXPECT_EQ(expected_name, resource3.name); + EXPECT_TRUE(resource3.nameIsValid()); + EXPECT_EQ(resource_source.controller, nullptr); + + Engine::Utils::Resource resource4(testing_name, &controller); + resource4.getResource(); + Engine::Utils::Resource* resource4_ptr = &resource4; + resource4 = std::move(resource4); + Engine::Utils::Resource* resource4_ptr2 = &resource4; + + EXPECT_EQ(resource4_ptr, resource4_ptr2); + EXPECT_EQ(expected_controller, resource4.controller); + EXPECT_EQ(expected_version, resource4.version); + EXPECT_EQ(expected_id, resource4.id); + EXPECT_EQ(expected_name, resource4.name); + EXPECT_TRUE(resource4.nameIsValid()); +}; + + + +// ================== // +// == Data Control == // +// ================== // +TEST(ResourceGet, HandlesInitialization) { + Engine::Utils::ResourceController controller; + TestingRes record; + record.str = "ValidResource"; + record.val_i = 42; + std::string resource_name = "Res1"; + controller.emplace_back(resource_name, record); + + Engine::Utils::Resource resource(resource_name, &controller); + + TestingRes* ptr = resource.getResource(); + ASSERT_NE(ptr, nullptr); + EXPECT_EQ(ptr->str, "ValidResource"); + EXPECT_EQ(ptr->val_i, 42); +}; + +TEST(ResourceMassiveResourceGet, HandlesMassiveAddRemove) { + Engine::Utils::ResourceController controller; + + for(int i = 0; i < 500; ++i) { + TestingRes record; + record.str = "Data_" + std::to_string(i); + record.val_i = i; + controller.emplace_back("Res_" + std::to_string(i), record); + }; + + Engine::Utils::Resource res_10("Res_10", &controller); + Engine::Utils::Resource res_250("Res_250", &controller); + Engine::Utils::Resource res_499("Res_499", &controller); + + ASSERT_NE(res_10.getResource(), nullptr); + EXPECT_EQ(res_10.getResource()->val_i, 10); + + ASSERT_NE(res_250.getResource(), nullptr); + EXPECT_EQ(res_250.getResource()->val_i, 250); + + for(int i = 500; i < 1000; ++i) { + TestingRes record; + record.str = "Data_" + std::to_string(i); + record.val_i = i; + controller.emplace_back("Res_" + std::to_string(i), record); + }; + + Engine::Utils::Resource res_800("Res_800", &controller); + + ASSERT_NE(res_10.getResource(), nullptr); + EXPECT_EQ(res_10.getResource()->val_i, 10); + + ASSERT_NE(res_250.getResource(), nullptr); + EXPECT_EQ(res_250.getResource()->val_i, 250); + + ASSERT_NE(res_800.getResource(), nullptr); + EXPECT_EQ(res_800.getResource()->val_i, 800); + + for(int i = 0; i < 200; ++i) controller.erase("Res_" + std::to_string(i)); + + EXPECT_EQ(res_10.getResource(), nullptr); + EXPECT_FALSE(res_10.nameIsValid()); + + ASSERT_NE(res_250.getResource(), nullptr); + EXPECT_EQ(res_250.getResource()->val_i, 250); + + ASSERT_NE(res_499.getResource(), nullptr); + EXPECT_EQ(res_499.getResource()->val_i, 499); + + ASSERT_NE(res_800.getResource(), nullptr); + EXPECT_EQ(res_800.getResource()->val_i, 800); + + for(int i = 400; i < 600; ++i) { + controller.erase("Res_" + std::to_string(i)); + } + + EXPECT_EQ(res_499.getResource(), nullptr); + + ASSERT_NE(res_250.getResource(), nullptr); + EXPECT_EQ(res_250.getResource()->val_i, 250); + + ASSERT_NE(res_800.getResource(), nullptr); + EXPECT_EQ(res_800.getResource()->val_i, 800); +}; + +TEST(ResourceGetNotExisting, HandlesInitialization) { + Engine::Utils::ResourceController controller; + + Engine::Utils::Resource null_ctrl_res("NonExistent", nullptr); + EXPECT_EQ(null_ctrl_res.getResource(), nullptr); + + Engine::Utils::Resource missing_res("NonExistent", &controller); + EXPECT_EQ(missing_res.getResource(), nullptr); + EXPECT_FALSE(missing_res.nameIsValid()); +}; + +TEST(ResourceSetGetName, HandlesInitialization) { + Engine::Utils::ResourceController controller; + TestingRes record1, record2; + record1.str = "First"; + record2.str = "Second"; + + controller.emplace_back("Res1", record1); + controller.emplace_back("Res2", record2); + + Engine::Utils::Resource resource("Res1", &controller); + EXPECT_EQ(resource.getName(), "Res1"); + EXPECT_EQ(resource.getResource()->str, "First"); + + resource.setName("Res2"); + EXPECT_EQ(resource.getName(), "Res2"); + EXPECT_EQ(resource.version, controller.getLatestsVersion() - 1); + EXPECT_EQ(resource.getResource()->str, "Second"); +}; + +TEST(ResourceSetGetController, HandlesInitialization) { + Engine::Utils::ResourceController controller1; + Engine::Utils::ResourceController controller2; + + TestingRes record; + record.str = "Ctrl2Data"; + controller2.emplace_back("SharedName", record); + + Engine::Utils::Resource resource; + EXPECT_EQ(resource.getController(), nullptr); + + resource.setController(&controller1); + EXPECT_EQ(resource.getController(), &controller1); + + resource.setController(&controller2); + resource.setName("SharedName"); + EXPECT_EQ(resource.getController(), &controller2); + ASSERT_NE(resource.getResource(), nullptr); + EXPECT_EQ(resource.getResource()->str, "Ctrl2Data"); +}; + + + +// ================ // +// == Validation == // +// ================ // +TEST(ResourceValidate, HandlesInitialization) { + Engine::Utils::ResourceController controller; + TestingRes record; + record.str = "DynamicRes"; + controller.emplace_back("DynamicRes", record); + + Engine::Utils::Resource resource("DynamicRes", &controller); + + EXPECT_TRUE(resource.validate()); + EXPECT_EQ(resource.version, controller.getLatestsVersion()); + EXPECT_NE(resource.id, -1); + + EXPECT_TRUE(resource.validate()); +}; + +TEST(ResourceValidateNotExisting, HandlesInitialization) { + Engine::Utils::ResourceController controller; + Engine::Utils::Resource resource("Missing", &controller); + + EXPECT_FALSE(resource.validate()); + + resource.setController(nullptr); + EXPECT_FALSE(resource.validate()); +}; \ No newline at end of file diff --git a/Tests/Unit/Utils/Resource/ResourceController.cpp b/Tests/Unit/Utils/Resource/ResourceController.cpp index aa3ecd3..79eaca6 100644 --- a/Tests/Unit/Utils/Resource/ResourceController.cpp +++ b/Tests/Unit/Utils/Resource/ResourceController.cpp @@ -13,7 +13,6 @@ #define private public #define protected public -#include "Utils/Resource/Resource.h" #include "Utils/Resource/ResourceController.h" #undef private @@ -668,6 +667,4 @@ TEST(ResourceControllerValidateVersion, HandlesInitialization){ EXPECT_FALSE(controller.validateVersion(version)); EXPECT_NE(version, controller.getLatestsVersion()); version = controller.validateVersion(version); -}; - -// integration with Resource \ No newline at end of file +}; \ No newline at end of file From 26829d56573269e63aa992c65d85fa3ac6898dad Mon Sep 17 00:00:00 2001 From: Daynlight Date: Mon, 24 Aug 2026 01:49:36 +0100 Subject: [PATCH 08/13] Shaders usues now Resource --- .../Core/DataSerializer/DataSerializer.cpp | 4 ++- .../DataSerializer/ShaderSerialization.cpp | 16 +++++++---- .../Core/DataSerializer/ShaderSerialization.h | 7 ++--- Engine/Core/Core/Objects/GameObject.cpp | 25 +++++++++++++----- Engine/Core/Core/Objects/GameObject.h | 1 + Engine/Core/Core/Resources/Resources.cpp | 24 ++++++++--------- Engine/Core/Core/Resources/Resources.h | 4 +-- Engine/Editor/Editor/UI/UI_Objects.cpp | 3 +-- Engine/Editor/Editor/UI/UI_ShaderEditors.cpp | 25 ++++++++++-------- Engine/Editor/Editor/UI/UI_Shaders.cpp | 7 +++-- .../Game/GameData/Assets/Meshes/Default.msh | Bin 575 -> 575 bytes .../GameData/Assets/Meshes/screen_quad.msh | Bin 195 -> 195 bytes Examples/Game/GameData/Objects.obj | Bin 2001 -> 2001 bytes Examples/Game/GameData/Resources.res | Bin 33 -> 33 bytes vendor/CWindow | 2 +- vendor/googletest | 2 +- 16 files changed, 73 insertions(+), 47 deletions(-) diff --git a/Engine/Core/Core/DataSerializer/DataSerializer.cpp b/Engine/Core/Core/DataSerializer/DataSerializer.cpp index eb7dbe3..856253c 100644 --- a/Engine/Core/Core/DataSerializer/DataSerializer.cpp +++ b/Engine/Core/Core/DataSerializer/DataSerializer.cpp @@ -113,7 +113,9 @@ void Engine::DataSerializer::loadAllMeshes(Engine::Utils::ResourceControllergetRegisterShader().at(type).getSource(); shader_serializer.save(shader_name, type, source, Engine::Core::Resources::get().shaders); }; #endif diff --git a/Engine/Core/Core/DataSerializer/ShaderSerialization.cpp b/Engine/Core/Core/DataSerializer/ShaderSerialization.cpp index 6c73cb6..a22c8aa 100644 --- a/Engine/Core/Core/DataSerializer/ShaderSerialization.cpp +++ b/Engine/Core/Core/DataSerializer/ShaderSerialization.cpp @@ -15,7 +15,7 @@ CMRC_DECLARE(GameData); #ifndef PRODUCTION -void Engine::ShaderSerialization::save(const std::string &shader_name, GLuint type, const std::string& source, std::unordered_map& shaders){ +void Engine::ShaderSerialization::save(const std::string &shader_name, GLuint type, const std::string& source, Engine::Utils::ResourceController& shaders){ Engine::Utils::Logger::get().info("ShaderSerialization", "Saving shader: " + shader_name + " type=" + std::to_string(type)); std::string local_path = Engine::Config::GAME_DATA_FOLDER + Engine::Config::ASSETS_FOLDER + Engine::Config::SHADERS_FOLDER + shader_name + "/" + Engine::Config::SHADER_TYPE_TO_NAME[type]; @@ -43,7 +43,7 @@ void Engine::ShaderSerialization::save(const std::string &shader_name, GLuint ty -void Engine::ShaderSerialization::load(const std::string& shader_name, std::unordered_map& shaders){ +void Engine::ShaderSerialization::load(const std::string& shader_name, Engine::Utils::ResourceController& shaders){ Engine::Utils::Logger::get().info("ShaderSerialization", "Loading shader: " + shader_name); std::string local_path = Engine::Config::GAME_DATA_FOLDER + Engine::Config::ASSETS_FOLDER + Engine::Config::SHADERS_FOLDER + shader_name; CW::Renderer::Shader shader; @@ -74,8 +74,14 @@ void Engine::ShaderSerialization::load(const std::string& shader_name, std::unor }; if(shader.getRegisterShader().size() != 0){ - shaders[shader_name] = std::move(shader); - shaders[shader_name].compile(); + shaders.emplace_back(shader_name, std::move(shader)); + CW::Renderer::Shader* shader_rec = shaders.getResource(shaders.getID(shader_name)); + if(!shader_rec){ + Engine::Utils::Logger::get().erro("ShaderSerialization", "Shader failed to add: " + shader_name); + return; + }; + + shader_rec->compile(); Engine::Utils::Logger::get().info("ShaderSerialization", "Shader loaded: " + shader_name); } else { Engine::Utils::Logger::get().info("ShaderSerialization", "No shader source found for: " + shader_name); @@ -84,7 +90,7 @@ void Engine::ShaderSerialization::load(const std::string& shader_name, std::unor -void Engine::ShaderSerialization::loadAll(std::unordered_map& shaders) { +void Engine::ShaderSerialization::loadAll(Engine::Utils::ResourceController& shaders) { Engine::Utils::Logger::get().info("ShaderSerialization", "Scanning and loading all shaders..."); std::string root_path = Engine::Config::GAME_DATA_FOLDER + Engine::Config::ASSETS_FOLDER + Engine::Config::SHADERS_FOLDER; diff --git a/Engine/Core/Core/DataSerializer/ShaderSerialization.h b/Engine/Core/Core/DataSerializer/ShaderSerialization.h index bb41a0b..21583a1 100644 --- a/Engine/Core/Core/DataSerializer/ShaderSerialization.h +++ b/Engine/Core/Core/DataSerializer/ShaderSerialization.h @@ -18,6 +18,7 @@ #include #endif +#include "Utils/Resource/ResourceController.h" #include "Utils/config.h" #include "Utils/Logger.h" @@ -30,10 +31,10 @@ class ShaderSerialization { ~ShaderSerialization() = default; #ifndef PRODUCTION - void save(const std::string& shader_name, GLuint type, const std::string& source, std::unordered_map& shaders); + void save(const std::string& shader_name, GLuint type, const std::string& source, Engine::Utils::ResourceController& shaders); #endif - void load(const std::string& shader_name, std::unordered_map& shaders); + void load(const std::string& shader_name, Engine::Utils::ResourceController& shaders); - void loadAll(std::unordered_map& shaders); + void loadAll(Engine::Utils::ResourceController& shaders); }; }; // namespace Engine diff --git a/Engine/Core/Core/Objects/GameObject.cpp b/Engine/Core/Core/Objects/GameObject.cpp index 7aee00b..71b55d8 100644 --- a/Engine/Core/Core/Objects/GameObject.cpp +++ b/Engine/Core/Core/Objects/GameObject.cpp @@ -20,7 +20,7 @@ void PatchScriptPointers(std::vector& materials, const std::vector& textures, const std::vector& scripts, glm::vec3 position, glm::vec3 rotation, glm::vec3 scale) - : scripts(scripts), mesh(mesh, &Engine::Core::Resources::get().meshes) { + : scripts(scripts), mesh(mesh, &Engine::Core::Resources::get().meshes), shader(shader, &Engine::Core::Resources::get().shaders) { Engine::Utils::Logger::get().info("GameObject", "GameObject Constructor Called!"); game_object_data.name = name; game_object_data.mesh = mesh; @@ -268,17 +268,28 @@ void Engine::Core::GameObject::render(CW::Renderer::Renderer *renderer, Engine:: }; }; - Engine::Core::Resources::get().getShader(this->copy_game_object_data.shader).getUniforms().emplace_back(&shadows_uniform); - Engine::Core::Resources::get().getShader(this->copy_game_object_data.shader).getUniforms().emplace_back(&uniform); + if(this->copy_game_object_data.shader != shader.getName()){ + shader.setName(this->copy_game_object_data.shader); + }; + + if(!shader.getController()) shader.setController(&Engine::Core::Resources::get().shaders); + CW::Renderer::Shader* render_shader = shader.getResource(); + if(!render_shader) { + Engine::Utils::Logger::get().erro("GameObject", "Failed to find shader"); + return; + }; + + render_shader->getUniforms().emplace_back(&shadows_uniform); + render_shader->getUniforms().emplace_back(&uniform); - Engine::Core::Resources::get().getShader(this->copy_game_object_data.shader).bind(); + render_shader->bind(); std::vector translation; for(std::string el : copy_game_object_data.materials){ translation.emplace_back(Engine::Core::Resources::get().materials.translate_material(el)); }; - GLint loc = glGetUniformLocation(Engine::Core::Resources::get().getShader(copy_game_object_data.shader).getShaderProgram(), "mat_translate"); + GLint loc = glGetUniformLocation(render_shader->getShaderProgram(), "mat_translate"); glUniform1iv(loc, translation.size(), translation.data()); @@ -287,7 +298,7 @@ void Engine::Core::GameObject::render(CW::Renderer::Renderer *renderer, Engine:: else mesh->render(); - Engine::Core::Resources::get().getShader(this->copy_game_object_data.shader).unbind(); + render_shader->unbind(); for(unsigned int i = 0; i < copy_game_object_data.textures.size(); i++) { Engine::Core::Resources::get().getTexture(this->copy_game_object_data.textures[i]).unbind(); @@ -297,7 +308,7 @@ void Engine::Core::GameObject::render(CW::Renderer::Renderer *renderer, Engine:: }; }; - Engine::Core::Resources::get().getShader(this->copy_game_object_data.shader).getUniforms().clear(); + render_shader->getUniforms().clear(); if(copy_game_object_data.gl_depth_lequal) glDepthFunc(GL_LESS); diff --git a/Engine/Core/Core/Objects/GameObject.h b/Engine/Core/Core/Objects/GameObject.h index 189afbe..cb36ebc 100644 --- a/Engine/Core/Core/Objects/GameObject.h +++ b/Engine/Core/Core/Objects/GameObject.h @@ -43,6 +43,7 @@ class GameObject : public Engine::Core::Object{ std::string mesh_last = ""; Engine::Utils::Resource mesh; + Engine::Utils::Resource shader; Engine::ScriptShared::GameObjectData game_object_data; Engine::ScriptShared::GameObjectData copy_game_object_data; diff --git a/Engine/Core/Core/Resources/Resources.cpp b/Engine/Core/Core/Resources/Resources.cpp index a42f749..bf43604 100644 --- a/Engine/Core/Core/Resources/Resources.cpp +++ b/Engine/Core/Core/Resources/Resources.cpp @@ -60,23 +60,23 @@ CW::Renderer::Texture &Engine::Core::Resources::getTexture(const std::string &pa -CW::Renderer::Shader &Engine::Core::Resources::getShader(const std::string &path_to_asset){ - auto it = shaders.find(path_to_asset); +// CW::Renderer::Shader &Engine::Core::Resources::getShader(const std::string &path_to_asset){ + // auto it = shaders.find(path_to_asset); - if (it != shaders.end()) { - return it->second; - } + // if (it != shaders.end()) { + // return it->second; + // } - DataSerializer::get().loadShader(path_to_asset); + // DataSerializer::get().loadShader(path_to_asset); - auto ita = shaders.find(path_to_asset); + // auto ita = shaders.find(path_to_asset); - if (ita != shaders.end()) { - return ita->second; - }; + // if (ita != shaders.end()) { + // return ita->second; + // }; - return shaders[Engine::Config::DEFAULT_SHADER]; -}; + // return shaders[Engine::Config::DEFAULT_SHADER]; +// }; diff --git a/Engine/Core/Core/Resources/Resources.h b/Engine/Core/Core/Resources/Resources.h index 926f08c..c4482a3 100644 --- a/Engine/Core/Core/Resources/Resources.h +++ b/Engine/Core/Core/Resources/Resources.h @@ -40,7 +40,7 @@ class Resources{ }; std::unordered_map textures; - std::unordered_map shaders; + Engine::Utils::ResourceController shaders; Engine::Utils::ResourceController meshes; Engine::Core::Lights lights; Engine::Core::Materials materials; @@ -57,7 +57,7 @@ class Resources{ void destroy(); CW::Renderer::Texture& getTexture(const std::string& path_to_asset); - CW::Renderer::Shader& getShader(const std::string& path_to_asset); + // CW::Renderer::Shader& getShader(const std::string& path_to_asset); private: Resources(); diff --git a/Engine/Editor/Editor/UI/UI_Objects.cpp b/Engine/Editor/Editor/UI/UI_Objects.cpp index f4d9a65..b4d1c29 100644 --- a/Engine/Editor/Editor/UI/UI_Objects.cpp +++ b/Engine/Editor/Editor/UI/UI_Objects.cpp @@ -112,8 +112,7 @@ void Engine::Editor::UI_Objects::guiObjectEditor(){ memcpy(shader_buffer, object.game_object_data.shader.data(), object.game_object_data.shader.size()); shader_buffer[object.game_object_data.shader.size()] = '\0'; if(ImGui::InputText("shader", shader_buffer, Engine::Config::OBJECT_NAME_BUFFER_SIZE)){ - auto its = Engine::Core::Resources::get().shaders.find(shader_buffer); - if(its == Engine::Core::Resources::get().shaders.end()) return; + if(!Engine::Core::Resources::get().shaders.exists(shader_buffer)) return; object.stopScripts(); object.game_object_data.shader = std::string(shader_buffer + '\0'); object.startScripts(scene); diff --git a/Engine/Editor/Editor/UI/UI_ShaderEditors.cpp b/Engine/Editor/Editor/UI/UI_ShaderEditors.cpp index b0874b3..f00d5a8 100644 --- a/Engine/Editor/Editor/UI/UI_ShaderEditors.cpp +++ b/Engine/Editor/Editor/UI/UI_ShaderEditors.cpp @@ -33,10 +33,12 @@ void Engine::Editor::UI_ShaderEditor::guiShaderLoad(const std::string& name, GLe shader_type = type; memset(buffer, '\0', Engine::Config::SHADER_EDITOR_BUFFER_SIZE); - auto it = Engine::Core::Resources::get().shaders.find(name); - if(it == Engine::Core::Resources::get().shaders.end()) return; + if(!Engine::Core::Resources::get().shaders.exists(name)) return; - const std::unordered_map& reg = Engine::Core::Resources::get().getShader(name).getRegisterShader(); + CW::Renderer::Shader* shader = Engine::Core::Resources::get().shaders.getResource(Engine::Core::Resources::get().shaders.getID(name)); + if(!shader) return; + + const std::unordered_map& reg = shader->getRegisterShader(); auto ita = reg.find(type); if(ita == reg.end()) return; @@ -59,10 +61,11 @@ void Engine::Editor::UI_ShaderEditor::guiShaderEditor(){ ImGui::InputTextMultiline("##Shader Content", buffer, Engine::Config::SHADER_EDITOR_BUFFER_SIZE, ImVec2(width, height), ImGuiInputTextFlags_WordWrap); - auto it = Engine::Core::Resources::get().shaders.find(shader_name); - if(it == Engine::Core::Resources::get().shaders.end()) return; - - auto& reg = Engine::Core::Resources::get().getShader(shader_name).getRegisterShader(); + if(!Engine::Core::Resources::get().shaders.exists(shader_name)) return; + CW::Renderer::Shader* shader = Engine::Core::Resources::get().shaders.getResource(Engine::Core::Resources::get().shaders.getID(shader_name)); + if(!shader) return; + + auto& reg = shader->getRegisterShader(); auto it2 = reg.find(shader_type); if(it2 == reg.end()) return; @@ -71,10 +74,10 @@ void Engine::Editor::UI_ShaderEditor::guiShaderEditor(){ if(shader_is_updated){ shader_is_updated = false; - Engine::Core::Resources::get().getShader(shader_name).destroy(); - Engine::Core::Resources::get().getShader(shader_name).removeShaders(shader_type); - Engine::Core::Resources::get().getShader(shader_name).setShader(buffer, shader_type); - Engine::Core::Resources::get().getShader(shader_name).compile(); + shader->destroy(); + shader->removeShaders(shader_type); + shader->setShader(buffer, shader_type); + shader->compile(); DataSerializer::get().saveShaders(shader_name, shader_type); Engine::Utils::Logger::get().info("UI_ShaderEditor", "Saved { " + shader_name + " : " + Engine::Config::SHADER_TYPE_TO_NAME[shader_type] + " }"); diff --git a/Engine/Editor/Editor/UI/UI_Shaders.cpp b/Engine/Editor/Editor/UI/UI_Shaders.cpp index a10ad9f..5e84519 100644 --- a/Engine/Editor/Editor/UI/UI_Shaders.cpp +++ b/Engine/Editor/Editor/UI/UI_Shaders.cpp @@ -68,9 +68,12 @@ void Engine::Editor::UI_Shaders::guiShaderList(){ Engine::Core::Resources::get().shaders.clear(); }; - for (const auto& [ key, values ] : Engine::Core::Resources::get().shaders) { + for (const auto& [ key, values ] : Engine::Core::Resources::get().shaders.getNameToID()) { if(ImGui::CollapsingHeader(key.c_str())){ - for (const auto& [key_s, values_s] : values.getRegisterShader()){ + CW::Renderer::Shader* shader = Engine::Core::Resources::get().shaders.getResource(values); + if(!shader) continue; + + for (const auto& [key_s, values_s] : shader->getRegisterShader()){ std::string button_label = Engine::Config::SHADER_TYPE_TO_NAME[key_s] + "##-" + key; if (ImGui::Button(button_label.c_str())){ bool exists = std::any_of( diff --git a/Examples/Game/GameData/Assets/Meshes/Default.msh b/Examples/Game/GameData/Assets/Meshes/Default.msh index 976fac070f13abbe17acd8301e21f3a74e8201a1..fa3567a64bc067453a76e5db929d522394a29f87 100644 GIT binary patch delta 34 scmV+-0Nww;1iu83uag4;Jd>vZTmb=*upN_10S}YV0R@v?0ZNgte9*-U-T(jq delta 20 ccmdnbvY%zb`pJhGYbLuh)=YdIGjY8Q0AKS7L;wH) diff --git a/Examples/Game/GameData/Assets/Meshes/screen_quad.msh b/Examples/Game/GameData/Assets/Meshes/screen_quad.msh index 8f71699d25d83dcd13f90eb1233129e5b0baf839..37d1898a7acd6cbf650781bf53e87b21a5378e31 100644 GIT binary patch delta 12 TcmX@ic$jg5^~83YiPk;cX0i<{7hHJ=%XXl+@Z`75+>>uH3s25vL&&wVg5*Rd%LCN|<(M2CCf{XJ Y2HUcYZQ*2Jpf-OtIfSsnu>0_g@uj>+sy3X?xFicLPws5E&g5VJE&Gd0*xmS;LP zxr0%fiNRs=dUmo|5SHygDUrzmY+OJo s;mO=ATrjCtR*;nNrZEOpHP5=pWPmW@f1*(>t+`^~`0G*XG`2YX_ diff --git a/Examples/Game/GameData/Resources.res b/Examples/Game/GameData/Resources.res index 752a25619d2dd535c0b71bc8d5cc261850a79c41..950433efd77c5fbee42e7ba5fa8ee3856ecc63be 100644 GIT binary patch literal 33 icmWe-U|?`dEXq}=Q7|+!&@%u7g|vcVptutdGXMZ??FHxn literal 33 icmWe-U|?`dEXq}=Q7|+y)H47Bg|vcVptutdGXMZ?*9GSQ diff --git a/vendor/CWindow b/vendor/CWindow index eb01867..d675d7e 160000 --- a/vendor/CWindow +++ b/vendor/CWindow @@ -1 +1 @@ -Subproject commit eb018671b9d9cdbc5e2e0578c6209978e81e2464 +Subproject commit d675d7e70465b7e1fd6be96804a832fb8b9f2462 diff --git a/vendor/googletest b/vendor/googletest index 91c99b6..7260682 160000 --- a/vendor/googletest +++ b/vendor/googletest @@ -1 +1 @@ -Subproject commit 91c99b6ffecb6f37ca11c25a0db84007c263c1f2 +Subproject commit 7260682388d493f155be62c3ce2efc7c7a9a3dcf From 12e06acfe409c2ac9bfc8af1daddd867e3ed9e23 Mon Sep 17 00:00:00 2001 From: Daynlight Date: Tue, 25 Aug 2026 18:19:41 +0100 Subject: [PATCH 09/13] Resource vs Unordered_map benchmark --- .gitmodules | 3 + Benchmark/CMakeLists.txt | 25 + Benchmark/Utils/Resource.hpp | 436 ++++++++++++++++++ Benchmark/main.cpp | 16 + CMakeLists.txt | 7 + Engine/Utils/Utils/Resource/Resource.hpp | 2 +- .../Utils/Resource/ResourceController.hpp | 12 +- .../Game/GameData/Assets/Meshes/Default.msh | Bin 575 -> 575 bytes .../GameData/Assets/Meshes/screen_quad.msh | Bin 195 -> 195 bytes Examples/Game/GameData/Objects.obj | Bin 2001 -> 2001 bytes Examples/Game/GameData/Resources.res | Bin 33 -> 33 bytes vendor/fmt | 1 + 12 files changed, 495 insertions(+), 7 deletions(-) create mode 100644 Benchmark/CMakeLists.txt create mode 100644 Benchmark/Utils/Resource.hpp create mode 100644 Benchmark/main.cpp create mode 160000 vendor/fmt diff --git a/.gitmodules b/.gitmodules index 896f358..4a4da93 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,3 +9,6 @@ [submodule "vendor/googletest"] path = vendor/googletest url = https://github.com/google/googletest.git +[submodule "vendor/fmt"] + path = vendor/fmt + url = https://github.com/fmtlib/fmt diff --git a/Benchmark/CMakeLists.txt b/Benchmark/CMakeLists.txt new file mode 100644 index 0000000..d51ba62 --- /dev/null +++ b/Benchmark/CMakeLists.txt @@ -0,0 +1,25 @@ +# Engine +# Copyright 2026 Daynlight +# Licensed under the GNU General, Version 3.0. +# See LICENSE file for details. + + + +cmake_minimum_required(VERSION 3.15) +project(Benchmark LANGUAGES CXX) + +set(src + main.cpp +) + +add_executable(Benchmark ${src}) + +target_link_libraries(Benchmark PRIVATE + Utils + fmt +) + +target_include_directories(unit_tests PRIVATE + ${CMAKE_SOURCE_DIR}/Engine/Core + ${CMAKE_SOURCE_DIR}/Engine/Utils +) diff --git a/Benchmark/Utils/Resource.hpp b/Benchmark/Utils/Resource.hpp new file mode 100644 index 0000000..c1d9736 --- /dev/null +++ b/Benchmark/Utils/Resource.hpp @@ -0,0 +1,436 @@ +// Engine +// Copyright 2026 Daynlight +// Licensed under the GNU General, Version 3.0. +// See LICENSE file for details. + + + +#include +#include +#include + +#include +#include +#include +#include + +#include "Utils/Resource/ResourceController.h" +#include "Utils/Resource/Resource.h" + + + +// Unified Interface +template +class BenchmarkingControllerInterface{ +public: + virtual void emplace_back(const std::string& name, const T& record) noexcept = 0; + virtual void emplace_back(const std::string& name, T&& record) noexcept = 0; + virtual void erase(const std::string& name) noexcept = 0; + virtual void clear() noexcept = 0; +}; + +template +class BenchmarkingResourceInterface{ +public: + virtual T* getResource() noexcept = 0; + virtual std::string getName() const noexcept = 0; + virtual void setName(const std::string& name) noexcept = 0; + virtual bool nameIsValid() const noexcept = 0; + virtual void setController(BenchmarkingControllerInterface* controller) noexcept = 0; + virtual BenchmarkingControllerInterface* getController() noexcept = 0; +}; + + + +// unordered_map +template +class BenchmarkingUnorderedMapResourceController : public BenchmarkingControllerInterface { +public: + std::unordered_map data; + +public: + void emplace_back(const std::string& name, const T& record) noexcept{ + data[name] = record; + }; + void emplace_back(const std::string& name, T&& record) noexcept{ + data[name] = std::move(record); + }; + void erase(const std::string& name) noexcept{ + data.erase(name); + }; + void clear() noexcept{ + data.clear(); + }; +}; + +template +class BenchmarkingUnorderedMapResource : public BenchmarkingResourceInterface { +public: + BenchmarkingUnorderedMapResourceController* data; + std::string active_name = ""; + +public: + T* getResource() noexcept { + auto it = data->data.find(active_name); + if(it == data->data.end()) return nullptr; + else return &(data->data[active_name]); + }; + std::string getName() const noexcept{ + return active_name; + }; + void setName(const std::string& name) noexcept{ + active_name = name; + }; + bool nameIsValid() const noexcept{ + auto it = data->data.find(active_name); + if(it == data->data.end()) return false; + return true; + }; + void setController(BenchmarkingControllerInterface* controller) noexcept{ + // data = controller; + }; + BenchmarkingControllerInterface* getController() noexcept{ + return data; + }; +}; + +// resource and resource_controller +template +class BenchmarkingResourceController : public BenchmarkingControllerInterface{ +public: + Engine::Utils::ResourceController controller; +public: + void emplace_back(const std::string& name, const T& record) noexcept{ + controller.emplace_back(name, record); + }; + void emplace_back(const std::string& name, T&& record) noexcept{ + controller.emplace_back(name, std::move(record)); + }; + void erase(const std::string& name) noexcept{ + controller.erase(name); + }; + void clear() noexcept{ + controller.clear(); + }; +}; + +template +class BenchmarkingResource : public BenchmarkingResourceInterface{ +public: + Engine::Utils::Resource resource; + BenchmarkingControllerInterface* controller = nullptr; +public: + T* getResource() noexcept{ + return resource.getResource(); + }; + std::string getName() const noexcept{ + return resource.getName(); + }; + void setName(const std::string& name) noexcept{ + resource.setName(name); + }; + bool nameIsValid() const noexcept{ + return resource.nameIsValid(); + }; + void setController(BenchmarkingControllerInterface* controller) noexcept{ + this->controller = controller; + }; + BenchmarkingControllerInterface* getController() noexcept{ + return controller; + }; +}; + + + +class BenchmarkData{ +public: + int val = 0; + +public: + BenchmarkData() noexcept {}; + ~BenchmarkData() noexcept {}; + BenchmarkData(const BenchmarkData& second) noexcept + : val(second.val) {}; + BenchmarkData& operator=(const BenchmarkData& second) noexcept { + if(this == &second) return *this; + val = second.val; + return *this; + }; + BenchmarkData(BenchmarkData&& second) noexcept + : val(std::move(second.val)) {}; + BenchmarkData& operator=(BenchmarkData&& second) noexcept { + if(this == &second) return *this; + val = std::move(second.val); + return *this; + }; + + bool operator==(const BenchmarkData& second) const noexcept { + if(val != second.val) return false; + return true; + }; +}; + + + +int benchmarkRealWorkloadWithFocusOnGetResource(BenchmarkingControllerInterface& controller, BenchmarkingResourceInterface& resource) { + const unsigned int total_operations = 1000000; + const int key_pool_size = 5000; + + const unsigned int emplace_item_prob = 10; + const unsigned int emplace_move_item_prob = 10 + emplace_item_prob; + const unsigned int set_name_prob = 10 + emplace_move_item_prob; + const unsigned int get_resource_prob = 50 + set_name_prob; + const unsigned int erase_prob = 10 + get_resource_prob; + const unsigned int clear_prob = 10 + erase_prob; + + std::mt19937 rng(42); + std::uniform_int_distribution op_dist(0, 99); + std::uniform_int_distribution key_dist(0, key_pool_size - 1); + std::uniform_int_distribution val_dist(1, 1000000); + + int checksum = 0; + + for (unsigned int i = 0; i < total_operations; ++i) { + const int op = op_dist(rng); + const std::string key = std::to_string(key_dist(rng)); + + if (op < emplace_item_prob) { + BenchmarkData data; + data.val = val_dist(rng); + controller.emplace_back(key, data); + } + else if (op < emplace_move_item_prob) { + BenchmarkData data; + data.val = val_dist(rng); + controller.emplace_back(key, std::move(data)); + } + else if(op < set_name_prob){ + resource.setName(key); + } + else if (op < get_resource_prob) { + BenchmarkData* ptr = resource.getResource(); + if (ptr != nullptr) checksum = checksum + ptr->val; + } + else if (op < erase_prob) { + controller.erase(key); + } + else if(op < clear_prob){ + controller.clear(); + }; + }; + + return checksum; +}; + +int benchmarkEmplaceThenGet(BenchmarkingControllerInterface& controller, BenchmarkingResourceInterface& resource) { + const unsigned int total_operations = 1000000; + const int key_pool_size = 5000; + + std::mt19937 rng(42); + std::uniform_int_distribution op_dist(0, 99); + std::uniform_int_distribution key_dist(0, key_pool_size - 1); + std::uniform_int_distribution val_dist(1, 1000000); + + int checksum = 0; + + for (unsigned int i = 0; i < key_pool_size; ++i) { + const int op = op_dist(rng); + const std::string key = std::to_string(i); + + if (op < 50) { + BenchmarkData data; + data.val = val_dist(rng); + controller.emplace_back(key, data); + } + else { + BenchmarkData data; + data.val = val_dist(rng); + controller.emplace_back(key, std::move(data)); + }; + }; + + for (unsigned int i = 0; i < total_operations; ++i) { + const int op = op_dist(rng); + const std::string key = std::to_string(key_dist(rng)); + + if(op < 5){ + resource.setName(key); + } + else { + BenchmarkData* ptr = resource.getResource(); + if (ptr != nullptr) checksum = checksum + ptr->val; + }; + }; + + return checksum; +}; + +int benchmarkDirectLookup(BenchmarkingControllerInterface& controller, BenchmarkingResourceInterface& resource) { + const unsigned int total_operations = 1000000; + const int key_pool_size = 5000; + + std::mt19937 rng(42); + std::uniform_int_distribution key_dist(0, key_pool_size - 1); + + int checksum = 0; + + for (int i = 0; i < key_pool_size; ++i) { + const std::string key = std::to_string(i); + + BenchmarkData data; + data.val = i; + + controller.emplace_back(key, std::move(data)); + }; + + resource.setName("2500"); + + for (unsigned int i = 0; i < total_operations; ++i) { + BenchmarkData* ptr = resource.getResource(); + if (ptr != nullptr) checksum += ptr->val; + }; + + return checksum; +}; + + + +void benchmarkResourceVSUnorderedMap(){ + { + fmt::println(fg(fmt::color::blue) | fmt::emphasis::bold, "Benchmark Real Workload With Focus On Get Resource"); + std::chrono::duration unordered_map_duration; + std::chrono::duration resource_duration; + int unordered_map_checksum = 0; + int resource_checksum = 0; + + { + std::chrono::time_point test_start = std::chrono::high_resolution_clock::now(); + BenchmarkingUnorderedMapResourceController resource_controller_unordered_map_benchmark; + BenchmarkingUnorderedMapResource resource_unordered_map_benchmark; + resource_unordered_map_benchmark.data = &resource_controller_unordered_map_benchmark; + unordered_map_checksum = benchmarkRealWorkloadWithFocusOnGetResource(resource_controller_unordered_map_benchmark, resource_unordered_map_benchmark); + std::chrono::time_point test_end = std::chrono::high_resolution_clock::now(); + unordered_map_duration = test_end - test_start; + } + + { + std::chrono::time_point test_start = std::chrono::high_resolution_clock::now(); + BenchmarkingResourceController resource_controller_benchmark; + BenchmarkingResource resource_benchmark; + resource_benchmark.resource.setController(&resource_controller_benchmark.controller); + resource_checksum = benchmarkRealWorkloadWithFocusOnGetResource(resource_controller_benchmark, resource_benchmark); + std::chrono::time_point test_end = std::chrono::high_resolution_clock::now(); + resource_duration = test_end - test_start; + } + + if(unordered_map_duration.count() < resource_duration.count()) + fmt::println(fg(fmt::color::green), "Unordered: {}", unordered_map_duration); + else + fmt::println(fg(fmt::color::red), "Unordered: {}", unordered_map_duration); + + if(unordered_map_duration.count() > resource_duration.count()) + fmt::println(fg(fmt::color::green), "Resource: {}", resource_duration); + else + fmt::println(fg(fmt::color::red), "Resource: {}", resource_duration); + + fmt::println(fg(fmt::color::purple), "Unordered - Resource = {}", unordered_map_duration - resource_duration); + fmt::println(fg(fmt::color::purple), "Unordered / Resource = {}", unordered_map_duration / resource_duration); + + fmt::println(fg(fmt::color::yellow), "Unordered checksum = {}", unordered_map_checksum); + fmt::println(fg(fmt::color::yellow), "Resource checksum = {}", resource_checksum); + + fmt::println(""); + } + + { + fmt::println(fg(fmt::color::blue) | fmt::emphasis::bold, "Benchmark Emplace Then Get"); + std::chrono::duration unordered_map_duration; + std::chrono::duration resource_duration; + int unordered_map_checksum = 0; + int resource_checksum = 0; + + { + std::chrono::time_point test_start = std::chrono::high_resolution_clock::now(); + BenchmarkingUnorderedMapResourceController resource_controller_unordered_map_benchmark; + BenchmarkingUnorderedMapResource resource_unordered_map_benchmark; + resource_unordered_map_benchmark.data = &resource_controller_unordered_map_benchmark; + unordered_map_checksum = benchmarkEmplaceThenGet(resource_controller_unordered_map_benchmark, resource_unordered_map_benchmark); + std::chrono::time_point test_end = std::chrono::high_resolution_clock::now(); + unordered_map_duration = test_end - test_start; + } + + { + std::chrono::time_point test_start = std::chrono::high_resolution_clock::now(); + BenchmarkingResourceController resource_controller_benchmark; + BenchmarkingResource resource_benchmark; + resource_benchmark.resource.setController(&resource_controller_benchmark.controller); + resource_checksum = benchmarkEmplaceThenGet(resource_controller_benchmark, resource_benchmark); + std::chrono::time_point test_end = std::chrono::high_resolution_clock::now(); + resource_duration = test_end - test_start; + } + + if(unordered_map_duration.count() < resource_duration.count()) + fmt::println(fg(fmt::color::green), "Unordered: {}", unordered_map_duration); + else + fmt::println(fg(fmt::color::red), "Unordered: {}", unordered_map_duration); + + if(unordered_map_duration.count() > resource_duration.count()) + fmt::println(fg(fmt::color::green), "Resource: {}", resource_duration); + else + fmt::println(fg(fmt::color::red), "Resource: {}", resource_duration); + + fmt::println(fg(fmt::color::purple), "Unordered - Resource = {}", unordered_map_duration - resource_duration); + fmt::println(fg(fmt::color::purple), "Unordered / Resource = {}", unordered_map_duration / resource_duration); + + fmt::println(fg(fmt::color::yellow), "Unordered checksum = {}", unordered_map_checksum); + fmt::println(fg(fmt::color::yellow), "Resource checksum = {}", resource_checksum); + + fmt::println(""); + } + + { + fmt::println(fg(fmt::color::blue) | fmt::emphasis::bold, "Benchmark Direct Lookup"); + std::chrono::duration unordered_map_duration; + std::chrono::duration resource_duration; + int unordered_map_checksum = 0; + int resource_checksum = 0; + + { + std::chrono::time_point test_start = std::chrono::high_resolution_clock::now(); + BenchmarkingUnorderedMapResourceController resource_controller_unordered_map_benchmark; + BenchmarkingUnorderedMapResource resource_unordered_map_benchmark; + resource_unordered_map_benchmark.data = &resource_controller_unordered_map_benchmark; + unordered_map_checksum = benchmarkDirectLookup(resource_controller_unordered_map_benchmark, resource_unordered_map_benchmark); + std::chrono::time_point test_end = std::chrono::high_resolution_clock::now(); + unordered_map_duration = test_end - test_start; + } + + { + std::chrono::time_point test_start = std::chrono::high_resolution_clock::now(); + BenchmarkingResourceController resource_controller_benchmark; + BenchmarkingResource resource_benchmark; + resource_benchmark.resource.setController(&resource_controller_benchmark.controller); + resource_checksum = benchmarkDirectLookup(resource_controller_benchmark, resource_benchmark); + std::chrono::time_point test_end = std::chrono::high_resolution_clock::now(); + resource_duration = test_end - test_start; + } + + if(unordered_map_duration.count() < resource_duration.count()) + fmt::println(fg(fmt::color::green), "Unordered: {}", unordered_map_duration); + else + fmt::println(fg(fmt::color::red), "Unordered: {}", unordered_map_duration); + + if(unordered_map_duration.count() > resource_duration.count()) + fmt::println(fg(fmt::color::green), "Resource: {}", resource_duration); + else + fmt::println(fg(fmt::color::red), "Resource: {}", resource_duration); + + fmt::println(fg(fmt::color::purple), "Unordered - Resource = {}", unordered_map_duration - resource_duration); + fmt::println(fg(fmt::color::purple), "Unordered / Resource = {}", unordered_map_duration / resource_duration); + + fmt::println(fg(fmt::color::yellow), "Unordered checksum = {}", unordered_map_checksum); + fmt::println(fg(fmt::color::yellow), "Resource checksum = {}", resource_checksum); + + fmt::println(""); + } +}; \ No newline at end of file diff --git a/Benchmark/main.cpp b/Benchmark/main.cpp new file mode 100644 index 0000000..c073691 --- /dev/null +++ b/Benchmark/main.cpp @@ -0,0 +1,16 @@ +// Engine +// Copyright 2026 Daynlight +// Licensed under the GNU General, Version 3.0. +// See LICENSE file for details. + + + +#include "Utils/Resource.hpp" + + + +int main(){ + benchmarkResourceVSUnorderedMap(); + + return 0; +}; diff --git a/CMakeLists.txt b/CMakeLists.txt index 82c9241..b6d2ad0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ execute_process( add_subdirectory(vendor/CWindow) add_subdirectory(vendor/cmrc) +add_subdirectory(vendor/fmt) add_subdirectory(vendor/googletest vendor/googletest EXCLUDE_FROM_ALL) @@ -47,6 +48,10 @@ if(NOT PRODUCTION) DESTINATION "${ENGINE_SRC_DEST}" PATTERN "Examples" EXCLUDE) + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/Benchmark" + DESTINATION "${ENGINE_SRC_DEST}" + PATTERN "Examples" EXCLUDE) + file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/vendor" DESTINATION "${ENGINE_SRC_DEST}" PATTERN "Examples" EXCLUDE) @@ -76,6 +81,8 @@ add_subdirectory(Engine) enable_testing() add_subdirectory(Tests) +add_subdirectory(Benchmark) + install(TARGETS Engine DESTINATION bin diff --git a/Engine/Utils/Utils/Resource/Resource.hpp b/Engine/Utils/Utils/Resource/Resource.hpp index 20957f3..9636aa5 100644 --- a/Engine/Utils/Utils/Resource/Resource.hpp +++ b/Engine/Utils/Utils/Resource/Resource.hpp @@ -146,8 +146,8 @@ template bool Engine::Utils::Resource::validate() noexcept { if(!controller) return 0; - if(!controller->exists(name)) return 0; if(!controller->validateVersion(version)){ + if(!controller->exists(name)) return 0; id = controller->getID(name); version = controller->getLatestsVersion(); }; diff --git a/Engine/Utils/Utils/Resource/ResourceController.hpp b/Engine/Utils/Utils/Resource/ResourceController.hpp index 9dbc715..ede3404 100644 --- a/Engine/Utils/Utils/Resource/ResourceController.hpp +++ b/Engine/Utils/Utils/Resource/ResourceController.hpp @@ -76,16 +76,16 @@ inline Engine::Utils::ResourceController &Engine::Utils::ResourceController void Engine::Utils::ResourceController::emplace_back(const std::string& name, const T& record) noexcept { - version += 1; - auto it = name_to_id.find(name); if (it != name_to_id.end()) { data[it->second] = record; } else { + if (data.size() >= data.capacity()) version += 1; + unsigned int new_id = static_cast(data.size()); data.emplace_back(record); - name_to_id[name] = new_id; + name_to_id.emplace_hint(it, name, new_id); id_to_name.push_back(name); }; }; @@ -94,16 +94,16 @@ void Engine::Utils::ResourceController::emplace_back(const std::string& name, template void Engine::Utils::ResourceController::emplace_back(const std::string& name, T&& record) noexcept { - version += 1; - auto it = name_to_id.find(name); if (it != name_to_id.end()) { data[it->second] = std::move(record); } else { + if (data.size() >= data.capacity()) version += 1; + unsigned int new_id = static_cast(data.size()); data.emplace_back(std::move(record)); - name_to_id[name] = new_id; + name_to_id.emplace_hint(it, name, new_id); id_to_name.push_back(name); }; }; diff --git a/Examples/Game/GameData/Assets/Meshes/Default.msh b/Examples/Game/GameData/Assets/Meshes/Default.msh index fa3567a64bc067453a76e5db929d522394a29f87..976fac070f13abbe17acd8301e21f3a74e8201a1 100644 GIT binary patch delta 20 ccmdnbvY%zb`pJhGYbLuh)=YdIGjY8Q0AKS7L;wH) delta 34 scmV+-0Nww;1iu83uag4;Jd>vZTmb=*upN_10S}YV0R@v?0ZNgte9*-U-T(jq diff --git a/Examples/Game/GameData/Assets/Meshes/screen_quad.msh b/Examples/Game/GameData/Assets/Meshes/screen_quad.msh index 37d1898a7acd6cbf650781bf53e87b21a5378e31..8f71699d25d83dcd13f90eb1233129e5b0baf839 100644 GIT binary patch delta 12 TcmX@ic$jg5^~7?YiPkm%AWa0Y delta 12 TcmX@ic$jg5^~83YiPk;u>0_g@uj>+sy3X?xFicLPws5E&g5VJE&Gd0*xmS;LP zxr0%fiNRs=dUmo|5SHygDUrzmY+OJo s;mO=ATrjCtR*;nNrZEOpHP5=pWPmW@f1*(>t+`^~`0G*XG`2YX_ delta 156 zcmcb}f02KKFXQBFM$ySGjB=A37&#_CWs;tJk5OgvK1QX<3xHxBj0%(0nf6UCXR~Eu zaG0#ZybY>cX0i<{7hHJ=%XXl+@Z`75+>>uH3s25vL&&wVg5*Rd%LCN|<(M2CCf{XJ Y2HUcYZQ*2Jpf-OtIfSsn Date: Tue, 25 Aug 2026 21:25:01 +0100 Subject: [PATCH 10/13] Textures now uses Resource --- .../DataSerializer/TextureSerialization.cpp | 152 ++++++++++-------- .../DataSerializer/TextureSerialization.h | 5 +- Engine/Core/Core/Objects/GameObject.cpp | 27 +++- Engine/Core/Core/Objects/GameObject.h | 1 + Engine/Core/Core/Resources/Resources.cpp | 16 +- Engine/Core/Core/Resources/Resources.h | 4 +- .../Game/GameData/Assets/Meshes/Default.msh | Bin 575 -> 575 bytes .../GameData/Assets/Meshes/screen_quad.msh | Bin 195 -> 195 bytes Examples/Game/GameData/Objects.obj | Bin 2001 -> 2001 bytes Examples/Game/GameData/Resources.res | Bin 33 -> 33 bytes vendor/CWindow | 2 +- 11 files changed, 121 insertions(+), 86 deletions(-) diff --git a/Engine/Core/Core/DataSerializer/TextureSerialization.cpp b/Engine/Core/Core/DataSerializer/TextureSerialization.cpp index 7a9c9f4..483ce7e 100644 --- a/Engine/Core/Core/DataSerializer/TextureSerialization.cpp +++ b/Engine/Core/Core/DataSerializer/TextureSerialization.cpp @@ -46,65 +46,70 @@ void Engine::TextureSerialization::save(const std::string& texture_name, const C #endif -void Engine::TextureSerialization::load(const std::string& texture_name, std::unordered_map& textures) { - std::string file_path = Engine::Config::GAME_DATA_FOLDER + Engine::Config::ASSETS_FOLDER + Engine::Config::TEXTURES_FOLDER + texture_name; +void Engine::TextureSerialization::load(const std::string& texture_name, Engine::Utils::ResourceController& textures) { +// std::string file_path = Engine::Config::GAME_DATA_FOLDER + Engine::Config::ASSETS_FOLDER + Engine::Config::TEXTURES_FOLDER + texture_name; -#ifndef PRODUCTION - if (!fs::exists(file_path)) { - Engine::Utils::Logger::get().warn("TextureSerialization", "Texture file not found: " + file_path); - return; - }; - - std::ifstream inFile(file_path); - if (!inFile.is_open()) { - Engine::Utils::Logger::get().erro("TextureSerialization", "Failed to open file: " + file_path); - return; - }; - - if (!std::filesystem::is_directory(file_path)) { - CW::Renderer::TextureLoader loader = CW::Renderer::TextureLoader(file_path); - - textures.emplace(texture_name, CW::Renderer::Texture()).first; - textures[texture_name].compile(loader.data); - } -#else - try { - auto fs = cmrc::GameData::get_filesystem(); +// #ifndef PRODUCTION +// if (!fs::exists(file_path)) { +// Engine::Utils::Logger::get().warn("TextureSerialization", "Texture file not found: " + file_path); +// return; +// }; + +// std::ifstream inFile(file_path); +// if (!inFile.is_open()) { +// Engine::Utils::Logger::get().erro("TextureSerialization", "Failed to open file: " + file_path); +// return; +// }; + +// if (!std::filesystem::is_directory(file_path)) { +// CW::Renderer::TextureLoader loader = CW::Renderer::TextureLoader(file_path); + + +// CW::Renderer::Texture texture_temp = CW::Renderer::Texture(loader.data); +// textures.emplace_back(texture_name, std::move(texture_temp)); + +// } +// #else +// try { +// auto fs = cmrc::GameData::get_filesystem(); - if (fs.exists(file_path)) { - auto file = fs.open(file_path); +// if (fs.exists(file_path)) { +// auto file = fs.open(file_path); - const unsigned char* data_ptr = reinterpret_cast(file.begin()); - CW::Renderer::TextureLoader loader(data_ptr, file.size()); - - textures.emplace(texture_name, CW::Renderer::Texture()).first; - textures[texture_name].compile(loader.data); - } else { - Engine::Utils::Logger::get().warn("TextureSerialization", "Texture file not found in CMRC: " + file_path); - } - } catch (const std::exception& e) { - Engine::Utils::Logger::get().warn("Resources", "[getTexture] CMRC Exception: " + std::string(e.what())); - }; -#endif +// const unsigned char* data_ptr = reinterpret_cast(file.begin()); +// CW::Renderer::TextureLoader loader(data_ptr, file.size()); + + +// CW::Renderer::Texture texture_temp = CW::Renderer::Texture(loader.data); +// textures.emplace_back(texture_name, std::move(texture_temp)); + +// // textures.emplace(texture_name, CW::Renderer::Texture()).first; +// // textures[texture_name].compile(loader.data); +// } else { +// Engine::Utils::Logger::get().warn("TextureSerialization", "Texture file not found in CMRC: " + file_path); +// } +// } catch (const std::exception& e) { +// Engine::Utils::Logger::get().warn("Resources", "[getTexture] CMRC Exception: " + std::string(e.what())); +// }; +// #endif }; -void Engine::TextureSerialization::loadAll(std::unordered_map& textures){ +void Engine::TextureSerialization::loadAll(Engine::Utils::ResourceController& textures) { Engine::Utils::Logger::get().info("DataSerializer", "Scanning and loading all textures..."); std::string root_path = Engine::Config::GAME_DATA_FOLDER + Engine::Config::ASSETS_FOLDER + Engine::Config::TEXTURES_FOLDER; - if (!root_path.empty() && root_path.back() == '/') root_path.pop_back(); #ifndef PRODUCTION try { if (std::filesystem::exists(root_path) && std::filesystem::is_directory(root_path)) { - for (const auto& entry : std::filesystem::directory_iterator(root_path)) { + for (const auto& entry : std::filesystem::recursive_directory_iterator(root_path)) { if (entry.is_regular_file()) { - std::string file_name = entry.path().filename().string(); + std::string relative_path = std::filesystem::relative(entry.path(), root_path).string(); - if (textures.find(file_name) != textures.end()) continue; + if (textures.exists(relative_path)) continue; std::ifstream file(entry.path(), std::ios::binary | std::ios::ate); if (file.is_open()) { @@ -115,50 +120,57 @@ void Engine::TextureSerialization::loadAll(std::unordered_map(buffer.data()), size)) { CW::Renderer::TextureLoader loader(buffer.data(), size); - auto it = textures.emplace(file_name, CW::Renderer::Texture()).first; - it->second.compile(loader.data); - - Engine::Utils::Logger::get().info("DataSerializer", "Loaded texture from Disk: " + file_name); - }; - }; - }; - }; + CW::Renderer::Texture texture_temp(loader.data); + textures.emplace_back(relative_path, std::move(texture_temp)); + + Engine::Utils::Logger::get().info("DataSerializer", "Loaded texture from Disk: " + relative_path); + } + } + } + } } else { Engine::Utils::Logger::get().warn("DataSerializer", "Filesystem - Directory not found: " + root_path); } } catch (const std::filesystem::filesystem_error& e) { Engine::Utils::Logger::get().warn("DataSerializer", "[Filesystem] Could not scan local textures folder: " + std::string(e.what())); - }; + } #else try { auto fs = cmrc::GameData::get_filesystem(); if (fs.exists(root_path)) { - for (auto&& entry : fs.iterate_directory(root_path)) { - if (entry.is_file()) { - std::string file_name = entry.filename(); - - if (textures.find(file_name) != textures.end()) continue; - - std::string full_cmrc_path = root_path + "/" + file_name; - auto file = fs.open(full_cmrc_path); - const unsigned char* data_ptr = reinterpret_cast(file.begin()); - - CW::Renderer::TextureLoader loader(data_ptr, file.size()); - - auto it = textures.emplace(file_name, CW::Renderer::Texture()).first; - it->second.compile(loader.data); - - Engine::Utils::Logger::get().info("DataSerializer", "Loaded texture from CMRC: " + file_name); - }; + std::function scan_cmrc_dir = [&](const std::string& current_dir) { + for (auto&& entry : fs.iterate_directory(current_dir)) { + std::string full_path = current_dir + "/" + entry.filename(); + + if (entry.is_file()) { + std::string relative_path = full_path.substr(root_path.length() + 1); + + if (textures.exists(relative_path)) continue; + + auto file = fs.open(full_path); + const unsigned char* data_ptr = reinterpret_cast(file.begin()); + + CW::Renderer::TextureLoader loader(data_ptr, file.size()); + + CW::Renderer::Texture texture_temp(loader.data); + textures.emplace_back(relative_path, std::move(texture_temp)); + + Engine::Utils::Logger::get().info("DataSerializer", "Loaded texture from CMRC: " + relative_path); + } else if (entry.is_directory()) { + scan_cmrc_dir(full_path); + } + } }; + + scan_cmrc_dir(root_path); } else { Engine::Utils::Logger::get().warn("DataSerializer", "CMRC - Directory not found: " + root_path); } } catch (const std::exception& e) { Engine::Utils::Logger::get().warn("DataSerializer", "[CMRC] Could not scan textures folder: " + std::string(e.what())); - }; + } #endif Engine::Utils::Logger::get().info("DataSerializer", "Finished loading all textures."); -}; \ No newline at end of file +} \ No newline at end of file diff --git a/Engine/Core/Core/DataSerializer/TextureSerialization.h b/Engine/Core/Core/DataSerializer/TextureSerialization.h index ce420b8..4f209e6 100644 --- a/Engine/Core/Core/DataSerializer/TextureSerialization.h +++ b/Engine/Core/Core/DataSerializer/TextureSerialization.h @@ -20,6 +20,7 @@ #include "Utils/config.h" #include "Utils/Logger.h" +#include "Utils/Resource/ResourceController.h" @@ -32,8 +33,8 @@ class TextureSerialization { #ifndef PRODUCTION void save(const std::string& texture_path, const CW::Renderer::Texture& source); #endif - void load(const std::string& texture_path, std::unordered_map& textures); + void load(const std::string& texture_path, Engine::Utils::ResourceController& textures); - void loadAll(std::unordered_map& textures); + void loadAll(Engine::Utils::ResourceController& textures); }; }; // namespace Engine diff --git a/Engine/Core/Core/Objects/GameObject.cpp b/Engine/Core/Core/Objects/GameObject.cpp index 71b55d8..3429d20 100644 --- a/Engine/Core/Core/Objects/GameObject.cpp +++ b/Engine/Core/Core/Objects/GameObject.cpp @@ -253,8 +253,26 @@ void Engine::Core::GameObject::render(CW::Renderer::Renderer *renderer, Engine:: uniform["model"]->set(model); + for(unsigned int i = 0; i < copy_game_object_data.textures.size(); i++){ - Engine::Core::Resources::get().getTexture(this->copy_game_object_data.textures[i]).bind(i); + if(i >= textures.size()) + textures.emplace_back(Engine::Utils::Resource(copy_game_object_data.textures[i], &Engine::Core::Resources::get().textures)); + else{ + if(textures[i].getName() != copy_game_object_data.textures[i]) + textures[i].setName(copy_game_object_data.textures[i]); + if(textures[i].getController() == nullptr) + textures[i].setController(&Engine::Core::Resources::get().textures); + }; + }; + + for(unsigned int i = 0; i < textures.size(); i++){ + CW::Renderer::Texture* txt = textures[i].getResource(); + if(txt == nullptr){ + Engine::Utils::Logger::get().erro("GameObject", "Failed to find texture: " + textures[i].getName()); + continue; + }; + txt->bind(i); + uniform["texture" + std::to_string(i)]->set(i); @@ -300,8 +318,11 @@ void Engine::Core::GameObject::render(CW::Renderer::Renderer *renderer, Engine:: render_shader->unbind(); - for(unsigned int i = 0; i < copy_game_object_data.textures.size(); i++) { - Engine::Core::Resources::get().getTexture(this->copy_game_object_data.textures[i]).unbind(); + for(unsigned int i = 0; i < textures.size(); i++){ + CW::Renderer::Texture* txt = textures[i].getResource(); + if(txt == nullptr) continue; + txt->unbind(); + if(this->copy_game_object_data.gl_nearest){ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); diff --git a/Engine/Core/Core/Objects/GameObject.h b/Engine/Core/Core/Objects/GameObject.h index cb36ebc..71e016b 100644 --- a/Engine/Core/Core/Objects/GameObject.h +++ b/Engine/Core/Core/Objects/GameObject.h @@ -44,6 +44,7 @@ class GameObject : public Engine::Core::Object{ std::string mesh_last = ""; Engine::Utils::Resource mesh; Engine::Utils::Resource shader; + std::vector> textures; Engine::ScriptShared::GameObjectData game_object_data; Engine::ScriptShared::GameObjectData copy_game_object_data; diff --git a/Engine/Core/Core/Resources/Resources.cpp b/Engine/Core/Core/Resources/Resources.cpp index bf43604..dd3510c 100644 --- a/Engine/Core/Core/Resources/Resources.cpp +++ b/Engine/Core/Core/Resources/Resources.cpp @@ -46,17 +46,17 @@ void Engine::Core::Resources::destroy(){ -CW::Renderer::Texture &Engine::Core::Resources::getTexture(const std::string &path_to_asset){ - auto it = textures.find(path_to_asset); - if (it != textures.end()) return it->second; +// CW::Renderer::Texture &Engine::Core::Resources::getTexture(const std::string &path_to_asset){ +// auto it = textures.find(path_to_asset); +// if (it != textures.end()) return it->second; - DataSerializer::get().loadTexture(path_to_asset); +// DataSerializer::get().loadTexture(path_to_asset); - auto ita = textures.find(path_to_asset); - if (ita != textures.end()) return ita->second; +// auto ita = textures.find(path_to_asset); +// if (ita != textures.end()) return ita->second; - return textures[Engine::Config::DEFAULT_TEXTURE]; -}; +// return textures[Engine::Config::DEFAULT_TEXTURE]; +// }; diff --git a/Engine/Core/Core/Resources/Resources.h b/Engine/Core/Core/Resources/Resources.h index c4482a3..6b77767 100644 --- a/Engine/Core/Core/Resources/Resources.h +++ b/Engine/Core/Core/Resources/Resources.h @@ -39,7 +39,7 @@ class Resources{ completed_compilation_paths.push_back(path); }; - std::unordered_map textures; + Engine::Utils::ResourceController textures; Engine::Utils::ResourceController shaders; Engine::Utils::ResourceController meshes; Engine::Core::Lights lights; @@ -56,7 +56,7 @@ class Resources{ void destroy(); - CW::Renderer::Texture& getTexture(const std::string& path_to_asset); + // CW::Renderer::Texture& getTexture(const std::string& path_to_asset); // CW::Renderer::Shader& getShader(const std::string& path_to_asset); private: diff --git a/Examples/Game/GameData/Assets/Meshes/Default.msh b/Examples/Game/GameData/Assets/Meshes/Default.msh index 976fac070f13abbe17acd8301e21f3a74e8201a1..fa3567a64bc067453a76e5db929d522394a29f87 100644 GIT binary patch delta 34 scmV+-0Nww;1iu83uag4;Jd>vZTmb=*upN_10S}YV0R@v?0ZNgte9*-U-T(jq delta 20 ccmdnbvY%zb`pJhGYbLuh)=YdIGjY8Q0AKS7L;wH) diff --git a/Examples/Game/GameData/Assets/Meshes/screen_quad.msh b/Examples/Game/GameData/Assets/Meshes/screen_quad.msh index 8f71699d25d83dcd13f90eb1233129e5b0baf839..37d1898a7acd6cbf650781bf53e87b21a5378e31 100644 GIT binary patch delta 12 TcmX@ic$jg5^~83YiPk;cX0i<{7hHJ=%XXl+@Z`75+>>uH3s25vL&&wVg5*Rd%LCN|<(M2CCf{XJ Y2HUcYZQ*2Jpf-OtIfSsnu>0_g@uj>+sy3X?xFicLPws5E&g5VJE&Gd0*xmS;LP zxr0%fiNRs=dUmo|5SHygDUrzmY+OJo s;mO=ATrjCtR*;nNrZEOpHP5=pWPmW@f1*(>t+`^~`0G*XG`2YX_ diff --git a/Examples/Game/GameData/Resources.res b/Examples/Game/GameData/Resources.res index a99ca8d9e7061fecbf1a30b169769af4139c2052..5cd65c4a2680a697e634d661888934bb40195090 100644 GIT binary patch literal 33 icmWe-U|?`dEXq}=Q7|;L)H47Bg|vcVptutdGXMZ@I0ftg literal 33 icmWe-U|?`dEXq}=Q7|;O&@%u7g|vcVptutdGXMZ@q6P5) diff --git a/vendor/CWindow b/vendor/CWindow index d675d7e..ef5a0c6 160000 --- a/vendor/CWindow +++ b/vendor/CWindow @@ -1 +1 @@ -Subproject commit d675d7e70465b7e1fd6be96804a832fb8b9f2462 +Subproject commit ef5a0c648782e79bedcd0df5eda7c8998339b97e From 17f3f6a366e8921d4bf34c3f0fbef0153a75d4f2 Mon Sep 17 00:00:00 2001 From: Daynlight Date: Tue, 25 Aug 2026 21:43:24 +0100 Subject: [PATCH 11/13] Readme.md --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 190cbeb..deeb01d 100644 --- a/README.md +++ b/README.md @@ -343,6 +343,12 @@ Production is designed to create one executable with no additional files require - [x] CameraController Refactor. - [x] CameraController ActiveCameraCache Avoid Hashing. - [x] CameraController Tests. +- [x] Resource and ResourceController for avoiding hashes. +- [x] Resource and ResourceController benchmark. +- [x] Textures uses Resource and ResourceController. +- [x] Shaders uses Resource and ResourceController. +- [x] Meshes uses Resource and ResourceController. +- [x] Tests for Resource and ResourceController. - [ ] Issue with rotation Camera. - [ ] One Unified Scene Class. - [ ] Scene Save. From 6cb808572e446bf4dee321fe80e69ebdcb6d9bc7 Mon Sep 17 00:00:00 2001 From: Daynlight Date: Tue, 25 Aug 2026 21:46:00 +0100 Subject: [PATCH 12/13] Readme.md --- vendor/googletest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/googletest b/vendor/googletest index 7260682..e273a2d 160000 --- a/vendor/googletest +++ b/vendor/googletest @@ -1 +1 @@ -Subproject commit 7260682388d493f155be62c3ce2efc7c7a9a3dcf +Subproject commit e273a2d81ee3dc263cb58d7a78d403b6791b0b4b From 6abfa2123700b89c94c417b69be466d1a3b9c333 Mon Sep 17 00:00:00 2001 From: Daynlight Date: Tue, 25 Aug 2026 21:51:41 +0100 Subject: [PATCH 13/13] Readme.md --- .../Game/GameData/Assets/Meshes/Default.msh | Bin 575 -> 575 bytes .../GameData/Assets/Meshes/screen_quad.msh | Bin 195 -> 195 bytes Examples/Game/GameData/Objects.obj | Bin 2001 -> 2001 bytes Examples/Game/GameData/Resources.res | Bin 33 -> 33 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Examples/Game/GameData/Assets/Meshes/Default.msh b/Examples/Game/GameData/Assets/Meshes/Default.msh index fa3567a64bc067453a76e5db929d522394a29f87..976fac070f13abbe17acd8301e21f3a74e8201a1 100644 GIT binary patch delta 20 ccmdnbvY%zb`pJhGYbLuh)=YdIGjY8Q0AKS7L;wH) delta 34 scmV+-0Nww;1iu83uag4;Jd>vZTmb=*upN_10S}YV0R@v?0ZNgte9*-U-T(jq diff --git a/Examples/Game/GameData/Assets/Meshes/screen_quad.msh b/Examples/Game/GameData/Assets/Meshes/screen_quad.msh index 37d1898a7acd6cbf650781bf53e87b21a5378e31..8f71699d25d83dcd13f90eb1233129e5b0baf839 100644 GIT binary patch delta 12 TcmX@ic$jg5^~7?YiPkm%AWa0Y delta 12 TcmX@ic$jg5^~83YiPk;u>0_g@uj>+sy3X?xFicLPws5E&g5VJE&Gd0*xmS;LP zxr0%fiNRs=dUmo|5SHygDUrzmY+OJo s;mO=ATrjCtR*;nNrZEOpHP5=pWPmW@f1*(>t+`^~`0G*XG`2YX_ delta 156 zcmcb}f02KKFXQBFM$ySGjB=A37&#_CWs;tJk5OgvK1QX<3xHxBj0%(0nf6UCXR~Eu zaG0#ZybY>cX0i<{7hHJ=%XXl+@Z`75+>>uH3s25vL&&wVg5*Rd%LCN|<(M2CCf{XJ Y2HUcYZQ*2Jpf-OtIfSsn