Added Project Manager mostly, just need to make a Asset Metadata save file so you can reload assets
This commit is contained in:
parent
bb3ea1ba2c
commit
6a29c5bdee
4
.idea/material_theme_project_new.xml
generated
4
.idea/material_theme_project_new.xml
generated
@ -3,7 +3,9 @@
|
||||
<component name="MaterialThemeProjectNewConfig">
|
||||
<option name="metadata">
|
||||
<MTProjectMetadataState>
|
||||
<option name="userId" value="-126d4bf4:196bd985816:-7fff" />
|
||||
<option name="migrated" value="true" />
|
||||
<option name="pristineConfig" value="false" />
|
||||
<option name="userId" value="-126d4bf4:196bd985816:-7ffe" />
|
||||
</MTProjectMetadataState>
|
||||
</option>
|
||||
</component>
|
||||
|
127
imgui.ini
127
imgui.ini
@ -14,74 +14,74 @@ Size=1920,1158
|
||||
Collapsed=0
|
||||
|
||||
[Window][Inspector]
|
||||
Pos=1553,19
|
||||
Size=367,537
|
||||
Pos=1529,19
|
||||
Size=391,636
|
||||
Collapsed=0
|
||||
DockId=0x0000001B,0
|
||||
|
||||
[Window][Scene Tree]
|
||||
Pos=0,19
|
||||
Size=341,444
|
||||
Size=340,763
|
||||
Collapsed=0
|
||||
DockId=0x0000000F,0
|
||||
|
||||
[Window][Viewport]
|
||||
Pos=343,19
|
||||
Size=1208,659
|
||||
Pos=342,19
|
||||
Size=1185,488
|
||||
Collapsed=0
|
||||
DockId=0x00000017,0
|
||||
DockId=0x00000011,0
|
||||
|
||||
[Window][##MainMenuBar]
|
||||
Size=1920,19
|
||||
Size=1280,19
|
||||
Collapsed=0
|
||||
|
||||
[Window][Performance Info]
|
||||
Pos=1628,680
|
||||
Size=292,268
|
||||
Pos=1587,794
|
||||
Size=333,220
|
||||
Collapsed=0
|
||||
DockId=0x00000019,0
|
||||
DockId=0x00000015,0
|
||||
|
||||
[Window][Console]
|
||||
Pos=343,680
|
||||
Size=1207,497
|
||||
Pos=342,509
|
||||
Size=1185,273
|
||||
Collapsed=0
|
||||
DockId=0x00000013,0
|
||||
DockId=0x00000012,0
|
||||
|
||||
[Window][Tilemap Editor]
|
||||
Pos=265,19
|
||||
Size=1263,674
|
||||
Collapsed=0
|
||||
DockId=0x00000017,1
|
||||
DockId=0x00000011,1
|
||||
|
||||
[Window][Profiler]
|
||||
Pos=343,955
|
||||
Size=1232,222
|
||||
Collapsed=0
|
||||
DockId=0x00000011,0
|
||||
DockId=0x00000008,0
|
||||
|
||||
[Window][Profiler Timeline]
|
||||
Pos=265,69
|
||||
Size=623,651
|
||||
Collapsed=0
|
||||
DockId=0x00000015,1
|
||||
DockId=0x00000008,1
|
||||
|
||||
[Window][Profiler (Unity Style)]
|
||||
Pos=265,430
|
||||
Size=623,290
|
||||
Collapsed=0
|
||||
DockId=0x00000015,1
|
||||
DockId=0x00000008,1
|
||||
|
||||
[Window][Profiler Timeline View]
|
||||
Pos=265,526
|
||||
Size=1263,651
|
||||
Collapsed=0
|
||||
DockId=0x00000015,1
|
||||
DockId=0x00000008,1
|
||||
|
||||
[Window][Color Correction]
|
||||
Pos=1628,950
|
||||
Size=292,227
|
||||
Pos=1587,1016
|
||||
Size=333,161
|
||||
Collapsed=0
|
||||
DockId=0x0000001A,0
|
||||
DockId=0x00000016,0
|
||||
|
||||
[Window][Asset Browser]
|
||||
Pos=0,658
|
||||
@ -113,10 +113,10 @@ Collapsed=0
|
||||
DockId=0x0000000E,0
|
||||
|
||||
[Window][Audio Output]
|
||||
Pos=1552,680
|
||||
Size=74,497
|
||||
Pos=1529,794
|
||||
Size=56,383
|
||||
Collapsed=0
|
||||
DockId=0x00000014,0
|
||||
DockId=0x00000019,0
|
||||
|
||||
[Window][Master Bus]
|
||||
Pos=1003,570
|
||||
@ -128,7 +128,7 @@ DockId=0x0000000D,0
|
||||
Pos=0,465
|
||||
Size=341,712
|
||||
Collapsed=0
|
||||
DockId=0x00000010,0
|
||||
DockId=0x00000003,0
|
||||
|
||||
[Window][Import Preview]
|
||||
Pos=584,22
|
||||
@ -136,10 +136,10 @@ Size=550,695
|
||||
Collapsed=0
|
||||
|
||||
[Window][Lua Globals]
|
||||
Pos=1553,558
|
||||
Size=367,120
|
||||
Pos=1529,657
|
||||
Size=391,135
|
||||
Collapsed=0
|
||||
DockId=0x0000001C,0
|
||||
DockId=0x00000013,0
|
||||
|
||||
[Window][Import Assets]
|
||||
Pos=626,263
|
||||
@ -151,6 +151,17 @@ Pos=298,22
|
||||
Size=600,209
|
||||
Collapsed=0
|
||||
|
||||
[Window][File Explorer]
|
||||
Pos=0,784
|
||||
Size=1527,393
|
||||
Collapsed=0
|
||||
DockId=0x0000001E,0
|
||||
|
||||
[Window][ConfirmClearScene]
|
||||
Pos=808,551
|
||||
Size=304,75
|
||||
Collapsed=0
|
||||
|
||||
[Table][0x96376740,2]
|
||||
RefScale=13
|
||||
Column 0 Weight=1.0000
|
||||
@ -186,33 +197,35 @@ Column 1 Width=86
|
||||
Column 2 Weight=1.0000
|
||||
|
||||
[Docking][Data]
|
||||
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1920,1158 Split=X
|
||||
DockNode ID=0x00000005 Parent=0x11111111 SizeRef=989,1158 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=341,701 Split=Y Selected=0x12EF0F59
|
||||
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=342,637 Split=Y Selected=0x12EF0F59
|
||||
DockNode ID=0x0000000F Parent=0x00000003 SizeRef=341,444 HiddenTabBar=1 Selected=0x12EF0F59
|
||||
DockNode ID=0x00000010 Parent=0x00000003 SizeRef=341,712 HiddenTabBar=1 Selected=0x30401527
|
||||
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=342,519 HiddenTabBar=1 Selected=0x36AF052B
|
||||
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1577,701 Split=Y Selected=0xC450F867
|
||||
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,659 Split=X Selected=0xC450F867
|
||||
DockNode ID=0x00000017 Parent=0x00000007 SizeRef=1208,860 CentralNode=1 HiddenTabBar=1 Selected=0xC450F867
|
||||
DockNode ID=0x00000018 Parent=0x00000007 SizeRef=367,860 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x0000001B Parent=0x00000018 SizeRef=367,537 HiddenTabBar=1 Selected=0x36DC96AB
|
||||
DockNode ID=0x0000001C Parent=0x00000018 SizeRef=367,120 HiddenTabBar=1 Selected=0x8CFF897F
|
||||
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,497 Split=X Selected=0xEA83D666
|
||||
DockNode ID=0x00000015 Parent=0x00000008 SizeRef=1283,172 Split=X Selected=0xEA83D666
|
||||
DockNode ID=0x00000011 Parent=0x00000015 SizeRef=1206,168 HiddenTabBar=1 Selected=0x9B5D3198
|
||||
DockNode ID=0x00000012 Parent=0x00000015 SizeRef=75,168 Split=X Selected=0x56009A08
|
||||
DockNode ID=0x00000013 Parent=0x00000012 SizeRef=1207,497 Selected=0xEA83D666
|
||||
DockNode ID=0x00000014 Parent=0x00000012 SizeRef=74,497 HiddenTabBar=1 Selected=0x56009A08
|
||||
DockNode ID=0x00000016 Parent=0x00000008 SizeRef=292,172 Split=Y Selected=0x3FC1A724
|
||||
DockNode ID=0x00000019 Parent=0x00000016 SizeRef=314,268 HiddenTabBar=1 Selected=0x3FC1A724
|
||||
DockNode ID=0x0000001A Parent=0x00000016 SizeRef=314,227 HiddenTabBar=1 Selected=0xA873C17F
|
||||
DockNode ID=0x00000006 Parent=0x11111111 SizeRef=289,1158 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x00000009 Parent=0x00000006 SizeRef=449,488 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x0000000B Parent=0x00000009 SizeRef=449,556 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x0000000D Parent=0x0000000B SizeRef=449,860 Selected=0x36DC96AB
|
||||
DockNode ID=0x0000000E Parent=0x0000000B SizeRef=449,296 HiddenTabBar=1 Selected=0x9D7E7171
|
||||
DockNode ID=0x0000000C Parent=0x00000009 SizeRef=449,143 HiddenTabBar=1 Selected=0xB6C74292
|
||||
DockNode ID=0x0000000A Parent=0x00000006 SizeRef=449,211 HiddenTabBar=1 Selected=0xD83E5DD3
|
||||
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1920,1158 Split=X
|
||||
DockNode ID=0x00000005 Parent=0x11111111 SizeRef=989,1158 Split=X
|
||||
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=341,701 Split=Y Selected=0x12EF0F59
|
||||
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=342,637 HiddenTabBar=1 Selected=0x12EF0F59
|
||||
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=342,519 HiddenTabBar=1 Selected=0x36AF052B
|
||||
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1577,701 Split=Y Selected=0xC450F867
|
||||
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,684 Split=X Selected=0xC450F867
|
||||
DockNode ID=0x00000017 Parent=0x00000007 SizeRef=1184,860 Split=Y Selected=0xC450F867
|
||||
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=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
|
||||
DockNode ID=0x0000001C Parent=0x00000018 SizeRef=367,520 Split=Y Selected=0x8CFF897F
|
||||
DockNode ID=0x00000013 Parent=0x0000001C SizeRef=367,135 HiddenTabBar=1 Selected=0x8CFF897F
|
||||
DockNode ID=0x00000014 Parent=0x0000001C SizeRef=367,383 Split=X Selected=0x56009A08
|
||||
DockNode ID=0x00000019 Parent=0x00000014 SizeRef=56,70 HiddenTabBar=1 Selected=0x56009A08
|
||||
DockNode ID=0x0000001A Parent=0x00000014 SizeRef=333,70 Split=Y Selected=0x3FC1A724
|
||||
DockNode ID=0x00000015 Parent=0x0000001A SizeRef=181,220 HiddenTabBar=1 Selected=0x3FC1A724
|
||||
DockNode ID=0x00000016 Parent=0x0000001A SizeRef=181,161 HiddenTabBar=1 Selected=0xA873C17F
|
||||
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,472 HiddenTabBar=1 Selected=0xEA83D666
|
||||
DockNode ID=0x00000006 Parent=0x11111111 SizeRef=289,1158 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x00000009 Parent=0x00000006 SizeRef=449,488 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x0000000B Parent=0x00000009 SizeRef=449,556 Split=Y Selected=0x36DC96AB
|
||||
DockNode ID=0x0000000D Parent=0x0000000B SizeRef=449,860 Selected=0x36DC96AB
|
||||
DockNode ID=0x0000000E Parent=0x0000000B SizeRef=449,296 HiddenTabBar=1 Selected=0x9D7E7171
|
||||
DockNode ID=0x0000000C Parent=0x00000009 SizeRef=449,143 HiddenTabBar=1 Selected=0xB6C74292
|
||||
DockNode ID=0x0000000A Parent=0x00000006 SizeRef=449,211 HiddenTabBar=1 Selected=0xD83E5DD3
|
||||
|
||||
|
BIN
src/assets/icons/folder-outline.png
Normal file
BIN
src/assets/icons/folder-outline.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
BIN
src/assets/icons/movie-open-outline.png
Normal file
BIN
src/assets/icons/movie-open-outline.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.3 KiB |
@ -550,7 +550,10 @@ void Engine::Init()
|
||||
ProjectManager::Init();
|
||||
Logger::LogVerbose("Init Script Core");
|
||||
ScriptCore::Init();
|
||||
Logger::LogVerbose("Resverving Objects");
|
||||
|
||||
Logger::LogVerbose("Init Files Core");
|
||||
FileExplorer::Init();
|
||||
Logger::LogVerbose("Reserving Objects");
|
||||
|
||||
// These values were AI Generated.
|
||||
|
||||
@ -570,7 +573,7 @@ void Engine::Init()
|
||||
|
||||
|
||||
|
||||
ProjectManager::LoadProject("C:/Users/spenc/OneDrive/Desktop", "TestProject");
|
||||
//ProjectManager::LoadProject("C:/Users/spenc/OneDrive/Desktop", "TestProject");
|
||||
}
|
||||
|
||||
core::types::Vec2 ScreenToWorld(const core::types::Vec2 &screenPos, const core::types::Vec2 &viewportSize, const core::types::Vec2 &cameraPos, float zoom)
|
||||
@ -757,7 +760,16 @@ void Engine::Run()
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
|
||||
if (ImGui::MenuItem("Load Project"))
|
||||
{
|
||||
std::string file = OpenFileDialog(FileDialogType::Project);
|
||||
Logger::LogInfo("Loading Project.");
|
||||
if (!file.empty())
|
||||
{
|
||||
ProjectManager::LoadProject(file);
|
||||
}
|
||||
selected = nullptr;
|
||||
}
|
||||
if (ImGui::MenuItem("Create New Project"))
|
||||
{
|
||||
OpenNewProjectMenu = true;
|
||||
@ -766,6 +778,8 @@ void Engine::Run()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
@ -915,6 +929,10 @@ void Engine::Run()
|
||||
ShowAssetBrowser();
|
||||
DrawAudioPlayingList();
|
||||
DrawImGuiWindow();
|
||||
FileExplorer::Update();
|
||||
FileExplorer::Show(nullptr);
|
||||
FileExplorer::ProcessLoadQueue();
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
// ProjectManager.cpp
|
||||
|
||||
#include "ProjectManager.h"
|
||||
#include "../../core/utils/EngineConfig.h"
|
||||
#include "../../core/utils/Logging.h"
|
||||
#include "../../Engine.h"
|
||||
#include "../../core/utils/FileDialog.h"
|
||||
#include "../../core/utils/utils.h"
|
||||
#include "../../core/utils/AssetManager.h"
|
||||
|
||||
#include "SceneSerializer.h"
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
@ -16,6 +17,351 @@
|
||||
#include <cstring>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool FileExplorer::s_initialized = false;
|
||||
std::string FileExplorer::SelectedPath;
|
||||
fs::path FileExplorer::s_root;
|
||||
fs::path FileExplorer::s_currentDir;
|
||||
std::unordered_set<std::string> FileExplorer::s_knownFiles;
|
||||
const char* FileExplorer::ICONS_PATH = "./src/assets/icons/";
|
||||
unsigned int FileExplorer::s_folderIcon = 0;
|
||||
|
||||
std::string FileExplorer::fileSearchQuery = "";
|
||||
bool FileExplorer::sortAscending = true;
|
||||
int FileExplorer::sortMode = 0;
|
||||
bool FileExplorer::showScenes = true;
|
||||
bool FileExplorer::showImages = true;
|
||||
bool FileExplorer::showAudio = true;
|
||||
bool FileExplorer::showScripts = true;
|
||||
bool FileExplorer::showOther = true;
|
||||
|
||||
std::vector<fs::path> FileExplorer::s_loadQueue;
|
||||
size_t FileExplorer::s_loadIndex = 0;
|
||||
bool FileExplorer::s_loadingInit = false;
|
||||
|
||||
|
||||
bool FileExplorer::Init()
|
||||
{
|
||||
if (s_initialized)
|
||||
return false;
|
||||
|
||||
if (!ProjectManager::HasProject())
|
||||
return false;
|
||||
|
||||
// Resolve and verify root…
|
||||
s_root = fs::path(ProjectManager::ResolveResPath("res://"));
|
||||
s_currentDir = s_root;
|
||||
if (!fs::exists(s_root) || !fs::is_directory(s_root)) {
|
||||
Logger::LogError("FileExplorer: invalid root path '%s'", s_root.string().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
s_folderIcon = EngineLoadTextureIfNeeded(std::string(ICONS_PATH) + "folder-outline.png");
|
||||
|
||||
std::error_code ec;
|
||||
fs::recursive_directory_iterator it(s_root, fs::directory_options::skip_permission_denied, ec);
|
||||
fs::recursive_directory_iterator end;
|
||||
for (; it != end; it.increment(ec)) {
|
||||
if (ec) {
|
||||
Logger::LogWarning("FileExplorer: skipping '%s': %s",
|
||||
it->path().string().c_str(),
|
||||
ec.message().c_str());
|
||||
ec.clear();
|
||||
continue;
|
||||
}
|
||||
if (it->is_regular_file())
|
||||
s_loadQueue.push_back(it->path());
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void FileExplorer::Show(bool* p_open)
|
||||
{
|
||||
if (!s_initialized) return;
|
||||
if (!ImGui::Begin("File Explorer", p_open,
|
||||
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_HorizontalScrollbar))
|
||||
{
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
// --- Left pane: folder tree ---
|
||||
ImGui::BeginChild("##FolderPane", ImVec2(250, 0), true);
|
||||
ImGui::TextUnformatted("res://");
|
||||
ImGui::Separator();
|
||||
DrawFolderTree(s_root);
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
// --- Right pane: content + toolbar ---
|
||||
ImGui::BeginChild("##ContentPane", ImVec2(0, 0), false);
|
||||
|
||||
// Filters / Search
|
||||
if (ImGui::Button("Filters / Sort")) ImGui::OpenPopup("FileFilterPopup");
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(200);
|
||||
char buf[256];
|
||||
strncpy(buf, fileSearchQuery.c_str(), sizeof(buf));
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
if (ImGui::InputTextWithHint("##Search", "Search...", buf, sizeof(buf)))
|
||||
fileSearchQuery = buf;
|
||||
|
||||
if (ImGui::BeginPopup("FileFilterPopup")) {
|
||||
ImGui::Text("Sort By:");
|
||||
if (ImGui::Selectable("Name", sortMode == 0)) sortMode = 0;
|
||||
if (ImGui::Selectable("Type", sortMode == 1)) sortMode = 1;
|
||||
ImGui::Checkbox("Ascending", &sortAscending);
|
||||
ImGui::Separator();
|
||||
ImGui::Text("Type:");
|
||||
ImGui::Checkbox("Scenes", &showScenes);
|
||||
ImGui::Checkbox("Images", &showImages);
|
||||
ImGui::Checkbox("Audio", &showAudio);
|
||||
ImGui::Checkbox("Scripts", &showScripts);
|
||||
ImGui::Checkbox("Other", &showOther);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// “Up” button
|
||||
if (s_currentDir != s_root) {
|
||||
if (ImGui::Button("Up")) s_currentDir = s_currentDir.parent_path();
|
||||
ImGui::SameLine();
|
||||
}
|
||||
|
||||
// Current path display
|
||||
fs::path rel = fs::relative(s_currentDir, s_root);
|
||||
std::string displayPath = "res://" +
|
||||
(rel.empty() ? std::string() : rel.generic_string() + "/");
|
||||
ImGui::TextUnformatted(displayPath.c_str());
|
||||
ImGui::Separator();
|
||||
|
||||
// Gather & filter
|
||||
std::vector<fs::directory_entry> entries;
|
||||
for (auto &e : fs::directory_iterator(s_currentDir)) {
|
||||
if (!e.is_directory()) {
|
||||
AssetType t = AssetManager::AssetTypeFromPath(e.path().string());
|
||||
switch (t) {
|
||||
case AssetType::Scene: if (!showScenes) continue; break;
|
||||
case AssetType::Image: if (!showImages) continue; break;
|
||||
case AssetType::Audio: if (!showAudio) continue; break;
|
||||
case AssetType::Script: if (!showScripts) continue; break;
|
||||
default: if (!showOther) continue; break;
|
||||
}
|
||||
}
|
||||
if (!fileSearchQuery.empty() &&
|
||||
e.path().filename().string().find(fileSearchQuery) == std::string::npos)
|
||||
continue;
|
||||
entries.push_back(e);
|
||||
}
|
||||
|
||||
// Sort
|
||||
std::sort(entries.begin(), entries.end(), [&](auto &a, auto &b) {
|
||||
if (sortMode == 1) {
|
||||
bool da = a.is_directory(), db = b.is_directory();
|
||||
if (da != db) return sortAscending ? da > db : da < db;
|
||||
return sortAscending
|
||||
? a.path().extension() < b.path().extension()
|
||||
: a.path().extension() > b.path().extension();
|
||||
}
|
||||
return sortAscending
|
||||
? a.path().filename() < b.path().filename()
|
||||
: a.path().filename() > b.path().filename();
|
||||
});
|
||||
|
||||
// Icon grid setup
|
||||
constexpr float iconSize = 64.0f, padding = 8.0f;
|
||||
float avail = ImGui::GetContentRegionAvail().x;
|
||||
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);
|
||||
|
||||
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:
|
||||
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();
|
||||
}
|
||||
|
||||
ImGui::Columns(1);
|
||||
ImGui::EndChild();
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void FileExplorer::Update()
|
||||
{
|
||||
if (!s_initialized)
|
||||
{
|
||||
Init();
|
||||
return;
|
||||
}
|
||||
|
||||
std::error_code ec;
|
||||
std::unordered_set<std::string> currentFiles;
|
||||
for (auto it = fs::recursive_directory_iterator(s_root,
|
||||
fs::directory_options::skip_permission_denied, ec),
|
||||
end = fs::recursive_directory_iterator{};
|
||||
it != end; it.increment(ec))
|
||||
{
|
||||
if (ec) {
|
||||
Logger::LogWarning("FileExplorer: skipping '%s': %s",
|
||||
it->path().string().c_str(),
|
||||
ec.message().c_str());
|
||||
ec.clear();
|
||||
continue;
|
||||
}
|
||||
if (!it->is_regular_file()) continue;
|
||||
|
||||
auto pathStr = it->path().string();
|
||||
currentFiles.insert(pathStr);
|
||||
|
||||
if (!s_knownFiles.count(pathStr)) {
|
||||
s_knownFiles.insert(pathStr);
|
||||
s_loadQueue.push_back(it->path());
|
||||
Logger::LogVerbose("FileExplorer: added '%s'", pathStr.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
// detect deletions
|
||||
for (auto it = s_knownFiles.begin(); it != s_knownFiles.end(); )
|
||||
{
|
||||
if (!currentFiles.count(*it)) {
|
||||
Logger::LogVerbose("FileExplorer: removed '%s'", it->c_str());
|
||||
AssetManager::GetAssetByPath(*it);
|
||||
it = s_knownFiles.erase(it);
|
||||
}
|
||||
else ++it;
|
||||
}
|
||||
}
|
||||
|
||||
bool FileExplorer::LoadingDone()
|
||||
{
|
||||
return s_initialized && s_loadIndex >= s_loadQueue.size();
|
||||
}
|
||||
|
||||
void FileExplorer::DrawFolderTree(const fs::path &path)
|
||||
{
|
||||
for (auto &e : fs::directory_iterator(path)) {
|
||||
if (!e.is_directory()) continue;
|
||||
auto &d = e.path();
|
||||
ImGui::PushID(d.string().c_str());
|
||||
ImGui::Image((ImTextureID)(intptr_t)s_folderIcon, ImVec2(16,16)); ImGui::SameLine();
|
||||
bool open = ImGui::TreeNodeEx(d.string().c_str(), ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanAvailWidth, "%s", d.filename().string().c_str());
|
||||
if (ImGui::IsItemClicked()) s_currentDir = d;
|
||||
if (open) { DrawFolderTree(d); ImGui::TreePop(); }
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
void FileExplorer::ProcessLoadQueue()
|
||||
{
|
||||
while (!s_loadQueue.empty()) {
|
||||
fs::path p = s_loadQueue.back();
|
||||
s_loadQueue.pop_back();
|
||||
|
||||
// Load the asset and get the type,... Long way...
|
||||
AssetManager::LoadAssetAsync(p.string(), AssetManager::AssetTypeFromExtension(AssetManager::GetFileExtension(p.string())));
|
||||
|
||||
Logger::LogVerbose("FileExplorer: imported '%s'", p.string().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::string FileExplorer::IconFileForPath(const fs::path &path)
|
||||
{
|
||||
auto ext = path.extension().string();
|
||||
if (ext == ".cene") return "movie-open-outline.png";
|
||||
return "error.png";
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
std::string ProjectManager::s_currentProjectPath;
|
||||
@ -102,7 +448,7 @@ bool CreateDirectories(const fs::path &baseDir)
|
||||
"Scenes",
|
||||
"Images",
|
||||
"Sounds",
|
||||
"Fomts",
|
||||
"Fonts",
|
||||
"Shaders",
|
||||
"Scripts",
|
||||
"Videos",
|
||||
@ -129,25 +475,49 @@ bool CreateDirectories(const fs::path &baseDir)
|
||||
return allOk;
|
||||
}
|
||||
|
||||
bool ProjectManager::HasProject() {
|
||||
if (s_currentProjectPath.empty() || s_currentProjectName.empty())
|
||||
{
|
||||
return false;
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string ProjectManager::ResolveResPath(const std::string &resPath)
|
||||
{
|
||||
constexpr const char *prefix = "res://";
|
||||
// if it’s not a “res://” path, just return it
|
||||
if (resPath.rfind(prefix, 0) != 0)
|
||||
return resPath;
|
||||
|
||||
if (s_currentProjectPath.empty() || s_currentProjectName.empty())
|
||||
if (s_currentProjectPath.empty())
|
||||
{
|
||||
Logger::LogError("Cannot resolve res path: 'project not loaded!'");
|
||||
Logger::LogError("Cannot resolve res path: project not loaded!");
|
||||
return resPath;
|
||||
}
|
||||
|
||||
fs::path baseDir = fs::path(s_currentProjectPath) / s_currentProjectName;
|
||||
std::string relativePart = resPath.substr(strlen(prefix));
|
||||
fs::path fullPath = baseDir / relativePart;
|
||||
// start from whatever s_currentProjectPath holds
|
||||
fs::path baseDir{s_currentProjectPath};
|
||||
|
||||
return fullPath.lexically_normal().string();
|
||||
// only append the project name if it isn't already the last path component
|
||||
if (!s_currentProjectName.empty() &&
|
||||
baseDir.filename().string() != s_currentProjectName)
|
||||
{
|
||||
baseDir /= s_currentProjectName;
|
||||
}
|
||||
|
||||
// drop the "res://" prefix
|
||||
std::string relativePart = resPath.substr(strlen(prefix));
|
||||
// build & normalize
|
||||
fs::path fullPath = (baseDir / relativePart).lexically_normal();
|
||||
|
||||
return fullPath.string();
|
||||
}
|
||||
|
||||
|
||||
bool ProjectManager::Init()
|
||||
{
|
||||
s_currentProjectPath.clear();
|
||||
@ -157,63 +527,60 @@ bool ProjectManager::Init()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectManager::LoadProject(const std::string &projectPath,
|
||||
const std::string &projectName)
|
||||
bool ProjectManager::LoadProject(const std::string &projectFilePath)
|
||||
{
|
||||
fs::path baseDir = fs::path(projectPath) / projectName;
|
||||
fs::path projFile = baseDir / (projectName + ".cproj");
|
||||
|
||||
if (!fs::exists(projFile))
|
||||
{
|
||||
Logger::LogInfo("Project '%s' not found at '%s' creating new one.",
|
||||
projectName.c_str(), projectPath.c_str());
|
||||
return SaveProject(projectPath, projectName);
|
||||
fs::path projFile{ projectFilePath };
|
||||
if (projFile.extension() != ".cproj" || !fs::exists(projFile)) {
|
||||
Logger::LogError("Project file not found or invalid: '%s'",
|
||||
projectFilePath.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
fs::path baseDir = projFile.parent_path();
|
||||
std::string projectName = projFile.stem().string();
|
||||
|
||||
YAML::Node config;
|
||||
try
|
||||
{
|
||||
try {
|
||||
config = YAML::LoadFile(projFile.string());
|
||||
}
|
||||
catch (const YAML::Exception &e)
|
||||
{
|
||||
catch (const YAML::Exception &e) {
|
||||
Logger::LogError("Failed to parse project file '%s': %s",
|
||||
projFile.string().c_str(), e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string savedName = config["Name"].as<std::string>(projectName);
|
||||
std::string createdDate = config["CreatedDate"].as<std::string>("unknown");
|
||||
std::string s_defaultScene = config["s_defaultScene"].as<std::string>("s_defaultScene");
|
||||
// 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", savedName.c_str());
|
||||
Logger::LogInfo("Loading Project: '%s' from '%s'",
|
||||
savedName.c_str(), projFile.string().c_str());
|
||||
|
||||
s_currentProjectPath = projectPath;
|
||||
s_currentProjectPath = baseDir.string();
|
||||
s_currentProjectName = savedName;
|
||||
|
||||
std::string resScenePath = config["s_defaultScene"].as<std::string>("");
|
||||
if (!defaultScene.empty()) {
|
||||
s_defaultScene = ResolveResPath(defaultScene);
|
||||
Logger::LogDebug("Loading Default Scene: %s", s_defaultScene.c_str());
|
||||
|
||||
if (!resScenePath.empty())
|
||||
{
|
||||
s_defaultScene = ResolveResPath(resScenePath);
|
||||
Logger::LogDebug("Loading Scene: %s", s_defaultScene.c_str());
|
||||
|
||||
if (!std::filesystem::exists(s_defaultScene))
|
||||
{
|
||||
Logger::LogError("Scene file does not exist: %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("Loaded project '%s'", savedName.c_str());
|
||||
Logger::LogInfo("Successfully loaded project '%s'", savedName.c_str());
|
||||
|
||||
CreateDirectories(baseDir);
|
||||
|
||||
SceneLoader::LoadScene(s_defaultScene);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool ProjectManager::CreateProject(const std::string &projectPath,
|
||||
const std::string &projectName)
|
||||
{
|
||||
@ -228,14 +595,11 @@ bool ProjectManager::CreateProject(const std::string &projectPath,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set current project path before scene creation
|
||||
s_currentProjectPath = baseDir.string();
|
||||
s_currentProjectName = projectName;
|
||||
|
||||
// Create initial scene
|
||||
fs::path scenePath = baseDir / "Assets" / "Scenes" / "main.cene";
|
||||
fs::path scenePath = baseDir / "Assets" / "Scenes" / projectName / ".cene";
|
||||
|
||||
SceneLoader::SaveScene(scenePath.string());
|
||||
|
||||
s_defaultScene = scenePath.string();
|
||||
|
||||
@ -275,6 +639,9 @@ bool ProjectManager::CreateProject(const std::string &projectPath,
|
||||
|
||||
CreateDirectories(baseDir);
|
||||
|
||||
SceneLoader::SaveScene(scenePath.string());
|
||||
|
||||
|
||||
SceneLoader::LoadScene(scenePath.string());
|
||||
|
||||
return true;
|
||||
@ -351,8 +718,16 @@ const std::string &ProjectManager::GetCurrentProjectName()
|
||||
const std::string &ProjectManager::GetCurrentAssetsPath()
|
||||
{
|
||||
static std::string assetsPath;
|
||||
fs::path p = fs::path(s_currentProjectPath) / s_currentProjectName / "Assets";
|
||||
assetsPath = p.string();
|
||||
return assetsPath;
|
||||
fs::path baseDir{s_currentProjectPath};
|
||||
|
||||
if (!s_currentProjectName.empty() &&
|
||||
baseDir.filename().string() != s_currentProjectName)
|
||||
{
|
||||
baseDir /= s_currentProjectName;
|
||||
}
|
||||
|
||||
fs::path assetDir = (baseDir / "Assets").lexically_normal();
|
||||
assetsPath = assetDir.string();
|
||||
return assetsPath;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,65 @@
|
||||
|
||||
#include <string>
|
||||
#include <filesystem>
|
||||
#include <vector>
|
||||
#include <unordered_set>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
class FileExplorer
|
||||
{
|
||||
public:
|
||||
// Shows the explorer window (call every frame)
|
||||
static void Show(bool* p_open = nullptr);
|
||||
static bool Init();
|
||||
|
||||
static void Update();
|
||||
static void ProcessLoadQueue();
|
||||
|
||||
|
||||
|
||||
static bool LoadingDone();
|
||||
|
||||
static const std::vector<fs::path>& GetLoadQueue() { return s_loadQueue; }
|
||||
|
||||
|
||||
static std::string SelectedPath;
|
||||
|
||||
private:
|
||||
static bool s_initialized;
|
||||
|
||||
// File browsing state
|
||||
static fs::path s_root;
|
||||
static fs::path s_currentDir;
|
||||
|
||||
static std::unordered_set<std::string> s_knownFiles; // <-- new
|
||||
|
||||
|
||||
// Icons
|
||||
static const char* ICONS_PATH;
|
||||
static unsigned int s_folderIcon;
|
||||
|
||||
// Filters & view state (unchanged)...
|
||||
static std::string fileSearchQuery;
|
||||
static bool sortAscending;
|
||||
static int sortMode;
|
||||
static bool showScenes, showImages, showAudio, showScripts, showOther;
|
||||
|
||||
// Asset loading queue
|
||||
static std::vector<fs::path> s_loadQueue;
|
||||
static size_t s_loadIndex;
|
||||
static bool s_loadingInit;
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
|
||||
class ProjectManager
|
||||
{
|
||||
@ -10,8 +69,7 @@ public:
|
||||
|
||||
/// Load an existing project at projectPath/projectName.
|
||||
/// Reads the .cproj, sets current path/name, and ensures folders.
|
||||
static bool LoadProject(const std::string& projectPath,
|
||||
const std::string& projectName);
|
||||
static bool LoadProject(const std::string& projectFilePath);
|
||||
|
||||
/// Save (or create) a project at projectPath/projectName.
|
||||
/// Writes the .cproj YAML, sets current path/name, and ensures folders.
|
||||
@ -25,6 +83,8 @@ public:
|
||||
|
||||
static void ShowCreateProjectPopup();
|
||||
|
||||
static bool HasProject();
|
||||
|
||||
|
||||
static const std::string& GetCurrentProjectPath();
|
||||
static const std::string& GetCurrentProjectName();
|
||||
|
@ -43,6 +43,7 @@ void SceneLoader::SaveScene(const std::string &path)
|
||||
YAML::Emitter out;
|
||||
YAML::Emitter sceneData;
|
||||
|
||||
|
||||
// Serialize object list only
|
||||
sceneData << YAML::BeginSeq;
|
||||
for (const auto &obj : objects)
|
||||
@ -57,6 +58,8 @@ void SceneLoader::SaveScene(const std::string &path)
|
||||
for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i)
|
||||
hashHex << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(hash[i]);
|
||||
|
||||
|
||||
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "engine_version" << YAML::Value << g_engineConfig.version;
|
||||
out << YAML::Key << "scene_name" << YAML::Value << std::filesystem::path(path).stem().string();
|
||||
@ -75,7 +78,7 @@ void SceneLoader::SaveScene(const std::string &path)
|
||||
out << YAML::Key << "threshold" << YAML::Value << Renderer::GetColorCorrection()->threshold;
|
||||
out << YAML::EndMap;
|
||||
|
||||
AssetManager::Save(out);
|
||||
//AssetManager::Save(out);
|
||||
|
||||
out << YAML::EndMap;
|
||||
|
||||
@ -150,15 +153,15 @@ void SceneLoader::LoadScene(const std::string &path)
|
||||
Logger::LogWarning("Scene hash does not match! File may be corrupted or tampered.");
|
||||
}
|
||||
|
||||
if (root["Assets"])
|
||||
{
|
||||
currentStep = "Loading Assets";
|
||||
currentDetail = "Parsing asset data...";
|
||||
loadingUI.Update(currentStep, currentDetail, 0.05f);
|
||||
|
||||
Logger::LogDebug("Loading Assets");
|
||||
AssetManager::Load(root["Assets"]);
|
||||
}
|
||||
//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("Reseting Scene.");
|
||||
currentStep = "Clearing Previous Scene";
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <iostream>
|
||||
#include "../audio/AudioEngine.h"
|
||||
#include "LoadingWindow.h"
|
||||
#include <filesystem>
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
#include "../../Entitys/Object.h"
|
||||
@ -11,12 +12,25 @@
|
||||
#include <ft2build.h>
|
||||
#include FT_FREETYPE_H
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
|
||||
|
||||
std::unordered_map<uint64_t, std::shared_ptr<AssetInfo>> AssetManager::s_Assets;
|
||||
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"
|
||||
if (!ext.empty() && ext.front() == '.')
|
||||
ext.erase(0, 1); // "PNG"
|
||||
std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
|
||||
return ext; // "png"
|
||||
}
|
||||
|
||||
|
||||
|
||||
AssetType AssetManager::AssetTypeFromExtension(std::string ext)
|
||||
{
|
||||
@ -75,6 +89,12 @@ AssetType AssetManager::AssetTypeFromExtension(std::string ext)
|
||||
|
||||
|
||||
|
||||
AssetType AssetManager::AssetTypeFromPath(const std::string& filepath)
|
||||
{
|
||||
return AssetTypeFromExtension(GetFileExtension(filepath));
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char *MiniaudioResultToString(ma_result result)
|
||||
{
|
||||
|
@ -157,8 +157,12 @@ public:
|
||||
|
||||
static uint64_t GenerateUAID();
|
||||
|
||||
|
||||
static std::string GetFileExtension(const std::string& filepath);
|
||||
static AssetType AssetTypeFromExtension(std::string ext);
|
||||
|
||||
static AssetType AssetTypeFromPath(const std::string& filepath);
|
||||
|
||||
private:
|
||||
static std::unordered_map<uint64_t, std::shared_ptr<AssetInfo>> s_Assets;
|
||||
static std::unordered_map<std::string, uint64_t> s_PathToUAID;
|
||||
|
@ -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 = false;
|
||||
bool Logger::s_PrintToTerminal = true;
|
||||
|
||||
const char *Logger::ToString(Level level)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user