From 86abf8e5b7de04772598ff591b004f62a3ee9479 Mon Sep 17 00:00:00 2001 From: OusmBlueNinja <89956790+OusmBlueNinja@users.noreply.github.com> Date: Sun, 11 May 2025 22:54:48 -0500 Subject: [PATCH] Added Project Asset Pack file --- imgui.ini | 18 +- src/src/Engine.cpp | 5 + src/src/core/functions/ProjectManager.cpp | 417 +++++++++++++-------- src/src/core/functions/ProjectManager.h | 3 +- src/src/core/functions/SceneSerializer.cpp | 26 +- src/src/core/functions/SceneSerializer.h | 4 +- src/src/core/utils/AssetManager.cpp | 107 +++--- src/src/core/utils/AssetManager.h | 4 + src/src/core/utils/FileDialog.cpp | 1 + src/src/core/utils/FileDialog.h | 1 + src/src/core/utils/Logging.cpp | 2 +- src/vendor/imgui/imconfig.h | 24 +- 12 files changed, 394 insertions(+), 218 deletions(-) diff --git a/imgui.ini b/imgui.ini index eff096c..755fd4e 100644 --- a/imgui.ini +++ b/imgui.ini @@ -27,12 +27,12 @@ DockId=0x0000000F,0 [Window][Viewport] Pos=342,19 -Size=1185,488 +Size=1185,526 Collapsed=0 DockId=0x00000011,0 [Window][##MainMenuBar] -Size=1280,19 +Size=1920,19 Collapsed=0 [Window][Performance Info] @@ -42,8 +42,8 @@ Collapsed=0 DockId=0x00000015,0 [Window][Console] -Pos=342,509 -Size=1185,273 +Pos=342,547 +Size=1185,235 Collapsed=0 DockId=0x00000012,0 @@ -125,8 +125,8 @@ Collapsed=0 DockId=0x0000000D,0 [Window][Resources] -Pos=0,465 -Size=341,712 +Pos=0,19 +Size=341,701 Collapsed=0 DockId=0x00000003,0 @@ -147,7 +147,7 @@ Size=536,391 Collapsed=0 [Window][Create New Project] -Pos=298,22 +Pos=505,191 Size=600,209 Collapsed=0 @@ -208,8 +208,8 @@ DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1920,115 DockNode ID=0x0000001D Parent=0x00000017 SizeRef=1208,763 Split=X Selected=0xC450F867 DockNode ID=0x0000000F Parent=0x0000001D SizeRef=340,399 HiddenTabBar=1 Selected=0x12EF0F59 DockNode ID=0x00000010 Parent=0x0000001D SizeRef=1185,399 Split=Y Selected=0xC450F867 - DockNode ID=0x00000011 Parent=0x00000010 SizeRef=1185,488 CentralNode=1 HiddenTabBar=1 Selected=0xC450F867 - DockNode ID=0x00000012 Parent=0x00000010 SizeRef=1185,273 HiddenTabBar=1 Selected=0xEA83D666 + DockNode ID=0x00000011 Parent=0x00000010 SizeRef=1185,526 CentralNode=1 HiddenTabBar=1 Selected=0xC450F867 + DockNode ID=0x00000012 Parent=0x00000010 SizeRef=1185,235 HiddenTabBar=1 Selected=0xEA83D666 DockNode ID=0x0000001E Parent=0x00000017 SizeRef=1208,393 HiddenTabBar=1 Selected=0x9C2B5678 DockNode ID=0x00000018 Parent=0x00000007 SizeRef=391,860 Split=Y Selected=0x36DC96AB DockNode ID=0x0000001B Parent=0x00000018 SizeRef=367,636 HiddenTabBar=1 Selected=0x36DC96AB diff --git a/src/src/Engine.cpp b/src/src/Engine.cpp index f74cd83..a03192a 100644 --- a/src/src/Engine.cpp +++ b/src/src/Engine.cpp @@ -760,6 +760,11 @@ void Engine::Run() ImGui::Separator(); ImGui::Spacing(); + if (ImGui::MenuItem("Save Project")) + { + Logger::LogInfo("Saving Project."); + ProjectManager::SaveCurrentProject(); + } if (ImGui::MenuItem("Load Project")) { std::string file = OpenFileDialog(FileDialogType::Project); diff --git a/src/src/core/functions/ProjectManager.cpp b/src/src/core/functions/ProjectManager.cpp index fbcd35f..3d9d196 100644 --- a/src/src/core/functions/ProjectManager.cpp +++ b/src/src/core/functions/ProjectManager.cpp @@ -16,7 +16,7 @@ #include #include - +#define ASSET_MANEFEST_NAME "assets.capk" @@ -184,88 +184,102 @@ void FileExplorer::Show(bool* p_open) int cols = std::max(1, int(avail / (iconSize + padding))); ImGui::Columns(cols, nullptr, false); - // Draw each entry for (auto &e : entries) { - fs::path p = e.path(); - std::string pathStr = p.string(); - AssetType type = AssetManager::AssetTypeFromPath(pathStr); + fs::path p = e.path(); + std::string pathStr = p.string(); + AssetType type = AssetManager::AssetTypeFromPath(pathStr); - ImGui::PushID(pathStr.c_str()); + ImGui::PushID(pathStr.c_str()); - // --- IMAGE THUMBNAIL w/ InvisibleButton for clicks --- - if (type == AssetType::Image) { - if (auto* asset = AssetManager::GetAssetByPath(pathStr)) - if (asset->type == AssetType::Image) { - auto* img = dynamic_cast(asset); - if (img) { - if (ImGui::ImageButton("##Image", (ImTextureID)(intptr_t)img->textureID, ImVec2(iconSize, iconSize))) - { - s_currentDir = p; - } - } - } - } - else if (e.is_directory()) { - if (ImGui::ImageButton("##item", - (ImTextureID)(intptr_t)s_folderIcon, - ImVec2(iconSize, iconSize))) - { - s_currentDir = p; - } - } - else { - std::string label; - switch (type) { - case AssetType::Prefab: label = "Prefab"; break; - case AssetType::Scene: label = "Scene"; break; - case AssetType::Audio: label = "Audio"; break; - case AssetType::Script: label = "Script"; break; - case AssetType::Video: label = "Video"; break; - case AssetType::Font: label = "Font"; break; - case AssetType::Shader: label = "Shader"; break; - default: + // 1) pick thumbnail + ImTextureID thumbID = 0; + if (e.is_directory()) { + thumbID = (ImTextureID)(intptr_t)s_folderIcon; + } else if (type == AssetType::Image) { + if (auto* asset = AssetManager::GetAssetByPath(pathStr)) + if (asset->type == AssetType::Image) + if (auto* img = dynamic_cast(asset)) + thumbID = (ImTextureID)(intptr_t)img->textureID; + } + if (!thumbID) { + GLuint iconTex = EngineLoadTextureIfNeeded( + std::string(ICONS_PATH) + IconFileForPath(p)); + thumbID = (ImTextureID)(intptr_t)iconTex; + } + + // 2) DRAW the single widget with a consistent ID: "##entry" + bool clicked = false; + if (e.is_directory() || type == AssetType::Image) { + clicked = ImGui::ImageButton( + "##entry", + thumbID, + ImVec2(iconSize, iconSize)); + } else { + std::string label; + switch (type) { + case AssetType::Prefab: label = "Prefab"; break; + case AssetType::Scene: label = "Scene"; break; + case AssetType::Audio: label = "Audio"; break; + case AssetType::Script: label = "Script"; break; + case AssetType::Video: label = "Video"; break; + case AssetType::Font: label = "Font"; break; + case AssetType::Shader: label = "Shader"; break; + default: label = p.extension().string(); if (!label.empty() && label.front()=='.') label.erase(0,1); break; - } - if (ImGui::Button(label.c_str(), - ImVec2(iconSize, iconSize))) - { - SelectedPath = pathStr; - } } - - if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) { - if (auto* asset = AssetManager::GetAssetByPath(pathStr)) { - if (type == AssetType::Image) - ImGui::SetDragDropPayload(ASSET_TEXTURE, - &asset->uaid, - sizeof(asset->uaid)); - else if (type == AssetType::Prefab) - ImGui::SetDragDropPayload(ASSET_PREFAB, - &asset->uaid, - sizeof(asset->uaid)); - ImGui::TextUnformatted(p.filename().string().c_str()); - } - ImGui::EndDragDropSource(); - } - - if (ImGui::BeginPopupContextItem()) { - if (e.is_directory() && ImGui::MenuItem("Open")) - s_currentDir = p; - if (!e.is_directory() && ImGui::MenuItem("Open File")) - SelectedPath = pathStr; - if (ImGui::MenuItem("Copy Path")) - ImGui::SetClipboardText(pathStr.c_str()); - ImGui::EndPopup(); - } - - ImGui::TextWrapped("%s", p.filename().string().c_str()); - ImGui::NextColumn(); - ImGui::PopID(); + clicked = ImGui::Button( + (std::string("##entry") + label).c_str(), + ImVec2(iconSize, iconSize)); } + // 3) handle click/navigation + if (clicked) { + if (e.is_directory()) + s_currentDir = p; + else + SelectedPath = pathStr; + } + + // 4) context menu tied to the same "##entry" ID + if (ImGui::BeginPopupContextItem("##entry")) { + if (e.is_directory() && ImGui::MenuItem("Open")) + s_currentDir = p; + if (!e.is_directory() && ImGui::MenuItem("Open File")) + SelectedPath = pathStr; + if (ImGui::MenuItem("Copy Path")) + ImGui::SetClipboardText(pathStr.c_str()); + ImGui::EndPopup(); + } + + // 5) drag-drop source also tied to "##entry" + if (!e.is_directory() && + ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + if (auto* asset = AssetManager::GetAssetByPath(pathStr)) { + if (type == AssetType::Image) + ImGui::SetDragDropPayload(ASSET_TEXTURE, + &asset->uaid, + sizeof(asset->uaid)); + else if (type == AssetType::Prefab) + ImGui::SetDragDropPayload(ASSET_PREFAB, + &asset->uaid, + sizeof(asset->uaid)); + } + ImGui::TextUnformatted(p.filename().string().c_str()); + ImGui::EndDragDropSource(); + } + + // 6) label and next column + ImGui::TextWrapped("%s", p.filename().string().c_str()); + ImGui::NextColumn(); + + ImGui::PopID(); +} + + ImGui::Columns(1); ImGui::EndChild(); ImGui::End(); @@ -536,7 +550,7 @@ bool ProjectManager::LoadProject(const std::string &projectFilePath) return false; } - fs::path baseDir = projFile.parent_path(); + fs::path baseDir = projFile.parent_path(); std::string projectName = projFile.stem().string(); YAML::Node config; @@ -549,47 +563,62 @@ bool ProjectManager::LoadProject(const std::string &projectFilePath) return false; } - // Read settings std::string savedName = config["Name"].as(projectName); std::string defaultScene = config["s_defaultScene"].as(""); - Logger::LogInfo("Loading Project: '%s' from '%s'", - savedName.c_str(), projFile.string().c_str()); + Logger::LogDebug("Loading '%s'", + savedName.c_str()); + // update project pointers s_currentProjectPath = baseDir.string(); s_currentProjectName = savedName; + // ensure folders + CreateDirectories(baseDir); + + // --- Load the asset manifest from Assets/asset_manifest.yaml --- + { + fs::path manifest = baseDir / "Assets" / ASSET_MANEFEST_NAME; + if (fs::exists(manifest)) { + YAML::Node doc = YAML::LoadFile(manifest.string()); + if (doc["Assets"]) { + AssetManager::Load(doc["Assets"]); + Logger::LogDebug("Loaded asset manifest: %s", + manifest.string().c_str()); + } + } else { + Logger::LogDebug("No asset manifest found at '%s', skipping.", + manifest.string().c_str()); + } + } + + // finally load the default scene (if any) if (!defaultScene.empty()) { s_defaultScene = ResolveResPath(defaultScene); Logger::LogDebug("Loading Default Scene: %s", s_defaultScene.c_str()); - if (!fs::exists(s_defaultScene)) { Logger::LogError("Default scene does not exist: %s", s_defaultScene.c_str()); return false; } - SceneLoader::LoadScene(s_defaultScene); } - Logger::LogInfo("Successfully loaded project '%s'", savedName.c_str()); - - CreateDirectories(baseDir); - - SceneLoader::LoadScene(s_defaultScene); - + Logger::LogOk("loaded project '%s'", savedName.c_str()); return true; } -bool ProjectManager::CreateProject(const std::string &projectPath, - const std::string &projectName) + +bool ProjectManager::CreateProject( + const std::string &projectPath, + const std::string &projectName) { - fs::path baseDir = fs::path(projectPath) / projectName; + fs::path baseDir = fs::path(projectPath) / projectName; fs::path projFile = baseDir / (projectName + ".cproj"); std::error_code ec; - if (!fs::create_directories(baseDir, ec) && ec) - { + // 1) create project root + if (!fs::create_directories(baseDir, ec) && ec) { Logger::LogError("Failed to create project directory '%s': %s", projectPath.c_str(), ec.message().c_str()); return false; @@ -598,113 +627,205 @@ bool ProjectManager::CreateProject(const std::string &projectPath, s_currentProjectPath = baseDir.string(); s_currentProjectName = projectName; - fs::path scenePath = baseDir / "Assets" / "Scenes" / projectName / ".cene"; + CreateDirectories(baseDir); + fs::path sceneDir = baseDir / "Assets" / "Scenes"; + fs::path sceneFile = sceneDir / (projectName + ".cene"); + s_defaultScene = sceneFile.string(); - s_defaultScene = scenePath.string(); - - // Write .cproj YAML - YAML::Emitter out; - out << YAML::BeginMap; - out << YAML::Key << "Name" << YAML::Value << projectName; - out << YAML::Key << "EngineVersion" << YAML::Value << g_engineConfig.version; - fs::path relPath = fs::relative(scenePath, baseDir); - out << YAML::Key << "s_defaultScene" << YAML::Value << ("res://" + relPath.generic_string()); - - auto now = std::chrono::system_clock::now(); - auto t = std::chrono::system_clock::to_time_t(now); - std::tm tm{}; -#if defined(_WIN32) - gmtime_s(&tm, &t); -#else - gmtime_r(&t, &tm); -#endif - char buf[32]; - std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &tm); - out << YAML::Key << "CreatedDate" << YAML::Value << buf; - out << YAML::EndMap; - - std::ofstream fout(projFile); - if (!fout.is_open()) { - Logger::LogError("Could not open project file for writing: %s", - projFile.string().c_str()); - return false; + YAML::Emitter out; + out << YAML::BeginMap; + out << YAML::Key << "Name" << YAML::Value << projectName; + out << YAML::Key << "EngineVersion" << YAML::Value << g_engineConfig.version; + + fs::path rel = fs::relative(sceneFile, baseDir); + out << YAML::Key << "s_defaultScene" + << YAML::Value << ("res://" + rel.generic_string()); + + auto now = std::chrono::system_clock::now(); + auto t = std::chrono::system_clock::to_time_t(now); + std::tm tm{}; + #if defined(_WIN32) + gmtime_s(&tm, &t); + #else + gmtime_r(&t, &tm); + #endif + char buf[32]; + std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &tm); + out << YAML::Key << "CreatedDate" << YAML::Value << buf; + out << YAML::EndMap; + + std::ofstream fout(projFile); + if (!fout.is_open()) { + Logger::LogError("Could not open project file for writing: %s", + projFile.string().c_str()); + return false; + } + fout << out.c_str(); } - fout << out.c_str(); - fout.close(); Logger::LogOk("Created project '%s' at '%s'", projectName.c_str(), projectPath.c_str()); - CreateDirectories(baseDir); - - SceneLoader::SaveScene(scenePath.string()); - - - SceneLoader::LoadScene(scenePath.string()); + SceneLoader::SaveScene(sceneFile.string()); + SceneLoader::LoadScene(sceneFile.string()); return true; } -bool ProjectManager::SaveProject(const std::string &projectPath, - const std::string &projectName) +bool ProjectManager::SaveCurrentProject() { - fs::path baseDir = fs::path(projectPath) / projectName; + if (s_currentProjectPath.empty() || s_currentProjectName.empty()) + { + Logger::LogError("Cannot save project: no project loaded"); + return false; + } + + fs::path baseDir = fs::path(s_currentProjectPath); + fs::path projFile = baseDir / (s_currentProjectName + ".cproj"); + + { + YAML::Emitter out; + out << YAML::BeginMap; + out << YAML::Key << "Name" << YAML::Value << s_currentProjectName; + out << YAML::Key << "EngineVersion" << YAML::Value << g_engineConfig.version; + + fs::path rel = fs::relative(s_defaultScene, baseDir); + out << YAML::Key << "s_defaultScene" + << YAML::Value << ("res://" + rel.generic_string()); + + auto now = std::chrono::system_clock::now(); + auto t = std::chrono::system_clock::to_time_t(now); + std::tm tm{}; + #if defined(_WIN32) + gmtime_s(&tm, &t); + #else + gmtime_r(&t, &tm); + #endif + char buf[32]; + std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &tm); + out << YAML::Key << "CreatedDate" << YAML::Value << buf; + out << YAML::EndMap; + + std::ofstream fout(projFile); + if (!fout.is_open()) + { + Logger::LogError("Could not open project file for writing: %s", + projFile.string().c_str()); + return false; + } + fout << out.c_str(); + } + + Logger::LogOk("Saved project"); + + CreateDirectories(baseDir); + + { + fs::path manifest = baseDir / "Assets" / ASSET_MANEFEST_NAME; + YAML::Emitter manOut; + manOut << YAML::BeginMap; + AssetManager::Save(manOut); + manOut << YAML::EndMap; + + std::ofstream mf(manifest); + if (!mf.is_open()) + { + Logger::LogError("Failed to write asset manifest: %s", + manifest.string().c_str()); + } + else + { + mf << manOut.c_str(); + Logger::LogDebug("Wrote asset manifest: %s", + manifest.string().c_str()); + } + } + + return true; +} + + + +bool ProjectManager::SaveProject( + const std::string &projectPath, + const std::string &projectName) +{ + fs::path baseDir = fs::path(projectPath) / projectName; fs::path projFile = baseDir / (projectName + ".cproj"); std::error_code ec; - if (!fs::create_directories(baseDir, ec) && ec) - { + if (!fs::create_directories(baseDir, ec) && ec) { Logger::LogError("Failed to create project directory '%s': %s", projectPath.c_str(), ec.message().c_str()); return false; } - - YAML::Emitter out; out << YAML::BeginMap; - out << YAML::Key << "Name" << YAML::Value << projectName; - out << YAML::Key << "EngineVersion" << YAML::Value << g_engineConfig.version; - fs::path relPath = fs::relative(s_defaultScene, - fs::path(s_currentProjectPath) / s_currentProjectName); - out << YAML::Key << "s_defaultScene" << YAML::Value << ("res://" + relPath.generic_string()); + out << YAML::Key << "Name" << YAML::Value << projectName; + out << YAML::Key << "EngineVersion" << YAML::Value << g_engineConfig.version; + fs::path sceneRel = fs::relative(s_defaultScene, + fs::path(s_currentProjectPath) / s_currentProjectName); + out << YAML::Key << "s_defaultScene" + << YAML::Value << ("res://" + sceneRel.generic_string()); + + // timestamp auto now = std::chrono::system_clock::now(); - auto t = std::chrono::system_clock::to_time_t(now); + auto t = std::chrono::system_clock::to_time_t(now); std::tm tm{}; -#if defined(_WIN32) + #if defined(_WIN32) gmtime_s(&tm, &t); -#else + #else gmtime_r(&t, &tm); -#endif + #endif char buf[32]; std::strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", &tm); out << YAML::Key << "CreatedDate" << YAML::Value << buf; out << YAML::EndMap; std::ofstream fout(projFile); - if (!fout.is_open()) - { + if (!fout.is_open()) { Logger::LogError("Could not open project file for writing: %s", projFile.string().c_str()); return false; } fout << out.c_str(); fout.close(); - - Logger::LogOk("Saved project '%s' at '%s'", - projectName.c_str(), projectPath.c_str()); + Logger::LogOk("Saved project '%s'", + projectName.c_str()); CreateDirectories(baseDir); + { + fs::path manifest = baseDir / "Assets" / ASSET_MANEFEST_NAME; + YAML::Emitter assetOut; + assetOut << YAML::BeginMap; + AssetManager::Save(assetOut); + assetOut << YAML::EndMap; + + std::ofstream mf(manifest); + if (!mf.is_open()) { + Logger::LogError("Failed to write asset manifest: %s", + manifest.string().c_str()); + } else { + mf << assetOut.c_str(); + mf.close(); + Logger::LogDebug("Wrote asset manifest: %s", + manifest.string().c_str()); + } + } + + // update our in-memory project pointers s_currentProjectPath = projectPath; s_currentProjectName = projectName; return true; } + const std::string &ProjectManager::GetCurrentProjectPath() { return s_currentProjectPath; diff --git a/src/src/core/functions/ProjectManager.h b/src/src/core/functions/ProjectManager.h index eb48a3b..1866b7f 100644 --- a/src/src/core/functions/ProjectManager.h +++ b/src/src/core/functions/ProjectManager.h @@ -57,7 +57,6 @@ private: static std::string IconFileForPath(const fs::path &path); static void DrawFolderTree(const fs::path &path); - // Initializes file queue by scanning res:// recursively static void InitLoading(); }; @@ -76,6 +75,8 @@ public: static bool SaveProject(const std::string& projectPath, const std::string& projectName); + static bool SaveCurrentProject(); + // Creates a project at the path with the name // makes a .cproj file at the path in the name folder static bool CreateProject(const std::string& projectPath, diff --git a/src/src/core/functions/SceneSerializer.cpp b/src/src/core/functions/SceneSerializer.cpp index d055a90..b15c166 100644 --- a/src/src/core/functions/SceneSerializer.cpp +++ b/src/src/core/functions/SceneSerializer.cpp @@ -38,7 +38,7 @@ bool VerifySceneHash(const YAML::Node &root) return hashHex.str() == root["scene_hash"].as(); } -void SceneLoader::SaveScene(const std::string &path) +void SceneLoader::SaveScene(const std::string &path, bool standalone) { YAML::Emitter out; YAML::Emitter sceneData; @@ -78,7 +78,8 @@ void SceneLoader::SaveScene(const std::string &path) out << YAML::Key << "threshold" << YAML::Value << Renderer::GetColorCorrection()->threshold; out << YAML::EndMap; - //AssetManager::Save(out); + if (standalone) + AssetManager::Save(out); out << YAML::EndMap; @@ -88,7 +89,7 @@ void SceneLoader::SaveScene(const std::string &path) Logger::LogOk("Scene Saved"); } -void SceneLoader::LoadScene(const std::string &path) +void SceneLoader::LoadScene(const std::string &path, bool standalone) { bool legacyLoad = false; @@ -152,16 +153,17 @@ void SceneLoader::LoadScene(const std::string &path) { Logger::LogWarning("Scene hash does not match! File may be corrupted or tampered."); } + if (standalone) { + if (root["Assets"]) + { + currentStep = "Loading Assets"; + currentDetail = "Parsing asset data..."; + loadingUI.Update(currentStep, currentDetail, 0.05f); - //if (root["Assets"]) - //{ - // currentStep = "Loading Assets"; - // currentDetail = "Parsing asset data..."; - // loadingUI.Update(currentStep, currentDetail, 0.05f); - // - // Logger::LogDebug("Loading Assets"); - // AssetManager::Load(root["Assets"]); - //} + Logger::LogDebug("Loading Assets"); + AssetManager::Load(root["Assets"]); + } + } Logger::LogDebug("Reseting Scene."); currentStep = "Clearing Previous Scene"; diff --git a/src/src/core/functions/SceneSerializer.h b/src/src/core/functions/SceneSerializer.h index b7b5ce2..49211ad 100644 --- a/src/src/core/functions/SceneSerializer.h +++ b/src/src/core/functions/SceneSerializer.h @@ -5,7 +5,7 @@ class SceneLoader { public: - static void SaveScene(const std::string &path); - static void LoadScene(const std::string &path); + static void SaveScene(const std::string &path, bool standalone = false); + static void LoadScene(const std::string &path, bool standalone = false); }; diff --git a/src/src/core/utils/AssetManager.cpp b/src/src/core/utils/AssetManager.cpp index 9301409..980d848 100644 --- a/src/src/core/utils/AssetManager.cpp +++ b/src/src/core/utils/AssetManager.cpp @@ -9,6 +9,8 @@ #include #include "../../Entitys/Object.h" +#include "../../core/functions/ProjectManager.h" + #include #include FT_FREETYPE_H @@ -21,6 +23,10 @@ std::unordered_map AssetManager::s_PathToUAID; uint64_t AssetManager::s_NextUAID = 1; + + + + std::string AssetManager::GetFileExtension(const std::string& filepath) { std::string ext = fs::path(filepath).extension().string(); // ".PNG" @@ -600,19 +606,29 @@ void AssetManager::ClearAllAssets() } +namespace fs = std::filesystem; + void AssetManager::Save(YAML::Emitter &out) { + // Write out each asset’s UAID and a res:// path out << YAML::Key << "Assets" << YAML::BeginSeq; + fs::path projectRoot = fs::path(ProjectManager::GetCurrentProjectPath()); for (const auto &[uaid, asset] : s_Assets) { + // compute res:// relative path + fs::path fullPath = asset->path; + fs::path rel = fs::relative(fullPath, projectRoot); + std::string resPath = std::string("res://") + rel.generic_string(); + out << YAML::BeginMap; - out << YAML::Key << "uaid" << YAML::Value << asset->uaid; - out << YAML::Key << "path" << YAML::Value << asset->path; + out << YAML::Key << "uaid" << YAML::Value << asset->uaid; + out << YAML::Key << "path" << YAML::Value << resPath; out << YAML::Key << "filename" << YAML::Value << asset->filename; out << YAML::Key << "filetype" << YAML::Value << asset->filetype; - out << YAML::Key << "type" << YAML::Value << static_cast(asset->type); - out << YAML::Key << "hash" << YAML::Value << asset->hash; + out << YAML::Key << "type" << YAML::Value << static_cast(asset->type); + out << YAML::Key << "hash" << YAML::Value << asset->hash; out << YAML::Key << "lastModified" << YAML::Value << asset->lastModified; + // let each subclass dump its own data asset->Save(out); out << YAML::EndMap; } @@ -621,66 +637,69 @@ void AssetManager::Save(YAML::Emitter &out) void AssetManager::Load(const YAML::Node &node) { - if (!node) - return; + if (!node) return; LoadingWindow loadingUI; loadingUI.Create("Loading Assets"); + fs::path projectRoot = fs::path(ProjectManager::GetCurrentProjectPath()); const size_t total = node.size(); size_t index = 0; for (const auto &item : node) { + // 1) read the res:// path and convert to real FS path + std::string resPath = item["path"].as(); + std::string fsPath = ProjectManager::ResolveResPath(resPath); - uint64_t uaid = item["uaid"].as(); - std::string path = item["path"].as(); - AssetType type = static_cast(item["type"].as()); + uint64_t uaid = item["uaid"].as(); + AssetType type = static_cast(item["type"].as()); + // 2) allocate the right subclass std::shared_ptr asset; - if (type == AssetType::Image) - asset = std::make_shared(); - else if (type == AssetType::Audio) - asset = std::make_shared(); - else if (type == AssetType::Prefab) - asset = std::make_shared(); - else if (type == AssetType::Font) - asset = std::make_shared(); - else - continue; + switch (type) { + case AssetType::Image: asset = std::make_shared(); break; + case AssetType::Audio: asset = std::make_shared(); break; + case AssetType::Prefab: asset = std::make_shared(); break; + case AssetType::Font: asset = std::make_shared(); break; + default: continue; + } - float progress = static_cast(index) / total; - loadingUI.Update("Loading Asset", path, progress); + // 3) progress UI + float progress = static_cast(index++) / total; + loadingUI.Update("Loading Asset", fsPath, progress); - asset->uaid = uaid; - asset->path = path; - asset->filename = item["filename"] ? item["filename"].as() : GetFilenameFromPath(path); - asset->filetype = item["filetype"] ? item["filetype"].as() : GetFileExtension(path); - asset->hash = item["hash"] ? item["hash"].as() : ""; + // 4) populate fields + asset->uaid = uaid; + asset->path = fsPath; // now points at real file + asset->filename = item["filename"] ? item["filename"].as() + : GetFilenameFromPath(fsPath); + asset->filetype = item["filetype"] ? item["filetype"].as() + : GetFileExtension(fsPath); + asset->hash = item["hash"] ? item["hash"].as() : ""; asset->lastModified = item["lastModified"] ? item["lastModified"].as() : 0; - asset->loaded = false; + asset->loaded = false; + // 5) subclass‐specific load asset->Load(item); - s_Assets[uaid] = asset; - s_PathToUAID[path] = uaid; + // 6) insert into maps + s_Assets [uaid] = asset; + s_PathToUAID[asset->path] = uaid; + if (uaid >= s_NextUAID) s_NextUAID = uaid + 1; - if (uaid >= s_NextUAID) - s_NextUAID = uaid + 1; - - if (type == AssetType::Image) - LoadImageInternal(path, uaid); - else if (type == AssetType::Audio) - LoadAudioInternal(path, uaid); - else if (type == AssetType::Prefab) - LoadPrefabInternal(path, uaid); - else if (type == AssetType::Font) - LoadFontInternal(path, uaid); - else - Logger::LogError("[Engine Error] Unhandled Internal Asset Loading. %s", AssetTypeToString(type)); - - ++index; + // 7) internal loading + switch (type) { + case AssetType::Image: LoadImageInternal(fsPath, uaid); break; + case AssetType::Audio: LoadAudioInternal(fsPath, uaid); break; + case AssetType::Prefab: LoadPrefabInternal(fsPath, uaid); break; + case AssetType::Font: LoadFontInternal(fsPath, uaid); break; + default: + Logger::LogError("[Engine Error] Unhandled asset type %s", + AssetTypeToString(type)); + } } + loadingUI.Destroy(); } diff --git a/src/src/core/utils/AssetManager.h b/src/src/core/utils/AssetManager.h index 7d79760..10b6280 100644 --- a/src/src/core/utils/AssetManager.h +++ b/src/src/core/utils/AssetManager.h @@ -158,6 +158,10 @@ public: static uint64_t GenerateUAID(); + bool SaveManifest(const std::string &manifestPath); + bool LoadManifest(const std::string &manifestPath); + + static std::string GetFileExtension(const std::string& filepath); static AssetType AssetTypeFromExtension(std::string ext); diff --git a/src/src/core/utils/FileDialog.cpp b/src/src/core/utils/FileDialog.cpp index 808ecf8..f4426fe 100644 --- a/src/src/core/utils/FileDialog.cpp +++ b/src/src/core/utils/FileDialog.cpp @@ -25,6 +25,7 @@ static std::unordered_map filters = { { FileDialogType::Fonts, "Font Files\0*.ttf;*.otf;*.fnt\0All Files\0*.*\0" }, { FileDialogType::Models, "3D Models\0*.obj;*.fbx;*.gltf;*.dae\0All Files\0*.*\0" }, { FileDialogType::Project, "Project File\0*.cproj\0All Files\0*.*\0" }, + { FileDialogType::AssetManifests, "Asset Manifest Files\0*.cmanifest;*.assetmanifest;*.yaml\0All Files\0*.*\0" }, { FileDialogType::All, "All Files\0*.*\0" } }; diff --git a/src/src/core/utils/FileDialog.h b/src/src/core/utils/FileDialog.h index f0aaecb..98cc46d 100644 --- a/src/src/core/utils/FileDialog.h +++ b/src/src/core/utils/FileDialog.h @@ -14,6 +14,7 @@ enum class FileDialogType { Fonts, // .ttf, .otf Models, // .obj, .fbx, .gltf, etc. Project, + AssetManifests, All }; diff --git a/src/src/core/utils/Logging.cpp b/src/src/core/utils/Logging.cpp index 1a7fef0..05f6dcf 100644 --- a/src/src/core/utils/Logging.cpp +++ b/src/src/core/utils/Logging.cpp @@ -56,7 +56,7 @@ bool Logger::s_ShowWarning = true; bool Logger::s_ShowError = true; bool Logger::s_ShowDebug = false; bool Logger::s_ShowVerbose = false; -bool Logger::s_PrintToTerminal = true; +bool Logger::s_PrintToTerminal = false; const char *Logger::ToString(Level level) { diff --git a/src/vendor/imgui/imconfig.h b/src/vendor/imgui/imconfig.h index a1e29e8..a8ae48f 100644 --- a/src/vendor/imgui/imconfig.h +++ b/src/vendor/imgui/imconfig.h @@ -16,7 +16,29 @@ //---- Define assertion handler. Defaults to calling assert(). // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. -//#define IM_ASSERT(_EXPR) MyAssert(_EXPR) + +#include + +static inline void ImGuiAssertHandler(const char* expr, const char* file, int line) +{ + std::fprintf(stderr, + "Assertion failed: (%s), at %s:%d\n", + expr, file, line); +#if defined(_MSC_VER) + __debugbreak(); // MSVC +#elif defined(__GNUC__) || defined(__clang__) + __builtin_trap(); // GCC / Clang +#else + std::abort(); // Fallback +#endif +} + +#undef IM_ASSERT +#define IM_ASSERT(_EXPR) \ +do { \ +if (!(_EXPR)) \ +ImGuiAssertHandler(#_EXPR, __FILE__, __LINE__); \ +} while (0) //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows