From 357dc136feee4263417da476e2951cb2c618bf8f Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 28 Apr 2026 17:23:10 +0800 Subject: [PATCH] editor: centralize engine runtime access --- editor/AGENTS.md | 13 +- editor/CMakeLists.txt | 2 +- editor/app/Bootstrap/Application.cpp | 30 +++-- editor/app/Bootstrap/Application.h | 2 + editor/app/Composition/EditorContext.cpp | 29 +++- editor/app/Composition/EditorContext.h | 9 +- editor/app/Composition/EditorShellRuntime.cpp | 7 +- editor/app/Composition/EditorShellRuntime.h | 3 +- editor/app/Core/Engine/EditorEngineServices.h | 32 +++++ .../Viewport/EditorViewportRuntimeServices.h | 6 +- .../app/Core/Windowing/EditorFrameServices.h | 3 + .../Windowing/EditorWorkspaceShellRuntime.h | 5 +- .../EditorViewportRuntimeServicesFactory.cpp | 3 +- .../EditorViewportRuntimeServicesFactory.h | 5 +- .../Viewport/Passes/SceneViewportGridPass.cpp | 20 +-- .../Viewport/Passes/SceneViewportGridPass.h | 5 +- .../SceneViewportSelectionOutlinePass.cpp | 21 +-- .../SceneViewportSelectionOutlinePass.h | 4 +- .../SceneViewportRenderPassBundle.cpp | 10 +- .../Viewport/SceneViewportRenderPassBundle.h | 6 +- .../Viewport/SceneViewportRenderService.cpp | 17 ++- .../Viewport/SceneViewportRenderService.h | 7 +- .../Viewport/ViewportHostService.cpp | 14 +- .../Rendering/Viewport/ViewportHostService.h | 7 +- .../EngineEditorServices.cpp} | 124 +++++++++++++----- .../Services/Engine/EngineEditorServices.h | 11 ++ .../Services/Scene/EngineEditorSceneBackend.h | 12 +- .../Content/EditorWindowContentController.h | 3 + ...EditorWorkspaceWindowContentController.cpp | 3 +- editor/app/Windowing/EditorWindowManager.cpp | 4 + editor/app/Windowing/EditorWindowManager.h | 3 + .../Runtime/EditorWindowRuntimeController.cpp | 3 + .../Runtime/EditorWindowRuntimeController.h | 4 + .../unit/test_hierarchy_scene_binding.cpp | 4 +- .../unit/test_inspector_presentation.cpp | 4 +- .../unit/test_scene_viewport_runtime.cpp | 4 +- 36 files changed, 337 insertions(+), 102 deletions(-) create mode 100644 editor/app/Core/Engine/EditorEngineServices.h rename editor/app/Services/{Scene/EngineEditorSceneBackend.cpp => Engine/EngineEditorServices.cpp} (76%) create mode 100644 editor/app/Services/Engine/EngineEditorServices.h diff --git a/editor/AGENTS.md b/editor/AGENTS.md index 59d6f1ae..b77eb90a 100644 --- a/editor/AGENTS.md +++ b/editor/AGENTS.md @@ -11,7 +11,8 @@ - 产品装配应以 `app/Core/Product/EditorProductManifest.*` 为单一事实源。正式 panel 集、action route、runtime owner、viewport renderer owner 先在 manifest 中声明,再派生 shell / menu / command / runtime / viewport 注册。 - UI widget / shell / workspace 代码优先保持 model/state/request/frame/result 风格。新增行为要能被 `tests/UI/Editor/unit` 以纯状态方式测试。 - scene/project 的用户操作应通过 runtime 或 command route 进入,不要在 draw/append 阶段直接改 scene 或文件系统。 -- scene 事实所有权走 `app/Core/Scene/EditorSceneBackend.h` 合约。`EditorSceneRuntime` 只消费显式 backend;只有 `app/Services/Scene/EngineEditorSceneBackend.*` 可以直接触碰 engine `SceneManager::Get()` / `ResourceManager::Get()` 这类全局 runtime。 +- engine 全局 runtime 访问权统一收口到 `app/Core/Engine/EditorEngineServices.h` 合约和 `app/Services/Engine/EngineEditorServices.*` 生产实现。`SceneManager::Get()`、`ResourceManager::Get()`、`RenderObjectIdRegistry::Get()` 这类入口只能在该生产 adapter 内出现。 +- scene 事实所有权走 `app/Core/Scene/EditorSceneBackend.h` 合约。`EditorSceneRuntime` 只消费显式 backend;`EngineEditorSceneBackend` 必须吃显式注入的 engine manager / resource manager,不要在 scene runtime、panel、composition 或 viewport pass 中重新触碰 engine 全局单例。 - scene 渲染私有逻辑不要塞进 panel 或 shell。新增渲染能力时先判断它属于 engine `Rendering/RHI`、editor viewport pass bundle,还是 UI overlay。 - 运行时路径以 `app/Core/Environment/EditorRuntimePaths.h` 为显式契约。workspace、executable、resource、project、capture 根路径由 bootstrap 一次性解析并向下传递;不要在下游重新从 repo root、当前工作目录或文档文件推导运行环境。 - 资源路径、图标、shader、截图输出都应走明确服务或 host 接口。不要硬编码从当前工作目录猜路径;手动验证截图不得写回 source tree。 @@ -31,7 +32,8 @@ - `EditorSelectionService` 是 hierarchy/project/inspector/scene viewport 之间的选择同步核心。不要在单个 panel 内维护另一套长期选择真相。 - `EditorProjectRuntime` 包装 `ProjectBrowserModel`,负责 project tree/grid、选择、文件操作、scene asset open request。文件系统改动后要刷新并 revalidate selection。 - `ProjectPanel` 只消费由 `EditorContext` / `EditorPanelServices` 提供的 `EditorProjectRuntime`,不再拥有或初始化自己的 project runtime。测试也应显式创建 `EditorProjectRuntime` 并通过 `SetProjectRuntime()` 注入,不要把 `projectRoot` 传给 panel。 -- `EditorSceneBackend` 是 scene document/backend 的显式边界;`EngineEditorSceneBackend` 是当前接入 engine 全局 scene/resource runtime 的唯一生产实现。`EditorSceneRuntime` 负责 startup scene 编排、editor scene camera、hierarchy selection、component list、transform edit history 和 scene tool state,但不直接访问 engine 单例。 +- `EditorEngineServices` 是 editor 接入 engine 全局 runtime 的唯一生产 adapter。`Application` 创建它并向 `EditorContext`、window shell runtime、viewport runtime 传递;下游只消费显式服务。 +- `EditorSceneBackend` 是 scene document/backend 的显式边界;`EngineEditorSceneBackend` 由 `EditorEngineServices` 创建,并通过显式 `SceneManager&` / `ResourceManager&` 接入真实 engine runtime。`EditorSceneRuntime` 负责 startup scene 编排、editor scene camera、hierarchy selection、component list、transform edit history 和 scene tool state,但不直接访问 engine 单例。 当前目录地图: @@ -43,13 +45,13 @@ - `include/XCEditor/Viewport`:viewport slot/shell/input bridge。这里是通用 UI viewport 容器,不是 scene renderer。 - `include/XCEditor/Windowing`:多窗口 workspace 状态、同步计划和 presentation policy。 - `src/**`:对应公共头的实现。保持偏纯函数/状态机风格。 -- `app/Core`:产品级 contracts、session、command focus、selection、panel services、scene/project/viewport/windowing 接口。 +- `app/Core`:产品级 contracts、session、command focus、selection、panel services、engine services、scene/project/viewport/windowing 接口。 - `app/Core/Scene`:scene backend 合约和 editor scene runtime 可消费的公共 scene 标识工具。 - `app/Core/Environment`:运行时路径契约。bootstrap 负责解析 `EditorRuntimePaths`,core/composition/features/rendering 只消费显式路径。 - `app/Core/Product`:产品 manifest。这里定义正式 panel 集、route 归属、runtime owner 和 viewport renderer owner。 - `app/Composition`:装配编辑器 shell。`EditorContext` 拥有 session、project runtime、scene runtime、selection、command bridge;`EditorShellRuntime` 驱动 shell interaction、hosted panels 和 viewport runtime。 - `app/Features`:产品面板与场景视图工具。 -- `app/Services`:产品 runtime 的生产服务实现。scene 的 engine 接入集中在 `app/Services/Scene/EngineEditorSceneBackend.*`;project runtime 集中在 `app/Services/Project`。 +- `app/Services`:产品 runtime 的生产服务实现。engine 全局 runtime 接入集中在 `app/Services/Engine/EngineEditorServices.*`;scene backend 由该 adapter 生产;project runtime 集中在 `app/Services/Project`。 - `app/Rendering`:编辑器 viewport、icon、object-id picking、grid/outline/helper pass 相关服务。渲染执行仍走 engine `Rendering + RHI`。 - `app/Host`:宿主接口实现。Win32/D3D12 细节只能待在这里或 rendering host 实现里。 - `app/Windowing`:窗口实例、内容控制器、生命周期协调器、workspace 多窗口同步、截图和 frame orchestration。 @@ -82,7 +84,7 @@ wWinMain - `app/Features/Scene/SceneViewportController.*`:场景视图产品交互,处理 Q/W/E/R 工具切换、F 聚焦、鼠标导航、scene icon picking、transform gizmo。 - `app/Core/Scene/EditorSceneBackend.h`:scene backend contract、startup scene result 和 game object item id helpers。 - `app/Services/Scene/EditorSceneRuntime.*`:scene selection、editor camera、transform undo/redo、component mutation 和 scene render request 的事实来源;它必须通过注入的 `EditorSceneBackend` 访问真实 scene。 -- `app/Services/Scene/EngineEditorSceneBackend.*`:当前唯一允许直接接入 engine `SceneManager` / `ResourceManager` 的 scene backend 生产实现。 +- `app/Services/Engine/EngineEditorServices.*`:当前唯一允许直接接入 engine `SceneManager` / `ResourceManager` / `RenderObjectIdRegistry` 的生产 adapter。 - `app/Rendering/Viewport/ViewportHostService.*`:离屏 viewport 资源管理和 renderer 注册。 - `app/Rendering/Viewport/SceneViewportRenderService.*`:调用 engine `SceneRenderer`,插入 grid、selection outline、selected helpers、object-id 等 editor pass。 - object-id picking 依赖有效 object-id surface 和 frame serial,修改时要覆盖 `test_viewport_object_id_picker.cpp` 及相关 viewport render plan 测试。 @@ -126,6 +128,7 @@ ctest --test-dir build -C Debug -R "editor|xceditor" --output-on-failure - 已更新根 `AGENT.md` 和本文件,去掉旧 `--project` 说法,记录当前 XCUI editor、`XCEditorCore` 分层和 product manifest 规则。 - 已移除 `ProjectPanel` 自持 `EditorProjectRuntime` 的 fallback 路径;project runtime 事实源现在只来自 `EditorContext`,面板测试改为显式 runtime 注入。 - 已把 scene 的 engine 全局访问收敛到 `EngineEditorSceneBackend`,让 `EditorSceneRuntime` 通过 `EditorSceneBackend` 合约初始化、打开 scene 和执行 hierarchy mutation;新增 backend contract 单测覆盖无 backend 失败和 fake backend 注入。 +- 已新增 `EditorEngineServices` 边界,把 `SceneManager::Get()`、`ResourceManager::Get()`、`RenderObjectIdRegistry::Get()` 从 `Application`、`EditorContext` 和 viewport shader/object-id 路径收口到 `app/Services/Engine/EngineEditorServices.*`;`EditorContext` 现在通过显式 engine service 创建 scene backend,并会在 scene runtime 初始化失败时返回失败。 - 本次改动验证过: - `cmake --build build --config Debug --target XCEditor` - `cmake --build build --config Debug --target editor_app_core_tests` diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 992c9f7a..018584e5 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -280,10 +280,10 @@ if(XCENGINE_BUILD_XCUI_EDITOR_CORE) ) set(XCUI_EDITOR_APP_SUPPORT_SOURCES + app/Services/Engine/EngineEditorServices.cpp app/Services/Scene/EditorSceneRuntime.cpp app/Services/Project/EditorProjectRuntime.cpp app/Services/Project/ProjectBrowserModel.cpp - app/Services/Scene/EngineEditorSceneBackend.cpp ) set(XCUI_EDITOR_APP_CORE_SOURCES diff --git a/editor/app/Bootstrap/Application.cpp b/editor/app/Bootstrap/Application.cpp index 56224c72..9eabbf28 100644 --- a/editor/app/Bootstrap/Application.cpp +++ b/editor/app/Bootstrap/Application.cpp @@ -3,6 +3,7 @@ #include "SystemInteractionService.h" #include "EditorContext.h" #include "EditorShellRuntime.h" +#include "Engine/EngineEditorServices.h" #include "EditorUtilityWindowRegistry.h" #include "EditorWorkspacePanelRegistry.h" #include "EditorWindowManager.h" @@ -21,8 +22,6 @@ #include #include #include -#include - #include #include @@ -156,6 +155,7 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) { m_hInstance = hInstance; m_resourceService = std::make_unique(m_hInstance); m_runtimePaths = ResolveRuntimePaths(m_resourceService->GetExecutableDirectory()); + m_engineServices = App::CreateEngineEditorServices(); EnableDpiAwareness(); const std::filesystem::path logRoot = m_resourceService->GetExecutableDirectory() / "logs"; @@ -163,10 +163,15 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) { SetUnhandledExceptionFilter(&Application::HandleUnhandledException); AppendUIEditorRuntimeTrace("app", "initialize begin"); - if (!m_editorContext->Initialize(m_runtimePaths)) { + if (m_engineServices == nullptr) { + AppendUIEditorRuntimeTrace("app", "engine services initialization failed"); + return false; + } + if (!m_editorContext->Initialize(m_runtimePaths, *m_engineServices)) { AppendUIEditorRuntimeTrace( "app", - "shell asset validation failed: " + m_editorContext->GetValidationMessage()); + "editor context initialization failed: " + + m_editorContext->GetValidationMessage()); return false; } if (!RegisterWindowClass()) { @@ -189,14 +194,16 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) { m_runtimePaths); m_renderRuntimeFactory = std::make_unique(); - App::EditorWorkspaceShellRuntimeFactory workspaceShellRuntimeFactory = []() { + App::EditorWorkspaceShellRuntimeFactory workspaceShellRuntimeFactory = + [engineServices = m_engineServices.get()]() { return App::CreateEditorWorkspaceShellRuntime( App::CreateEditorWorkspacePanelRuntimeSet(), App::CreateEditorIconService(), - App::CreateEditorViewportRuntimeServices()); - }; + App::CreateEditorViewportRuntimeServices(engineServices)); + }; m_windowManager = std::make_unique( *m_editorContext, + *m_engineServices, *m_windowSystem, *m_renderRuntimeFactory, *m_resourceService, @@ -288,7 +295,10 @@ void Application::Shutdown() { } m_systemInteractionHost.reset(); - ::XCEngine::Resources::ResourceManager::Get().Shutdown(); + if (m_engineServices != nullptr) { + m_engineServices->Shutdown(); + m_engineServices.reset(); + } if (m_windowClassAtom != 0 && m_hInstance != nullptr) { UnregisterClassW(kWindowClassName, m_hInstance); @@ -357,7 +367,9 @@ int Application::Run(HINSTANCE hInstance, int nCmdShow) { } if (m_windowManager != nullptr) { - ::XCEngine::Resources::ResourceManager::Get().UpdateAsyncLoads(); + if (m_engineServices != nullptr) { + m_engineServices->UpdateAsyncLoads(); + } m_windowManager->DestroyClosedWindows(); if (!m_windowManager->HasWindows()) { break; diff --git a/editor/app/Bootstrap/Application.h b/editor/app/Bootstrap/Application.h index fee9bad1..79486d83 100644 --- a/editor/app/Bootstrap/Application.h +++ b/editor/app/Bootstrap/Application.h @@ -17,6 +17,7 @@ class EditorWindowSystem; namespace App { class EditorContext; +class EditorEngineServices; class EditorWindowManager; class EditorWindowHostRuntime; } @@ -61,6 +62,7 @@ private: std::chrono::steady_clock::time_point m_smokeTestStartTime = {}; std::chrono::milliseconds m_smokeTestDuration = std::chrono::milliseconds::zero(); std::unique_ptr m_editorContext = {}; + std::unique_ptr m_engineServices = {}; std::unique_ptr m_windowSystem = {}; std::unique_ptr m_windowHostRuntime = {}; std::unique_ptr m_renderRuntimeFactory = {}; diff --git a/editor/app/Composition/EditorContext.cpp b/editor/app/Composition/EditorContext.cpp index 4ddc520f..868f9d22 100644 --- a/editor/app/Composition/EditorContext.cpp +++ b/editor/app/Composition/EditorContext.cpp @@ -1,8 +1,9 @@ #include "EditorContext.h" #include "EditorShellAssetBuilder.h" -#include "Scene/EngineEditorSceneBackend.h" +#include "Engine/EditorEngineServices.h" #include "Scene/EditorSceneRuntime.h" #include "Panels/EditorPanelIds.h" +#include "Viewport/EditorViewportRuntimeServices.h" #include "WorkspaceEventSync.h" #include #include @@ -53,7 +54,11 @@ UIEditorWorkspacePanelPresentationModel* FindMutablePresentation( } // namespace -bool EditorContext::Initialize(const EditorRuntimePaths& runtimePaths) { +bool EditorContext::Initialize( + const EditorRuntimePaths& runtimePaths, + EditorEngineServices& engineServices) { + m_valid = false; + m_validationMessage.clear(); AppendUIEditorRuntimeTrace("startup", "EditorContext::Initialize begin"); m_shellAsset = BuildEditorApplicationShellAsset(runtimePaths); AppendUIEditorRuntimeTrace("startup", "BuildEditorApplicationShellAsset complete"); @@ -63,6 +68,7 @@ bool EditorContext::Initialize(const EditorRuntimePaths& runtimePaths) { std::string("ValidateEditorShellAsset complete valid=") + (m_shellValidation.IsValid() ? "1" : "0")); if (!m_shellValidation.IsValid()) { + m_validationMessage = m_shellValidation.message; return false; } @@ -76,9 +82,13 @@ bool EditorContext::Initialize(const EditorRuntimePaths& runtimePaths) { m_projectRuntime.Initialize(runtimePaths.projectRoot); AppendUIEditorRuntimeTrace("startup", "EditorProjectRuntime::Initialize end"); m_projectRuntime.BindSelectionService(&m_selectionService); - m_sceneRuntime.SetBackend(CreateEngineEditorSceneBackend()); + m_sceneRuntime.SetBackend(engineServices.CreateSceneBackend()); AppendUIEditorRuntimeTrace("startup", "EditorSceneRuntime::Initialize begin"); - m_sceneRuntime.Initialize(m_session.projectRoot); + if (!m_sceneRuntime.Initialize(m_session.projectRoot)) { + m_validationMessage = "Editor scene runtime failed to initialize."; + AppendUIEditorRuntimeTrace("startup", m_validationMessage); + return false; + } AppendUIEditorRuntimeTrace("startup", "EditorSceneRuntime::Initialize end"); m_sceneRuntime.BindSelectionService(&m_selectionService); ResetEditorColorPickerToolState(m_colorPickerToolState); @@ -95,6 +105,7 @@ bool EditorContext::Initialize(const EditorRuntimePaths& runtimePaths) { m_lastStatus.clear(); m_lastMessage.clear(); SetReadyStatus(); + m_valid = true; AppendUIEditorRuntimeTrace("startup", "EditorContext::Initialize end"); return true; } @@ -131,11 +142,11 @@ void EditorContext::SyncSessionFromWorkspace( } bool EditorContext::IsValid() const { - return m_shellValidation.IsValid(); + return m_valid; } const std::string& EditorContext::GetValidationMessage() const { - return m_shellValidation.message; + return m_validationMessage; } const EditorShellAsset& EditorContext::GetShellAsset() const { @@ -300,6 +311,12 @@ std::vector EditorContext::SyncWorkspacePanelFrameEvents( return SyncWorkspaceEvents(*this, panelEvents); } +void EditorContext::SyncSceneViewportRenderRequest( + EditorSceneViewportRuntime& sceneViewportRuntime) { + sceneViewportRuntime.SetRenderRequest( + m_sceneRuntime.BuildSceneViewportRenderRequest()); +} + } // namespace XCEngine::UI::Editor::App namespace XCEngine::UI::Editor::App { diff --git a/editor/app/Composition/EditorContext.h b/editor/app/Composition/EditorContext.h index 7fa2900e..bf487331 100644 --- a/editor/app/Composition/EditorContext.h +++ b/editor/app/Composition/EditorContext.h @@ -30,11 +30,14 @@ class SystemInteractionService; namespace XCEngine::UI::Editor::App { +class EditorEngineServices; class EditorEditCommandRoute; class EditorContext : public EditorFrameServices { public: - bool Initialize(const EditorRuntimePaths& runtimePaths); + bool Initialize( + const EditorRuntimePaths& runtimePaths, + EditorEngineServices& engineServices); void AttachTextMeasurer(const UIEditorTextMeasurer& textMeasurer) override; void SetSystemInteractionHost(System::SystemInteractionService* systemInteractionHost); void BindEditCommandRoutes( @@ -86,6 +89,8 @@ public: const UIEditorShellInteractionState& interactionState) const override; std::vector SyncWorkspacePanelFrameEvents( const std::vector& panelEvents) override; + void SyncSceneViewportRenderRequest( + EditorSceneViewportRuntime& sceneViewportRuntime) override; private: void AppendConsoleEntry(std::string channel, std::string message); @@ -103,6 +108,8 @@ private: EditorUtilityWindowRequestState m_utilityWindowRequestState = {}; EditorHostCommandBridge m_hostCommandBridge = {}; System::SystemInteractionService* m_systemInteractionHost = nullptr; + bool m_valid = false; + std::string m_validationMessage = {}; std::string m_lastStatus = {}; std::string m_lastMessage = {}; }; diff --git a/editor/app/Composition/EditorShellRuntime.cpp b/editor/app/Composition/EditorShellRuntime.cpp index 4fa91d01..61b0d6f5 100644 --- a/editor/app/Composition/EditorShellRuntime.cpp +++ b/editor/app/Composition/EditorShellRuntime.cpp @@ -21,7 +21,8 @@ void EditorShellRuntime::Initialize( const EditorRuntimePaths& runtimePaths, Rendering::Host::UiTextureHost& textureHost, Host::EditorHostResourceService& resourceService, - UIEditorTextMeasurer& textMeasurer) { + UIEditorTextMeasurer& textMeasurer, + EditorEngineServices& engineServices) { assert(m_iconService != nullptr); assert(m_viewportRuntimeServices != nullptr); if (m_iconService == nullptr || m_viewportRuntimeServices == nullptr) { @@ -29,7 +30,7 @@ void EditorShellRuntime::Initialize( } m_iconService->Initialize(textureHost, resourceService); - m_viewportRuntimeServices->Initialize(runtimePaths); + m_viewportRuntimeServices->Initialize(runtimePaths, engineServices); m_workspacePanels.Initialize( EditorWorkspacePanelInitializationContext{ .runtimePaths = runtimePaths, @@ -248,6 +249,8 @@ void EditorShellRuntime::Update( }); m_traceEntries = frameServices.SyncWorkspacePanelFrameEvents( m_workspacePanels.CollectFrameEvents()); + frameServices.SyncSceneViewportRenderRequest( + m_viewportRuntimeServices->GetSceneViewportRuntime()); } } // namespace XCEngine::UI::Editor::App diff --git a/editor/app/Composition/EditorShellRuntime.h b/editor/app/Composition/EditorShellRuntime.h index 6649e46e..0881fd02 100644 --- a/editor/app/Composition/EditorShellRuntime.h +++ b/editor/app/Composition/EditorShellRuntime.h @@ -54,7 +54,8 @@ public: const EditorRuntimePaths& runtimePaths, Rendering::Host::UiTextureHost& textureHost, Host::EditorHostResourceService& resourceService, - UIEditorTextMeasurer& textMeasurer) override; + UIEditorTextMeasurer& textMeasurer, + EditorEngineServices& engineServices) override; void Shutdown() override; void ResetInteractionState() override; void AttachViewportWindowRenderer(Rendering::Host::ViewportRenderHost& renderer) override; diff --git a/editor/app/Core/Engine/EditorEngineServices.h b/editor/app/Core/Engine/EditorEngineServices.h new file mode 100644 index 00000000..495634e0 --- /dev/null +++ b/editor/app/Core/Engine/EditorEngineServices.h @@ -0,0 +1,32 @@ +#pragma once + +#include "Scene/EditorSceneBackend.h" + +#include +#include +#include +#include + +#include +#include + +namespace XCEngine::UI::Editor::App { + +class EditorEngineServices { +public: + virtual ~EditorEngineServices() = default; + + virtual void UpdateAsyncLoads() = 0; + virtual void Shutdown() = 0; + + virtual std::unique_ptr CreateSceneBackend() = 0; + + virtual ::XCEngine::Resources::ResourceHandle<::XCEngine::Resources::Shader> + LoadShader(const ::XCEngine::Containers::String& path) = 0; + + virtual bool TryResolveRenderObjectId( + ::XCEngine::Rendering::RenderObjectId renderObjectId, + std::uint64_t& outRuntimeObjectId) const = 0; +}; + +} // namespace XCEngine::UI::Editor::App diff --git a/editor/app/Core/Viewport/EditorViewportRuntimeServices.h b/editor/app/Core/Viewport/EditorViewportRuntimeServices.h index 34ffa21e..ba145c4e 100644 --- a/editor/app/Core/Viewport/EditorViewportRuntimeServices.h +++ b/editor/app/Core/Viewport/EditorViewportRuntimeServices.h @@ -20,6 +20,8 @@ class ViewportRenderHost; namespace XCEngine::UI::Editor::App { +class EditorEngineServices; + class EditorSceneViewportRuntime { public: virtual ~EditorSceneViewportRuntime() = default; @@ -32,7 +34,9 @@ class EditorViewportRuntimeServices { public: virtual ~EditorViewportRuntimeServices() = default; - virtual void Initialize(const EditorRuntimePaths& runtimePaths) = 0; + virtual void Initialize( + const EditorRuntimePaths& runtimePaths, + EditorEngineServices& engineServices) = 0; virtual void Shutdown() = 0; virtual void AttachWindowRenderer(Rendering::Host::ViewportRenderHost& windowRenderer) = 0; virtual void DetachWindowRenderer() = 0; diff --git a/editor/app/Core/Windowing/EditorFrameServices.h b/editor/app/Core/Windowing/EditorFrameServices.h index 7fd209d1..80d590a4 100644 --- a/editor/app/Core/Windowing/EditorFrameServices.h +++ b/editor/app/Core/Windowing/EditorFrameServices.h @@ -17,6 +17,7 @@ namespace XCEngine::UI::Editor::App { class EditorEditCommandRoute; +class EditorSceneViewportRuntime; struct WorkspaceTraceEntry { std::string channel = {}; @@ -57,6 +58,8 @@ public: const UIEditorShellInteractionState& interactionState) const = 0; virtual std::vector SyncWorkspacePanelFrameEvents( const std::vector& panelEvents) = 0; + virtual void SyncSceneViewportRenderRequest( + EditorSceneViewportRuntime& sceneViewportRuntime) = 0; }; } // namespace XCEngine::UI::Editor::App diff --git a/editor/app/Core/Windowing/EditorWorkspaceShellRuntime.h b/editor/app/Core/Windowing/EditorWorkspaceShellRuntime.h index 2e08aa1a..26648a7f 100644 --- a/editor/app/Core/Windowing/EditorWorkspaceShellRuntime.h +++ b/editor/app/Core/Windowing/EditorWorkspaceShellRuntime.h @@ -42,6 +42,8 @@ class EditorHostResourceService; namespace XCEngine::UI::Editor::App { +class EditorEngineServices; + enum class EditorWorkspaceShellCursorKind : std::uint8_t { Arrow = 0, ResizeEW @@ -55,7 +57,8 @@ public: const EditorRuntimePaths& runtimePaths, Rendering::Host::UiTextureHost& textureHost, Host::EditorHostResourceService& resourceService, - UIEditorTextMeasurer& textMeasurer) = 0; + UIEditorTextMeasurer& textMeasurer, + EditorEngineServices& engineServices) = 0; virtual void Shutdown() = 0; virtual void ResetInteractionState() = 0; virtual void AttachViewportWindowRenderer(Rendering::Host::ViewportRenderHost& renderer) = 0; diff --git a/editor/app/Rendering/Viewport/EditorViewportRuntimeServicesFactory.cpp b/editor/app/Rendering/Viewport/EditorViewportRuntimeServicesFactory.cpp index 31a9157d..f73d3e50 100644 --- a/editor/app/Rendering/Viewport/EditorViewportRuntimeServicesFactory.cpp +++ b/editor/app/Rendering/Viewport/EditorViewportRuntimeServicesFactory.cpp @@ -4,7 +4,8 @@ namespace XCEngine::UI::Editor::App { -std::unique_ptr CreateEditorViewportRuntimeServices() { +std::unique_ptr CreateEditorViewportRuntimeServices( + EditorEngineServices*) { return std::make_unique(); } diff --git a/editor/app/Rendering/Viewport/EditorViewportRuntimeServicesFactory.h b/editor/app/Rendering/Viewport/EditorViewportRuntimeServicesFactory.h index 11422c84..1723f0f1 100644 --- a/editor/app/Rendering/Viewport/EditorViewportRuntimeServicesFactory.h +++ b/editor/app/Rendering/Viewport/EditorViewportRuntimeServicesFactory.h @@ -6,6 +6,9 @@ namespace XCEngine::UI::Editor::App { -std::unique_ptr CreateEditorViewportRuntimeServices(); +class EditorEngineServices; + +std::unique_ptr CreateEditorViewportRuntimeServices( + EditorEngineServices* engineServices); } // namespace XCEngine::UI::Editor::App diff --git a/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.cpp b/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.cpp index 4dd31a8f..bd7e6369 100644 --- a/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.cpp +++ b/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.cpp @@ -1,10 +1,11 @@ #include "Viewport/Passes/SceneViewportGridPass.h" +#include "Engine/EditorEngineServices.h" + #include #include #include -#include #include #include #include @@ -284,8 +285,10 @@ public: Impl() = default; void SetShaderPath( - const ::XCEngine::Containers::String& shaderPath) { + const ::XCEngine::Containers::String& shaderPath, + EditorEngineServices* engineServices) { m_shaderPath = shaderPath; + m_engineServices = engineServices; DestroyResources(); } @@ -477,17 +480,16 @@ private: return false; } - if (m_shaderPath.Empty()) { + if (m_shaderPath.Empty() || m_engineServices == nullptr) { ::XCEngine::Debug::Logger::Get().Error( ::XCEngine::Debug::LogCategory::Rendering, - "SceneViewportGridPassRenderer requires a valid shader path"); + "SceneViewportGridPassRenderer requires a valid shader path and engine services"); return false; } m_device = renderContext.device; m_backendType = renderContext.backendType; - m_shader = ::XCEngine::Resources::ResourceManager::Get() - .Load<::XCEngine::Resources::Shader>(m_shaderPath); + m_shader = m_engineServices->LoadShader(m_shaderPath); if (!m_shader.IsValid()) { ::XCEngine::Debug::Logger::Get().Error( ::XCEngine::Debug::LogCategory::Rendering, @@ -609,6 +611,7 @@ private: ::XCEngine::RHI::RHIDescriptorPool* m_constantPool = nullptr; ::XCEngine::RHI::RHIDescriptorSet* m_constantSet = nullptr; ::XCEngine::Containers::String m_shaderPath = {}; + EditorEngineServices* m_engineServices = nullptr; ::XCEngine::Resources::ResourceHandle<::XCEngine::Resources::Shader> m_shader = {}; ::XCEngine::RHI::Format m_renderTargetFormat = @@ -629,8 +632,9 @@ void SceneViewportGridPassRenderer::Shutdown() { } void SceneViewportGridPassRenderer::SetShaderPath( - const ::XCEngine::Containers::String& shaderPath) { - m_impl->SetShaderPath(shaderPath); + const ::XCEngine::Containers::String& shaderPath, + EditorEngineServices* engineServices) { + m_impl->SetShaderPath(shaderPath, engineServices); } bool SceneViewportGridPassRenderer::Render( diff --git a/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.h b/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.h index 9365d59a..196307c7 100644 --- a/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.h +++ b/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.h @@ -11,6 +11,8 @@ namespace XCEngine::UI::Editor::App { +class EditorEngineServices; + class SceneViewportGridPassRenderer { public: SceneViewportGridPassRenderer(); @@ -22,7 +24,8 @@ public: void Shutdown(); void SetShaderPath( - const ::XCEngine::Containers::String& shaderPath); + const ::XCEngine::Containers::String& shaderPath, + EditorEngineServices* engineServices); bool Render( const ::XCEngine::Rendering::RenderContext& renderContext, diff --git a/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp b/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp index 8d335380..db5d7ff7 100644 --- a/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp +++ b/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp @@ -1,5 +1,6 @@ #include "Viewport/Passes/SceneViewportSelectionOutlinePass.h" +#include "Engine/EditorEngineServices.h" #include "Viewport/ViewportRenderTargets.h" #include @@ -7,7 +8,6 @@ #include #include -#include #include #include #include @@ -274,9 +274,11 @@ public: void SetShaderPaths( const ::XCEngine::Containers::String& selectionMaskShaderPath, - const ::XCEngine::Containers::String& selectionOutlineShaderPath) { + const ::XCEngine::Containers::String& selectionOutlineShaderPath, + EditorEngineServices* engineServices) { m_selectionMaskShaderPath = selectionMaskShaderPath; m_shaderPath = selectionOutlineShaderPath; + m_engineServices = engineServices; if (m_selectionMaskPass != nullptr) { m_selectionMaskPass->Shutdown(); } @@ -499,17 +501,15 @@ private: return false; } - if (m_shaderPath.Empty()) { + if (m_shaderPath.Empty() || m_engineServices == nullptr) { ::XCEngine::Debug::Logger::Get().Error( ::XCEngine::Debug::LogCategory::Rendering, - "SceneViewportSelectionOutlinePassRenderer requires a valid shader path"); + "SceneViewportSelectionOutlinePassRenderer requires a valid shader path and engine services"); return false; } ::XCEngine::Resources::ResourceHandle<::XCEngine::Resources::Shader> - shader = - ::XCEngine::Resources::ResourceManager::Get() - .Load<::XCEngine::Resources::Shader>(m_shaderPath); + shader = m_engineServices->LoadShader(m_shaderPath); if (!shader.IsValid()) { ::XCEngine::Debug::Logger::Get().Error( ::XCEngine::Debug::LogCategory::Rendering, @@ -709,6 +709,7 @@ private: ::XCEngine::RHI::RHIDescriptorPool* m_texturePool = nullptr; ::XCEngine::RHI::RHIDescriptorSet* m_textureSet = nullptr; ::XCEngine::Containers::String m_shaderPath = {}; + EditorEngineServices* m_engineServices = nullptr; std::optional< ::XCEngine::Resources::ResourceHandle<::XCEngine::Resources::Shader>> m_shader = {}; @@ -731,10 +732,12 @@ void SceneViewportSelectionOutlinePassRenderer::Shutdown() { void SceneViewportSelectionOutlinePassRenderer::SetShaderPaths( const ::XCEngine::Containers::String& selectionMaskShaderPath, - const ::XCEngine::Containers::String& selectionOutlineShaderPath) { + const ::XCEngine::Containers::String& selectionOutlineShaderPath, + EditorEngineServices* engineServices) { m_impl->SetShaderPaths( selectionMaskShaderPath, - selectionOutlineShaderPath); + selectionOutlineShaderPath, + engineServices); } bool SceneViewportSelectionOutlinePassRenderer::Render( diff --git a/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.h b/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.h index 85f0da3a..6f07381a 100644 --- a/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.h +++ b/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.h @@ -13,6 +13,7 @@ namespace XCEngine::UI::Editor::App { +class EditorEngineServices; struct ViewportRenderTargets; class SceneViewportSelectionOutlinePassRenderer { @@ -31,7 +32,8 @@ public: void Shutdown(); void SetShaderPaths( const ::XCEngine::Containers::String& selectionMaskShaderPath, - const ::XCEngine::Containers::String& selectionOutlineShaderPath); + const ::XCEngine::Containers::String& selectionOutlineShaderPath, + EditorEngineServices* engineServices); bool Render( const ::XCEngine::Rendering::RenderContext& renderContext, diff --git a/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.cpp b/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.cpp index 0424c2f1..ab013535 100644 --- a/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.cpp +++ b/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.cpp @@ -9,11 +9,15 @@ void SceneViewportRenderPassBundle::Shutdown() { } void SceneViewportRenderPassBundle::Initialize( - const SceneViewportShaderPaths& shaderPaths) { - m_gridRenderer.SetShaderPath(shaderPaths.infiniteGridShaderPath); + const SceneViewportShaderPaths& shaderPaths, + EditorEngineServices& engineServices) { + m_gridRenderer.SetShaderPath( + shaderPaths.infiniteGridShaderPath, + &engineServices); m_selectionOutlineRenderer.SetShaderPaths( shaderPaths.selectionMaskShaderPath, - shaderPaths.selectionOutlineShaderPath); + shaderPaths.selectionOutlineShaderPath, + &engineServices); } SceneViewportRenderPlanBuildResult diff --git a/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.h b/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.h index e82638f3..4f95866a 100644 --- a/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.h +++ b/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.h @@ -8,12 +8,16 @@ namespace XCEngine::UI::Editor::App { +class EditorEngineServices; + class SceneViewportRenderPassBundle { public: ~SceneViewportRenderPassBundle() = default; void Shutdown(); - void Initialize(const SceneViewportShaderPaths& shaderPaths); + void Initialize( + const SceneViewportShaderPaths& shaderPaths, + EditorEngineServices& engineServices); SceneViewportRenderPlanBuildResult BuildRenderPlan( ViewportRenderTargets& targets, diff --git a/editor/app/Rendering/Viewport/SceneViewportRenderService.cpp b/editor/app/Rendering/Viewport/SceneViewportRenderService.cpp index 417d7365..e7029913 100644 --- a/editor/app/Rendering/Viewport/SceneViewportRenderService.cpp +++ b/editor/app/Rendering/Viewport/SceneViewportRenderService.cpp @@ -1,8 +1,8 @@ #include "Viewport/SceneViewportRenderService.h" +#include "Engine/EditorEngineServices.h" #include "Viewport/ViewportObjectIdPicker.h" -#include #include #include @@ -53,13 +53,16 @@ SceneViewportRenderService::GetViewportResourceRequirements() { } void SceneViewportRenderService::Initialize( - const SceneViewportShaderPaths& shaderPaths) { - m_renderPassBundle.Initialize(shaderPaths); + const SceneViewportShaderPaths& shaderPaths, + EditorEngineServices& engineServices) { + m_engineServices = &engineServices; + m_renderPassBundle.Initialize(shaderPaths, engineServices); } void SceneViewportRenderService::Shutdown() { m_renderRequest = {}; m_renderPassBundle.Shutdown(); + m_engineServices = nullptr; m_sceneRenderer.reset(); m_device = nullptr; m_lastTargets = nullptr; @@ -211,10 +214,10 @@ ViewportObjectIdPickResult SceneViewportRenderService::PickObject( } std::uint64_t runtimeObjectId = 0u; - if (!::XCEngine::Rendering::RenderObjectIdRegistry::Get() - .TryResolveRuntimeObjectId( - result.renderObjectId, - runtimeObjectId)) { + if (m_engineServices == nullptr || + !m_engineServices->TryResolveRenderObjectId( + result.renderObjectId, + runtimeObjectId)) { return result; } diff --git a/editor/app/Rendering/Viewport/SceneViewportRenderService.h b/editor/app/Rendering/Viewport/SceneViewportRenderService.h index 7b1949f8..4d0f59c6 100644 --- a/editor/app/Rendering/Viewport/SceneViewportRenderService.h +++ b/editor/app/Rendering/Viewport/SceneViewportRenderService.h @@ -25,6 +25,8 @@ class RHIDevice; namespace XCEngine::UI::Editor::App { +class EditorEngineServices; + class SceneViewportRenderService : public IViewportContentRenderer , public EditorSceneViewportRuntime @@ -35,7 +37,9 @@ public: static EditorViewportResourceRequirements GetViewportResourceRequirements(); - void Initialize(const SceneViewportShaderPaths& shaderPaths); + void Initialize( + const SceneViewportShaderPaths& shaderPaths, + EditorEngineServices& engineServices); void Shutdown(); void SetRenderRequest(SceneViewportRenderRequest request) override; const IViewportObjectPickerService& GetObjectPicker() const override; @@ -55,6 +59,7 @@ private: SceneViewportRenderRequest m_renderRequest = {}; std::unique_ptr<::XCEngine::Rendering::SceneRenderer> m_sceneRenderer = {}; SceneViewportRenderPassBundle m_renderPassBundle = {}; + EditorEngineServices* m_engineServices = nullptr; ::XCEngine::RHI::RHIDevice* m_device = nullptr; ViewportRenderTargets* m_lastTargets = nullptr; ::XCEngine::Rendering::RenderContext m_lastRenderContext = {}; diff --git a/editor/app/Rendering/Viewport/ViewportHostService.cpp b/editor/app/Rendering/Viewport/ViewportHostService.cpp index a9a69ffd..6fa41bc8 100644 --- a/editor/app/Rendering/Viewport/ViewportHostService.cpp +++ b/editor/app/Rendering/Viewport/ViewportHostService.cpp @@ -1,5 +1,6 @@ #include "ViewportHostService.h" +#include "Engine/EditorEngineServices.h" #include "Panels/EditorPanelIds.h" #include "Product/EditorProductManifest.h" #include "Viewport/SceneViewportResourcePaths.h" @@ -41,12 +42,18 @@ private: } // namespace -ViewportHostService::ViewportHostService() = default; +ViewportHostService::ViewportHostService(EditorEngineServices* engineServices) + : m_engineServices(engineServices) {} ViewportHostService::~ViewportHostService() = default; -void ViewportHostService::Initialize(const EditorRuntimePaths& runtimePaths) { - m_sceneViewportRuntime.Initialize(BuildSceneViewportShaderPaths(runtimePaths)); +void ViewportHostService::Initialize( + const EditorRuntimePaths& runtimePaths, + EditorEngineServices& engineServices) { + m_engineServices = &engineServices; + m_sceneViewportRuntime.Initialize( + BuildSceneViewportShaderPaths(runtimePaths), + engineServices); m_placeholderRenderers.clear(); for (const EditorProductPanelDescriptor& panel : GetEditorProductPanels()) { if (panel.presentationKind != UIEditorPanelPresentationKind::ViewportShell) { @@ -123,6 +130,7 @@ void ViewportHostService::Shutdown() { m_windowRenderer = nullptr; m_device = nullptr; m_surfacePresentationEnabled = false; + m_engineServices = nullptr; m_entries.clear(); m_retiredTargetsBySlot.clear(); } diff --git a/editor/app/Rendering/Viewport/ViewportHostService.h b/editor/app/Rendering/Viewport/ViewportHostService.h index 305e0e40..ba28cb20 100644 --- a/editor/app/Rendering/Viewport/ViewportHostService.h +++ b/editor/app/Rendering/Viewport/ViewportHostService.h @@ -20,10 +20,12 @@ namespace XCEngine::UI::Editor::App { class ViewportHostService final : public EditorViewportRuntimeServices { public: - ViewportHostService(); + ViewportHostService(EditorEngineServices* engineServices = nullptr); ~ViewportHostService(); - void Initialize(const EditorRuntimePaths& runtimePaths) override; + void Initialize( + const EditorRuntimePaths& runtimePaths, + EditorEngineServices& engineServices) override; void Shutdown() override; void AttachWindowRenderer(Rendering::Host::ViewportRenderHost& windowRenderer) override; void DetachWindowRenderer() override; @@ -81,6 +83,7 @@ private: ::XCEngine::RHI::RHIDevice* m_device = nullptr; ViewportRenderTargetManager m_renderTargetManager = {}; bool m_surfacePresentationEnabled = false; + EditorEngineServices* m_engineServices = nullptr; std::unordered_map m_entries = {}; std::vector> m_retiredTargetsBySlot = {}; std::vector> m_placeholderRenderers = {}; diff --git a/editor/app/Services/Scene/EngineEditorSceneBackend.cpp b/editor/app/Services/Engine/EngineEditorServices.cpp similarity index 76% rename from editor/app/Services/Scene/EngineEditorSceneBackend.cpp rename to editor/app/Services/Engine/EngineEditorServices.cpp index c754e716..140eab87 100644 --- a/editor/app/Services/Scene/EngineEditorSceneBackend.cpp +++ b/editor/app/Services/Engine/EngineEditorServices.cpp @@ -1,3 +1,4 @@ +#include "Engine/EngineEditorServices.h" #include "Scene/EngineEditorSceneBackend.h" #include @@ -5,6 +6,7 @@ #include #include #include +#include #include #include @@ -27,7 +29,10 @@ using ::XCEngine::Components::GameObject; using ::XCEngine::Components::Scene; using ::XCEngine::Components::SceneManager; using ::XCEngine::Components::TransformComponent; +using ::XCEngine::Rendering::RenderObjectId; +using ::XCEngine::Rendering::RenderObjectIdRegistry; using ::XCEngine::Resources::ResourceManager; +using ::XCEngine::Resources::Shader; void TraceSceneStartup(std::string message) { ::XCEngine::UI::Editor::AppendUIEditorRuntimeTrace("startup", std::move(message)); @@ -40,8 +45,7 @@ struct ClipboardNode { std::vector children = {}; }; -Scene* ResolvePrimaryScene() { - SceneManager& sceneManager = SceneManager::Get(); +Scene* ResolvePrimaryScene(SceneManager& sceneManager) { if (Scene* activeScene = sceneManager.GetActiveScene(); activeScene != nullptr) { return activeScene; @@ -169,8 +173,10 @@ std::optional FindSiblingIndex( return static_cast(std::distance(siblings.begin(), it)); } -GameObject* FindGameObjectByItemId(std::string_view itemId) { - Scene* scene = ResolvePrimaryScene(); +GameObject* FindGameObjectByItemId( + SceneManager& sceneManager, + std::string_view itemId) { + Scene* scene = ResolvePrimaryScene(sceneManager); const std::optional gameObjectId = ParseEditorGameObjectItemId(itemId); if (scene == nullptr || !gameObjectId.has_value()) { @@ -181,12 +187,13 @@ GameObject* FindGameObjectByItemId(std::string_view itemId) { } bool MoveGameObjectRelativeToTarget( + SceneManager& sceneManager, std::string_view itemId, std::string_view targetItemId, bool placeAfterTarget) { - Scene* scene = ResolvePrimaryScene(); - GameObject* gameObject = FindGameObjectByItemId(itemId); - GameObject* target = FindGameObjectByItemId(targetItemId); + Scene* scene = ResolvePrimaryScene(sceneManager); + GameObject* gameObject = FindGameObjectByItemId(sceneManager, itemId); + GameObject* target = FindGameObjectByItemId(sceneManager, targetItemId); if (scene == nullptr || gameObject == nullptr || target == nullptr || @@ -231,6 +238,12 @@ bool MoveGameObjectRelativeToTarget( class EngineEditorSceneBackend final : public EditorSceneBackend { public: + EngineEditorSceneBackend( + SceneManager& sceneManager, + ResourceManager& resourceManager) + : m_sceneManager(sceneManager) + , m_resourceManager(resourceManager) {} + EditorStartupSceneResult EnsureStartupScene( const std::filesystem::path& projectRoot) override { EditorStartupSceneResult result = {}; @@ -239,10 +252,10 @@ public: return result; } - ResourceManager::Get().SetResourceRoot(projectRoot.string().c_str()); + m_resourceManager.SetResourceRoot(projectRoot.string().c_str()); TraceSceneStartup("ResourceManager::SetResourceRoot complete"); - if (Scene* activeScene = ResolvePrimaryScene(); + if (Scene* activeScene = ResolvePrimaryScene(m_sceneManager); activeScene != nullptr) { result.ready = true; result.sceneName = activeScene->GetName(); @@ -252,24 +265,22 @@ public: const std::filesystem::path startupScenePath = (projectRoot / "Assets" / "Scenes" / "Main.xc").lexically_normal(); - SceneManager& sceneManager = SceneManager::Get(); - if (std::filesystem::exists(startupScenePath) && std::filesystem::is_regular_file(startupScenePath)) { TraceSceneStartup( "SceneManager::LoadScene begin path=" + startupScenePath.string()); { ResourceManager::ScopedDeferredSceneLoad deferredSceneLoad( - ResourceManager::Get()); - sceneManager.LoadScene(startupScenePath.string()); + m_resourceManager); + m_sceneManager.LoadScene(startupScenePath.string()); } TraceSceneStartup("SceneManager::LoadScene end"); Scene* loadedScene = - sceneManager.GetScene(startupScenePath.stem().string()); + m_sceneManager.GetScene(startupScenePath.stem().string()); if (loadedScene == nullptr) { - loadedScene = ResolvePrimaryScene(); + loadedScene = ResolvePrimaryScene(m_sceneManager); } else { - sceneManager.SetActiveScene(loadedScene); + m_sceneManager.SetActiveScene(loadedScene); } if (loadedScene != nullptr) { @@ -283,9 +294,9 @@ public: } } - if (Scene* scene = sceneManager.CreateScene("Main"); + if (Scene* scene = m_sceneManager.CreateScene("Main"); scene != nullptr) { - sceneManager.SetActiveScene(scene); + m_sceneManager.SetActiveScene(scene); result.ready = true; result.sceneName = scene->GetName(); TraceSceneStartup( @@ -299,7 +310,7 @@ public: } Scene* GetActiveScene() const override { - return ResolvePrimaryScene(); + return ResolvePrimaryScene(m_sceneManager); } bool OpenSceneAsset(const std::filesystem::path& scenePath) override { @@ -314,24 +325,23 @@ public: return false; } - SceneManager& sceneManager = SceneManager::Get(); { ResourceManager::ScopedDeferredSceneLoad deferredSceneLoad( - ResourceManager::Get()); - sceneManager.LoadScene(scenePath.string()); + m_resourceManager); + m_sceneManager.LoadScene(scenePath.string()); } - Scene* loadedScene = sceneManager.GetScene(scenePath.stem().string()); + Scene* loadedScene = m_sceneManager.GetScene(scenePath.stem().string()); if (loadedScene == nullptr) { - loadedScene = ResolvePrimaryScene(); + loadedScene = ResolvePrimaryScene(m_sceneManager); } else { - sceneManager.SetActiveScene(loadedScene); + m_sceneManager.SetActiveScene(loadedScene); } return loadedScene != nullptr; } GameObject* FindGameObject(std::string_view itemId) const override { - return FindGameObjectByItemId(itemId); + return FindGameObjectByItemId(m_sceneManager, itemId); } bool RenameGameObject( @@ -347,7 +357,7 @@ public: } bool DeleteGameObject(std::string_view itemId) override { - Scene* scene = ResolvePrimaryScene(); + Scene* scene = ResolvePrimaryScene(m_sceneManager); GameObject* gameObject = FindGameObject(itemId); if (scene == nullptr || gameObject == nullptr) { return false; @@ -358,7 +368,7 @@ public: } std::string DuplicateGameObject(std::string_view itemId) override { - Scene* scene = ResolvePrimaryScene(); + Scene* scene = ResolvePrimaryScene(m_sceneManager); GameObject* gameObject = FindGameObject(itemId); if (scene == nullptr || gameObject == nullptr) { return {}; @@ -391,13 +401,21 @@ public: bool MoveGameObjectBefore( std::string_view itemId, std::string_view targetItemId) override { - return MoveGameObjectRelativeToTarget(itemId, targetItemId, false); + return MoveGameObjectRelativeToTarget( + m_sceneManager, + itemId, + targetItemId, + false); } bool MoveGameObjectAfter( std::string_view itemId, std::string_view targetItemId) override { - return MoveGameObjectRelativeToTarget(itemId, targetItemId, true); + return MoveGameObjectRelativeToTarget( + m_sceneManager, + itemId, + targetItemId, + true); } bool MoveGameObjectToRoot(std::string_view itemId) override { @@ -409,12 +427,54 @@ public: gameObject->SetParent(nullptr); return true; } + +private: + SceneManager& m_sceneManager; + ResourceManager& m_resourceManager; +}; + +class EngineEditorServices final : public EditorEngineServices { +public: + void UpdateAsyncLoads() override { + ResourceManager::Get().UpdateAsyncLoads(); + } + + void Shutdown() override { + ResourceManager::Get().Shutdown(); + } + + std::unique_ptr CreateSceneBackend() override { + return CreateEngineEditorSceneBackend( + SceneManager::Get(), + ResourceManager::Get()); + } + + ::XCEngine::Resources::ResourceHandle LoadShader( + const ::XCEngine::Containers::String& path) override { + return ResourceManager::Get().Load(path); + } + + bool TryResolveRenderObjectId( + RenderObjectId renderObjectId, + std::uint64_t& outRuntimeObjectId) const override { + return RenderObjectIdRegistry::Get().TryResolveRuntimeObjectId( + renderObjectId, + outRuntimeObjectId); + } }; } // namespace -std::unique_ptr CreateEngineEditorSceneBackend() { - return std::make_unique(); +std::unique_ptr CreateEngineEditorSceneBackend( + SceneManager& sceneManager, + ResourceManager& resourceManager) { + return std::make_unique( + sceneManager, + resourceManager); +} + +std::unique_ptr CreateEngineEditorServices() { + return std::make_unique(); } } // namespace XCEngine::UI::Editor::App diff --git a/editor/app/Services/Engine/EngineEditorServices.h b/editor/app/Services/Engine/EngineEditorServices.h new file mode 100644 index 00000000..4b591c17 --- /dev/null +++ b/editor/app/Services/Engine/EngineEditorServices.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Engine/EditorEngineServices.h" + +#include + +namespace XCEngine::UI::Editor::App { + +std::unique_ptr CreateEngineEditorServices(); + +} // namespace XCEngine::UI::Editor::App diff --git a/editor/app/Services/Scene/EngineEditorSceneBackend.h b/editor/app/Services/Scene/EngineEditorSceneBackend.h index 3561705e..754e485a 100644 --- a/editor/app/Services/Scene/EngineEditorSceneBackend.h +++ b/editor/app/Services/Scene/EngineEditorSceneBackend.h @@ -4,8 +4,18 @@ #include +namespace XCEngine::Components { +class SceneManager; +} + +namespace XCEngine::Resources { +class ResourceManager; +} + namespace XCEngine::UI::Editor::App { -std::unique_ptr CreateEngineEditorSceneBackend(); +std::unique_ptr CreateEngineEditorSceneBackend( + ::XCEngine::Components::SceneManager& sceneManager, + ::XCEngine::Resources::ResourceManager& resourceManager); } // namespace XCEngine::UI::Editor::App diff --git a/editor/app/Windowing/Content/EditorWindowContentController.h b/editor/app/Windowing/Content/EditorWindowContentController.h index df3254fd..87e32962 100644 --- a/editor/app/Windowing/Content/EditorWindowContentController.h +++ b/editor/app/Windowing/Content/EditorWindowContentController.h @@ -51,6 +51,8 @@ class EditorHostResourceService; namespace XCEngine::UI::Editor::App { +class EditorEngineServices; + struct EditorWindowContentCapabilities { bool workspace = false; bool dockHost = false; @@ -67,6 +69,7 @@ struct EditorWindowContentInitializationContext { Host::EditorHostResourceService& resourceService; UIEditorTextMeasurer& textMeasurer; Rendering::Host::ViewportRenderHost& viewportRenderer; + EditorEngineServices& engineServices; }; struct EditorWindowContentFrameContext { diff --git a/editor/app/Windowing/Content/EditorWorkspaceWindowContentController.cpp b/editor/app/Windowing/Content/EditorWorkspaceWindowContentController.cpp index e4fdfab5..24f88570 100644 --- a/editor/app/Windowing/Content/EditorWorkspaceWindowContentController.cpp +++ b/editor/app/Windowing/Content/EditorWorkspaceWindowContentController.cpp @@ -118,7 +118,8 @@ void EditorWorkspaceWindowContentController::Initialize( context.runtimePaths, context.textureHost, context.resourceService, - context.textMeasurer); + context.textMeasurer, + context.engineServices); m_shellRuntime->AttachViewportWindowRenderer(context.viewportRenderer); } diff --git a/editor/app/Windowing/EditorWindowManager.cpp b/editor/app/Windowing/EditorWindowManager.cpp index 23bfc910..cd915c56 100644 --- a/editor/app/Windowing/EditorWindowManager.cpp +++ b/editor/app/Windowing/EditorWindowManager.cpp @@ -21,6 +21,7 @@ namespace XCEngine::UI::Editor::App { EditorWindowManager::EditorWindowManager( EditorFrameServices& frameServices, + EditorEngineServices& engineServices, EditorWindowSystem& windowSystem, Rendering::Host::EditorWindowRenderRuntimeFactory& renderRuntimeFactory, Host::EditorHostResourceService& resourceService, @@ -28,6 +29,7 @@ EditorWindowManager::EditorWindowManager( EditorWorkspaceShellRuntimeFactory workspaceShellRuntimeFactory, EditorUtilityWindowPanelFactory utilityPanelFactory) : m_frameServices(frameServices) + , m_engineServices(engineServices) , m_renderRuntimeFactory(renderRuntimeFactory) , m_resourceService(resourceService) , m_hostRuntime(hostRuntime) { @@ -79,6 +81,7 @@ EditorHostWindow* EditorWindowManager::CreateWorkspaceWindow( params.primary, std::make_unique( m_frameServices, + m_engineServices, m_resourceService, m_contentFactory->CreateWorkspaceContentController(windowState), m_renderRuntimeFactory.CreateWindowRenderRuntime())); @@ -108,6 +111,7 @@ EditorHostWindow* EditorWindowManager::CreateUtilityWindow( params.primary, std::make_unique( m_frameServices, + m_engineServices, m_resourceService, m_contentFactory->CreateUtilityContentController(descriptor), m_renderRuntimeFactory.CreateWindowRenderRuntime())); diff --git a/editor/app/Windowing/EditorWindowManager.h b/editor/app/Windowing/EditorWindowManager.h index 8c17d864..b6f046ca 100644 --- a/editor/app/Windowing/EditorWindowManager.h +++ b/editor/app/Windowing/EditorWindowManager.h @@ -35,6 +35,7 @@ class EditorHostResourceService; namespace XCEngine::UI::Editor::App { class EditorWindowContentFactory; +class EditorEngineServices; class EditorWindowHostRuntimeServices; class EditorWindowLifecycleCoordinator; class EditorUtilityWindowCoordinator; @@ -46,6 +47,7 @@ class EditorWindowManager final : public EditorWindowHostCoordinator { public: EditorWindowManager( EditorFrameServices& frameServices, + EditorEngineServices& engineServices, EditorWindowSystem& windowSystem, Rendering::Host::EditorWindowRenderRuntimeFactory& renderRuntimeFactory, Host::EditorHostResourceService& resourceService, @@ -98,6 +100,7 @@ private: bool requestSkipNextSteadyStateFrame); EditorFrameServices& m_frameServices; + EditorEngineServices& m_engineServices; Rendering::Host::EditorWindowRenderRuntimeFactory& m_renderRuntimeFactory; Host::EditorHostResourceService& m_resourceService; EditorWindowHostRuntimeServices& m_hostRuntime; diff --git a/editor/app/Windowing/Runtime/EditorWindowRuntimeController.cpp b/editor/app/Windowing/Runtime/EditorWindowRuntimeController.cpp index 31256187..ad9f65f8 100644 --- a/editor/app/Windowing/Runtime/EditorWindowRuntimeController.cpp +++ b/editor/app/Windowing/Runtime/EditorWindowRuntimeController.cpp @@ -45,10 +45,12 @@ bool LoadHostPngTexture( EditorWindowRuntimeController::EditorWindowRuntimeController( EditorFrameServices& frameServices, + EditorEngineServices& engineServices, Host::EditorHostResourceService& resourceService, std::unique_ptr contentController, std::unique_ptr renderRuntime) : m_frameServices(frameServices) + , m_engineServices(engineServices) , m_resourceService(resourceService) , m_renderRuntime(std::move(renderRuntime)) , m_contentController(std::move(contentController)) {} @@ -172,6 +174,7 @@ bool EditorWindowRuntimeController::Initialize( .resourceService = m_resourceService, .textMeasurer = m_renderRuntime->GetTextMeasurer(), .viewportRenderer = m_renderRuntime->GetViewportRenderHost(), + .engineServices = m_engineServices, }); m_contentController->SetViewportSurfacePresentationEnabled( initializeResult.hasViewportSurfacePresentation); diff --git a/editor/app/Windowing/Runtime/EditorWindowRuntimeController.h b/editor/app/Windowing/Runtime/EditorWindowRuntimeController.h index 0395ed8e..6d7c4edf 100644 --- a/editor/app/Windowing/Runtime/EditorWindowRuntimeController.h +++ b/editor/app/Windowing/Runtime/EditorWindowRuntimeController.h @@ -34,10 +34,13 @@ class EditorHostResourceService; namespace XCEngine::UI::Editor::App { +class EditorEngineServices; + class EditorWindowRuntimeController final { public: EditorWindowRuntimeController( EditorFrameServices& frameServices, + EditorEngineServices& engineServices, Host::EditorHostResourceService& resourceService, std::unique_ptr contentController, std::unique_ptr renderRuntime); @@ -102,6 +105,7 @@ private: void RefreshDisplayedFrameStats(); EditorFrameServices& m_frameServices; + EditorEngineServices& m_engineServices; Host::EditorHostResourceService& m_resourceService; std::unique_ptr m_renderRuntime = {}; EditorWindowScreenshotController m_screenshotController = {}; diff --git a/tests/UI/Editor/unit/test_hierarchy_scene_binding.cpp b/tests/UI/Editor/unit/test_hierarchy_scene_binding.cpp index 8a0ef69f..cbf1adf6 100644 --- a/tests/UI/Editor/unit/test_hierarchy_scene_binding.cpp +++ b/tests/UI/Editor/unit/test_hierarchy_scene_binding.cpp @@ -63,7 +63,9 @@ private: }; std::unique_ptr CreateTestSceneBackend() { - return CreateEngineEditorSceneBackend(); + return CreateEngineEditorSceneBackend( + SceneManager::Get(), + ::XCEngine::Resources::ResourceManager::Get()); } TEST(HierarchySceneBindingTests, BuildFromSceneUsesRealGameObjectIds) { diff --git a/tests/UI/Editor/unit/test_inspector_presentation.cpp b/tests/UI/Editor/unit/test_inspector_presentation.cpp index f92e7648..3e5c2e62 100644 --- a/tests/UI/Editor/unit/test_inspector_presentation.cpp +++ b/tests/UI/Editor/unit/test_inspector_presentation.cpp @@ -89,7 +89,9 @@ void SaveMainScene(const TemporaryProjectRoot& projectRoot) { } void BindEngineSceneBackend(EditorSceneRuntime& runtime) { - runtime.SetBackend(CreateEngineEditorSceneBackend()); + runtime.SetBackend(CreateEngineEditorSceneBackend( + SceneManager::Get(), + ::XCEngine::Resources::ResourceManager::Get())); } const UIEditorPropertyGridSection* FindSection( diff --git a/tests/UI/Editor/unit/test_scene_viewport_runtime.cpp b/tests/UI/Editor/unit/test_scene_viewport_runtime.cpp index c44b197c..9f7b1239 100644 --- a/tests/UI/Editor/unit/test_scene_viewport_runtime.cpp +++ b/tests/UI/Editor/unit/test_scene_viewport_runtime.cpp @@ -108,7 +108,9 @@ void SaveMainScene(const TemporaryProjectRoot& projectRoot, const Math::Vector3& } void BindEngineSceneBackend(EditorSceneRuntime& runtime) { - runtime.SetBackend(CreateEngineEditorSceneBackend()); + runtime.SetBackend(CreateEngineEditorSceneBackend( + SceneManager::Get(), + ::XCEngine::Resources::ResourceManager::Get())); } UIInputEvent MakePointerEvent(