diff --git a/Tetragrama/Components/HierarchyViewUIComponent.cpp b/Tetragrama/Components/HierarchyViewUIComponent.cpp index a67125dc7..7ac09d2ce 100644 --- a/Tetragrama/Components/HierarchyViewUIComponent.cpp +++ b/Tetragrama/Components/HierarchyViewUIComponent.cpp @@ -162,7 +162,7 @@ namespace Tetragrama::Components { auto* mc = actor->GetComponent(); if (mc && mc->RenderInstanceId != UINT32_MAX) - current_scene->RemoveMeshInstance(mc->RenderInstanceId); + current_scene->RemoveMeshInstance(mc->RenderInstanceId, ctx->RenderResourceManager); if (selected) current_scene->SelectedActorHandle = {}; pending_delete = h; diff --git a/Tetragrama/Components/ProjectViewUIComponent.cpp b/Tetragrama/Components/ProjectViewUIComponent.cpp index 30f13ec80..65ca8d388 100644 --- a/Tetragrama/Components/ProjectViewUIComponent.cpp +++ b/Tetragrama/Components/ProjectViewUIComponent.cpp @@ -278,7 +278,6 @@ namespace Tetragrama::Components char name[MAX_FILE_PATH_COUNT]; entry.Path.CopyFilename(name, sizeof(name)); - // --- UE thumbnail-first card layout --- // Icon fills the top portion, name overlaid on a semi-transparent footer strip. const float sz = m_thumbnail_size; const float pad = 6.0f; @@ -324,7 +323,6 @@ namespace Tetragrama::Components ImGui::EndPopup(); } - // ---- DrawList rendering ---- ImDrawList* dl = ImGui::GetWindowDrawList(); ImVec2 icon_end = {origin.x + card_w, origin.y + sz}; @@ -344,7 +342,6 @@ namespace Tetragrama::Components if (!dark_theme) dl->AddRect(origin, card_end, card_border, rounding, 0, 1.0f); - // --- Icon (vector, centered in the thumbnail area) --- // When a per-asset thumbnail is ready, call // dl->AddImage((ImTextureID)(intptr_t)thumb.Index, ixo, {ixo.x + ic, ixo.y + ic * 0.92f}) // instead of DrawContentIcon(). diff --git a/ZEngine/ZEngine/Core/VFS/Meta/MetaFileIO.cpp b/ZEngine/ZEngine/Core/VFS/Meta/MetaFileIO.cpp index 1d24dbbde..9f9381845 100644 --- a/ZEngine/ZEngine/Core/VFS/Meta/MetaFileIO.cpp +++ b/ZEngine/ZEngine/Core/VFS/Meta/MetaFileIO.cpp @@ -27,9 +27,7 @@ namespace ZEngine::Core::VFS } } // namespace - // ------------------------------------------------------------------------- // MetaFileIO - // ------------------------------------------------------------------------- VFSPath MetaFileIO::MetaPathFor(const VFSPath& asset_path) { diff --git a/ZEngine/ZEngine/Core/VFS/Registry/DependencyGraph.cpp b/ZEngine/ZEngine/Core/VFS/Registry/DependencyGraph.cpp index 0a42fd06f..78a2f1c58 100644 --- a/ZEngine/ZEngine/Core/VFS/Registry/DependencyGraph.cpp +++ b/ZEngine/ZEngine/Core/VFS/Registry/DependencyGraph.cpp @@ -4,9 +4,7 @@ namespace ZEngine::Core::VFS { - // ------------------------------------------------------------------------- // AdjacencyList - // ------------------------------------------------------------------------- bool AdjacencyList::Contains(const uuids::uuid& uuid) const { @@ -70,9 +68,7 @@ namespace ZEngine::Core::VFS return false; } - // ------------------------------------------------------------------------- // DependencyGraph - // ------------------------------------------------------------------------- void DependencyGraph::Initialize(Core::Memory::ArenaAllocator* arena) { diff --git a/ZEngine/ZEngine/Rendering/Cameras/FlyCamera.cpp b/ZEngine/ZEngine/Rendering/Cameras/FlyCamera.cpp index fa6824608..40fe404c9 100644 --- a/ZEngine/ZEngine/Rendering/Cameras/FlyCamera.cpp +++ b/ZEngine/ZEngine/Rendering/Cameras/FlyCamera.cpp @@ -44,9 +44,7 @@ namespace ZEngine::Rendering::Cameras UpdateMatrices(); } - // --------------------------------------------------------------------------- // Public accessors - // --------------------------------------------------------------------------- Quaternion FlyCamera::GetOrientation() const { @@ -73,9 +71,7 @@ namespace ZEngine::Rendering::Cameras return rotate(GetOrientation(), Vec3f(0.0f, 1.0f, 0.0f)); } - // --------------------------------------------------------------------------- // Configuration - // --------------------------------------------------------------------------- void FlyCamera::SetViewportSize(float logicalW, float logicalH) { @@ -98,9 +94,7 @@ namespace ZEngine::Rendering::Cameras m_viewDirty = true; } - // --------------------------------------------------------------------------- // OnUpdate — main entry point called once per frame by the controller - // --------------------------------------------------------------------------- void FlyCamera::OnUpdate(float dt) { @@ -191,9 +185,7 @@ namespace ZEngine::Rendering::Cameras Input.FlushDeltas(); } - // --------------------------------------------------------------------------- // Private update methods - // --------------------------------------------------------------------------- void FlyCamera::UpdateFree(float dt) { @@ -305,9 +297,7 @@ namespace ZEngine::Rendering::Cameras } } - // --------------------------------------------------------------------------- // Focus / bookmarks - // --------------------------------------------------------------------------- void FlyCamera::FocusOn(Vec3f center, float radius) { @@ -376,9 +366,7 @@ namespace ZEngine::Rendering::Cameras State = FlyCameraState::Animating; } - // --------------------------------------------------------------------------- // Ray unprojection - // --------------------------------------------------------------------------- FlyCamera::Ray FlyCamera::GetRayFromViewport(float viewportX, float viewportY) const { @@ -400,9 +388,7 @@ namespace ZEngine::Rendering::Cameras return {Position, mag > 0.0001f ? dir / mag : f}; } - // --------------------------------------------------------------------------- // Private helpers - // --------------------------------------------------------------------------- Vec3f FlyCamera::KeyboardMoveDir() const { diff --git a/ZEngine/ZEngine/Rendering/RenderResourceManager.cpp b/ZEngine/ZEngine/Rendering/RenderResourceManager.cpp index 896c4e3ad..b4a27fe9e 100644 --- a/ZEngine/ZEngine/Rendering/RenderResourceManager.cpp +++ b/ZEngine/ZEngine/Rendering/RenderResourceManager.cpp @@ -617,6 +617,29 @@ namespace ZEngine::Rendering return {}; } + void RenderResourceManager::ReleaseMeshGeometry(const uuids::uuid& uuid) + { + std::lock_guard lock(m_uuid_map_mutex); + + // Find and invalidate the slot + for (uint32_t i = 0; i < m_uuid_to_buffer_count; ++i) + { + if (m_uuid_to_buffer[i].UUID == uuid) + { + BufferHandle h = m_uuid_to_buffer[i].Handle; + + // Free the mesh slot (geometry bytes stay in VB/IB — append-only) + if (h.IsValid() && !(h.Generation & GBUF_GEN_TAG) && h.Index < m_mesh_slot_count) + m_mesh_slots[h.Index].Generation = 0; + + // Remove from UUID map (swap with last entry) + m_uuid_to_buffer[i] = m_uuid_to_buffer[--m_uuid_to_buffer_count]; + ZENGINE_CORE_INFO("[RRM] Released mesh geometry slot for UUID {}", uuids::to_string(uuid)) + return; + } + } + } + void RenderResourceManager::Release(BufferHandle handle) { if (!handle.IsValid()) diff --git a/ZEngine/ZEngine/Rendering/RenderResourceManager.h b/ZEngine/ZEngine/Rendering/RenderResourceManager.h index e2eb5cb1e..80e943a01 100644 --- a/ZEngine/ZEngine/Rendering/RenderResourceManager.h +++ b/ZEngine/ZEngine/Rendering/RenderResourceManager.h @@ -240,12 +240,16 @@ namespace ZEngine::Rendering void ResetGeometryBuffers(); /// @brief Find the BufferHandle registered for a mesh asset by UUID. - /// @details Returns an invalid handle if the mesh has not been uploaded yet or - /// the UUID is not in the uuid-to-buffer map. - /// @param uuid Asset UUID from the meta file. - /// @return Valid BufferHandle if found; invalid otherwise. BufferHandle FindMeshBuffer(const uuids::uuid& uuid) const; + /// @brief Release the geometry slot for a mesh and unregister its UUID. + /// @details Frees the MeshSlot so it can be reused by a future upload. + /// The VB/IB bytes are not reclaimed (append-only buffer) but the + /// slot index becomes available for the next UploadMesh call. + /// No-op if the UUID is not registered. + /// @param uuid Asset UUID of the mesh to release. + void ReleaseMeshGeometry(const uuids::uuid& uuid); + /// @brief Write CPU data into an existing HOST_VISIBLE BufferView. /// @details Uses the ring allocator for staging; falls back to a one-shot staging /// buffer and RecordAndSubmit. Render-thread only. diff --git a/ZEngine/ZEngine/Rendering/Scenes/RenderScene.cpp b/ZEngine/ZEngine/Rendering/Scenes/RenderScene.cpp index d754370e1..0fdb625d3 100644 --- a/ZEngine/ZEngine/Rendering/Scenes/RenderScene.cpp +++ b/ZEngine/ZEngine/Rendering/Scenes/RenderScene.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -35,20 +36,40 @@ namespace ZEngine::Rendering::Scenes return id; } - void RenderScene::RemoveMeshInstance(uint32_t id) + void RenderScene::RemoveMeshInstance(uint32_t id, Rendering::RenderResourceManager* rrm) { + uuids::uuid freed_uuid; + SeqBeginWrite(); for (uint32_t i = 0; i < Instances.size(); ++i) { if (Instances[i].Id == id) { + freed_uuid = Instances[i].MeshUUID; Instances.erase(i); break; } } SeqEndWrite(); + + // Release geometry if no other instance references the same mesh UUID. + if (rrm && !freed_uuid.is_nil()) + { + bool still_used = false; + for (uint32_t i = 0; i < Instances.size(); ++i) + { + if (Instances[i].MeshUUID == freed_uuid) + { + still_used = true; + break; + } + } + if (!still_used) + rrm->ReleaseMeshGeometry(freed_uuid); + } + MarkInstancesDirty(); } diff --git a/ZEngine/ZEngine/Rendering/Scenes/RenderScene.h b/ZEngine/ZEngine/Rendering/Scenes/RenderScene.h index 6431090c1..9c1b59fc3 100644 --- a/ZEngine/ZEngine/Rendering/Scenes/RenderScene.h +++ b/ZEngine/ZEngine/Rendering/Scenes/RenderScene.h @@ -8,6 +8,11 @@ #include #include +namespace ZEngine::Rendering +{ + class RenderResourceManager; +} + namespace ZEngine::Rendering::Scenes { struct GridConfig @@ -108,13 +113,11 @@ namespace ZEngine::Rendering::Scenes PaddedAtomic GridDirty[3] = {}; GridConfig Grid = {}; - // --- Main-thread-only write operations --- uint32_t AddMeshInstance(const uuids::uuid& uuid, const char* name); - void RemoveMeshInstance(uint32_t id); + void RemoveMeshInstance(uint32_t id, ZEngine::Rendering::RenderResourceManager* rrm = nullptr); void SetInstanceTransform(uint32_t id, const Core::Maths::Mat4f& t); void MarkInstancesDirty(); - // --- Render-thread read (seqlock snapshot) --- // Fills `out` with a consistent copy; retries if a write was in progress. void GetInstancesSnapshot(Core::Memory::ArenaAllocator* scratch, Core::Containers::Array& out) const;