Starting on prefabs

This commit is contained in:
OusmBlueNinja 2025-05-06 21:24:23 -05:00
parent c3ce41307a
commit 3ec06233e7
16 changed files with 1545 additions and 1300 deletions

View File

@ -16,19 +16,6 @@
"cStandard": "c17",
"cppStandard": "c++20",
"intelliSenseMode": "linux-gcc-x64"
},
{
"name": "main",
"includePath": [
"${default}"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "10.0.22621.0",
"compilerPath": "cl.exe"
}
],
"version": 4

177
.vscode/settings.json vendored
View File

@ -1,88 +1,93 @@
{
"files.associations": {
"*.pyx": "python",
"*.js": "javascript",
"*.c": "c",
"*.scene": "yaml",
"*.cene": "yaml",
"*.h": "cpp",
"memory": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"format": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"text_encoding": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp",
"fstream": "cpp",
"codecvt": "cpp",
"*.inc": "cpp",
"future": "cpp",
"any": "cpp",
"ranges": "cpp",
"unordered_set": "cpp",
"source_location": "cpp",
"csignal": "cpp"
}
"files.associations": {
"*.pyx": "python",
"*.js": "javascript",
"*.c": "c",
"*.scene": "yaml",
"*.cene": "yaml",
"*.h": "cpp",
"memory": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"format": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"text_encoding": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp",
"fstream": "cpp",
"codecvt": "cpp",
"*.inc": "cpp",
"future": "cpp",
"any": "cpp",
"ranges": "cpp",
"unordered_set": "cpp",
"source_location": "cpp",
"csignal": "cpp"
},
// Use MS IntelliSense so IntelliCode works
"C_Cpp.intelliSenseEngine": "default",
"C_Cpp.limitSymbolsToIncludedHeaders": true,
"C_Cpp.exploreMode": "lightweight",
}

View File

@ -10,24 +10,24 @@ Collapsed=1
[Window][WindowOverViewport_11111111]
Pos=0,19
Size=1280,701
Size=1920,1158
Collapsed=0
[Window][Inspector]
Pos=913,19
Size=367,202
Pos=1553,19
Size=367,659
Collapsed=0
DockId=0x00000018,0
[Window][Scene Tree]
Pos=0,19
Size=342,350
Size=342,579
Collapsed=0
DockId=0x0000000F,0
[Window][Viewport]
Pos=344,19
Size=567,202
Size=1207,659
Collapsed=0
DockId=0x00000017,0
@ -36,14 +36,14 @@ Size=1280,19
Collapsed=0
[Window][Performance Info]
Pos=1094,223
Size=186,497
Pos=1606,680
Size=314,497
Collapsed=0
DockId=0x00000016,0
[Window][Console]
Pos=344,223
Size=715,273
Pos=344,680
Size=1206,273
Collapsed=0
DockId=0x00000013,0
@ -54,8 +54,8 @@ Collapsed=0
DockId=0x00000017,1
[Window][Profiler]
Pos=344,498
Size=715,222
Pos=344,955
Size=1206,222
Collapsed=0
DockId=0x00000014,0
@ -112,8 +112,8 @@ Collapsed=0
DockId=0x0000000E,0
[Window][Audio Output]
Pos=1061,223
Size=31,497
Pos=1552,680
Size=52,497
Collapsed=0
DockId=0x00000012,0
@ -124,13 +124,23 @@ Collapsed=0
DockId=0x0000000D,0
[Window][Resources]
Pos=0,371
Size=342,349
Pos=0,600
Size=342,577
Collapsed=0
DockId=0x00000010,0
[Window][Import Preview]
Pos=351,22
Size=550,695
Collapsed=0
[Table][0x96376740,2]
RefScale=13
Column 0 Weight=1.0000
Column 1 Width=120
[Docking][Data]
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X
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=342,701 Split=Y Selected=0x12EF0F59
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=342,637 Split=Y Selected=0x12EF0F59

View File

