Updated Asset Manager and TileMap componenet

This commit is contained in:
OusmBlueNinja 2025-04-24 16:52:36 -05:00
parent e8e93db51f
commit 6b100d6609
18 changed files with 7824 additions and 174 deletions

View File

@ -10,24 +10,24 @@ Collapsed=1
[Window][WindowOverViewport_11111111]
Pos=0,19
Size=1920,1158
Size=1280,701
Collapsed=0
[Window][Inspector]
Pos=1573,19
Size=347,1158
Pos=790,19
Size=490,701
Collapsed=0
DockId=0x00000006,0
[Window][Scene Tree]
Pos=0,19
Size=342,575
Size=342,348
Collapsed=0
DockId=0x00000003,0
[Window][Viewport]
Pos=344,19
Size=1227,847
Size=444,390
Collapsed=0
DockId=0x00000007,0
@ -36,14 +36,14 @@ Size=1280,19
Collapsed=0
[Window][Performance Info]
Pos=344,868
Size=1227,309
Pos=344,411
Size=444,309
Collapsed=0
DockId=0x00000008,3
[Window][Console]
Pos=344,868
Size=1227,309
Pos=344,411
Size=444,309
Collapsed=0
DockId=0x00000008,0
@ -54,8 +54,8 @@ Collapsed=0
DockId=0x00000007,1
[Window][Profiler]
Pos=344,868
Size=1227,309
Pos=344,411
Size=444,309
Collapsed=0
DockId=0x00000008,2
@ -78,25 +78,30 @@ Collapsed=0
DockId=0x00000008,1
[Window][Color Correction]
Pos=344,868
Size=1227,309
Pos=344,411
Size=444,309
Collapsed=0
DockId=0x00000008,1
[Window][Asset Browser]
Pos=0,596
Size=342,581
Pos=0,369
Size=342,351
Collapsed=0
DockId=0x00000004,0
[Window][Confirm Deletion]
Pos=722,488
Size=325,75
Collapsed=0
[Docking][Data]
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1920,1158 Split=X
DockNode ID=0x00000005 Parent=0x11111111 SizeRef=1571,1158 Split=X
DockSpace ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1280,701 Split=X
DockNode ID=0x00000005 Parent=0x11111111 SizeRef=788,1158 Split=X
DockNode ID=0x00000001 Parent=0x00000005 SizeRef=342,701 Split=Y Selected=0x12EF0F59
DockNode ID=0x00000003 Parent=0x00000001 SizeRef=342,575 HiddenTabBar=1 Selected=0x12EF0F59
DockNode ID=0x00000004 Parent=0x00000001 SizeRef=342,581 HiddenTabBar=1 Selected=0x36AF052B
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=1227,701 Split=Y Selected=0xC450F867
DockNode ID=0x00000002 Parent=0x00000005 SizeRef=444,701 Split=Y Selected=0xC450F867
DockNode ID=0x00000007 Parent=0x00000002 SizeRef=606,847 CentralNode=1 HiddenTabBar=1 Selected=0xC450F867
DockNode ID=0x00000008 Parent=0x00000002 SizeRef=606,309 Selected=0x9B5D3198
DockNode ID=0x00000006 Parent=0x11111111 SizeRef=347,1158 HiddenTabBar=1 Selected=0x36DC96AB
DockNode ID=0x00000006 Parent=0x11111111 SizeRef=490,1158 HiddenTabBar=1 Selected=0x36DC96AB

View File

@ -5,6 +5,8 @@ src_dirs:
- src/include/lua
- src/vendor/imgui
- src/vendor/box2d
- src/vendor/xxhash
# Include directories (-I)
include_dirs:
@ -13,7 +15,7 @@ include_dirs:
- src/vendor
- src/vendor/imgui
- src/vendor/box2d
- src/vendor/xxhash
- C:/msys64/mingw64/include

View File

