Refactor editor shell host layers

This commit is contained in:
2026-03-26 23:52:05 +08:00
parent f87bc53875
commit 31675e00c8
18 changed files with 738 additions and 518 deletions

View File

@@ -1,65 +1,20 @@
#include "Application.h"
#include "Core/EditorWindowTitle.h"
#include "Layers/EditorLayer.h"
#include "Core/EditorContext.h"
#include "Core/EditorConsoleSink.h"
#include "Core/EditorEvents.h"
#include "Core/EventBus.h"
#include "Platform/Win32Utf8.h"
#include <XCEngine/Debug/Logger.h>
#include <XCEngine/Debug/FileLogSink.h>
#include <XCEngine/Debug/ConsoleLogSink.h>
#include <imgui_internal.h>
#include <filesystem>
#include <stdio.h>
#include <windows.h>
#include <string>
namespace {
std::string WideToUtf8(const std::wstring& value) {
if (value.empty()) {
return {};
}
int len = WideCharToMultiByte(CP_UTF8, 0, value.c_str(), -1, nullptr, 0, nullptr, nullptr);
if (len <= 0) {
return {};
}
std::string result(len - 1, '\0');
WideCharToMultiByte(CP_UTF8, 0, value.c_str(), -1, &result[0], len, nullptr, nullptr);
return result;
}
std::wstring Utf8ToWide(const std::string& value) {
if (value.empty()) {
return {};
}
int len = MultiByteToWideChar(CP_UTF8, 0, value.c_str(), -1, nullptr, 0);
if (len <= 0) {
return {};
}
std::wstring result(len - 1, L'\0');
MultiByteToWideChar(CP_UTF8, 0, value.c_str(), -1, &result[0], len);
return result;
}
std::string GetExecutableDirectoryUtf8() {
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(nullptr, exePath, MAX_PATH);
std::wstring exeDirW(exePath);
const size_t pos = exeDirW.find_last_of(L"\\/");
if (pos != std::wstring::npos) {
exeDirW = exeDirW.substr(0, pos);
}
return WideToUtf8(exeDirW);
}
std::string GetExecutableLogPath(const char* fileName) {
return GetExecutableDirectoryUtf8() + "\\" + fileName;
return XCEngine::Editor::Platform::GetExecutableDirectoryUtf8() + "\\" + fileName;
}
} // namespace
@@ -92,24 +47,17 @@ Application& Application::Get() {
}
bool Application::Initialize(HWND hwnd) {
// Set global exception filter first to catch any crashes
SetUnhandledExceptionFilter(GlobalExceptionFilter);
// Redirect stderr to log file to capture ImGui errors
{
const std::string stderrPath = GetExecutableLogPath("stderr.log");
freopen(stderrPath.c_str(), "w", stderr);
fprintf(stderr, "[TEST] stderr redirection test - this should appear in stderr.log\n");
fflush(stderr);
}
// Initialize logging first
Debug::Logger::Get().AddSink(std::make_unique<Debug::ConsoleLogSink>());
Debug::Logger::Get().AddSink(std::make_unique<Debug::EditorConsoleSink>());
// Get exe directory for log file path
const std::string exeDir = GetExecutableDirectoryUtf8();
const std::string exeDir = Platform::GetExecutableDirectoryUtf8();
std::string logPath = exeDir + "\\editor.log";
Debug::Logger::Get().AddSink(std::make_unique<Debug::FileLogSink>(logPath.c_str()));
Debug::Logger::Get().Info(Debug::LogCategory::General, "Editor Application starting...");
@@ -117,14 +65,10 @@ bool Application::Initialize(HWND hwnd) {
m_hwnd = hwnd;
if (!CreateDevice()) {
if (!m_windowRenderer.Initialize(hwnd, 1280, 720)) {
MessageBoxW(hwnd, L"Failed to create D3D12 device", L"Error", MB_OK | MB_ICONERROR);
return false;
}
if (!CreateRenderTarget()) {
MessageBoxW(hwnd, L"Failed to create render target", L"Error", MB_OK | MB_ICONERROR);
return false;
}
m_editorContext = std::make_shared<EditorContext>();
m_editorContext->SetProjectPath(exeDir);
@@ -136,7 +80,7 @@ bool Application::Initialize(HWND hwnd) {
});
m_imguiSession.Initialize(m_editorContext->GetProjectPath());
m_imguiBackend.Initialize(hwnd, m_device, m_srvHeap);
m_imguiBackend.Initialize(hwnd, m_windowRenderer.GetDevice(), m_windowRenderer.GetSrvHeap());
m_editorLayer = new EditorLayer();
m_editorLayer->SetContext(m_editorContext);
@@ -156,17 +100,7 @@ void Application::Shutdown() {
m_imguiBackend.Shutdown();
m_imguiSession.Shutdown();
CleanupRenderTarget();
if (m_fence) m_fence->Release();
if (m_commandList) m_commandList->Release();
if (m_commandAllocator) m_commandAllocator->Release();
if (m_commandQueue) m_commandQueue->Release();
if (m_rtvHeap) m_rtvHeap->Release();
if (m_srvHeap) m_srvHeap->Release();
if (m_swapChain) m_swapChain->Release();
if (m_device) m_device->Release();
m_windowRenderer.Shutdown();
}
void Application::Render() {
@@ -176,46 +110,9 @@ void Application::Render() {
UpdateWindowTitle();
ImGui::Render();
m_frameIndex = m_swapChain->GetCurrentBackBufferIndex();
m_commandAllocator->Reset();
m_commandList->Reset(m_commandAllocator, nullptr);
D3D12_RESOURCE_BARRIER barrier = {};
barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;
barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;
barrier.Transition.pResource = m_renderTargets[m_frameIndex];
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES;
m_commandList->ResourceBarrier(1, &barrier);
float clearColor[4] = { 0.22f, 0.22f, 0.22f, 1.0f };
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = m_rtvHeap->GetCPUDescriptorHandleForHeapStart();
rtvHandle.ptr += m_frameIndex * m_rtvDescriptorSize;
m_commandList->ClearRenderTargetView(rtvHandle, clearColor, 0, nullptr);
m_commandList->OMSetRenderTargets(1, &rtvHandle, FALSE, nullptr);
ID3D12DescriptorHeap* heaps[] = { m_srvHeap };
m_commandList->SetDescriptorHeaps(1, heaps);
m_imguiBackend.RenderDrawData(m_commandList);
barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;
barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;
m_commandList->ResourceBarrier(1, &barrier);
m_commandList->Close();
ID3D12CommandList* cmdLists[] = { m_commandList };
m_commandQueue->ExecuteCommandLists(1, cmdLists);
m_swapChain->Present(1, 0);
m_fenceValue++;
m_commandQueue->Signal(m_fence, m_fenceValue);
if (m_fence->GetCompletedValue() < m_fenceValue) {
m_fence->SetEventOnCompletion(m_fenceValue, nullptr);
}
m_windowRenderer.Render(m_imguiBackend, clearColor);
}
void Application::UpdateWindowTitle() {
@@ -223,23 +120,7 @@ void Application::UpdateWindowTitle() {
return;
}
auto& sceneManager = m_editorContext->GetSceneManager();
std::string sceneName = sceneManager.HasActiveScene() ? sceneManager.GetCurrentSceneName() : "No Scene";
if (sceneName.empty()) {
sceneName = "Untitled Scene";
}
if (sceneManager.IsSceneDirty()) {
sceneName += " *";
}
if (sceneManager.GetCurrentScenePath().empty()) {
sceneName += " (Unsaved)";
} else {
sceneName += " - ";
sceneName += std::filesystem::path(sceneManager.GetCurrentScenePath()).filename().string();
}
const std::wstring title = Utf8ToWide(sceneName + " - XCEngine Editor");
const std::wstring title = Platform::Utf8ToWide(BuildEditorWindowTitle(*m_editorContext));
if (title != m_lastWindowTitle) {
SetWindowTextW(m_hwnd, title.c_str());
m_lastWindowTitle = title;
@@ -247,107 +128,7 @@ void Application::UpdateWindowTitle() {
}
void Application::OnResize(int width, int height) {
if (width <= 0 || height <= 0) return;
m_width = width;
m_height = height;
CleanupRenderTarget();
if (m_swapChain) {
DXGI_SWAP_CHAIN_DESC desc;
m_swapChain->GetDesc(&desc);
m_swapChain->ResizeBuffers(3, width, height, desc.BufferDesc.Format, desc.Flags);
}
CreateRenderTarget();
}
bool Application::CreateDevice() {
HRESULT hr = D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device));
if (FAILED(hr)) {
return false;
}
D3D12_COMMAND_QUEUE_DESC queueDesc = {};
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
queueDesc.Priority = 0;
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
queueDesc.NodeMask = 0;
hr = m_device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&m_commandQueue));
if (FAILED(hr)) return false;
hr = m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&m_commandAllocator));
if (FAILED(hr)) return false;
hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, m_commandAllocator, nullptr, IID_PPV_ARGS(&m_commandList));
if (FAILED(hr)) return false;
m_commandList->Close();
hr = m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence));
if (FAILED(hr)) return false;
IDXGIFactory4* factory = nullptr;
hr = CreateDXGIFactory1(IID_PPV_ARGS(&factory));
if (FAILED(hr)) return false;
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {};
swapChainDesc.BufferCount = 3;
swapChainDesc.Width = m_width;
swapChainDesc.Height = m_height;
swapChainDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
swapChainDesc.SampleDesc.Count = 1;
IDXGISwapChain1* swapChain1 = nullptr;
hr = factory->CreateSwapChainForHwnd(m_commandQueue, m_hwnd, &swapChainDesc, nullptr, nullptr, &swapChain1);
factory->Release();
if (FAILED(hr)) return false;
hr = swapChain1->QueryInterface(IID_PPV_ARGS(&m_swapChain));
swapChain1->Release();
if (FAILED(hr)) return false;
D3D12_DESCRIPTOR_HEAP_DESC rtvDesc = {};
rtvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
rtvDesc.NumDescriptors = 3;
rtvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
hr = m_device->CreateDescriptorHeap(&rtvDesc, IID_PPV_ARGS(&m_rtvHeap));
if (FAILED(hr)) return false;
m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
D3D12_DESCRIPTOR_HEAP_DESC srvDesc = {};
srvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
srvDesc.NumDescriptors = 1;
srvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
hr = m_device->CreateDescriptorHeap(&srvDesc, IID_PPV_ARGS(&m_srvHeap));
if (FAILED(hr)) return false;
return true;
}
bool Application::CreateRenderTarget() {
if (!m_swapChain || !m_device || !m_rtvHeap) return false;
for (UINT i = 0; i < 3; i++) {
HRESULT hr = m_swapChain->GetBuffer(i, IID_PPV_ARGS(&m_renderTargets[i]));
if (FAILED(hr)) return false;
D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = m_rtvHeap->GetCPUDescriptorHandleForHeapStart();
rtvHandle.ptr += i * m_rtvDescriptorSize;
m_device->CreateRenderTargetView(m_renderTargets[i], nullptr, rtvHandle);
}
return true;
}
void Application::CleanupRenderTarget() {
for (UINT i = 0; i < 3; i++) {
if (m_renderTargets[i]) {
m_renderTargets[i]->Release();
m_renderTargets[i] = nullptr;
}
}
m_windowRenderer.Resize(width, height);
}
}