@ -1,2 +1,4 @@
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -Isrc/vendor/xxhash -Isrc/vendor/miniaudio -Isrc/vendor/imguizmo -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\core\utils\Popup.cpp -o src\build\core\utils\Popup.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -Isrc/vendor/xxhash -Isrc/vendor/miniaudio -Isrc/vendor/imguizmo -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\editor\windows\AssetBrowser.cpp -o src\build\editor\windows\AssetBrowser.o
[LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\AnimationComponent.o src\build\Components\AudioPlayerComponent.o src\build\Components\CameraComponent.o src\build\Components\LightComponent.o src\build\Components\ParticleComponent.o src\build\Components\PhysicsComponent.o src\build\Components\ScriptComponent.o src\build\Components\SpriteComponent.o src\build\Components\TextComonent.o src\build\Components\TilemapComponent.o src\build\core\audio\AudioEngine.o src\build\core\utils\AssetManager.o src\build\core\utils\EngineConfig.o src\build\core\utils\ExceptionHandler.o src\build\core\utils\FileDialog.o src\build\core\utils\input.o src\build\core\utils\LoadingWindow.o src\build\core\utils\Logging.o src\build\core\utils\Popup.o src\build\core\utils\Profiler.o src\build\core\utils\Texture.o src\build\core\utils\utils.o src\build\editor\windows\AssetBrowser.o src\build\editor\windows\AudioInfo.o src\build\editor\windows\Inspector.o src\build\Entitys\Object.o src\build\utils\GameObjectsList.o src\build\utils\Shader.o src\build\utils\UID.o src\build\lapi.o src\build\lauxlib.o src\build\lbaselib.o src\build\lcode.o src\build\lcorolib.o src\build\lctype.o src\build\ldblib.o src\build\ldebug.o src\build\ldo.o src\build\ldump.o src\build\lfunc.o src\build\lgc.o src\build\linit.o src\build\liolib.o src\build\llex.o src\build\lmathlib.o src\build\lmem.o src\build\loadlib.o src\build\lobject.o src\build\lopcodes.o src\build\loslib.o src\build\lparser.o src\build\lstate.o src\build\lstring.o src\build\lstrlib.o src\build\ltable.o src\build\ltablib.o src\build\ltm.o src\build\lua.o src\build\luac.o src\build\lundump.o src\build\lutf8lib.o src\build\lvm.o src\build\lzio.o src\build\imgui.o src\build\imgui_demo.o src\build\imgui_draw.o src\build\imgui_impl_glfw.o src\build\imgui_impl_opengl3.o src\build\imgui_tables.o src\build\imgui_widgets.o src\build\aabb.o src\build\arena_allocator.o src\build\array.o src\build\bitset.o src\build\body.o src\build\broad_phase.o src\build\constraint_graph.o src\build\contact.o src\build\contact_solver.o src\build\core.o src\build\distance.o src\build\distance_joint.o src\build\dynamic_tree.o src\build\geometry.o src\build\hull.o src\build\id_pool.o src\build\island.o src\build\joint.o src\build\manifold.o src\build\math_functions.o src\build\motor_joint.o src\build\mouse_joint.o src\build\mover.o src\build\prismatic_joint.o src\build\revolute_joint.o src\build\sensor.o src\build\shape.o src\build\solver.o src\build\solver_set.o src\build\table.o src\build\timer.o src\build\types.o src\build\weld_joint.o src\build\wheel_joint.o src\build\world.o src\build\xxhash.o src\build\miniaudio.o src\build\ImGuizmo.o -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto -ldbghelp
[ERROR] Runtime crash
Command 'src\build\app.exe' returned non-zero exit status 3.

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,8 @@
#include "../core/utils/AssetManager.h"
#include "../core/audio/AudioEngine.h"
AudioPlayerComponent::AudioPlayerComponent(Object* owner)
: Component(owner)
{}

View File

@ -9,6 +9,8 @@
#include "../core/utils/Logging.h"
class Object;
class Component {

View File

@ -35,6 +35,9 @@
#include <glm/gtc/type_ptr.hpp>
#include <functional>
#include <fstream>
#include <sstream>
#include <iomanip>
@ -55,6 +58,8 @@
#include <json.hpp>
using json = nlohmann::json;
static std::shared_ptr<Object> selected = nullptr;
static bool playing = false;
static bool lastPlaying = false;
@ -75,6 +80,7 @@ static const std::string tempScenePath = "__tmp_scene.yaml";
GLFWwindow *window = nullptr;
Engine::Engine()
{
@ -1246,9 +1252,9 @@ void Engine::Run()
}
else if (previewObj && mouseReleased && hoveringViewport)
{
previewObj = nullptr;
previewUAID = 0;
}
else if (previewObj && (!hoveringViewport || !draggingTexture))
{

View File

@ -286,4 +286,6 @@ void Object::Load(const YAML::Node &node)
AddChild(child);
}
}
}
}

