Files
XCEngine/editor/src/Application.cpp

215 lines
6.5 KiB
C++

#include "Application.h"
#include "Core/EditorLoggingSetup.h"
#include "Core/ProjectRootResolver.h"
#include "Core/EditorWindowTitle.h"
#include "Layers/EditorLayer.h"
#include "Core/EditorContext.h"
#include "Core/EditorEvents.h"
#include "Core/EventBus.h"
#include "UI/BuiltInIcons.h"
#include "Platform/Win32Utf8.h"
#include "Platform/WindowsProcessDiagnostics.h"
#include <XCEngine/Debug/Logger.h>
#include <windows.h>
namespace XCEngine {
namespace Editor {
Application& Application::Get() {
static Application instance;
return instance;
}
bool Application::InitializeWindowRenderer(HWND hwnd) {
RECT clientRect = {};
if (!GetClientRect(hwnd, &clientRect)) {
MessageBoxW(hwnd, L"Failed to query editor client area", L"Error", MB_OK | MB_ICONERROR);
return false;
}
const int clientWidth = clientRect.right - clientRect.left;
const int clientHeight = clientRect.bottom - clientRect.top;
if (clientWidth <= 0 || clientHeight <= 0) {
MessageBoxW(hwnd, L"Editor client area is invalid", L"Error", MB_OK | MB_ICONERROR);
return false;
}
if (m_windowRenderer.Initialize(hwnd, clientWidth, clientHeight)) {
return true;
}
MessageBoxW(hwnd, L"Failed to initialize editor window renderer", L"Error", MB_OK | MB_ICONERROR);
return false;
}
void Application::InitializeEditorContext(const std::string& projectPath) {
m_editorContext = std::make_shared<EditorContext>();
m_editorContext->SetProjectPath(projectPath);
m_exitRequestedHandlerId = m_editorContext->GetEventBus().Subscribe<EditorExitRequestedEvent>(
[this](const EditorExitRequestedEvent&) {
if (m_hwnd) {
PostMessageW(m_hwnd, WM_CLOSE, 0, 0);
}
});
}
void Application::InitializeImGui(HWND hwnd) {
m_imguiSession.Initialize(
m_editorContext->GetProjectPath(),
UI::ImGuiBackendBridge::GetDpiScaleForHwnd(hwnd));
m_imguiBackend.Initialize(
hwnd,
m_windowRenderer.GetDevice(),
m_windowRenderer.GetCommandQueue(),
m_windowRenderer.GetSrvHeap(),
m_windowRenderer.GetSrvDescriptorSize(),
m_windowRenderer.GetSrvDescriptorCount());
UI::InitializeBuiltInIcons(
m_imguiBackend,
m_windowRenderer.GetDevice(),
m_windowRenderer.GetCommandQueue());
m_viewportHostService.Initialize(m_imguiBackend, m_windowRenderer.GetRHIDevice());
static_cast<EditorContext*>(m_editorContext.get())->SetViewportHostService(&m_viewportHostService);
}
void Application::AttachEditorLayer() {
m_editorLayer = new EditorLayer();
m_editorLayer->SetContext(m_editorContext);
m_layerStack.pushLayer(std::unique_ptr<Core::Layer>(m_editorLayer));
m_layerStack.onAttach();
}
void Application::DetachEditorLayer() {
m_layerStack.onDetach();
m_editorLayer = nullptr;
}
void Application::ShutdownEditorContext() {
if (m_editorContext && m_exitRequestedHandlerId) {
m_editorContext->GetEventBus().Unsubscribe<EditorExitRequestedEvent>(m_exitRequestedHandlerId);
m_exitRequestedHandlerId = 0;
}
m_editorContext.reset();
}
void Application::RenderEditorFrame() {
static constexpr float kClearColor[4] = { 0.22f, 0.22f, 0.22f, 1.0f };
if (!m_windowRenderer.BeginFrame()) {
return;
}
m_imguiBackend.BeginFrame();
m_viewportHostService.BeginFrame();
m_layerStack.onImGuiRender();
UpdateWindowTitle();
ImGui::Render();
m_windowRenderer.Render(
m_imguiBackend,
kClearColor,
[this](const Rendering::RenderContext& renderContext) {
if (m_editorContext) {
m_viewportHostService.RenderRequestedViewports(*m_editorContext, renderContext);
}
});
}
bool Application::Initialize(HWND hwnd) {
Platform::InstallCrashExceptionFilter();
Platform::RedirectStderrToExecutableLog();
const std::string exeDir = Platform::GetExecutableDirectoryUtf8();
ConfigureEditorLogging(exeDir);
const std::string projectRoot = ResolveEditorProjectRootUtf8();
const bool workingDirectoryChanged = SetEditorWorkingDirectory(projectRoot);
auto& logger = Debug::Logger::Get();
const std::string projectRootMessage = "Editor project root: " + projectRoot;
logger.Info(Debug::LogCategory::General, projectRootMessage.c_str());
if (!workingDirectoryChanged) {
const std::string warningMessage = "Failed to switch editor working directory to project root: " + projectRoot;
logger.Warning(Debug::LogCategory::General, warningMessage.c_str());
}
m_hwnd = hwnd;
if (!InitializeWindowRenderer(hwnd)) {
return false;
}
InitializeEditorContext(projectRoot);
InitializeImGui(hwnd);
AttachEditorLayer();
m_renderReady = true;
return true;
}
void Application::Shutdown() {
m_renderReady = false;
DetachEditorLayer();
if (m_editorContext) {
static_cast<EditorContext*>(m_editorContext.get())->SetViewportHostService(nullptr);
}
m_viewportHostService.Shutdown();
UI::ShutdownBuiltInIcons();
m_imguiBackend.Shutdown();
m_imguiSession.Shutdown();
ShutdownEditorContext();
m_windowRenderer.Shutdown();
}
void Application::Render() {
if (!m_renderReady) {
return;
}
RenderEditorFrame();
}
void Application::UpdateWindowTitle() {
if (!m_hwnd || !m_editorContext) {
return;
}
const std::wstring title = Platform::Utf8ToWide(BuildEditorWindowTitle(*m_editorContext));
if (title != m_lastWindowTitle) {
SetWindowTextW(m_hwnd, title.c_str());
m_lastWindowTitle = title;
}
}
void Application::OnResize(int width, int height) {
m_windowRenderer.Resize(width, height);
}
bool Application::SwitchProject(const std::string& projectPath) {
if (!m_editorContext || projectPath.empty()) {
return false;
}
m_imguiSession.SetProjectPath(projectPath);
m_editorContext->SetProjectPath(projectPath);
auto& logger = Debug::Logger::Get();
if (!SetEditorWorkingDirectory(projectPath)) {
const std::string warningMessage = "Failed to switch editor working directory to project root: " + projectPath;
logger.Warning(Debug::LogCategory::General, warningMessage.c_str());
}
const std::string infoMessage = "Switched editor project root: " + projectPath;
logger.Info(Debug::LogCategory::General, infoMessage.c_str());
m_lastWindowTitle.clear();
UpdateWindowTitle();
return true;
}
void Application::SaveProjectState() {
m_imguiSession.SaveSettings();
}
}
}