Added Project Asset Pack file
This commit is contained in:
parent
6a29c5bdee
commit
86abf8e5b7
18
imgui.ini
18
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
|
||||
|
@ -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);
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
#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<const ImageAssetInfo*>(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<const ImageAssetInfo*>(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<std::string>(projectName);
|
||||
std::string defaultScene = config["s_defaultScene"].as<std::string>("");
|
||||
|
||||
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;
|
||||
|
@ -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,
|
||||
|
@ -38,7 +38,7 @@ bool VerifySceneHash(const YAML::Node &root)
|
||||
return hashHex.str() == root["scene_hash"].as<std::string>();
|
||||
}
|
||||
|
||||
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";
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <stb_image.h>
|
||||
#include "../../Entitys/Object.h"
|
||||
|
||||
#include "../../core/functions/ProjectManager.h"
|
||||
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
@ -21,6 +23,10 @@ std::unordered_map<std::string, uint64_t> 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<int>(asset->type);
|
||||
out << YAML::Key << "hash" << YAML::Value << asset->hash;
|
||||
out << YAML::Key << "type" << YAML::Value << static_cast<int>(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>();
|
||||
std::string fsPath = ProjectManager::ResolveResPath(resPath);
|
||||
|
||||
uint64_t uaid = item["uaid"].as<uint64_t>();
|
||||
std::string path = item["path"].as<std::string>();
|
||||
AssetType type = static_cast<AssetType>(item["type"].as<int>());
|
||||
uint64_t uaid = item["uaid"].as<uint64_t>();
|
||||
AssetType type = static_cast<AssetType>(item["type"].as<int>());
|
||||
|
||||
// 2) allocate the right subclass
|
||||
std::shared_ptr<AssetInfo> asset;
|
||||
if (type == AssetType::Image)
|
||||
asset = std::make_shared<ImageAssetInfo>();
|
||||
else if (type == AssetType::Audio)
|
||||
asset = std::make_shared<AudioAssetInfo>();
|
||||
else if (type == AssetType::Prefab)
|
||||
asset = std::make_shared<PrefabAssetInfo>();
|
||||
else if (type == AssetType::Font)
|
||||
asset = std::make_shared<FontAssetInfo>();
|
||||
else
|
||||
continue;
|
||||
switch (type) {
|
||||
case AssetType::Image: asset = std::make_shared<ImageAssetInfo>(); break;
|
||||
case AssetType::Audio: asset = std::make_shared<AudioAssetInfo>(); break;
|
||||
case AssetType::Prefab: asset = std::make_shared<PrefabAssetInfo>(); break;
|
||||
case AssetType::Font: asset = std::make_shared<FontAssetInfo>(); break;
|
||||
default: continue;
|
||||
}
|
||||
|
||||
float progress = static_cast<float>(index) / total;
|
||||
loadingUI.Update("Loading Asset", path, progress);
|
||||
// 3) progress UI
|
||||
float progress = static_cast<float>(index++) / total;
|
||||
loadingUI.Update("Loading Asset", fsPath, progress);
|
||||
|
||||
asset->uaid = uaid;
|
||||
asset->path = path;
|
||||
asset->filename = item["filename"] ? item["filename"].as<std::string>() : GetFilenameFromPath(path);
|
||||
asset->filetype = item["filetype"] ? item["filetype"].as<std::string>() : GetFileExtension(path);
|
||||
asset->hash = item["hash"] ? item["hash"].as<std::string>() : "";
|
||||
// 4) populate fields
|
||||
asset->uaid = uaid;
|
||||
asset->path = fsPath; // now points at real file
|
||||
asset->filename = item["filename"] ? item["filename"].as<std::string>()
|
||||
: GetFilenameFromPath(fsPath);
|
||||
asset->filetype = item["filetype"] ? item["filetype"].as<std::string>()
|
||||
: GetFileExtension(fsPath);
|
||||
asset->hash = item["hash"] ? item["hash"].as<std::string>() : "";
|
||||
asset->lastModified = item["lastModified"] ? item["lastModified"].as<std::time_t>() : 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();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -25,6 +25,7 @@ static std::unordered_map<FileDialogType, const char*> 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" }
|
||||
};
|
||||
|
||||
|
@ -14,6 +14,7 @@ enum class FileDialogType {
|
||||
Fonts, // .ttf, .otf
|
||||
Models, // .obj, .fbx, .gltf, etc.
|
||||
Project,
|
||||
AssetManifests,
|
||||
All
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
24
src/vendor/imgui/imconfig.h
vendored
24
src/vendor/imgui/imconfig.h
vendored
@ -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 <cstdio>
|
||||
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user