View File

@ -6,6 +6,7 @@
#include "LoadingWindow.h"
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include "../../Entitys/Object.h"
@ -170,6 +171,71 @@ const char *MiniaudioResultToString(ma_result result)
// PrefabAssetInfo.cpp
PrefabAssetInfo::PrefabAssetInfo() {
type = AssetType::Prefab;
}
void PrefabAssetInfo::Save(YAML::Emitter& out) const {
out << YAML::BeginMap;
out << YAML::Key << "uaid" << YAML::Value << uaid;
out << YAML::Key << "path" << YAML::Value << path;
out << YAML::Key << "filename" << YAML::Value << filename;
out << YAML::Key << "filetype" << YAML::Value << filetype;
out << YAML::Key << "type" << YAML::Value << "Prefab";
out << YAML::Key << "hash" << YAML::Value << hash;
out << YAML::Key << "lastModified" << YAML::Value << lastModified;
out << YAML::Key << "loaded" << YAML::Value << loaded;
out << YAML::Key << "prefabYAML" << YAML::Value << prefabYAML;
// Prefab metadata
out << YAML::Key << "prefabName" << YAML::Value << prefabName;
out << YAML::EndMap;
}
void PrefabAssetInfo::Load(const YAML::Node& node) {
uaid = node["uaid"].as<uint64_t>();
path = node["path"].as<std::string>();
filename = node["filename"].as<std::string>();
filetype = node["filetype"].as<std::string>();
hash = node["hash"].as<std::string>();
lastModified = node["lastModified"].as<std::time_t>();
loaded = node["loaded"].as<bool>();
prefabYAML = node["prefabYAML"] ? node["prefabYAML"].as<std::string>() : "";
if (node["prefabName"])
prefabName = node["prefabName"].as<std::string>();
ReloadFromYAML();
}
void PrefabAssetInfo::ReloadFromYAML()
{
if (prefabYAML.empty())
return;
YAML::Node root;
try {
root = YAML::Load(prefabYAML);
}
catch (const std::exception& e) {
Logger::LogError("[Prefab] YAML parse error: %s", e.what());
return;
}
prefabRoot = std::make_shared<Object>("PrefabRoot");
prefabRoot->Load(root);
}
void AssetManager::Init()
{
Logger::LogOk("AssetManager Core");
@ -214,6 +280,9 @@ void AssetManager::LoadAssetAsync(const std::string &path, AssetType type)
LoadImageInternal(path, uaid);
else if (type == AssetType::Audio)
LoadAudioInternal(path, uaid);
else if (type == AssetType::Prefab)
LoadPrefabInternal(path, uaid);
}
void AssetManager::LoadImageInternal(const std::string &path, uint64_t uaid)
@ -273,6 +342,9 @@ void AssetManager::LoadImageInternal(const std::string &path, uint64_t uaid)
Logger::LogVerbose("[AssetManager] Loaded image: %s (%dx%d)", path.c_str(), w, h);
}
void AssetManager::LoadAudioInternal(const std::string &path, uint64_t uaid)
{
auto it = s_Assets.find(uaid);
@ -302,6 +374,55 @@ void AssetManager::LoadAudioInternal(const std::string &path, uint64_t uaid)
Logger::LogVerbose("[AssetManager] Loaded audio: %s", path.c_str());
}
void AssetManager::LoadPrefabInternal(const std::string& path, uint64_t uaid)
{
// Skip if already loaded and not dirty
auto it = s_Assets.find(uaid);
if (it != s_Assets.end() && it->second->loaded)
return;
if (!FileExists(path))
{
Logger::LogError("[AssetManager] Prefab file not found: %s", path.c_str());
return;
}
std::string yamlContent;
if (!ReadTextFile(path, yamlContent))
{
Logger::LogError("[AssetManager] Failed to read prefab file: %s", path.c_str());
return;
}
auto prefab = std::make_shared<PrefabAssetInfo>();
prefab->uaid = uaid;
prefab->path = path;
prefab->filename = GetFilenameFromPath(path);
prefab->filetype = GetFileExtension(path);
prefab->type = AssetType::Prefab;
prefab->prefabYAML = yamlContent;
prefab->lastModified = GetFileLastWrite(path);
prefab->hash = GetFileHash(path);
prefab->loaded = true;
prefab->ReloadFromYAML();
if (!prefab->prefabRoot)
{
Logger::LogError("[AssetManager] Failed to deserialize prefab object: %s", path.c_str());
return;
}
s_Assets[uaid] = prefab;
Logger::LogVerbose("[AssetManager] Loaded prefab: %s (UAID: %llu)", path.c_str(), uaid);
}
const AssetInfo *AssetManager::GetAssetByID(uint64_t uaid)
{
auto it = s_Assets.find(uaid);

View File

@ -9,7 +9,15 @@
#include <GL/glew.h>
#include "miniaudio.h"
enum class AssetType { Image, Audio, Unknown };
class Object;
enum class AssetType {
Image,
Audio,
Prefab,
Unknown
};
struct AssetInfo
{
@ -51,6 +59,25 @@ struct AudioAssetInfo : public AssetInfo
void Load(const YAML::Node& node) override;
};
struct PrefabAssetInfo : public AssetInfo
{
std::string prefabYAML;
std::shared_ptr<Object> prefabRoot = nullptr;
std::string prefabName = "Unnamed Prefab";
PrefabAssetInfo();
void Save(YAML::Emitter& out) const override;
void Load(const YAML::Node& node) override;
void ReloadFromYAML(); // reparses prefabYAML into prefabRoot
};
const char* MiniaudioResultToString(ma_result result);
@ -75,4 +102,6 @@ private:
static uint64_t GenerateUAID();
static void LoadImageInternal(const std::string& path, uint64_t uaid);
static void LoadAudioInternal(const std::string& path, uint64_t uaid);
static void LoadPrefabInternal(const std::string& path, uint64_t uaid);
};