@ -1,3 +1,3 @@
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\editor\windows\Inspector.cpp -o src\build\editor\windows\Inspector.o
[LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\AnimationComponent.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\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\Profiler.o src\build\core\utils\Texture.o src\build\core\utils\utils.o src\build\editor\windows\AssetBrowser.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 -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto
[RUN] Executed app.exe successfully.
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -Isrc/vendor/xxhash -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Components\AnimationComponent.cpp -o src\build\Components\AnimationComponent.o
[COMPILE] g++ -std=c++20 -Wall -g -Isrc/include -Isrc/include/lua -Isrc/vendor -Isrc/vendor/imgui -Isrc/vendor/box2d -Isrc/vendor/xxhash -IC:/msys64/mingw64/include -IC:\msys64\mingw64\lib\libyaml-cpp.a -Isrc\vendor\imgui -MMD -MP -c src\src\Engine.cpp -o src\build\Engine.o
[LINK] g++ src\build\Engine.o src\build\main.o src\build\Renderer.o src\build\Components\AnimationComponent.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\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\Profiler.o src\build\core\utils\Texture.o src\build\core\utils\utils.o src\build\editor\windows\AssetBrowser.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 -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto

View File

@ -1,10 +1,10 @@
engine_version: 0.1.0
scene_name: TilemapTest
scene_hash: da1e2dee8a989a2dc8390342cf9c900f4de6ad42a54b5f9250189f01645bbf27
scene_hash: 83d59efe885ac3d8546339353a2b5ed05c4f264ae8b17ad3695475e23e925ee6
format_version: 1
objects:
- name: Hello, Create
uid: ef684c7c34b34d81a41d052066bc806c
uid: b6da0e9b788248759d630d5599fdf8df
id: 0
position: [0, 0]
rotation: 0
@ -13,28 +13,28 @@ objects:
components:
- type: TilemapComponent
TextureUAID: 1
TexelWidth: 16
TexelHeight: 16
TexelWidth: 32
TexelHeight: 32
TileSize:
x: 32
y: 32
Tiles:
- [6, 1, 15]
- [6, 2, 14]
- [0, 0, 1]
- [6, 0, 16]
- [4, 3, 11]
- [1, 0, 2]
- [5, 3, 12]
- [2, 0, 3]
- [6, 3, 13]
- [0, 1, 4]
- [1, 1, 5]
- [2, 1, 6]
- [0, 2, 7]
- [1, 2, 8]
- [2, 2, 9]
- [3, 3, 10]
Tiles: []
children: []
- name: NewObject
uid: 248c6524f6b447cca4a249eb85500d59
id: 1
position: [0, 0]
rotation: 0
layer: 0
visable: true
components:
- type: AnimationComponent
TextureUAID: 2
TexelWidth: 64
TexelHeight: 64
FrameDuration: 0.0500000007
StartFrame: 0
EndFrame: 56
children: []
color_correction:
brightness: 1
@ -44,9 +44,33 @@ color_correction:
intensity: 1.20000005
threshold: 1
Assets:
- uaid: 3
path: C:\Users\spenc\OneDrive\Pictures\Pixel Holy Spell Effect 32x32 Pack 3\01.png
filename: 01.png
filetype: png
type: 0
size: [704, 576]
hash: 82866fcf3324b785
channels: 4
format: GL_RGBA
lastModified: 1687052107
- uaid: 2
path: C:\Users\spenc\OneDrive\Pictures\Pixel Holy Spell Effect 32x32 Pack 3\00.png
filename: 00.png
filetype: png
type: 0
size: [1216, 192]
hash: 2b0b3c20179d6f12
channels: 4
format: GL_RGBA
lastModified: 1687052065
- uaid: 1
path: C:\Users\spenc\OneDrive\Pictures\6656e7221e49a1774d2fb280357e56f8d25d9d95.png
filename: 6656e7221e49a1774d2fb280357e56f8d25d9d95.png
filetype: png
type: 0
size: [1024, 1024]
hash: e8aaee6025f21557
channels: 4
format: GL_RGBA
lastModified: 1744577923

View File

@ -49,7 +49,6 @@ void AnimationComponent::SetTextureAtlas(uint64_t uaid, int texelWidth, int texe
startFrame = 0;
endFrame = totalFrames > 0 ? totalFrames - 1 : 0;
if (start != 0)
{
startFrame = start;
@ -117,7 +116,7 @@ void AnimationComponent::Update(float dt)
currentFrame = startFrame;
else
{
currentFrame = endFrame;
currentFrame = startFrame;
playing = false;
}
}
@ -128,8 +127,8 @@ std::string AnimationComponent::GetName() const { return "AnimationComponent"; }
void AnimationComponent::Save(YAML::Emitter &out) const
{
out << YAML::Key << "AnimationComponent";
out << YAML::BeginMap;
out << YAML::Key << "type" << YAML::Value << GetName();
out << YAML::Key << "TextureUAID" << YAML::Value << textureUAID;
out << YAML::Key << "TexelWidth" << YAML::Value << atlas.frameWidth;
out << YAML::Key << "TexelHeight" << YAML::Value << atlas.frameHeight;
@ -141,16 +140,13 @@ void AnimationComponent::Save(YAML::Emitter &out) const
void AnimationComponent::Load(const YAML::Node &node)
{
if (!node["AnimationComponent"])
return;
const auto &data = node["AnimationComponent"];
uint64_t uaid = data["TextureUAID"].as<uint64_t>();
int texelWidth = data["TexelWidth"].as<int>();
int texelHeight = data["TexelHeight"].as<int>();
float duration = data["FrameDuration"].as<float>();
int start = data["StartFrame"] ? data["StartFrame"].as<int>() : 0;
int end = data["EndFrame"] ? data["EndFrame"].as<int>() : INT_MAX;
uint64_t uaid = node["TextureUAID"].as<uint64_t>();
int texelWidth = node["TexelWidth"].as<int>();
int texelHeight = node["TexelHeight"].as<int>();
float duration = node["FrameDuration"].as<float>();
int start = node["StartFrame"] ? node["StartFrame"].as<int>() : 0;
int end = node["EndFrame"] ? node["EndFrame"].as<int>() : 0;
SetTextureAtlas(uaid, texelWidth, texelHeight, duration, start, end);
}

View File

@ -16,6 +16,7 @@ void LightComponent::Save(YAML::Emitter& out) const
out << YAML::EndMap;
}
void LightComponent::Load(const YAML::Node& node)
{
if (node["color"])

View File

@ -53,8 +53,6 @@ static std::shared_ptr<Object> selected = nullptr;
static bool playing = false;
static bool lastPlaying = false;
static std::vector<std::shared_ptr<Object>> pendingDeletion;
static glm::vec2 cameraPos = {0, 0};
static float cameraZoom = 1.0f;
static ImVec2 lastMousePos = {};
@ -514,7 +512,6 @@ void Engine::Init()
Logger::LogVerbose("Resverving Objects");
// These values were AI Generated.
m_toDraw.reserve(2048); // ~2K sprites per frame (including UI, particles, objects)
@ -527,6 +524,13 @@ void Engine::Init()
Logger::LogInfo("Initialized Engine");
}
core::types::Vec2 ScreenToWorld(const core::types::Vec2 &screenPos, const core::types::Vec2 &viewportSize, const core::types::Vec2 &cameraPos, float zoom)
{
core::types::Vec2 viewportCenter = viewportSize * 0.5f;
core::types::Vec2 world = (screenPos - viewportCenter) / zoom + cameraPos;
return world;
}
void Engine::collectObjects(bool playing, const glm::vec2 &camPos, float camZoom)
{
@ -576,7 +580,6 @@ void Engine::collectObjects(bool playing, const glm::vec2 &camPos, float camZoom
if (auto animator = obj->GetComponent<AnimationComponent>())
m_animationsUpdates.push_back(animator.get());
if (playing)
{
if (auto script = obj->GetComponent<ScriptComponent>())
@ -725,7 +728,7 @@ void Engine::Run()
ImGui::EndMainMenuBar();
}
profiler.EndEngineSection(); // End BeginMainMenuBar
profiler.EndEngineSection();
if (g_engineConfig.settings.show_color_correction_window)
ShowColorCorrectionWindow();
@ -737,6 +740,35 @@ void Engine::Run()
ImGui::Begin("Scene Tree");
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
ImGui::IsKeyPressed(ImGuiKey_Delete) && selected)
{
ImGui::OpenPopup("Confirm Deletion");
}
if (ImGui::BeginPopupModal("Confirm Deletion", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
{
ImGui::Text("Are you sure you want to delete this object?");
ImGui::Separator();
if (ImGui::Button("Delete"))
{
pendingDeletion.push_back(selected);
selected = nullptr;
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("Cancel"))
{
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
if (ImGui::BeginPopupContextWindow("SceneTreeContext", ImGuiPopupFlags_MouseButtonRight))
{
if (ImGui::MenuItem("Create New"))
@ -968,7 +1000,41 @@ void Engine::Run()
GLuint texID = Renderer::GetFinalTexture();
ImGui::Image((ImTextureID)(uintptr_t)texID, size, ImVec2(0, 1), ImVec2(1, 0));
// Get window position and size to detect where mouse is
ImVec2 winPos = ImGui::GetWindowPos();
ImVec2 winSize = ImGui::GetWindowSize();
ImVec2 mousePos = ImGui::GetMousePos();
// Check if payload is being dropped inside the scene area
if (ImGui::BeginDragDropTarget())
{
if (const ImGuiPayload *payload = ImGui::AcceptDragDropPayload("ASSET_TEXTURE"))
{
if (payload->DataSize == sizeof(uint64_t))
{
uint64_t uaid = *(const uint64_t *)payload->Data;
glm::vec2 worldPos = ScreenToWorld(
core::types::Vec2(mousePos.x - winPos.x, mousePos.y - winPos.y),
core::types::Vec2(winSize.x, winSize.y),
cameraPos,
cameraZoom);
auto obj = std::make_shared<Object>("New Sprite");
obj->SetLocalPosition(worldPos);
auto sprite = obj->AddComponent<SpriteComponent>();
sprite->SetTexture(uaid);
objects.push_back(obj);
}
}
ImGui::EndDragDropTarget();
}
ImGui::End();
profiler.EndEngineSection();
ShowProfilerTimeline();
@ -1204,7 +1270,6 @@ void Engine::LoadScene(const std::string &path)
loadingUI.Update(currentStep, currentDetail, 0.05f);
Logger::LogVerbose("[LoadScene] Loading Assets");
AssetManager::ClearAllAssets();
AssetManager::Load(root["Assets"]);
}

View File

@ -5,25 +5,25 @@
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <future>
#include <iostream>
// Static definitions
std::unordered_map<uint64_t, AssetInfo> AssetManager::s_Assets;
std::unordered_map<std::string, uint64_t> AssetManager::s_PathToUAID;
std::mutex AssetManager::s_Mutex;
uint64_t AssetManager::s_NextUAID = 1;
void AssetManager::Init() {}
uint64_t AssetManager::GenerateUAID()
{
std::lock_guard<std::mutex> lock(s_Mutex);
return s_NextUAID++;
}
void AssetManager::LoadAssetAsync(const std::string &path, AssetType type)
{
{
std::lock_guard<std::mutex> lock(s_Mutex);
auto itPath = s_PathToUAID.find(path);
if (itPath != s_PathToUAID.end() && s_Assets[itPath->second].loaded)
{
@ -40,7 +40,7 @@ void AssetManager::LoadAssetAsync(const std::string &path, AssetType type)
info.filename = GetFilenameFromPath(path);
info.filetype = ::GetFileExtension(path);
info.type = type;
std::lock_guard<std::mutex> lock(s_Mutex);
s_Assets[uaid] = info;
s_PathToUAID[path] = uaid;
}
@ -59,10 +59,10 @@ void AssetManager::LoadAssetAsync(const std::string &path, AssetType type)
void AssetManager::LoadImageInternal(const std::string &path, uint64_t uaid)
{
{
std::lock_guard<std::mutex> lock(s_Mutex);
auto it = s_Assets.find(uaid);
if (it != s_Assets.end() && it->second.loaded)
return;
auto itPath = s_PathToUAID.find(path);
if (itPath != s_PathToUAID.end() && s_Assets[itPath->second].loaded)
return;
@ -70,6 +70,7 @@ void AssetManager::LoadImageInternal(const std::string &path, uint64_t uaid)
Logger::LogVerbose("[AssetManager] Begin loading image: %s (UAID: %llu)", path.c_str(), uaid);
stbi_set_flip_vertically_on_load(false);
int w, h, channels;
stbi_uc *pixels = stbi_load(path.c_str(), &w, &h, &channels, STBI_rgb_alpha);
if (!pixels)
@ -88,33 +89,35 @@ void AssetManager::LoadImageInternal(const std::string &path, uint64_t uaid)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
glBindTexture(GL_TEXTURE_2D, 0);
stbi_image_free(pixels);
if (texID == 0)
{
Logger::LogError("[AssetManager] Failed to Load asset.");
return;
}
{
std::lock_guard<std::mutex> lock(s_Mutex);
auto &asset = s_Assets[uaid];
asset.size = {static_cast<float>(w), static_cast<float>(h)};
asset.textureID = texID;
asset.loaded = true;
}
asset.channels = channels;
asset.format = "GL_RGBA";
asset.lastModified = GetFileLastWrite(path);
asset.hash = GetFileHash(path);
Logger::LogVerbose("[AssetManager] Finished loading image: %s (%dx%d) (UAID: %llu, Texture ID: %u)", path.c_str(), w, h, uaid, texID);
}
const AssetInfo *AssetManager::GetAssetByID(uint64_t uaid)
{
std::lock_guard<std::mutex> lock(s_Mutex);
auto it = s_Assets.find(uaid);
return it != s_Assets.end() ? &it->second : nullptr;
}
const AssetInfo *AssetManager::GetAssetByPath(const std::string &path)
{
std::lock_guard<std::mutex> lock(s_Mutex);
auto it = s_PathToUAID.find(path);
return it != s_PathToUAID.end() ? &s_Assets[it->second] : nullptr;
}
@ -126,7 +129,7 @@ const std::unordered_map<uint64_t, AssetInfo> &AssetManager::GetAllAssets()
void AssetManager::UnloadAsset(uint64_t uaid)
{
std::lock_guard<std::mutex> lock(s_Mutex);
auto it = s_Assets.find(uaid);
if (it != s_Assets.end())
{
@ -139,7 +142,7 @@ void AssetManager::UnloadAsset(uint64_t uaid)
void AssetManager::ClearAllAssets()
{
std::lock_guard<std::mutex> lock(s_Mutex);
for (auto &kv : s_Assets)
if (kv.second.textureID)
glDeleteTextures(1, &kv.second.textureID);
@ -149,7 +152,6 @@ void AssetManager::ClearAllAssets()
void AssetManager::Save(YAML::Emitter &out)
{
std::lock_guard<std::mutex> lock(s_Mutex);
out << YAML::Key << "Assets" << YAML::BeginSeq;
for (const auto &kv : s_Assets)
{
@ -161,6 +163,10 @@ void AssetManager::Save(YAML::Emitter &out)
<< YAML::Key << "filetype" << YAML::Value << a.filetype
<< YAML::Key << "type" << YAML::Value << static_cast<int>(a.type)
<< YAML::Key << "size" << YAML::Value << YAML::Flow << YAML::BeginSeq << a.size.x << a.size.y << YAML::EndSeq
<< YAML::Key << "hash" << YAML::Value << a.hash
<< YAML::Key << "channels" << YAML::Value << a.channels
<< YAML::Key << "format" << YAML::Value << a.format
<< YAML::Key << "lastModified" << YAML::Value << a.lastModified
<< YAML::EndMap;
}
out << YAML::EndSeq;
@ -170,6 +176,7 @@ void AssetManager::Load(const YAML::Node &node)
{
if (!node)
return;
for (const auto &item : node)
{
uint64_t uaid = item["uaid"].as<uint64_t>();
@ -178,35 +185,32 @@ void AssetManager::Load(const YAML::Node &node)
float sx = item["size"][0].as<float>();
float sy = item["size"][1].as<float>();
bool already = false;
{
std::lock_guard<std::mutex> lock(s_Mutex);
auto it = s_Assets.find(uaid);
if (it != s_Assets.end() && it->second.loaded)
{
already = true;
}
else
{
AssetInfo asset;
asset.uaid = uaid;
asset.path = path;
asset.filename = GetFilenameFromPath(path);
asset.filetype = ::GetFileExtension(path);
asset.filename = item["filename"] ? item["filename"].as<std::string>() : GetFilenameFromPath(path);
asset.filetype = item["filetype"] ? item["filetype"].as<std::string>() : ::GetFileExtension(path);
asset.type = type;
asset.size = {sx, sy};
asset.hash = item["hash"] ? item["hash"].as<std::string>() : "";
asset.channels = item["channels"] ? item["channels"].as<int>() : 4;
asset.format = item["format"] ? item["format"].as<std::string>() : "GL_RGBA";
asset.lastModified = item["lastModified"] ? item["lastModified"].as<std::time_t>() : 0;
asset.loaded = false;
asset.textureID = 0;
s_Assets[uaid] = asset;
s_PathToUAID[path] = uaid;
if (uaid >= s_NextUAID)
s_NextUAID = uaid + 1;
}
}
if (!already && type == AssetType::Image)
if (type == AssetType::Image)
{
Logger::LogVerbose("[AssetManager] Reloading from file: %s (UAID: %llu)", path.c_str(), uaid);
LoadImageInternal(path, uaid);
}
}
}

View File

@ -20,6 +20,12 @@ struct AssetInfo
AssetType type;
core::types::Vec2 size;
std::string hash;
int channels = 4;
std::string format;
std::time_t lastModified = 0;
bool loaded = false;
GLuint textureID = 0;
};
@ -43,7 +49,6 @@ public:
private:
static std::unordered_map<uint64_t, AssetInfo> s_Assets;
static std::unordered_map<std::string, uint64_t> s_PathToUAID;
static std::mutex s_Mutex;
static uint64_t s_NextUAID;
static uint64_t GenerateUAID();

View File

@ -20,6 +20,8 @@ Texture::Texture(const std::string &path)
}
}
Texture::Texture(uint64_t uaid)
{
const auto *asset = AssetManager::GetAssetByID(uaid);

View File

@ -4,8 +4,18 @@
#include <windows.h>
#include <filesystem>
#include <string>
#include <sstream>
#include <unordered_map>
#include <mutex>
#include <xxhash.h>
#include <filesystem>
#include <chrono>
#include <ctime>
#include "imgui.h"
#include "imgui_internal.h" // for ImGuiWindow, ImGuiDockNode
#include <fstream>
#include <sstream>
std::unordered_map<std::string, ImageCacheEntry> textureCache;
std::unordered_map<std::string, ImageCacheEntry> engineTextureCache;
@ -152,3 +162,50 @@ bool DeleteLatestLogFile()
return false; // File didn't exist
}
bool IsWindowVisibleTab(const char* name)
{
ImGuiWindow* win = ImGui::FindWindowByName(name);
if (!win || !win->DockNode)
return false;
return win->DockNode->SelectedTabId == win->ID;
}
std::string HashString(const std::string& data)
{
uint64_t hash = XXH3_64bits(data.data(), data.size());
std::ostringstream oss;
oss << std::hex << std::setfill('0') << std::setw(16) << hash;
return oss.str(); // returns lowercase 16-char hex string
}
std::string GetFileHash(const std::string &path)
{
std::ifstream stream(path, std::ios::binary);
if (!stream)
return "";
std::string data((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
return HashString(data);
}
std::time_t GetFileLastWrite(const std::string &path)
{
try
{
auto ftime = std::filesystem::last_write_time(path);
auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(
ftime - std::filesystem::file_time_type::clock::now() + std::chrono::system_clock::now());
return std::chrono::system_clock::to_time_t(sctp);
}
catch (...)
{
return 0; // return 0 if file doesn't exist or error occurs
}
}

View File

@ -1,8 +1,11 @@
#pragma once
#include <string>
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <ctime>
// here so i only need to include once.
@ -35,6 +38,13 @@ GLuint EngineLoadTextureIfNeeded(const std::string &path);
bool DeleteLatestLogFile();
bool IsWindowVisibleTab(const char* name);
std::string HashString(const std::string& data);
std::time_t GetFileLastWrite(const std::string &path);
std::string GetFileHash(const std::string &path);
// HSV → RGB helper
inline glm::vec3 HSVtoRGB(float h, float s, float v)

View File

@ -71,13 +71,13 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
ImGui::SeparatorText("Add Component");
static const char *componentTypes[] = {
"SpriteComponent",
"CameraComponent",
"LightComponent",
"ScriptComponent",
"TilemapComponent",
"ParticleComponent",
"AnimationComponent"};
"Sprite",
"Camera",
"Light",
"Script",
"Tilemap",
"Particle",
"Animation"};
static int selectedIndex = -1;
@ -99,19 +99,19 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
{
const std::string type = componentTypes[selectedIndex];
if (type == "SpriteComponent" && !selected->GetComponent<SpriteComponent>())
if (type == "Sprite" && !selected->GetComponent<SpriteComponent>())
selected->AddComponent<SpriteComponent>();
else if (type == "CameraComponent" && !selected->GetComponent<CameraComponent>())
else if (type == "Camera" && !selected->GetComponent<CameraComponent>())
selected->AddComponent<CameraComponent>();
else if (type == "LightComponent" && !selected->GetComponent<LightComponent>())
else if (type == "Light" && !selected->GetComponent<LightComponent>())
selected->AddComponent<LightComponent>();
else if (type == "ScriptComponent" && !selected->GetComponent<ScriptComponent>())
else if (type == "Script" && !selected->GetComponent<ScriptComponent>())
selected->AddComponent<ScriptComponent>();
else if (type == "TilemapComponent" && !selected->GetComponent<TilemapComponent>())
else if (type == "Tilemap" && !selected->GetComponent<TilemapComponent>())
selected->AddComponent<TilemapComponent>();
else if (type == "ParticleComponent" && !selected->GetComponent<ParticleComponent>())
else if (type == "Particle" && !selected->GetComponent<ParticleComponent>())
selected->AddComponent<ParticleComponent>();
else if (type == "AnimationComponent" && !selected->GetComponent<AnimationComponent>())
else if (type == "Animation" && !selected->GetComponent<AnimationComponent>())
selected->AddComponent<AnimationComponent>();
}
@ -468,7 +468,6 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
tilemap->SetTextureAtlas(texAsset->uaid, texelWidth, texelHeight);
}
// Atlas preview and grid
if (tilemap->GetTexture())
{
ImGui::SeparatorText("Atlas Preview");
@ -484,26 +483,28 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
{
ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), "Invalid texel size (must be >= 1)");
ImGui::Separator();
return;
}
int numCols = texWidth / texelWidth;
int numRows = texHeight / texelHeight;
if (numCols == 0 || numRows == 0)
{
ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), "Texel size too large for atlas resolution.");
ImGui::Separator();
return;
}
// Maintain aspect ratio
float previewSize = ImGui::GetContentRegionAvail().x;
float previewSize = ImGui::GetContentRegionAvail().x * 0.98;
float aspect = texHeight / (float)texWidth;
ImVec2 imageSize = ImVec2(previewSize, previewSize * aspect);
ImVec2 imageSize(previewSize, previewSize * aspect);
ImVec2 imagePos = ImGui::GetCursorScreenPos();
// Draw the atlas
ImGui::Image(texID, imageSize);
// Grid scale (tile-to-preview size)
// Grid cell size in pixels
float scaleX = imageSize.x / (float)texWidth;
float scaleY = imageSize.y / (float)texHeight;
float cellW = texelWidth * scaleX;
@ -513,66 +514,154 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
const ImU32 gridColor = IM_COL32(255, 255, 255, 48);
int linesDrawn = 0;
// Vertical lines
// Vertical grid lines
for (int col = 0; col <= numCols; ++col)
{
float x = imagePos.x + col * cellW;
if (x > imagePos.x + imageSize.x)
break;
drawList->AddLine(ImVec2(x, imagePos.y), ImVec2(x, imagePos.y + imageSize.y), gridColor);
drawList->AddLine(
ImVec2(x, imagePos.y),
ImVec2(x, imagePos.y + imageSize.y),
gridColor);
linesDrawn++;
}
// Horizontal lines
// Horizontal grid lines
for (int row = 0; row <= numRows; ++row)
{
float y = imagePos.y + row * cellH;
if (y > imagePos.y + imageSize.y)
break;
drawList->AddLine(ImVec2(imagePos.x, y), ImVec2(imagePos.x + imageSize.x, y), gridColor);
drawList->AddLine(
ImVec2(imagePos.x, y),
ImVec2(imagePos.x + imageSize.x, y),
gridColor);
linesDrawn++;
}
// --- Highlight tile under mouse ---
// ─────── Hover & Selection State ───────
static bool selecting = false;
static bool hasSelection = false;
static int selStartX = 0, selStartY = 0, selEndX = 0, selEndY = 0;
ImVec2 mousePos = ImGui::GetMousePos();
bool mouseOver = ImGui::IsItemHovered();
// Convert mouse → tile coords
int tileX = (int)((mousePos.x - imagePos.x) / cellW);
int tileY = (int)((mousePos.y - imagePos.y) / cellH);
// ─ Hover highlight (yellow glow) ─
if (mouseOver && tileX >= 0 && tileX < numCols && tileY >= 0 && tileY < numRows)
{
ImVec2 min(
imagePos.x + tileX * cellW,
imagePos.y + tileY * cellH);
ImVec2 max(
min.x + cellW,
min.y + cellH);
drawList->AddRectFilled(min, max, IM_COL32(255, 255, 0, 64), 2.0f);
drawList->AddRect(min, max, IM_COL32(255, 255, 0, 128), 2.0f);
}
// ─ Dragtoselect & singleclick selection ─
if (mouseOver)
{
// Convert mouse position to tile coordinates
float localX = mousePos.x - imagePos.x;
float localY = mousePos.y - imagePos.y;
int tileX = (int)(localX / cellW);
int tileY = (int)(localY / cellH);
if (tileX >= 0 && tileX < numCols && tileY >= 0 && tileY < numRows)
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
{
float highlightX = imagePos.x + tileX * cellW;
float highlightY = imagePos.y + tileY * cellH;
ImVec2 min = ImVec2(highlightX, highlightY);
ImVec2 max = ImVec2(highlightX + cellW, highlightY + cellH);
const ImU32 glowColor = IM_COL32(255, 255, 0, 64); // translucent yellow
drawList->AddRectFilled(min, max, glowColor, 2.0f);
// Optional: Outline
drawList->AddRect(min, max, IM_COL32(255, 255, 0, 128), 2.0f);
ImGui::Text("Hovered Tile: (%d, %d)", tileX, tileY);
selecting = true;
hasSelection = true;
selStartX = selEndX = tileX;
selStartY = selEndY = tileY;
}
if (selecting && ImGui::IsMouseDragging(ImGuiMouseButton_Left))
{
selEndX = tileX;
selEndY = tileY;
}
if (selecting && ImGui::IsMouseReleased(ImGuiMouseButton_Left))
{
selecting = false;
}
}
// Debug
// ─ Draw selection rectangle ─
if (hasSelection)
{
int x0 = std::min(selStartX, selEndX);
int y0 = std::min(selStartY, selEndY);
int x1 = std::max(selStartX, selEndX);
int y1 = std::max(selStartY, selEndY);
ImVec2 selMin(
imagePos.x + x0 * cellW,
imagePos.y + y0 * cellH);
ImVec2 selMax(
imagePos.x + (x1 + 1) * cellW,
imagePos.y + (y1 + 1) * cellH);
drawList->AddRectFilled(selMin, selMax, IM_COL32(0, 255, 255, 32));
drawList->AddRect(selMin, selMax, IM_COL32(0, 255, 255, 128), 2.0f);
}
// ─ Hovertile preview ─
if (mouseOver && tileX >= 0 && tileX < numCols && tileY >= 0 && tileY < numRows)
{
ImGui::SeparatorText("Hovered Tile");
ImVec2 uv0(
tileX * (float)texelWidth / texWidth,
tileY * (float)texelHeight / texHeight);
ImVec2 uv1(
(tileX + 1) * (float)texelWidth / texWidth,
(tileY + 1) * (float)texelHeight / texHeight);
ImGui::Image(texID, ImVec2(64, 64), uv0, uv1);
}
else
{
ImGui::SeparatorText("Hovered Tile");
ImGui::Dummy(ImVec2(64, 64));
}
// ─ Selectionregion preview ─
if (hasSelection)
{
int x0 = std::min(selStartX, selEndX);
int y0 = std::min(selStartY, selEndY);
int x1 = std::max(selStartX, selEndX);
int y1 = std::max(selStartY, selEndY);
ImGui::SeparatorText("Selection Preview");
ImVec2 uv0(
x0 * (float)texelWidth / texWidth,
y0 * (float)texelHeight / texHeight);
ImVec2 uv1(
(x1 + 1) * (float)texelWidth / texWidth,
(y1 + 1) * (float)texelHeight / texHeight);
ImVec2 imgSz(
(x1 - x0 + 1) * (float)texelWidth * scaleX,
(y1 - y0 + 1) * (float)texelHeight * scaleY);
ImGui::Image(texID, imgSz, uv0, uv1);
}
// Debug info
ImGui::Text("Atlas Resolution: %d x %d", texWidth, texHeight);
if (mouseOver && tileX >= 0 && tileX < numCols && tileY >= 0 && tileY < numRows)
{
ImGui::Text("Selected Tile: %d x %d (%d)", tileX, tileY, (tileX * tileY));
}
ImGui::Text("Tile Grid: %d x %d", numCols, numRows);
ImGui::Text("Grid Lines: %d", linesDrawn);
ImGui::Separator();
}
ImGui::Separator();
if (ImGui::Button("Remove TilemapComponent"))
selected->RemoveComponent<TilemapComponent>();
ImGui::Spacing();
}
ImGui::End();

View File

@ -4,6 +4,9 @@
std::vector<std::shared_ptr<Object>> objects;
std::string savedStateYAML;
std::vector<std::shared_ptr<Object>> pendingDeletion;
std::shared_ptr<Object> FindByTagRecursive(const std::shared_ptr<Object>& obj, const std::string& tag) {
if (obj->GetName() == tag)

View File

@ -6,5 +6,7 @@
extern std::vector<std::shared_ptr<Object>> objects;
extern std::string savedStateYAML;
extern std::vector<std::shared_ptr<Object>> pendingDeletion;
std::shared_ptr<Object> FindByTagRecursive(const std::shared_ptr<Object>& obj, const std::string& tag);

42
src/vendor/xxhash/xxhash.c vendored Normal file
View File

@ -0,0 +1,42 @@
/*
* xxHash - Extremely Fast Hash algorithm
* Copyright (C) 2012-2023 Yann Collet
*
* BSD 2-Clause License (https://www.opensource.org/licenses/bsd-license.php)
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You can contact the author at:
* - xxHash homepage: https://www.xxhash.com
* - xxHash source repository: https://github.com/Cyan4973/xxHash
*/
/*
* xxhash.c instantiates functions defined in xxhash.h
*/
#define XXH_STATIC_LINKING_ONLY /* access advanced declarations */
#define XXH_IMPLEMENTATION /* access definitions */
#include "xxhash.h"

7343
src/vendor/xxhash/xxhash.h vendored Normal file

File diff suppressed because it is too large Load Diff