#include "Application.h" #include "Layers/EditorLayer.h" #include "Core/EditorContext.h" #include "Core/EditorConsoleSink.h" #include #include #include #include #include #include #include #include extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); static LONG WINAPI GlobalExceptionFilter(EXCEPTION_POINTERS* exceptionPointers) { const char* logPath = "D:\\Xuanchi\\Main\\XCEngine\\editor\\bin\\Release\\crash.log"; FILE* f = fopen(logPath, "a"); if (f) { fprintf(f, "[CRASH] ExceptionCode=0x%08X, Address=0x%p\n", exceptionPointers->ExceptionRecord->ExceptionCode, exceptionPointers->ExceptionRecord->ExceptionAddress); fclose(f); } fprintf(stderr, "[CRASH] ExceptionCode=0x%08X, Address=0x%p\n", exceptionPointers->ExceptionRecord->ExceptionCode, exceptionPointers->ExceptionRecord->ExceptionAddress); return EXCEPTION_EXECUTE_HANDLER; } namespace XCEngine { namespace Editor { Application& Application::Get() { static Application instance; return instance; } 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 { wchar_t exePath[MAX_PATH]; GetModuleFileNameW(nullptr, exePath, MAX_PATH); std::wstring exeDirW(exePath); size_t pos = exeDirW.find_last_of(L"\\/"); if (pos != std::wstring::npos) { exeDirW = exeDirW.substr(0, pos); } std::string exeDir; int len = WideCharToMultiByte(CP_UTF8, 0, exeDirW.c_str(), -1, nullptr, 0, nullptr, nullptr); if (len > 0) { exeDir.resize(len - 1); WideCharToMultiByte(CP_UTF8, 0, exeDirW.c_str(), -1, &exeDir[0], len, nullptr, nullptr); } std::string stderrPath = exeDir + "\\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::Logger::Get().AddSink(std::make_unique()); // Get exe directory for log file path wchar_t exePath[MAX_PATH]; GetModuleFileNameW(nullptr, exePath, MAX_PATH); std::wstring exeDirW(exePath); size_t pos = exeDirW.find_last_of(L"\\/"); if (pos != std::wstring::npos) { exeDirW = exeDirW.substr(0, pos); } std::string exeDir; int len = WideCharToMultiByte(CP_UTF8, 0, exeDirW.c_str(), -1, nullptr, 0, nullptr, nullptr); if (len > 0) { exeDir.resize(len - 1); WideCharToMultiByte(CP_UTF8, 0, exeDirW.c_str(), -1, &exeDir[0], len, nullptr, nullptr); } std::string logPath = exeDir + "\\editor.log"; Debug::Logger::Get().AddSink(std::make_unique(logPath.c_str())); Debug::Logger::Get().Info(Debug::LogCategory::General, "Editor Application starting..."); Debug::Logger::Get().Info(Debug::LogCategory::General, ("Log file: " + logPath).c_str()); m_hwnd = hwnd; if (!CreateDevice()) { 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; } IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/msyh.ttc", 16.0f); io.Fonts->AddFontDefault(); unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); ApplyUnityDarkTheme(); ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX12_Init(m_device, 3, DXGI_FORMAT_R8G8B8A8_UNORM, m_srvHeap, m_srvHeap->GetCPUDescriptorHandleForHeapStart(), m_srvHeap->GetGPUDescriptorHandleForHeapStart()); m_editorContext = std::make_shared(); m_editorContext->SetProjectPath(exeDir); m_editorLayer = new EditorLayer(); m_editorLayer->SetContext(m_editorContext); m_layerStack.pushLayer(std::unique_ptr(m_editorLayer)); m_layerStack.onAttach(); return true; } void Application::Shutdown() { m_layerStack.onDetach(); ImGui_ImplDX12_Shutdown(); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); 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(); } void Application::Render() { ImGui_ImplDX12_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); m_layerStack.onImGuiRender(); 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.12f, 0.12f, 0.12f, 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); ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), 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); } } 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; } } } } }