View File

@ -12,7 +12,7 @@
//! Macro Fuckery my Gz
EngineConfig g_engineConfig{
.version = "0.8.2",
.version = "0.8.3",
.gl_version = "430",
.gl_maxLight = 512,
.settings = UserSettings{}

View File

@ -13,14 +13,16 @@
//TODO: Make this all memroy safe.
static std::unordered_map<FileDialogType, const char*> filters = {
{ FileDialogType::Images, "Image Files\0*.png;*.jpg;*.jpeg;*.bmp;*.tga;*.gif;*.dds\0All Files\0*.*\0" },
{ FileDialogType::Scenes, "CreateScene Files\0*.cene;*.cscene;*.yaml\0All Files\0*.*\0" },
{ FileDialogType::Audio, "Audio Files\0*.mp3;*.wav;*.ogg;*.flac;*.aac\0All Files\0*.*\0" },
{ FileDialogType::Scripts, "Lua Scripts\0*.lua\0All Files\0*.*\0" },
{ FileDialogType::Shaders, "Shader Files\0*.glsl;*.vert;*.frag;*.hlsl\0All Files\0*.*\0" },
{ 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::All, "All Files\0*.*\0" }
{ FileDialogType::Images, "Image Files\0*.png;*.jpg;*.jpeg;*.bmp;*.tga;*.gif;*.dds\0All Files\0*.*\0" },
{ FileDialogType::Scenes, "CreateScene Files\0*.cene;*.cscene;*.yaml\0All Files\0*.*\0" },
{ FileDialogType::Prefabs, "Prefab Files\0*.cpfb\0All Files\0*.*\0" },
{ FileDialogType::AssetPacks, "Asset Pack Files\0*.cpack;*.capk\0All Files\0*.*\0" },
{ FileDialogType::Audio, "Audio Files\0*.mp3;*.wav;*.ogg;*.flac;*.aac\0All Files\0*.*\0" },
{ FileDialogType::Scripts, "Lua Scripts\0*.lua\0All Files\0*.*\0" },
{ FileDialogType::Shaders, "Shader Files\0*.glsl;*.vert;*.frag;*.hlsl\0All Files\0*.*\0" },
{ 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::All, "All Files\0*.*\0" }
};

View File

@ -4,17 +4,21 @@
enum class FileDialogType {
Images,
Scenes,
Audio,
Scripts,
Shaders,
Fonts,
Models,
All
Images, // .png, .jpg, .bmp, etc.
Scenes, // .cene
Prefabs, // .cpfb
AssetPacks, // .cpack, .capk
Audio, // .wav, .mp3, .ogg
Scripts, // .lua, .py
Shaders, // .vert, .frag, .glsl
Fonts, // .ttf, .otf
Models, // .obj, .fbx, .gltf, etc.
All
};
std::string OpenFileDialog(FileDialogType type);
std::string SaveFileDialog(FileDialogType type);
std::string CreateFileDialog(FileDialogType type);

View File

@ -6,6 +6,11 @@
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <ctime>
#include <filesystem>
#include <sstream>
#include <algorithm>
#include <cctype>
#include <fstream>
// here so i only need to include once.
@ -76,4 +81,40 @@ inline std::string GetFileExtension(const std::string &path)
if (dot == std::string::npos)
return "";
return path.substr(dot + 1);
}
}
inline std::string GetFileExtension_Name(const std::string &path)
{
size_t dot = path.find_last_of('.');
if (dot == std::string::npos || dot == path.length() - 1)
return "";
std::string ext = path.substr(dot + 1);
// Convert to lowercase
std::transform(ext.begin(), ext.end(), ext.begin(),
[](unsigned char c) { return std::tolower(c); });
return ext;
}
inline bool FileExists(const std::string& path)
{
return std::filesystem::exists(path) && std::filesystem::is_regular_file(path);
}
inline bool ReadTextFile(const std::string& path, std::string& out)
{
std::ifstream file(path);
if (!file.is_open())
return false;
std::stringstream buffer;
buffer << file.rdbuf();
out = buffer.str();
return true;
}

