From 89e98d0f88e91a08e17cee097f3c8847eb1651ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20B=C3=B6ckelmann?= Date: Tue, 21 Apr 2026 09:05:09 +0200 Subject: [PATCH] ADD: Upload Intermediate Assets to GPU, closes #18 --- CMakeLists.txt | 16 ++++- src/engine/renderer/loader/AssetManager.cpp | 29 ++++++++ src/engine/renderer/loader/AssetManager.h | 6 ++ src/engine/renderer/loader/OBJLoader.cpp | 18 +++++ src/engine/renderer/loader/OBJLoader.h | 1 + src/engine/renderer/loader/TextureLoader.h | 2 +- .../renderer/loader/async/AssetLoader.cpp | 70 +++++++++++++++---- .../renderer/loader/async/AssetLoader.h | 7 +- src/main.cpp | 4 ++ 9 files changed, 137 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da784f7..09f4d72 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ FetchContent_Declare( GIT_REPOSITORY https://github.com/catchorg/Catch2.git GIT_TAG v3.7.1 ) -FetchContent_MakeAvailable(Catch2) + add_executable(LayoutEngineTests tests/layout/LayoutEngineTest.cpp @@ -38,7 +38,18 @@ target_include_directories(LayoutEngineTests PRIVATE src lib/glm ) -target_link_libraries(LayoutEngineTests PRIVATE Catch2::Catch2WithMain) + +include(FetchContent) + +FetchContent_Declare( + spdlog + GIT_REPOSITORY https://github.com/gabime/spdlog.git + GIT_TAG v1.17.0 +) + +FetchContent_MakeAvailable(Catch2 spdlog) + +target_link_libraries(LayoutEngineTests PRIVATE Catch2::Catch2WithMain spdlog::spdlog) include(CTest) include(Catch) @@ -322,6 +333,7 @@ if(BUILD_GAME) glad OpenGL::GL ${FREETYPE_LIBRARIES} + spdlog::spdlog ) endif() diff --git a/src/engine/renderer/loader/AssetManager.cpp b/src/engine/renderer/loader/AssetManager.cpp index a66fd66..8496357 100644 --- a/src/engine/renderer/loader/AssetManager.cpp +++ b/src/engine/renderer/loader/AssetManager.cpp @@ -12,6 +12,7 @@ #include "json.hpp" #include "OBJLoader.h" +#include "spdlog/spdlog.h" namespace fs = std::filesystem; using namespace nlohmann; @@ -122,6 +123,34 @@ std::shared_ptr AssetManager::loadUiTheme(const std::string &themeName, } } +void AssetManager::insertLoadedTexture(const std::string &name, const Texture2D &texture) { + if (textures.contains(name)) { + spdlog::warn("Texture '{}' already exists, skipping insert", name); + return; + } + + textures[name] = std::make_shared(texture.id); + spdlog::debug("Texture '{}' inserted successfully", name); +} + +void AssetManager::insertTexturedModel(const std::string &name, const TexturedModel &textured_model) { + if (models.contains(name)) { + spdlog::warn("Model '{}' already exists, skipping insert", name); + return; + } + + models[name] = std::make_shared(textured_model); + spdlog::debug("Model '{}' inserted successfully", name); +} + +void AssetManager::insertModelStages(const std::string &name, ModelStages modelStages) { + if (modelsWithStages.contains(name)) { + spdlog::warn("Asset '{}' already has stages, skipping insert", name); + return; + } + + modelsWithStages[name] = std::make_shared(modelStages); +} json AssetManager::readJsonFile(const std::string &path) { diff --git a/src/engine/renderer/loader/AssetManager.h b/src/engine/renderer/loader/AssetManager.h index 95dca62..7d356f0 100644 --- a/src/engine/renderer/loader/AssetManager.h +++ b/src/engine/renderer/loader/AssetManager.h @@ -10,6 +10,7 @@ #include "json.hpp" #include "../model/TexturedModel.h" #include "Loader.h" +#include "Texture2D.h" #include "../../core/gui/text/UiTheme.h" #include "../model/ModelStages.h" @@ -28,6 +29,11 @@ public: static std::shared_ptr getTexture(const std::string& texturePath); static std::shared_ptr getUiTheme(const std::string& themeName); static std::shared_ptr loadUiTheme(const std::string& themeName, const std::string& themePath); + + static void insertLoadedTexture(const std::string& name, const Texture2D& texture); + static void insertTexturedModel(const std::string & name, const TexturedModel & textured_model); + static void insertModelStages(const std::string &name, ModelStages modelStages); + private: static inline std::unordered_map> models; static inline std::unordered_map> modelsWithStages; diff --git a/src/engine/renderer/loader/OBJLoader.cpp b/src/engine/renderer/loader/OBJLoader.cpp index 473eeb9..8cbc9ff 100644 --- a/src/engine/renderer/loader/OBJLoader.cpp +++ b/src/engine/renderer/loader/OBJLoader.cpp @@ -158,3 +158,21 @@ RawModelData OBJLoader::loadModel(const std::string &modelPath) { } return {"", subModels}; } + +TexturedModel OBJLoader::uploadToGPU(RawModelData &rawModelData) { + Loader loader = Loader::instance(); + + std::vector subModels; + for (const auto&[vertices, normals, textureCoords, indices, textures] : rawModelData.subModels) { + RawModel rawModel = loader.loadToVAO(vertices, normals, textureCoords, indices); + + RawTextureData textureData = textures[0].textureData; + const Texture2D texture = TextureLoader::uploadToGPU(textureData); + + auto modelTexture = ModelTexture(texture.id); + auto subModel = SubModel(std::make_shared(rawModel), std::make_shared(modelTexture)); + subModels.push_back(subModel); + } + + return TexturedModel(subModels); +} diff --git a/src/engine/renderer/loader/OBJLoader.h b/src/engine/renderer/loader/OBJLoader.h index face3a7..2b4134d 100644 --- a/src/engine/renderer/loader/OBJLoader.h +++ b/src/engine/renderer/loader/OBJLoader.h @@ -16,6 +16,7 @@ class OBJLoader { public: static std::shared_ptr loadModel(const std::string &modelPath, const std::string &texturePath, Loader &loader); static RawModelData loadModel(const std::string &modelPath); + static TexturedModel uploadToGPU(RawModelData &rawModelData); }; diff --git a/src/engine/renderer/loader/TextureLoader.h b/src/engine/renderer/loader/TextureLoader.h index eeeb67a..e34ef00 100644 --- a/src/engine/renderer/loader/TextureLoader.h +++ b/src/engine/renderer/loader/TextureLoader.h @@ -18,7 +18,7 @@ public: static Texture2D loadTexture(const std::string& path, bool flipVertically= true); static RawTextureData loadRawTextureData(const std::string &path, bool flipVertically = true); static TextureData loadTextureData(const std::string &path, bool flipVertically = true, TextureType textureType); - static Texture2D uploadToGPU(RawTextureData& rawTextureData); + static Texture2D uploadToGPU(RawTextureData &rawTextureData); static Texture2D uploadToGPU(TextureData& textureData); static void free(Texture2D& texture); }; diff --git a/src/engine/renderer/loader/async/AssetLoader.cpp b/src/engine/renderer/loader/async/AssetLoader.cpp index 36fd4c2..bfde971 100644 --- a/src/engine/renderer/loader/async/AssetLoader.cpp +++ b/src/engine/renderer/loader/async/AssetLoader.cpp @@ -53,15 +53,7 @@ void AssetLoader::stop() { } } -std::vector AssetLoader::processUploadQueue(int maxPerFrame) { - std::vector results; - std::lock_guard lock(readyMutex); - for (int i = 0; i < maxPerFrame && !readyQueue.empty(); ++i) { - results.push_back(std::move(readyQueue.front())); - readyQueue.pop(); - } - return results; -} + LoadingProgress AssetLoader::getProgress() const { return {total.load(), loaded.load()}; @@ -84,8 +76,8 @@ void AssetLoader::loadingThreadFunc() { pendingQueue.pop(); } - IntermediateAsset result = std::visit([](auto& req) -> IntermediateAsset { - using T = std::decay_t; + IntermediateAsset result = std::visit([](T0& req) -> IntermediateAsset { + using T = std::decay_t; if constexpr (std::is_same_v) { return processTextureRequest(req); } else if constexpr (std::is_same_v) { @@ -98,7 +90,6 @@ void AssetLoader::loadingThreadFunc() { { std::lock_guard lock(readyMutex); readyQueue.push(std::move(result)); - ++loaded; } } } @@ -151,6 +142,61 @@ nlohmann::json AssetLoader::loadJson(const std::string &path) { return nlohmann::json::object(); } +void AssetLoader::processUploadQueue(int maxPerFrame) { + auto uploadQueue = determineUploadQueue(maxPerFrame); + for (const auto& intermediateAsset : uploadQueue) { + std::visit([](T0& rawData) -> IntermediateAsset { + using T = std::decay_t; + if constexpr (std::is_same_v) { + return processIntermediateTextureAsset(rawData); + } else if constexpr (std::is_same_v) { + return processIntermediateModelAsset(rawData); + } else { + return processIntermediateStagedModelAsset(rawData); + } + }, intermediateAsset); + ++loaded; + } +} + +std::vector AssetLoader::determineUploadQueue(const int maxPerFrame) { + std::vector results; + std::lock_guard lock(readyMutex); + for (int i = 0; i < maxPerFrame && !readyQueue.empty(); ++i) { + results.push_back(std::move(readyQueue.front())); + readyQueue.pop(); + } + + return results; +} + +void AssetLoader::processIntermediateTextureAsset(RawTextureData &textureData) { + const Texture2D texture = TextureLoader::uploadToGPU(textureData); + AssetManager::insertLoadedTexture(textureData.name, texture); +} + +void AssetLoader::processIntermediateModelAsset(RawModelData &modelData) { + const TexturedModel texturedModel = OBJLoader::uploadToGPU(modelData); + AssetManager::insertTexturedModel(modelData.name, texturedModel); +} + +void AssetLoader::processIntermediateStagedModelAsset(const RawStagedModelData &stagedModelData) { + ModelStages modelStages; + for (const auto&[stageName, conditionKey, minValue, maxValue, modelData] : stagedModelData.stages) { + RawModelData rawModelData = modelData; + processIntermediateModelAsset(rawModelData); + + const auto model = AssetManager::getModel(stageName); + const auto condition = ModelStageCondition(conditionKey, minValue, maxValue); + auto modelStageConfiguration = ModelStageConfiguration(model, stageName, condition); + modelStages.addModelStage(modelStageConfiguration); + } + + AssetManager::insertModelStages(stagedModelData.name, modelStages); +} + + + diff --git a/src/engine/renderer/loader/async/AssetLoader.h b/src/engine/renderer/loader/async/AssetLoader.h index 76a5d3e..d430bd9 100644 --- a/src/engine/renderer/loader/async/AssetLoader.h +++ b/src/engine/renderer/loader/async/AssetLoader.h @@ -59,7 +59,7 @@ public: void start(); void stop(); - std::vector processUploadQueue(int maxPerFrame); + void processUploadQueue(int maxPerFrame); LoadingProgress getProgress() const; @@ -70,6 +70,11 @@ private: static RawModelData processModelRequest(const ModelRequest& request); static RawStagedModelData processStagedModelRequest(const StagedModelRequest& request); static nlohmann::json loadJson(const std::string& path); + std::vector determineUploadQueue(int maxPerFrame); + + static void processIntermediateTextureAsset(RawTextureData &textureData); + static void processIntermediateModelAsset(RawModelData &modelData); + static void processIntermediateStagedModelAsset(const RawStagedModelData &stagedModelData); // Render-Thread schreibt, Loading Thread liest std::queue pendingQueue; diff --git a/src/main.cpp b/src/main.cpp index a8f447a..617294e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,6 +2,7 @@ #include "engine/core/Application.h" #include "game/DicewarsApp.h" +#include "spdlog/spdlog-inl.h" // TIP To Run code, press or click the icon in the gutter. Application* CreateApplication() @@ -9,6 +10,9 @@ Application* CreateApplication() return new DicewarsApp(); } int main() { + spdlog::set_level(spdlog::level::debug); // oder info für Release + spdlog::set_pattern("[%H:%M:%S] [%^%l%$] %v"); + auto app = CreateApplication(); app->run(); delete app;