Isolate XCNewEditor default build from ImGui headers

This commit is contained in:
2026-04-05 16:11:08 +08:00
parent 18f53bd920
commit 9db0d82082
17 changed files with 546 additions and 308 deletions

View File

@@ -32,7 +32,11 @@ Old `editor` replacement is explicitly out of scope for this phase.
- `Application.cpp` no longer directly includes `<imgui.h>`, 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 `<imgui.h>` 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 `<imgui.h>` 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 `<imgui.h>`, reducing default-path compile-time coupling before the larger compat-target split
- the main `Application.cpp` native host path no longer directly includes `<imgui.h>`, 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` -> `<imgui.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 `<imgui.h>`.
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.

View File

@@ -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&) {

View File

@@ -1,7 +1,5 @@
#pragma once
#include "UI/ImGuiBackendBridge.h"
#include <XCEngine/Rendering/RenderContext.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/RHI/RHICommandList.h>
@@ -16,6 +14,10 @@
#include <XCEngine/RHI/D3D12/D3D12Device.h>
#include <XCEngine/RHI/D3D12/D3D12SwapChain.h>
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <d3d12.h>
#include <functional>
#include <vector>
@@ -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;

View File

@@ -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<RHI::D3D12CommandList*>(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

View File

@@ -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
$<$<CONFIG:Debug,RelWithDebInfo>:/INCREMENTAL:NO>)
set_property(TARGET ${PROJECT_NAME} PROPERTY

View File

@@ -1,5 +1,4 @@
#include "Application.h"
#include "XCUIBackend/LegacyImGuiHostInterop.h"
#include "XCUIBackend/NativeWindowUICompositor.h"
#include <XCEngine/Core/Asset/ResourceManager.h>
@@ -9,6 +8,10 @@
#include <cmath>
#include <sstream>
#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<XCUIDemoPanel>(
&m_xcuiInputSource,
CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo)),
::XCEngine::Editor::XCUIBackend::CreateLegacyImGuiPanelCanvasHost());
m_layoutLabPanel = std::make_unique<XCUILayoutLabPanel>(
&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);

View File

@@ -3,12 +3,6 @@
#include <XCEngine/Input/InputTypes.h>
#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 <chrono>
#include <cstdint>
@@ -29,10 +26,24 @@
#include <windows.h>
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);

View File

@@ -1,6 +1,8 @@
#include "Application.h"
#include "XCUIBackend/LegacyImGuiHostInterop.h"
#include "panels/XCUIDemoPanel.h"
#include "panels/XCUILayoutLabPanel.h"
#include <imgui.h>
@@ -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<XCUIDemoPanel>(
&m_xcuiInputSource,
CreateHostedPreviewPresenter(IsNativeHostedPreviewEnabled(ShellPanelId::XCUIDemo)),
::XCEngine::Editor::XCUIBackend::CreateLegacyImGuiPanelCanvasHost());
m_layoutLabPanel = std::make_unique<XCUILayoutLabPanel>(
&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,

View File

@@ -0,0 +1,7 @@
#pragma once
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "../../../editor/src/Platform/D3D12WindowRenderer.h"

View File

@@ -0,0 +1,83 @@
#pragma once
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "D3D12WindowRenderer.h"
#include "../UI/ImGuiBackendBridge.h"
#include <XCEngine/RHI/D3D12/D3D12CommandList.h>
#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<RHI::D3D12CommandList*>(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

View File

@@ -1,23 +1,44 @@
#pragma once
#include "Platform/D3D12WindowRenderer.h"
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "XCUIBackend/UITextureRegistration.h"
#include <XCEngine/Rendering/RenderContext.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/RHI/RHIDevice.h>
#include <XCEngine/RHI/RHITexture.h>
#include <functional>
#include <memory>
#include <windows.h>
#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<void()>;
using RenderCallback = ::XCEngine::Editor::Platform::D3D12WindowRenderer::RenderCallback;
using RenderCallback =
std::function<void(const ::XCEngine::Rendering::RenderContext&, const ::XCEngine::Rendering::RenderSurface&)>;
virtual ~IEditorHostCompositor() = default;

View File

@@ -1,24 +1,45 @@
#pragma once
#include "Platform/D3D12WindowRenderer.h"
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "XCUIBackend/UITextureRegistration.h"
#include <XCEngine/Rendering/RenderContext.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/RHI/RHIDevice.h>
#include <XCEngine/RHI/RHITexture.h>
#include <functional>
#include <memory>
#include <windows.h>
#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<void()>;
using UiRenderCallback = std::function<void()>;
using RenderCallback = ::XCEngine::Editor::Platform::D3D12WindowRenderer::RenderCallback;
using RenderCallback =
std::function<void(const ::XCEngine::Rendering::RenderContext&, const ::XCEngine::Rendering::RenderSurface&)>;
virtual ~IWindowUICompositor() = default;

View File

@@ -1,5 +1,6 @@
#include "XCUIBackend/IEditorHostCompositor.h"
#include "Platform/D3D12WindowRendererImGuiInterop.h"
#include "UI/ImGuiBackendBridge.h"
#include <imgui.h>
@@ -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(

View File

@@ -1,5 +1,7 @@
#include "XCUIBackend/NativeWindowUICompositor.h"
#include "Platform/D3D12WindowRenderer.h"
#include <XCEngine/Rendering/RenderContext.h>
#include <XCEngine/Rendering/RenderSurface.h>
#include <XCEngine/RHI/RHICommandList.h>

View File

@@ -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)

View File

@@ -1,5 +1,6 @@
#include <gtest/gtest.h>
#include "Platform/D3D12WindowRenderer.h"
#include "XCUIBackend/IWindowUICompositor.h"
#include "XCUIBackend/NativeWindowUICompositor.h"
#include "XCUIBackend/UITextureRegistration.h"

View File

@@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include "Platform/D3D12WindowRenderer.h"
#include "Platform/D3D12WindowRendererImGuiInterop.h"
#include <type_traits>
@@ -16,7 +17,8 @@ TEST(D3D12WindowRendererApiTest, ExposesSurfaceAwareRenderCallbackAndAccessor) {
decltype(std::declval<D3D12WindowRenderer&>().GetCurrentRenderSurface()),
const RenderSurface*>);
static_assert(std::is_same_v<
decltype(std::declval<D3D12WindowRenderer&>().Render(
decltype(::XCEngine::Editor::Platform::RenderImGuiFrame(
std::declval<D3D12WindowRenderer&>(),
std::declval<::XCEngine::Editor::UI::ImGuiBackendBridge&>(),
std::declval<const float*>(),
std::declval<const Callback&>())),