From 9db0d82082e4dfbfc3973f741b1c26d24e003fc0 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Sun, 5 Apr 2026 16:11:08 +0800 Subject: [PATCH] Isolate XCNewEditor default build from ImGui headers --- docs/plan/XCUI_Phase_Status_2026-04-05.md | 25 ++- editor/src/Application.cpp | 4 +- editor/src/Platform/D3D12WindowRenderer.h | 66 +----- .../D3D12WindowRendererImGuiInterop.h | 82 +++++++ new_editor/CMakeLists.txt | 26 ++- new_editor/src/Application.cpp | 212 +----------------- new_editor/src/Application.h | 24 +- new_editor/src/ApplicationLegacyImGui.cpp | 172 ++++++++++++++ new_editor/src/Platform/D3D12WindowRenderer.h | 7 + .../D3D12WindowRendererImGuiInterop.h | 83 +++++++ .../src/XCUIBackend/IEditorHostCompositor.h | 25 ++- .../src/XCUIBackend/IWindowUICompositor.h | 25 ++- .../src/XCUIBackend/ImGuiHostCompositor.cpp | 8 +- .../XCUIBackend/NativeWindowUICompositor.cpp | 2 + tests/NewEditor/CMakeLists.txt | 88 +++++++- .../test_native_window_ui_compositor.cpp | 1 + tests/editor/test_window_renderer_api.cpp | 4 +- 17 files changed, 546 insertions(+), 308 deletions(-) create mode 100644 editor/src/Platform/D3D12WindowRendererImGuiInterop.h create mode 100644 new_editor/src/Platform/D3D12WindowRenderer.h create mode 100644 new_editor/src/Platform/D3D12WindowRendererImGuiInterop.h diff --git a/docs/plan/XCUI_Phase_Status_2026-04-05.md b/docs/plan/XCUI_Phase_Status_2026-04-05.md index 1d7c143b..61355eed 100644 --- a/docs/plan/XCUI_Phase_Status_2026-04-05.md +++ b/docs/plan/XCUI_Phase_Status_2026-04-05.md @@ -32,7 +32,11 @@ Old `editor` replacement is explicitly out of scope for this phase. - `Application.cpp` no longer directly includes ``, even though the compatibility host path is still compiled into `new_editor` - The `new_editor` build now also has an explicit compatibility-source slice: - legacy ImGui shell sources and vendored ImGui backend sources are now grouped into a dedicated compatibility static library instead of being compiled directly as part of the main `XCNewEditor` source list - - the main `XCNewEditor` target still sees ImGui headers through older editor bridge headers, but its default implementation source list is now narrower than the compatibility source list + - the main `XCNewEditor` target no longer compiles those legacy sources directly, but it still carries `${IMGUI_SOURCE_DIR}` / `${IMGUI_SOURCE_DIR}/backends` on its private include surface and still reaches `` through older editor bridge headers such as `editor/src/UI/ImGuiBackendBridge.h` +- The next checkpoint to append after this file should be the main-target header-isolation milestone: + - `XCNewEditor` drops direct `${IMGUI_SOURCE_DIR}` / `${IMGUI_SOURCE_DIR}/backends` include-directory requirements + - the default native compile path no longer reaches `` through `editor/src/UI/ImGuiBackendBridge.h` or equivalent bridge headers + - `XCNewEditorImGuiCompat` remains the explicit compatibility-only consumer of legacy ImGui headers and backend sources - Old `editor` replacement remains deferred; all active execution still stays inside XCUI shared code and `new_editor`. ## Three-Layer Status @@ -127,7 +131,7 @@ Current gap: Current gap: - The default shell host is now native, but the legacy ImGui shell and panel path still exists as a compatibility host and is still compiled into `new_editor`. -- The default native shell path is still compiled through an `Application` translation unit that directly includes legacy ImGui host/presenter/compositor code, and `new_editor/CMakeLists.txt` still treats those legacy ImGui sources and include paths as target-global defaults. +- The default native shell path is now split away from direct `ImGui::*` calls at the translation-unit/source-list level, but the main `XCNewEditor` target still keeps ImGui on its header/include surface through `target_include_directories(...)` and older editor bridge headers. - The native shell currently proves direct runtime composition, but its shell chrome is still a bespoke `Application`-side layout rather than a fully shared XCUI-authored editor shell document. - Editor-specialized widgets are still incomplete at the shared-module level: the authored prototypes exist, but virtualization, multi-selection/focus traversal, toolbar/menu chrome, menu interaction widgets, and icon-atlas widgets are not yet extracted into reusable XCUI modules. - The default native text path now uses a standalone Windows/GDI atlas through `XCUIStandaloneTextAtlasProvider`, but that provider still lives inside `new_editor` and is not yet promoted into a shared/cross-platform text subsystem. @@ -284,17 +288,18 @@ Current gap: - standalone atlas coverage now includes reset/rebuild, non-nominal size resolution, lazy glyph insertion/fallback behavior, and smoke use without any ImGui context - Legacy shell chrome / HUD rendering is now split out of the main `Application.cpp` translation unit: - the direct `ImGui::*` shell rendering path now lives in a dedicated legacy-only `Application` implementation file - - the main `Application.cpp` native host path no longer directly includes ``, reducing default-path compile-time coupling before the larger compat-target split + - the main `Application.cpp` native host path no longer directly includes ``, reducing default-path compile-time coupling while the remaining main-target header/include cleanup stays open - `new_editor` build composition is now split into main/native and compatibility slices: - the main `XCNewEditor` target no longer compiles legacy ImGui shell/panel/backend source files directly - legacy ImGui shell/panel/backend sources plus vendored ImGui sources now build behind a dedicated compatibility static library that the main executable links + - the remaining build-side cleanup is narrower now: `XCNewEditor` still carries ImGui include directories and older editor bridge headers on its direct compile surface, so the next checkpoint is header/include isolation rather than another source-list split ## Phase Risks Still Open - Schema instance validation is still open beyond `.xcschema` self-definition and artifact round-trip coverage. - `ScrollView` is still authored/static; no wheel-driven scrolling or virtualization yet. -- The default native shell path still compiles through an `Application.cpp` unit that directly pulls in ImGui compatibility host code, so the native default path is not yet isolated at the translation-unit boundary. -- `new_editor/CMakeLists.txt` still builds the legacy ImGui host/compositor/backend sources and include directories as target-global defaults instead of a compatibility-only slice. +- `Application.cpp` is now split away from direct `ImGui::*` calls, but `XCNewEditor` still depends on ImGui at the header/include level because `new_editor/CMakeLists.txt` still adds `${IMGUI_SOURCE_DIR}` / `${IMGUI_SOURCE_DIR}/backends` to the main target and the editor bridge chain still reaches `editor/src/UI/ImGuiBackendBridge.h` -> ``. +- `XCNewEditorImGuiCompat` is now the compatibility-source slice, but the main executable still links it unconditionally and has not yet reduced its direct include surface to a compat-free default-path baseline. - The default native text path now owns its atlas without ImGui, but the provider is still Windows-only and remains trapped inside `new_editor` instead of a shared/cross-platform text layer. - Hosted-preview compatibility presentation still depends on an ImGui-only inline presenter path when not using the queued native surface path. - Editor widget coverage is still prototype-driven inside `LayoutLab`; it has not yet been promoted into a full reusable shared widget/runtime layer with command routing, virtualization, and property-edit transactions. @@ -302,12 +307,12 @@ Current gap: ## Execution-Plan Alignment - Against `XCUI完整架构设计与执行计划.md`, current `new_editor` progress should be treated as an early `Phase 8` foothold rather than full `Milestone E` completion: - - landed: `NativeWindowUICompositor`, native shell packet composition, native hosted-preview publication, XCUI-owned texture registrations, native panel surface-image presentation, standalone native text-atlas ownership inside `new_editor` - - not yet landed: default-path translation-unit isolation from legacy ImGui host code, promotion of the native text-atlas path into a shared/cross-platform text subsystem, shared XCUI-authored editor shell chrome + - landed: `NativeWindowUICompositor`, native shell packet composition, native hosted-preview publication, XCUI-owned texture registrations, native panel surface-image presentation, standalone native text-atlas ownership inside `new_editor`, legacy `Application` TU split, and `XCNewEditorImGuiCompat` + - not yet landed: main-target header/include isolation from ImGui, promotion of the native text-atlas path into a shared/cross-platform text subsystem, shared XCUI-authored editor shell chrome - That means the next de-ImGui push should not keep centering on hosted-preview publication; that milestone is now effectively closed for the default native shell path. - The real remaining default-path blockers are: - - isolate legacy ImGui shell/compositor/presenter wiring from the default `Application` build path - - stop treating ImGui include paths and backend sources as the default `new_editor` compilation surface + - remove the main `XCNewEditor` target's direct ImGui header dependency by cutting the `D3D12WindowRenderer` / `ImGuiBackendBridge` include chain off the default compile path + - stop treating ImGui include paths as part of the default `new_editor` compilation surface, leaving them only on the compatibility slice - harden and promote `XCUIStandaloneTextAtlasProvider` / editor font bootstrap into a shared native text subsystem - move native shell chrome out of bespoke `Application` layout code and into a shared XCUI shell model or authored shell document @@ -315,7 +320,7 @@ Current gap: 1. Expand runtime/game-layer ownership from the current `SceneRuntime` UI context into scene-declared HUD/menu bootstrapping, draw submission, and higher-level runtime UI policies. 2. Promote the current editor-facing widget prototypes out of authored `LayoutLab` content and into reusable XCUI widget/runtime modules, then continue with toolbar/menu chrome, shell-state adoption, virtualization, and broader focus/multi-selection behavior. -3. Isolate legacy ImGui shell/compositor/presenter wiring from the default native path first, starting with `Application` translation-unit separation and a `new_editor` build split that stops treating ImGui include paths and sources as the default compilation surface. +3. Finish the remaining main-target de-ImGui cleanup first: remove direct ImGui header/include requirements from `XCNewEditor`, keep ImGui confined to `XCNewEditorImGuiCompat`, and append the next checkpoint once the default native compile path no longer reaches ``. 4. Promote the current standalone native text/font path out of `new_editor`, harden its atlas invalidation/caching contract, and remove the remaining default-path ImGui text/bootstrap ownership around compatibility-only code. 5. Promote the native shell chrome and card layout out of bespoke `Application` code into a shared XCUI/editor-layer shell model or authored shell document. 6. Continue phased validation, commit, push, and plan refresh after each stable batch. diff --git a/editor/src/Application.cpp b/editor/src/Application.cpp index 9985c9dc..adeb0a41 100644 --- a/editor/src/Application.cpp +++ b/editor/src/Application.cpp @@ -1,4 +1,5 @@ #include "Application.h" +#include "Platform/D3D12WindowRendererImGuiInterop.h" #include "Core/EditorLoggingSetup.h" #include "Core/ProjectRootResolver.h" #include "Core/EditorWindowTitle.h" @@ -264,7 +265,8 @@ void Application::RenderEditorFrame() { m_layerStack.onUIRender(); UpdateWindowTitle(); ImGui::Render(); - m_windowRenderer.Render( + Platform::RenderImGuiFrame( + m_windowRenderer, m_imguiBackend, kClearColor, [this](const Rendering::RenderContext& renderContext, const Rendering::RenderSurface&) { diff --git a/editor/src/Platform/D3D12WindowRenderer.h b/editor/src/Platform/D3D12WindowRenderer.h index 23007cc9..76aab005 100644 --- a/editor/src/Platform/D3D12WindowRenderer.h +++ b/editor/src/Platform/D3D12WindowRenderer.h @@ -1,7 +1,5 @@ #pragma once -#include "UI/ImGuiBackendBridge.h" - #include #include #include @@ -16,6 +14,10 @@ #include #include +#ifndef NOMINMAX +#define NOMINMAX +#endif + #include #include #include @@ -179,66 +181,6 @@ public: return true; } - void Render( - UI::ImGuiBackendBridge& imguiBackend, - const float clearColor[4], - const RenderCallback& beforeUiRender = {}, - const RenderCallback& afterUiRender = {}) { - auto* d3d12Queue = GetD3D12CommandQueue(); - auto* d3d12CommandList = GetD3D12CommandList(); - if (m_swapChain == nullptr || - d3d12Queue == nullptr || - d3d12CommandList == nullptr || - m_srvHeap == nullptr) { - return; - } - - const uint32_t backBufferIndex = m_swapChain->GetCurrentBackBufferIndex(); - if (backBufferIndex >= m_backBufferViews.size() || - backBufferIndex >= m_backBufferSurfaces.size() || - m_backBufferViews[backBufferIndex] == nullptr) { - return; - } - - RHI::RHIResourceView* renderTargetView = m_backBufferViews[backBufferIndex]; - Rendering::RenderSurface& renderSurface = m_backBufferSurfaces[backBufferIndex]; - d3d12CommandList->TransitionBarrier( - renderTargetView, - RHI::ResourceStates::Present, - RHI::ResourceStates::RenderTarget); - d3d12CommandList->SetRenderTargets(1, &renderTargetView, nullptr); - d3d12CommandList->ClearRenderTarget(renderTargetView, clearColor); - - // Host-owned swapchain surfaces are handed to the callback already bound and ready for rendering. - // The callback must leave the color attachment in RenderTarget state so ImGui can render after it. - if (beforeUiRender) { - beforeUiRender(GetRenderContext(), renderSurface); - - // Viewport rendering can bind offscreen render targets on the shared command list. - // Rebind the swapchain backbuffer so the subsequent ImGui draw data lands on the main window. - d3d12CommandList->SetRenderTargets(1, &renderTargetView, nullptr); - } - - ID3D12DescriptorHeap* descriptorHeaps[] = { m_srvHeap->GetDescriptorHeap() }; - d3d12CommandList->SetDescriptorHeaps(1, descriptorHeaps); - imguiBackend.RenderDrawData(d3d12CommandList->GetCommandList()); - - if (afterUiRender) { - d3d12CommandList->SetRenderTargets(1, &renderTargetView, nullptr); - afterUiRender(GetRenderContext(), renderSurface); - } - - d3d12CommandList->TransitionBarrier( - renderTargetView, - RHI::ResourceStates::RenderTarget, - RHI::ResourceStates::Present); - m_commandList->Close(); - - void* commandLists[] = { m_commandList }; - m_commandQueue->ExecuteCommandLists(1, commandLists); - m_swapChain->Present(1, 0); - } - ID3D12Device* GetDevice() const { const auto* device = GetD3D12Device(); return device ? device->GetDevice() : nullptr; diff --git a/editor/src/Platform/D3D12WindowRendererImGuiInterop.h b/editor/src/Platform/D3D12WindowRendererImGuiInterop.h new file mode 100644 index 00000000..cb713c85 --- /dev/null +++ b/editor/src/Platform/D3D12WindowRendererImGuiInterop.h @@ -0,0 +1,82 @@ +#pragma once + +#include "D3D12WindowRenderer.h" + +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif + +#include "../UI/ImGuiBackendBridge.h" + +namespace XCEngine { +namespace Editor { +namespace Platform { + +inline void RenderImGuiFrame( + D3D12WindowRenderer& windowRenderer, + UI::ImGuiBackendBridge& imguiBackend, + const float clearColor[4], + const D3D12WindowRenderer::RenderCallback& beforeUiRender = {}, + const D3D12WindowRenderer::RenderCallback& afterUiRender = {}) { + const Rendering::RenderSurface* renderSurface = windowRenderer.GetCurrentRenderSurface(); + Rendering::RenderContext renderContext = windowRenderer.GetRenderContext(); + if (!renderContext.IsValid() || + renderContext.commandList == nullptr || + renderContext.commandQueue == nullptr || + windowRenderer.GetSwapChain() == nullptr || + renderSurface == nullptr || + windowRenderer.GetSrvHeap() == nullptr) { + return; + } + auto* d3d12CommandList = static_cast(renderContext.commandList); + + const auto& colorAttachments = renderSurface->GetColorAttachments(); + if (colorAttachments.empty() || colorAttachments[0] == nullptr) { + return; + } + + RHI::RHIResourceView* renderTargetView = colorAttachments[0]; + renderContext.commandList->TransitionBarrier( + renderTargetView, + RHI::ResourceStates::Present, + RHI::ResourceStates::RenderTarget); + renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr); + renderContext.commandList->ClearRenderTarget(renderTargetView, clearColor); + + // Host-owned swapchain surfaces are handed to the callback already bound and ready for rendering. + // The callback must leave the color attachment in RenderTarget state so ImGui can render after it. + if (beforeUiRender) { + beforeUiRender(renderContext, *renderSurface); + + // Viewport rendering can bind offscreen render targets on the shared command list. + // Rebind the swapchain backbuffer so the subsequent ImGui draw data lands on the main window. + renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr); + } + + ID3D12DescriptorHeap* descriptorHeaps[] = { windowRenderer.GetSrvHeap() }; + d3d12CommandList->SetDescriptorHeaps(1, descriptorHeaps); + imguiBackend.RenderDrawData(d3d12CommandList->GetCommandList()); + + if (afterUiRender) { + renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr); + afterUiRender(renderContext, *renderSurface); + } + + renderContext.commandList->TransitionBarrier( + renderTargetView, + RHI::ResourceStates::RenderTarget, + RHI::ResourceStates::Present); + renderContext.commandList->Close(); + + void* commandLists[] = { renderContext.commandList }; + renderContext.commandQueue->ExecuteCommandLists(1, commandLists); + windowRenderer.GetSwapChain()->Present(1, 0); +} + +} // namespace Platform +} // namespace Editor +} // namespace XCEngine diff --git a/new_editor/CMakeLists.txt b/new_editor/CMakeLists.txt index a047bbf2..3eac9d15 100644 --- a/new_editor/CMakeLists.txt +++ b/new_editor/CMakeLists.txt @@ -79,27 +79,27 @@ set(NEW_EDITOR_IMGUI_COMPAT_SOURCES add_library(XCNewEditorImGuiCompat STATIC ${NEW_EDITOR_IMGUI_COMPAT_SOURCES}) add_executable(${PROJECT_NAME} WIN32 ${NEW_EDITOR_SOURCES}) -target_include_directories(XCNewEditorImGuiCompat PRIVATE +set(NEW_EDITOR_COMMON_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/src ${XCENGINE_ROOT_DIR}/engine/include - ${XCENGINE_ROOT_DIR}/editor/src +) + +set(NEW_EDITOR_IMGUI_COMPAT_INCLUDE_DIRS + ${NEW_EDITOR_COMMON_INCLUDE_DIRS} ${IMGUI_SOURCE_DIR} ${IMGUI_SOURCE_DIR}/backends ) -target_include_directories(${PROJECT_NAME} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/src - ${XCENGINE_ROOT_DIR}/engine/include - ${XCENGINE_ROOT_DIR}/editor/src - ${IMGUI_SOURCE_DIR} - ${IMGUI_SOURCE_DIR}/backends -) +target_include_directories(XCNewEditorImGuiCompat PRIVATE ${NEW_EDITOR_IMGUI_COMPAT_INCLUDE_DIRS}) + +target_include_directories(${PROJECT_NAME} PRIVATE ${NEW_EDITOR_COMMON_INCLUDE_DIRS}) file(TO_CMAKE_PATH "${XCENGINE_ROOT_DIR}" XCENGINE_ROOT_DIR_CMAKE) target_compile_definitions(XCNewEditorImGuiCompat PRIVATE UNICODE _UNICODE + NOMINMAX XCENGINE_NEW_EDITOR_REPO_ROOT="${XCENGINE_ROOT_DIR_CMAKE}" ) target_compile_options(XCNewEditorImGuiCompat PRIVATE /utf-8) @@ -107,6 +107,7 @@ target_compile_options(XCNewEditorImGuiCompat PRIVATE /utf-8) target_compile_definitions(${PROJECT_NAME} PRIVATE UNICODE _UNICODE + NOMINMAX XCENGINE_NEW_EDITOR_REPO_ROOT="${XCENGINE_ROOT_DIR_CMAKE}" ) target_compile_options(${PROJECT_NAME} PRIVATE /utf-8) @@ -123,7 +124,12 @@ if(MSVC) COMPILE_PDB_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/new_editor/compile-pdb-compat/Debug" COMPILE_PDB_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/new_editor/compile-pdb-compat/Release" COMPILE_PDB_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_BINARY_DIR}/new_editor/compile-pdb-compat/MinSizeRel" - COMPILE_PDB_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/new_editor/compile-pdb-compat/RelWithDebInfo") + COMPILE_PDB_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/new_editor/compile-pdb-compat/RelWithDebInfo" + PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/new_editor/pdb-compat" + PDB_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/new_editor/pdb-compat/Debug" + PDB_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}/new_editor/pdb-compat/Release" + PDB_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_BINARY_DIR}/new_editor/pdb-compat/MinSizeRel" + PDB_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_BINARY_DIR}/new_editor/pdb-compat/RelWithDebInfo") target_link_options(${PROJECT_NAME} PRIVATE $<$:/INCREMENTAL:NO>) set_property(TARGET ${PROJECT_NAME} PROPERTY diff --git a/new_editor/src/Application.cpp b/new_editor/src/Application.cpp index a3d18648..336049fc 100644 --- a/new_editor/src/Application.cpp +++ b/new_editor/src/Application.cpp @@ -1,5 +1,4 @@ #include "Application.h" -#include "XCUIBackend/LegacyImGuiHostInterop.h" #include "XCUIBackend/NativeWindowUICompositor.h" #include @@ -9,6 +8,10 @@ #include #include +#ifdef DrawText +#undef DrawText +#endif + namespace XCEngine { namespace NewEditor { @@ -37,48 +40,6 @@ void ShutdownAndDelete(ResourceType*& resource) { resource = nullptr; } -const char* GetHostedPreviewPathLabel(bool nativeRequested, bool nativePresenterBound) { - if (nativeRequested && nativePresenterBound) { - return "native queued offscreen surface"; - } - if (nativeRequested) { - return "native requested, hosted presenter bound"; - } - if (nativePresenterBound) { - return "hosted presenter requested, native presenter still bound"; - } - return "hosted presenter"; -} - -const char* GetHostedPreviewStateLabel( - bool hostedPreviewEnabled, - bool nativePresenterBound, - bool presentedThisFrame, - bool queuedToNativePassThisFrame, - bool surfaceImageAvailable, - bool surfaceAllocated, - bool surfaceReady, - bool descriptorAvailable) { - if (!hostedPreviewEnabled) { - return "disabled"; - } - - if (nativePresenterBound) { - if (surfaceImageAvailable && surfaceReady) { - return "live"; - } - if (queuedToNativePassThisFrame || surfaceAllocated || descriptorAvailable) { - return "warming"; - } - return "awaiting submit"; - } - - if (presentedThisFrame) { - return "live"; - } - return "idle"; -} - bool ContainsPoint(const UI::UIRect& rect, const UI::UIPoint& point) { return point.x >= rect.x && point.y >= rect.y && @@ -174,42 +135,10 @@ NativeShellPanelLayout MakePanelLayout( } } // namespace -std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> -Application::CreateHostedPreviewPresenter(bool nativePreview) { - if (nativePreview) { - return ::XCEngine::Editor::XCUIBackend::CreateQueuedNativeXCUIHostedPreviewPresenter( - m_hostedPreviewQueue, - m_hostedPreviewSurfaceRegistry); - } - - return ::XCEngine::Editor::XCUIBackend::CreateLegacyImGuiHostedPreviewPresenter(); -} - bool Application::IsNativeWindowHostEnabled() const { return m_windowHostMode == WindowHostMode::NativeXCUI; } -void Application::InitializePanelsForActiveWindowHost() { - if (IsNativeWindowHostEnabled()) { - InitializeNativeShell(); - return; - } - - InitializeLegacyImGuiPanels(); - ConfigureHostedPreviewPresenters(); -} - -void Application::InitializeLegacyImGuiPanels() { - m_demoPanel = std::make_unique( - &m_xcuiInputSource, - CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo)), - ::XCEngine::Editor::XCUIBackend::CreateLegacyImGuiPanelCanvasHost()); - m_layoutLabPanel = std::make_unique( - &m_xcuiInputSource, - CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab)), - ::XCEngine::Editor::XCUIBackend::CreateLegacyImGuiPanelCanvasHost()); -} - void Application::InitializeNativeShell() { m_nativeActivePanel = m_shellChromeState.IsPanelVisible(ShellPanelId::XCUIDemo) ? ShellPanelId::XCUIDemo @@ -238,115 +167,6 @@ bool Application::IsNativeHostedPreviewEnabled(ShellPanelId panelId) const { return m_shellChromeState.IsNativeHostedPreviewActive(panelId); } -void Application::ConfigureHostedPreviewPresenters() { - const ShellPanelChromeState* demoState = TryGetShellPanelState(ShellPanelId::XCUIDemo); - if (m_demoPanel != nullptr) { - m_demoPanel->SetVisible(demoState != nullptr && demoState->visible); - m_demoPanel->SetHostedPreviewEnabled(demoState == nullptr || demoState->hostedPreviewEnabled); - m_demoPanel->SetHostedPreviewPresenter(CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo))); - } - - const ShellPanelChromeState* layoutLabState = TryGetShellPanelState(ShellPanelId::XCUILayoutLab); - if (m_layoutLabPanel != nullptr) { - m_layoutLabPanel->SetVisible(layoutLabState != nullptr && layoutLabState->visible); - m_layoutLabPanel->SetHostedPreviewEnabled(layoutLabState == nullptr || layoutLabState->hostedPreviewEnabled); - m_layoutLabPanel->SetHostedPreviewPresenter( - CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab))); - } -} - -void Application::ConfigureShellCommandRouter() { - m_shellCommandRouter.Clear(); - - ShellCommandBindings bindings = {}; - bindings.getXCUIDemoPanelVisible = [this]() { - return m_shellChromeState.IsPanelVisible(ShellPanelId::XCUIDemo); - }; - bindings.setXCUIDemoPanelVisible = [this](bool visible) { - m_shellChromeState.SetPanelVisible(ShellPanelId::XCUIDemo, visible); - if (m_demoPanel != nullptr) { - m_demoPanel->SetVisible(visible); - } - }; - bindings.getXCUILayoutLabPanelVisible = [this]() { - return m_shellChromeState.IsPanelVisible(ShellPanelId::XCUILayoutLab); - }; - bindings.setXCUILayoutLabPanelVisible = [this](bool visible) { - m_shellChromeState.SetPanelVisible(ShellPanelId::XCUILayoutLab, visible); - if (m_layoutLabPanel != nullptr) { - m_layoutLabPanel->SetVisible(visible); - } - }; - bindings.getImGuiDemoWindowVisible = [this]() { - return IsShellViewToggleEnabled(ShellViewToggleId::ImGuiDemoWindow); - }; - bindings.setImGuiDemoWindowVisible = [this](bool visible) { - SetShellViewToggleEnabled(ShellViewToggleId::ImGuiDemoWindow, visible); - }; - bindings.getNativeBackdropVisible = [this]() { - return IsShellViewToggleEnabled(ShellViewToggleId::NativeBackdrop); - }; - bindings.setNativeBackdropVisible = [this](bool visible) { - SetShellViewToggleEnabled(ShellViewToggleId::NativeBackdrop, visible); - }; - bindings.getPulseAccentEnabled = [this]() { - return IsShellViewToggleEnabled(ShellViewToggleId::PulseAccent); - }; - bindings.setPulseAccentEnabled = [this](bool enabled) { - SetShellViewToggleEnabled(ShellViewToggleId::PulseAccent, enabled); - }; - bindings.getNativeXCUIOverlayVisible = [this]() { - return IsShellViewToggleEnabled(ShellViewToggleId::NativeXCUIOverlay); - }; - bindings.setNativeXCUIOverlayVisible = [this](bool visible) { - SetShellViewToggleEnabled(ShellViewToggleId::NativeXCUIOverlay, visible); - }; - bindings.getHostedPreviewHudVisible = [this]() { - return IsShellViewToggleEnabled(ShellViewToggleId::HostedPreviewHud); - }; - bindings.setHostedPreviewHudVisible = [this](bool visible) { - SetShellViewToggleEnabled(ShellViewToggleId::HostedPreviewHud, visible); - }; - bindings.getNativeDemoPanelPreviewEnabled = [this]() { - return IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo); - }; - bindings.setNativeDemoPanelPreviewEnabled = [this](bool enabled) { - m_shellChromeState.SetHostedPreviewMode( - ShellPanelId::XCUIDemo, - enabled ? ShellHostedPreviewMode::NativeOffscreen : ShellHostedPreviewMode::HostedPresenter); - }; - bindings.getNativeLayoutLabPreviewEnabled = [this]() { - return IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab); - }; - bindings.setNativeLayoutLabPreviewEnabled = [this](bool enabled) { - m_shellChromeState.SetHostedPreviewMode( - ShellPanelId::XCUILayoutLab, - enabled ? ShellHostedPreviewMode::NativeOffscreen : ShellHostedPreviewMode::HostedPresenter); - }; - bindings.onHostedPreviewModeChanged = [this]() { ConfigureHostedPreviewPresenters(); }; - - Application::RegisterShellViewCommands(m_shellCommandRouter, bindings); -} - -::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta -Application::DispatchShellShortcuts( - const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot& snapshot) { - ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot shellSnapshot = snapshot; - if (!IsNativeWindowHostEnabled()) { - ::XCEngine::Editor::XCUIBackend::ApplyLegacyImGuiHostInputCapture(shellSnapshot); - } - - if (!m_shellInputBridge.HasBaseline()) { - m_shellInputBridge.Prime(shellSnapshot); - } - const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta frameDelta = - m_shellInputBridge.Translate(shellSnapshot); - const ::XCEngine::Editor::XCUIBackend::XCUIEditorCommandInputSnapshot commandSnapshot = - Application::BuildShellShortcutSnapshot(frameDelta); - m_shellCommandRouter.InvokeMatchingShortcut({ &commandSnapshot }); - return frameDelta; -} - Application::HostedPreviewPanelDiagnostics Application::BuildHostedPreviewPanelDiagnostics( const char* debugName, const char* fallbackDebugSource, @@ -452,8 +272,7 @@ int Application::Run(HINSTANCE instance, int nCmdShow) { Frame(); } - m_demoPanel.reset(); - m_layoutLabPanel.reset(); + ResetLegacyPanels(); ShutdownWindowCompositor(); ShutdownRenderer(); resourceManager.Shutdown(); @@ -558,18 +377,6 @@ bool Application::InitializeRenderer() { return initialized; } -void Application::InitializeWindowCompositor() { - m_windowCompositor = IsNativeWindowHostEnabled() - ? ::XCEngine::Editor::XCUIBackend::CreateNativeWindowUICompositor() - : ::XCEngine::Editor::XCUIBackend::CreateLegacyImGuiWindowUICompositor(); - if (m_windowCompositor != nullptr) { - m_windowCompositor->Initialize( - m_hwnd, - m_windowRenderer, - []() { (void)::XCEngine::Editor::XCUIBackend::ConfigureLegacyImGuiHostFonts(); }); - } -} - void Application::ShutdownWindowCompositor() { DestroyHostedPreviewSurfaces(); if (m_windowCompositor != nullptr) { @@ -599,15 +406,6 @@ void Application::DestroyHostedPreviewSurfaces() { m_hostedPreviewSurfaces.clear(); } -void Application::SyncShellChromePanelStateFromPanels() { - m_shellChromeState.SetPanelVisible( - ShellPanelId::XCUIDemo, - m_demoPanel != nullptr && m_demoPanel->IsVisible()); - m_shellChromeState.SetPanelVisible( - ShellPanelId::XCUILayoutLab, - m_layoutLabPanel != nullptr && m_layoutLabPanel->IsVisible()); -} - void Application::SyncHostedPreviewSurfaces() { const auto isNativePreviewEnabled = [this](const std::string& debugName) { const ShellPanelChromeState* demoState = TryGetShellPanelState(ShellPanelId::XCUIDemo); diff --git a/new_editor/src/Application.h b/new_editor/src/Application.h index e7aa610c..4cc68abd 100644 --- a/new_editor/src/Application.h +++ b/new_editor/src/Application.h @@ -3,12 +3,6 @@ #include #include "XCUIBackend/XCUIEditorCommandRouter.h" -#include "panels/XCUIDemoPanel.h" -#include "panels/XCUILayoutLabPanel.h" - -#include "Platform/D3D12WindowRenderer.h" -#include "Rendering/MainWindowNativeBackdropRenderer.h" -#include "XCUIBackend/IWindowUICompositor.h" #include "XCUIBackend/NativeXCUIPanelCanvasHost.h" #include "XCUIBackend/XCUIDemoRuntime.h" #include "XCUIBackend/XCUIHostedPreviewPresenter.h" @@ -17,6 +11,9 @@ #include "XCUIBackend/XCUIRHIRenderBackend.h" #include "XCUIBackend/XCUIShellChromeState.h" #include "XCUIBackend/XCUIStandaloneTextAtlasProvider.h" +#include "XCUIBackend/UITextureRegistration.h" +#include "Platform/D3D12WindowRenderer.h" +#include "Rendering/MainWindowNativeBackdropRenderer.h" #include #include @@ -29,10 +26,24 @@ #include namespace XCEngine { +namespace Editor { +namespace XCUIBackend { + +class IWindowUICompositor; + +} // namespace XCUIBackend +} // namespace Editor + namespace NewEditor { +class XCUIDemoPanel; +class XCUILayoutLabPanel; + class Application { public: + Application(); + ~Application(); + using ShellChromeState = ::XCEngine::Editor::XCUIBackend::XCUIShellChromeState; using ShellPanelId = ::XCEngine::Editor::XCUIBackend::XCUIShellPanelId; using ShellViewToggleId = ::XCEngine::Editor::XCUIBackend::XCUIShellViewToggleId; @@ -416,6 +427,7 @@ private: HostedPreviewOffscreenSurface& previewSurface, const ::XCEngine::Rendering::RenderContext& renderContext, const ::XCEngine::UI::UIDrawData& drawData); + void ResetLegacyPanels(); void ConfigureShellCommandRouter(); ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta DispatchShellShortcuts( const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot& snapshot); diff --git a/new_editor/src/ApplicationLegacyImGui.cpp b/new_editor/src/ApplicationLegacyImGui.cpp index aa277d65..59d4698a 100644 --- a/new_editor/src/ApplicationLegacyImGui.cpp +++ b/new_editor/src/ApplicationLegacyImGui.cpp @@ -1,6 +1,8 @@ #include "Application.h" #include "XCUIBackend/LegacyImGuiHostInterop.h" +#include "panels/XCUIDemoPanel.h" +#include "panels/XCUILayoutLabPanel.h" #include @@ -65,6 +67,176 @@ const char* GetHostedPreviewStateLabel( } // namespace +Application::Application() = default; +Application::~Application() = default; + +std::unique_ptr<::XCEngine::Editor::XCUIBackend::IXCUIHostedPreviewPresenter> +Application::CreateHostedPreviewPresenter(bool nativePreview) { + if (nativePreview) { + return ::XCEngine::Editor::XCUIBackend::CreateQueuedNativeXCUIHostedPreviewPresenter( + m_hostedPreviewQueue, + m_hostedPreviewSurfaceRegistry); + } + + return ::XCEngine::Editor::XCUIBackend::CreateLegacyImGuiHostedPreviewPresenter(); +} + +void Application::InitializePanelsForActiveWindowHost() { + if (IsNativeWindowHostEnabled()) { + InitializeNativeShell(); + return; + } + + InitializeLegacyImGuiPanels(); + ConfigureHostedPreviewPresenters(); +} + +void Application::InitializeLegacyImGuiPanels() { + m_demoPanel = std::make_unique( + &m_xcuiInputSource, + CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo)), + ::XCEngine::Editor::XCUIBackend::CreateLegacyImGuiPanelCanvasHost()); + m_layoutLabPanel = std::make_unique( + &m_xcuiInputSource, + CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab)), + ::XCEngine::Editor::XCUIBackend::CreateLegacyImGuiPanelCanvasHost()); +} + +void Application::ConfigureHostedPreviewPresenters() { + const ShellPanelChromeState* demoState = TryGetShellPanelState(ShellPanelId::XCUIDemo); + if (m_demoPanel != nullptr) { + m_demoPanel->SetVisible(demoState != nullptr && demoState->visible); + m_demoPanel->SetHostedPreviewEnabled(demoState == nullptr || demoState->hostedPreviewEnabled); + m_demoPanel->SetHostedPreviewPresenter(CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo))); + } + + const ShellPanelChromeState* layoutLabState = TryGetShellPanelState(ShellPanelId::XCUILayoutLab); + if (m_layoutLabPanel != nullptr) { + m_layoutLabPanel->SetVisible(layoutLabState != nullptr && layoutLabState->visible); + m_layoutLabPanel->SetHostedPreviewEnabled(layoutLabState == nullptr || layoutLabState->hostedPreviewEnabled); + m_layoutLabPanel->SetHostedPreviewPresenter( + CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab))); + } +} + +void Application::ResetLegacyPanels() { + m_demoPanel.reset(); + m_layoutLabPanel.reset(); +} + +void Application::SyncShellChromePanelStateFromPanels() { + m_shellChromeState.SetPanelVisible( + ShellPanelId::XCUIDemo, + m_demoPanel != nullptr && m_demoPanel->IsVisible()); + m_shellChromeState.SetPanelVisible( + ShellPanelId::XCUILayoutLab, + m_layoutLabPanel != nullptr && m_layoutLabPanel->IsVisible()); +} + +void Application::ConfigureShellCommandRouter() { + m_shellCommandRouter.Clear(); + + ShellCommandBindings bindings = {}; + bindings.getXCUIDemoPanelVisible = [this]() { + return m_shellChromeState.IsPanelVisible(ShellPanelId::XCUIDemo); + }; + bindings.setXCUIDemoPanelVisible = [this](bool visible) { + m_shellChromeState.SetPanelVisible(ShellPanelId::XCUIDemo, visible); + if (m_demoPanel != nullptr) { + m_demoPanel->SetVisible(visible); + } + }; + bindings.getXCUILayoutLabPanelVisible = [this]() { + return m_shellChromeState.IsPanelVisible(ShellPanelId::XCUILayoutLab); + }; + bindings.setXCUILayoutLabPanelVisible = [this](bool visible) { + m_shellChromeState.SetPanelVisible(ShellPanelId::XCUILayoutLab, visible); + if (m_layoutLabPanel != nullptr) { + m_layoutLabPanel->SetVisible(visible); + } + }; + bindings.getImGuiDemoWindowVisible = [this]() { + return IsShellViewToggleEnabled(ShellViewToggleId::ImGuiDemoWindow); + }; + bindings.setImGuiDemoWindowVisible = [this](bool visible) { + SetShellViewToggleEnabled(ShellViewToggleId::ImGuiDemoWindow, visible); + }; + bindings.getNativeBackdropVisible = [this]() { + return IsShellViewToggleEnabled(ShellViewToggleId::NativeBackdrop); + }; + bindings.setNativeBackdropVisible = [this](bool visible) { + SetShellViewToggleEnabled(ShellViewToggleId::NativeBackdrop, visible); + }; + bindings.getPulseAccentEnabled = [this]() { + return IsShellViewToggleEnabled(ShellViewToggleId::PulseAccent); + }; + bindings.setPulseAccentEnabled = [this](bool enabled) { + SetShellViewToggleEnabled(ShellViewToggleId::PulseAccent, enabled); + }; + bindings.getNativeXCUIOverlayVisible = [this]() { + return IsShellViewToggleEnabled(ShellViewToggleId::NativeXCUIOverlay); + }; + bindings.setNativeXCUIOverlayVisible = [this](bool visible) { + SetShellViewToggleEnabled(ShellViewToggleId::NativeXCUIOverlay, visible); + }; + bindings.getHostedPreviewHudVisible = [this]() { + return IsShellViewToggleEnabled(ShellViewToggleId::HostedPreviewHud); + }; + bindings.setHostedPreviewHudVisible = [this](bool visible) { + SetShellViewToggleEnabled(ShellViewToggleId::HostedPreviewHud, visible); + }; + bindings.getNativeDemoPanelPreviewEnabled = [this]() { + return IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo); + }; + bindings.setNativeDemoPanelPreviewEnabled = [this](bool enabled) { + m_shellChromeState.SetHostedPreviewMode( + ShellPanelId::XCUIDemo, + enabled ? ShellHostedPreviewMode::NativeOffscreen : ShellHostedPreviewMode::HostedPresenter); + }; + bindings.getNativeLayoutLabPreviewEnabled = [this]() { + return IsNativeHostedPreviewEnabled(ShellPanelId::XCUILayoutLab); + }; + bindings.setNativeLayoutLabPreviewEnabled = [this](bool enabled) { + m_shellChromeState.SetHostedPreviewMode( + ShellPanelId::XCUILayoutLab, + enabled ? ShellHostedPreviewMode::NativeOffscreen : ShellHostedPreviewMode::HostedPresenter); + }; + bindings.onHostedPreviewModeChanged = [this]() { ConfigureHostedPreviewPresenters(); }; + + Application::RegisterShellViewCommands(m_shellCommandRouter, bindings); +} + +::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta +Application::DispatchShellShortcuts( + const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot& snapshot) { + ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameSnapshot shellSnapshot = snapshot; + if (!IsNativeWindowHostEnabled()) { + ::XCEngine::Editor::XCUIBackend::ApplyLegacyImGuiHostInputCapture(shellSnapshot); + } + + if (!m_shellInputBridge.HasBaseline()) { + m_shellInputBridge.Prime(shellSnapshot); + } + const ::XCEngine::Editor::XCUIBackend::XCUIInputBridgeFrameDelta frameDelta = + m_shellInputBridge.Translate(shellSnapshot); + const ::XCEngine::Editor::XCUIBackend::XCUIEditorCommandInputSnapshot commandSnapshot = + Application::BuildShellShortcutSnapshot(frameDelta); + m_shellCommandRouter.InvokeMatchingShortcut({ &commandSnapshot }); + return frameDelta; +} + +void Application::InitializeWindowCompositor() { + m_windowCompositor = IsNativeWindowHostEnabled() + ? ::XCEngine::Editor::XCUIBackend::CreateNativeWindowUICompositor() + : ::XCEngine::Editor::XCUIBackend::CreateLegacyImGuiWindowUICompositor(); + if (m_windowCompositor != nullptr) { + m_windowCompositor->Initialize( + m_hwnd, + m_windowRenderer, + []() { (void)::XCEngine::Editor::XCUIBackend::ConfigureLegacyImGuiHostFonts(); }); + } +} + void Application::FrameLegacyImGuiHost() { Application::BeginHostedPreviewFrameLifecycle( m_hostedPreviewQueue, diff --git a/new_editor/src/Platform/D3D12WindowRenderer.h b/new_editor/src/Platform/D3D12WindowRenderer.h new file mode 100644 index 00000000..bff574c0 --- /dev/null +++ b/new_editor/src/Platform/D3D12WindowRenderer.h @@ -0,0 +1,7 @@ +#pragma once + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include "../../../editor/src/Platform/D3D12WindowRenderer.h" diff --git a/new_editor/src/Platform/D3D12WindowRendererImGuiInterop.h b/new_editor/src/Platform/D3D12WindowRendererImGuiInterop.h new file mode 100644 index 00000000..5e091fe8 --- /dev/null +++ b/new_editor/src/Platform/D3D12WindowRendererImGuiInterop.h @@ -0,0 +1,83 @@ +#pragma once + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include "D3D12WindowRenderer.h" + +#include "../UI/ImGuiBackendBridge.h" + +#include + +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif + +namespace XCEngine { +namespace Editor { +namespace Platform { + +inline void RenderImGuiFrame( + D3D12WindowRenderer& windowRenderer, + UI::ImGuiBackendBridge& imguiBackend, + const float clearColor[4], + const D3D12WindowRenderer::RenderCallback& beforeUiRender = {}, + const D3D12WindowRenderer::RenderCallback& afterUiRender = {}) { + const Rendering::RenderSurface* renderSurface = windowRenderer.GetCurrentRenderSurface(); + Rendering::RenderContext renderContext = windowRenderer.GetRenderContext(); + auto* d3d12CommandList = dynamic_cast(renderContext.commandList); + if (!renderContext.IsValid() || + d3d12CommandList == nullptr || + renderContext.commandQueue == nullptr || + windowRenderer.GetSwapChain() == nullptr || + renderSurface == nullptr || + windowRenderer.GetSrvHeap() == nullptr) { + return; + } + + const auto& colorAttachments = renderSurface->GetColorAttachments(); + if (colorAttachments.empty() || colorAttachments[0] == nullptr) { + return; + } + + RHI::RHIResourceView* renderTargetView = colorAttachments[0]; + renderContext.commandList->TransitionBarrier( + renderTargetView, + RHI::ResourceStates::Present, + RHI::ResourceStates::RenderTarget); + renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr); + renderContext.commandList->ClearRenderTarget(renderTargetView, clearColor); + + if (beforeUiRender) { + beforeUiRender(renderContext, *renderSurface); + renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr); + } + + ID3D12DescriptorHeap* descriptorHeaps[] = { windowRenderer.GetSrvHeap() }; + d3d12CommandList->SetDescriptorHeaps(1, descriptorHeaps); + imguiBackend.RenderDrawData(d3d12CommandList->GetCommandList()); + + if (afterUiRender) { + renderContext.commandList->SetRenderTargets(1, &renderTargetView, nullptr); + afterUiRender(renderContext, *renderSurface); + } + + renderContext.commandList->TransitionBarrier( + renderTargetView, + RHI::ResourceStates::RenderTarget, + RHI::ResourceStates::Present); + renderContext.commandList->Close(); + + void* commandLists[] = { renderContext.commandList }; + renderContext.commandQueue->ExecuteCommandLists(1, commandLists); + windowRenderer.GetSwapChain()->Present(1, 0); +} + +} // namespace Platform +} // namespace Editor +} // namespace XCEngine diff --git a/new_editor/src/XCUIBackend/IEditorHostCompositor.h b/new_editor/src/XCUIBackend/IEditorHostCompositor.h index 712312ce..4b933fa5 100644 --- a/new_editor/src/XCUIBackend/IEditorHostCompositor.h +++ b/new_editor/src/XCUIBackend/IEditorHostCompositor.h @@ -1,23 +1,44 @@ #pragma once -#include "Platform/D3D12WindowRenderer.h" +#ifndef NOMINMAX +#define NOMINMAX +#endif + #include "XCUIBackend/UITextureRegistration.h" +#include +#include #include #include #include #include + #include +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif + namespace XCEngine { namespace Editor { +namespace Platform { + +class D3D12WindowRenderer; + +} // namespace Platform + namespace XCUIBackend { class IEditorHostCompositor { public: using ConfigureFontsCallback = std::function; - using RenderCallback = ::XCEngine::Editor::Platform::D3D12WindowRenderer::RenderCallback; + using RenderCallback = + std::function; virtual ~IEditorHostCompositor() = default; diff --git a/new_editor/src/XCUIBackend/IWindowUICompositor.h b/new_editor/src/XCUIBackend/IWindowUICompositor.h index bbe41ed7..92c7474b 100644 --- a/new_editor/src/XCUIBackend/IWindowUICompositor.h +++ b/new_editor/src/XCUIBackend/IWindowUICompositor.h @@ -1,24 +1,45 @@ #pragma once -#include "Platform/D3D12WindowRenderer.h" +#ifndef NOMINMAX +#define NOMINMAX +#endif + #include "XCUIBackend/UITextureRegistration.h" +#include +#include #include #include #include #include + #include +#ifdef min +#undef min +#endif + +#ifdef max +#undef max +#endif + namespace XCEngine { namespace Editor { +namespace Platform { + +class D3D12WindowRenderer; + +} // namespace Platform + namespace XCUIBackend { class IWindowUICompositor { public: using ConfigureFontsCallback = std::function; using UiRenderCallback = std::function; - using RenderCallback = ::XCEngine::Editor::Platform::D3D12WindowRenderer::RenderCallback; + using RenderCallback = + std::function; virtual ~IWindowUICompositor() = default; diff --git a/new_editor/src/XCUIBackend/ImGuiHostCompositor.cpp b/new_editor/src/XCUIBackend/ImGuiHostCompositor.cpp index 8e079152..a816d0a4 100644 --- a/new_editor/src/XCUIBackend/ImGuiHostCompositor.cpp +++ b/new_editor/src/XCUIBackend/ImGuiHostCompositor.cpp @@ -1,5 +1,6 @@ #include "XCUIBackend/IEditorHostCompositor.h" +#include "Platform/D3D12WindowRendererImGuiInterop.h" #include "UI/ImGuiBackendBridge.h" #include @@ -61,7 +62,12 @@ public: const RenderCallback& beforeUiRender, const RenderCallback& afterUiRender) override { ImGui::Render(); - windowRenderer.Render(m_backend, clearColor, beforeUiRender, afterUiRender); + ::XCEngine::Editor::Platform::RenderImGuiFrame( + windowRenderer, + m_backend, + clearColor, + beforeUiRender, + afterUiRender); } bool CreateTextureDescriptor( diff --git a/new_editor/src/XCUIBackend/NativeWindowUICompositor.cpp b/new_editor/src/XCUIBackend/NativeWindowUICompositor.cpp index 439b74b7..3e69e4d8 100644 --- a/new_editor/src/XCUIBackend/NativeWindowUICompositor.cpp +++ b/new_editor/src/XCUIBackend/NativeWindowUICompositor.cpp @@ -1,5 +1,7 @@ #include "XCUIBackend/NativeWindowUICompositor.h" +#include "Platform/D3D12WindowRenderer.h" + #include #include #include diff --git a/tests/NewEditor/CMakeLists.txt b/tests/NewEditor/CMakeLists.txt index 8029ea4f..f1f61b32 100644 --- a/tests/NewEditor/CMakeLists.txt +++ b/tests/NewEditor/CMakeLists.txt @@ -85,6 +85,9 @@ set(NEW_EDITOR_SHELL_CHROME_STATE_HEADER set(NEW_EDITOR_SHELL_CHROME_STATE_SOURCE ${CMAKE_SOURCE_DIR}/new_editor/src/XCUIBackend/XCUIShellChromeState.cpp ) +set(NEW_EDITOR_NATIVE_SHELL_LAYOUT_HEADER + ${CMAKE_SOURCE_DIR}/new_editor/src/XCUIBackend/XCUINativeShellLayout.h +) set(NEW_EDITOR_APPLICATION_HEADER ${CMAKE_SOURCE_DIR}/new_editor/src/Application.h ) @@ -115,6 +118,9 @@ set(NEW_EDITOR_IMGUI_TEXT_ATLAS_PROVIDER_HEADER set(NEW_EDITOR_IMGUI_TEXT_ATLAS_PROVIDER_SOURCE ${CMAKE_SOURCE_DIR}/new_editor/src/XCUIBackend/ImGuiTextAtlasProvider.cpp ) +set(NEW_EDITOR_IMGUI_HOST_COMPOSITOR_SOURCE + ${CMAKE_SOURCE_DIR}/new_editor/src/XCUIBackend/ImGuiHostCompositor.cpp +) set(NEW_EDITOR_FONT_SETUP_HEADER ${CMAKE_SOURCE_DIR}/new_editor/src/XCUIBackend/XCUIEditorFontSetup.h ) @@ -130,6 +136,12 @@ set(NEW_EDITOR_STANDALONE_TEXT_ATLAS_PROVIDER_SOURCE set(NEW_EDITOR_HOSTED_PREVIEW_PRESENTER_HEADER ${CMAKE_SOURCE_DIR}/new_editor/src/XCUIBackend/XCUIHostedPreviewPresenter.h ) +set(NEW_EDITOR_LEGACY_IMGUI_HOST_INTEROP_HEADER + ${CMAKE_SOURCE_DIR}/new_editor/src/XCUIBackend/LegacyImGuiHostInterop.h +) +set(NEW_EDITOR_LEGACY_IMGUI_HOST_INTEROP_SOURCE + ${CMAKE_SOURCE_DIR}/new_editor/src/XCUIBackend/LegacyImGuiHostInterop.cpp +) set(NEW_EDITOR_WINDOW_UI_COMPOSITOR_HEADER ${CMAKE_SOURCE_DIR}/new_editor/src/XCUIBackend/IWindowUICompositor.h ) @@ -411,6 +423,51 @@ else() message(STATUS "Skipping new_editor_xcui_hosted_preview_presenter_tests because presenter header or ImGui sources are missing.") endif() +if(EXISTS "${NEW_EDITOR_LEGACY_IMGUI_HOST_INTEROP_HEADER}" AND + EXISTS "${NEW_EDITOR_LEGACY_IMGUI_HOST_INTEROP_SOURCE}" AND + EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test_legacy_imgui_host_interop.cpp" AND + EXISTS "${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui.cpp") + add_executable(new_editor_legacy_imgui_host_interop_tests + test_legacy_imgui_host_interop.cpp + ${NEW_EDITOR_LEGACY_IMGUI_HOST_INTEROP_SOURCE} + ${NEW_EDITOR_IMGUI_HOST_COMPOSITOR_SOURCE} + ${NEW_EDITOR_FONT_SETUP_SOURCE} + ${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui.cpp + ${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_demo.cpp + ${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_draw.cpp + ${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_tables.cpp + ${CMAKE_BINARY_DIR}/_deps/imgui-src/imgui_widgets.cpp + ${CMAKE_BINARY_DIR}/_deps/imgui-src/backends/imgui_impl_win32.cpp + ${CMAKE_BINARY_DIR}/_deps/imgui-src/backends/imgui_impl_dx12.cpp + ) + + xcengine_configure_new_editor_test_target(new_editor_legacy_imgui_host_interop_tests) + + target_link_libraries(new_editor_legacy_imgui_host_interop_tests + PRIVATE + XCEngine + GTest::gtest + GTest::gtest_main + d3d12 + dxgi + user32 + gdi32 + comdlg32 + ) + + target_include_directories(new_editor_legacy_imgui_host_interop_tests PRIVATE + ${CMAKE_SOURCE_DIR}/engine/include + ${CMAKE_SOURCE_DIR}/new_editor/src + ${CMAKE_SOURCE_DIR}/editor/src + ${CMAKE_BINARY_DIR}/_deps/imgui-src + ${CMAKE_BINARY_DIR}/_deps/imgui-src/backends + ) + + xcengine_discover_new_editor_gtests(new_editor_legacy_imgui_host_interop_tests) +else() + message(STATUS "Skipping new_editor_legacy_imgui_host_interop_tests because helper, test source, or ImGui sources are missing.") +endif() + if(EXISTS "${NEW_EDITOR_WINDOW_UI_COMPOSITOR_HEADER}" AND EXISTS "${NEW_EDITOR_IMGUI_WINDOW_UI_COMPOSITOR_HEADER}" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test_imgui_window_ui_compositor.cpp") @@ -469,9 +526,6 @@ if(EXISTS "${NEW_EDITOR_WINDOW_UI_COMPOSITOR_HEADER}" AND target_include_directories(new_editor_native_window_ui_compositor_tests PRIVATE ${CMAKE_SOURCE_DIR}/engine/include ${CMAKE_SOURCE_DIR}/new_editor/src - ${CMAKE_SOURCE_DIR}/editor/src - ${CMAKE_BINARY_DIR}/_deps/imgui-src - ${CMAKE_BINARY_DIR}/_deps/imgui-src/backends ) xcengine_discover_new_editor_gtests(new_editor_native_window_ui_compositor_tests) @@ -586,6 +640,31 @@ else() message(STATUS "Skipping new_editor_xcui_shell_chrome_state_tests because shell chrome state files or the test source are missing.") endif() +if(EXISTS "${NEW_EDITOR_NATIVE_SHELL_LAYOUT_HEADER}" AND + EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test_xcui_native_shell_layout.cpp") + add_executable(new_editor_xcui_native_shell_layout_tests + test_xcui_native_shell_layout.cpp + ) + + xcengine_configure_new_editor_test_target(new_editor_xcui_native_shell_layout_tests) + + target_link_libraries(new_editor_xcui_native_shell_layout_tests + PRIVATE + XCEngine + GTest::gtest + GTest::gtest_main + ) + + target_include_directories(new_editor_xcui_native_shell_layout_tests PRIVATE + ${CMAKE_SOURCE_DIR}/engine/include + ${CMAKE_SOURCE_DIR}/new_editor/src + ) + + xcengine_discover_new_editor_gtests(new_editor_xcui_native_shell_layout_tests) +else() + message(STATUS "Skipping new_editor_xcui_native_shell_layout_tests because the layout helper header or the test source is missing.") +endif() + if(EXISTS "${NEW_EDITOR_APPLICATION_HEADER}" AND EXISTS "${NEW_EDITOR_COMMAND_ROUTER_SOURCE}" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test_application_shell_command_bindings.cpp") @@ -606,9 +685,6 @@ if(EXISTS "${NEW_EDITOR_APPLICATION_HEADER}" AND target_include_directories(new_editor_application_shell_command_bindings_tests PRIVATE ${CMAKE_SOURCE_DIR}/engine/include ${CMAKE_SOURCE_DIR}/new_editor/src - ${CMAKE_SOURCE_DIR}/editor/src - ${CMAKE_BINARY_DIR}/_deps/imgui-src - ${CMAKE_BINARY_DIR}/_deps/imgui-src/backends ) xcengine_discover_new_editor_gtests(new_editor_application_shell_command_bindings_tests) diff --git a/tests/NewEditor/test_native_window_ui_compositor.cpp b/tests/NewEditor/test_native_window_ui_compositor.cpp index 6bbe0d37..6ce35cc7 100644 --- a/tests/NewEditor/test_native_window_ui_compositor.cpp +++ b/tests/NewEditor/test_native_window_ui_compositor.cpp @@ -1,5 +1,6 @@ #include +#include "Platform/D3D12WindowRenderer.h" #include "XCUIBackend/IWindowUICompositor.h" #include "XCUIBackend/NativeWindowUICompositor.h" #include "XCUIBackend/UITextureRegistration.h" diff --git a/tests/editor/test_window_renderer_api.cpp b/tests/editor/test_window_renderer_api.cpp index a69e1e42..3208eedb 100644 --- a/tests/editor/test_window_renderer_api.cpp +++ b/tests/editor/test_window_renderer_api.cpp @@ -1,6 +1,7 @@ #include #include "Platform/D3D12WindowRenderer.h" +#include "Platform/D3D12WindowRendererImGuiInterop.h" #include @@ -16,7 +17,8 @@ TEST(D3D12WindowRendererApiTest, ExposesSurfaceAwareRenderCallbackAndAccessor) { decltype(std::declval().GetCurrentRenderSurface()), const RenderSurface*>); static_assert(std::is_same_v< - decltype(std::declval().Render( + decltype(::XCEngine::Editor::Platform::RenderImGuiFrame( + std::declval(), std::declval<::XCEngine::Editor::UI::ImGuiBackendBridge&>(), std::declval(), std::declval())),