View File

@ -13,6 +13,9 @@ static int sortMode = 0; // 0 = Name, 1 = Type, 2 = UAID
static bool showImages = true;
static bool showAudio = true;
static std::vector<std::pair<std::string, AssetType>> pendingImports;
static bool showImportPopup = false;
void ShowAssetBrowser()
{
PROFILE_ENGINE_SCOPE("Editor::AssetBrowser");
@ -20,50 +23,35 @@ void ShowAssetBrowser()
if (!g_engineConfig.settings.show_asset_window)
return;
// Open modal popup if needed
if (showImportPopup)
ImGui::OpenPopup("Import Preview");
ImGui::Begin("Resources");
// Top bar layout
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(6, 4));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8, 6));
// Load Buttons
if (ImGui::Button("Load Images"))
if (ImGui::Button("Import Assets"))
{
std::vector<std::string> paths = OpenMultipleFilesDialog(FileDialogType::Images);
std::vector<std::string> paths = OpenMultipleFilesDialog(FileDialogType::All);
if (!paths.empty())
{
LoadingWindow loader;
loader.Create("Loading Images...");
pendingImports.clear();
for (size_t i = 0; i < paths.size(); ++i)
for (const auto &path : paths)
{
const std::string &path = paths[i];
loader.Update("Loading Image", path, static_cast<float>(i + 1) / paths.size());
AssetManager::LoadAssetAsync(path, AssetType::Image);
std::string ext = GetFileExtension_Name(path);
AssetType type = AssetType::Unknown;
if (ext == "png" || ext == "jpg" || ext == "jpeg" || ext == "bmp" || ext == "tga" || ext == "gif" || ext == "dds")
type = AssetType::Image;
else if (ext == "wav" || ext == "mp3" || ext == "ogg" || ext == "flac" || ext == "aac")
type = AssetType::Audio;
else if (ext == "cpfb")
type = AssetType::Prefab;
pendingImports.emplace_back(path, type);
}
loader.Destroy();
}
}
ImGui::SameLine();
if (ImGui::Button("Load Audio"))
{
std::vector<std::string> paths = OpenMultipleFilesDialog(FileDialogType::Audio);
if (!paths.empty())
{
LoadingWindow loader;
loader.Create("Loading Audio...");
for (size_t i = 0; i < paths.size(); ++i)
{
const std::string &path = paths[i];
loader.Update("Loading Audio", path, static_cast<float>(i + 1) / paths.size());
AssetManager::LoadAssetAsync(path, AssetType::Audio);
}
loader.Destroy();
showImportPopup = true;
}
}
@ -72,7 +60,6 @@ void ShowAssetBrowser()
if (ImGui::Button("Filters / Sort"))
ImGui::OpenPopup("AssetBrowserFilterPopup");
// Filters Popup
if (ImGui::BeginPopup("AssetBrowserFilterPopup"))
{
ImGui::Text("Sort By:");
@ -93,59 +80,43 @@ void ShowAssetBrowser()
ImGui::EndPopup();
}
ImGui::PopStyleVar(2);
// Search field (spaced below buttons)
ImGui::Spacing();
ImGui::Spacing();
char buffer[256] = {};
strncpy(buffer, assetSearchQuery.c_str(), sizeof(buffer) - 1);
ImGui::SetNextItemWidth(-1);
if (ImGui::InputTextWithHint("##Search", "Search", buffer, sizeof(buffer)))
{
assetSearchQuery = buffer;
}
ImGui::Separator();
ImGui::BeginChild("##AssetScroll", ImVec2(0, 0), true);
const float padding = 8.0f;
const float thumbnailSize = 64.0f;
const float cellSize = thumbnailSize + padding;
float padding = 8.0f;
float thumbnailSize = 64.0f;
float cellSize = thumbnailSize + padding;
float availWidth = ImGui::GetContentRegionAvail().x;
int columns = static_cast<int>(availWidth / cellSize);
if (columns < 1)
columns = 1;
ImGui::Columns(columns, nullptr, false);
// Collect, filter and sort assets
std::vector<const AssetInfo *> sortedAssets;
for (const auto &[uaid, asset] : AssetManager::GetAllAssets())
{
if (!asset || !asset->loaded)
continue;
if (!assetSearchQuery.empty() &&
asset->filename.find(assetSearchQuery) == std::string::npos &&
asset->path.find(assetSearchQuery) == std::string::npos)
continue;
if ((asset->type == AssetType::Image && !showImages) ||
(asset->type == AssetType::Audio && !showAudio))
continue;
sortedAssets.push_back(asset.get());
}
std::sort(sortedAssets.begin(), sortedAssets.end(), [](const AssetInfo *a, const AssetInfo *b)
{
switch (sortMode)
{
switch (sortMode) {
case 0: return sortAscending ? a->filename < b->filename : a->filename > b->filename;
case 1: return sortAscending ? a->type < b->type : a->type > b->type;
case 2: return sortAscending ? a->uaid < b->uaid : a->uaid > b->uaid;
@ -153,38 +124,34 @@ void ShowAssetBrowser()
} });
int idx = 0;
for (const AssetInfo *baseAsset : sortedAssets)
for (const AssetInfo *asset : sortedAssets)
{
ImGui::PushID(idx++);
std::string displayName = GetFilenameFromPath(baseAsset->path);
std::string displayName = GetFilenameFromPath(asset->path);
if (baseAsset->type == AssetType::Image)
if (asset->type == AssetType::Image)
{
const auto *imageAsset = dynamic_cast<const ImageAssetInfo *>(baseAsset);
if (!imageAsset)
const auto *image = dynamic_cast<const ImageAssetInfo *>(asset);
if (!image)
{
ImGui::PopID();
continue;
}
ImGui::Image((ImTextureID)(intptr_t)imageAsset->textureID,
ImVec2(thumbnailSize, thumbnailSize));
ImGui::Image((ImTextureID)(intptr_t)image->textureID, ImVec2(thumbnailSize, thumbnailSize));
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
{
ImGui::SetDragDropPayload("ASSET_TEXTURE", &baseAsset->uaid, sizeof(uint64_t));
ImGui::SetDragDropPayload("ASSET_TEXTURE", &asset->uaid, sizeof(uint64_t));
ImGui::Text("%s", displayName.c_str());
ImGui::EndDragDropSource();
}
}
else if (baseAsset->type == AssetType::Audio)
else if (asset->type == AssetType::Audio)
{
std::string buttonLabel = baseAsset->filetype.empty() ? "Audio" : baseAsset->filetype;
ImGui::Button(buttonLabel.c_str(), ImVec2(thumbnailSize, thumbnailSize));
ImGui::Button(asset->filetype.empty() ? "Audio" : asset->filetype.c_str(), ImVec2(thumbnailSize, thumbnailSize));
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
{
ImGui::SetDragDropPayload("ASSET_AUDIO", &baseAsset->uaid, sizeof(uint64_t));
ImGui::SetDragDropPayload("ASSET_AUDIO", &asset->uaid, sizeof(uint64_t));
ImGui::Text("%s", displayName.c_str());
ImGui::EndDragDropSource();
}
@ -198,23 +165,17 @@ void ShowAssetBrowser()
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("Path: %s", baseAsset->path.c_str());
ImGui::Text("UAID: %llu", baseAsset->uaid);
if (baseAsset->type == AssetType::Image)
ImGui::Text("Path: %s", asset->path.c_str());
ImGui::Text("UAID: %llu", asset->uaid);
if (asset->type == AssetType::Image)
{
const auto *imageAsset = dynamic_cast<const ImageAssetInfo *>(baseAsset);
if (imageAsset)
auto *image = dynamic_cast<const ImageAssetInfo *>(asset);
if (image)
{
ImGui::Text("Texture ID: %u", imageAsset->textureID);
ImGui::Text("Size: (%.0f, %.0f)", imageAsset->size.x, imageAsset->size.y);
ImGui::Text("Texture ID: %u", image->textureID);
ImGui::Text("Size: (%.0f, %.0f)", image->size.x, image->size.y);
}
}
else if (baseAsset->type == AssetType::Audio)
{
ImGui::Text("Audio file");
}
ImGui::EndTooltip();
}
@ -222,23 +183,15 @@ void ShowAssetBrowser()
{
if (ImGui::MenuItem("Unload"))
{
Logger::LogInfo("[AssetBrowser] Unloaded: %s", baseAsset->path.c_str());
AssetManager::UnloadAsset(baseAsset->uaid);
AssetManager::UnloadAsset(asset->uaid);
ImGui::EndPopup();
ImGui::PopID();
continue;
}
if (ImGui::MenuItem("Copy Path"))
{
ImGui::SetClipboardText(baseAsset->path.c_str());
}
ImGui::SetClipboardText(asset->path.c_str());
if (ImGui::MenuItem("Copy UAID"))
{
ImGui::SetClipboardText(std::to_string(baseAsset->uaid).c_str());
}
ImGui::SetClipboardText(std::to_string(asset->uaid).c_str());
ImGui::EndPopup();
}
@ -250,4 +203,83 @@ void ShowAssetBrowser()
ImGui::Columns(1);
ImGui::EndChild();
ImGui::End();
if (ImGui::BeginPopupModal("Import Preview", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize))
{
ImGui::TextWrapped("Review and confirm asset imports. Adjust type if needed.");
ImGui::Spacing();
constexpr float tableWidth = 520.0f;
if (ImGui::BeginTable("ImportTable", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable, ImVec2(tableWidth, 300)))
{
ImGui::TableSetupColumn("Filename", ImGuiTableColumnFlags_WidthStretch);
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 120.0f);
ImGui::TableHeadersRow();
for (auto &[path, type] : pendingImports)
{
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
std::string filename = GetFilenameFromPath(path);
ImGui::TextWrapped("%s", filename.c_str());
ImGui::TableSetColumnIndex(1);
const char *currentLabel =
type == AssetType::Image ? "Image" : type == AssetType::Audio ? "Audio"
: type == AssetType::Prefab ? "Prefab"
: "Unknown";
ImGui::SetNextItemWidth(-1);
if (ImGui::BeginCombo(("##type_" + path).c_str(), currentLabel))
{
if (ImGui::Selectable("Image", type == AssetType::Image))
type = AssetType::Image;
if (ImGui::Selectable("Audio", type == AssetType::Audio))
type = AssetType::Audio;
if (ImGui::Selectable("Prefab", type == AssetType::Prefab))
type = AssetType::Prefab;
ImGui::EndCombo();
}
}
ImGui::EndTable();
}
ImGui::Spacing();
ImGui::Separator();
ImGui::Spacing();
float buttonWidth = 120.0f;
float totalWidth = buttonWidth * 2 + ImGui::GetStyle().ItemSpacing.x;
ImGui::SetCursorPosX((tableWidth - totalWidth) * 0.5f); // center buttons
if (ImGui::Button("Import", ImVec2(buttonWidth, 0)))
{
LoadingWindow loader;
loader.Create("Importing...");
for (size_t i = 0; i < pendingImports.size(); ++i)
{
const auto &[path, type] = pendingImports[i];
loader.Update("Importing", path, static_cast<float>(i + 1) / pendingImports.size());
AssetManager::LoadAssetAsync(path, type);
}
loader.Destroy();
pendingImports.clear();
showImportPopup = false;
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel", ImVec2(buttonWidth, 0)))
{
pendingImports.clear();
showImportPopup = false;
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
}