#include "Platform/Win32/EditorWindowRuntimeController.h" #include "Bootstrap/EditorResources.h" #include "Internal/EmbeddedPngLoader.h" #include "Platform/Win32/EditorWindowRuntimeInternal.h" #include "Composition/EditorContext.h" #include #include namespace XCEngine::UI::Editor::App::Internal { using App::Internal::LoadEmbeddedPngTexture; using namespace EditorWindowInternal; EditorWindowRuntimeController::EditorWindowRuntimeController( UIEditorWorkspaceController workspaceController) : m_workspaceController(std::move(workspaceController)) { } EditorWindowRuntimeController::~EditorWindowRuntimeController() = default; bool EditorWindowRuntimeController::IsReady() const { return m_ready; } const UIEditorWorkspaceController& EditorWindowRuntimeController::GetWorkspaceController() const { return m_workspaceController; } UIEditorWorkspaceController& EditorWindowRuntimeController::GetMutableWorkspaceController() { return m_workspaceController; } void EditorWindowRuntimeController::ReplaceWorkspaceController( UIEditorWorkspaceController workspaceController) { m_workspaceController = std::move(workspaceController); } const EditorShellRuntime& EditorWindowRuntimeController::GetShellRuntime() const { return m_shellRuntime; } EditorShellRuntime& EditorWindowRuntimeController::GetShellRuntime() { return m_shellRuntime; } const UIEditorShellInteractionFrame& EditorWindowRuntimeController::GetShellFrame() const { return m_shellRuntime.GetShellFrame(); } const UIEditorShellInteractionState& EditorWindowRuntimeController::GetShellInteractionState() const { return m_shellRuntime.GetShellInteractionState(); } void EditorWindowRuntimeController::SetExternalDockHostDropPreview( const Widgets::UIEditorDockHostDropPreviewState& preview) { m_shellRuntime.SetExternalDockHostDropPreview(preview); } void EditorWindowRuntimeController::ClearExternalDockHostDropPreview() { m_shellRuntime.ClearExternalDockHostDropPreview(); } void EditorWindowRuntimeController::SetDpiScale(float dpiScale) { m_renderer.SetDpiScale(dpiScale); } Host::NativeRenderer& EditorWindowRuntimeController::GetRenderer() { return m_renderer; } const Host::NativeRenderer& EditorWindowRuntimeController::GetRenderer() const { return m_renderer; } const ::XCEngine::UI::UITextureHandle& EditorWindowRuntimeController::GetTitleBarLogoIcon() const { return m_titleBarLogoIcon; } bool EditorWindowRuntimeController::Initialize( HWND hwnd, const std::filesystem::path& repoRoot, EditorContext& editorContext, const std::filesystem::path& captureRoot, bool autoCaptureOnStartup) { if (hwnd == nullptr) { LogRuntimeTrace("app", "window initialize skipped: hwnd is null"); return false; } if (!m_renderer.Initialize(hwnd)) { LogRuntimeTrace("app", "renderer initialization failed"); return false; } RECT clientRect = {}; GetClientRect(hwnd, &clientRect); const int clientWidth = (std::max)(clientRect.right - clientRect.left, 1L); const int clientHeight = (std::max)(clientRect.bottom - clientRect.top, 1L); if (!m_windowRenderer.Initialize(hwnd, clientWidth, clientHeight)) { LogRuntimeTrace("app", "d3d12 window renderer initialization failed"); m_renderer.Shutdown(); return false; } const Host::D3D12WindowRenderLoopAttachResult attachResult = m_windowRenderLoop.Attach(m_renderer, m_windowRenderer); if (!attachResult.interopWarning.empty()) { LogRuntimeTrace("app", attachResult.interopWarning); } editorContext.AttachTextMeasurer(m_renderer); m_shellRuntime.Initialize(repoRoot, m_renderer, m_renderer); m_shellRuntime.AttachViewportWindowRenderer(m_windowRenderer); m_shellRuntime.SetViewportSurfacePresentationEnabled( attachResult.hasViewportSurfacePresentation); std::string titleBarLogoError = {}; if (!LoadEmbeddedPngTexture( m_renderer, IDR_PNG_LOGO_ICON, m_titleBarLogoIcon, titleBarLogoError)) { LogRuntimeTrace("icons", "titlebar logo_icon.png: " + titleBarLogoError); } if (!m_shellRuntime.GetBuiltInIconError().empty()) { LogRuntimeTrace("icons", m_shellRuntime.GetBuiltInIconError()); } LogRuntimeTrace( "app", "shell runtime initialized: " + editorContext.DescribeWorkspaceState( m_workspaceController, m_shellRuntime.GetShellInteractionState())); m_ready = true; m_autoScreenshot.Initialize(captureRoot); if (autoCaptureOnStartup && IsAutoCaptureOnStartupEnabled()) { m_autoScreenshot.RequestCapture("startup"); editorContext.SetStatus("Capture", "Startup capture requested."); } return true; } void EditorWindowRuntimeController::Shutdown() { m_ready = false; m_autoScreenshot.Shutdown(); m_shellRuntime.Shutdown(); m_renderer.ReleaseTexture(m_titleBarLogoIcon); m_windowRenderLoop.Detach(); m_windowRenderer.Shutdown(); m_renderer.Shutdown(); } void EditorWindowRuntimeController::ResetInteractionState() { m_shellRuntime.ResetInteractionState(); } bool EditorWindowRuntimeController::ApplyResize(UINT width, UINT height) { if (!m_ready || width == 0u || height == 0u) { return false; } const Host::D3D12WindowRenderLoopResizeResult resizeResult = m_windowRenderLoop.ApplyResize(width, height); m_shellRuntime.SetViewportSurfacePresentationEnabled( resizeResult.hasViewportSurfacePresentation); if (!resizeResult.windowRendererWarning.empty()) { LogRuntimeTrace("present", resizeResult.windowRendererWarning); } if (!resizeResult.interopWarning.empty()) { LogRuntimeTrace("present", resizeResult.interopWarning); } return resizeResult.hasViewportSurfacePresentation; } Host::D3D12WindowRenderLoopFrameContext EditorWindowRuntimeController::BeginFrame() const { return m_windowRenderLoop.BeginFrame(); } Host::D3D12WindowRenderLoopPresentResult EditorWindowRuntimeController::Present( const ::XCEngine::UI::UIDrawData& drawData) const { return m_windowRenderLoop.Present(drawData); } void EditorWindowRuntimeController::CaptureIfRequested( const ::XCEngine::UI::UIDrawData& drawData, UINT pixelWidth, UINT pixelHeight, bool framePresented) { m_autoScreenshot.CaptureIfRequested( m_renderer, drawData, pixelWidth, pixelHeight, framePresented); } void EditorWindowRuntimeController::RequestManualScreenshot(std::string reason) { m_autoScreenshot.RequestCapture(std::move(reason)); } std::string EditorWindowRuntimeController::BuildCaptureStatusText() const { if (m_autoScreenshot.HasPendingCapture()) { return "Shot pending..."; } if (!m_autoScreenshot.GetLastCaptureError().empty()) { return TruncateText(m_autoScreenshot.GetLastCaptureError(), 38u); } if (!m_autoScreenshot.GetLastCaptureSummary().empty()) { return TruncateText(m_autoScreenshot.GetLastCaptureSummary(), 38u); } return {}; } } // namespace XCEngine::UI::Editor::App::Internal