Files
XCEngine/editor/src/Application.cpp

303 lines
11 KiB
C++
Raw Normal View History

#include "Application.h"
#include <imgui_impl_win32.h>
#include <imgui_impl_dx12.h>
#include <imgui_internal.h>
#include <stdio.h>
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
namespace UI {
Application& Application::Get() {
static Application instance;
return instance;
}
bool Application::Initialize(HWND hwnd) {
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_menuBar = std::make_unique<MenuBar>();
m_hierarchyPanel = std::make_unique<HierarchyPanel>();
m_sceneViewPanel = std::make_unique<SceneViewPanel>();
m_gameViewPanel = std::make_unique<GameViewPanel>();
m_inspectorPanel = std::make_unique<InspectorPanel>();
m_consolePanel = std::make_unique<ConsolePanel>();
m_projectPanel = std::make_unique<ProjectPanel>();
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);
}
m_projectPanel->Initialize(exeDir);
return true;
}
void Application::Shutdown() {
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();
SetupDockspace();
RenderUI();
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;
}
}
}
void Application::SetupDockspace() {
static ImGuiDockNodeFlags dockspaceFlags = ImGuiDockNodeFlags_NoWindowMenuButton;
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->Pos);
ImGui::SetNextWindowSize(viewport->Size);
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
windowFlags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
windowFlags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::Begin("MainDockspace", nullptr, windowFlags);
ImGui::PopStyleVar();
ImGui::PopStyleVar(2);
ImGuiID dockspaceId = ImGui::GetID("MyDockspace");
ImGui::DockSpace(dockspaceId, ImVec2(0.0f, 0.0f), dockspaceFlags);
static bool firstTime = true;
if (firstTime) {
firstTime = false;
ImGui::DockBuilderRemoveNode(dockspaceId);
ImGui::DockBuilderAddNode(dockspaceId, dockspaceFlags | ImGuiDockNodeFlags_DockSpace);
ImGui::DockBuilderSetNodeSize(dockspaceId, viewport->Size);
ImGuiID dockMain = dockspaceId;
ImGuiID dockBottom = ImGui::DockBuilderSplitNode(dockMain, ImGuiDir_Down, 0.25f, nullptr, &dockMain);
ImGuiID dockLeft = ImGui::DockBuilderSplitNode(dockMain, ImGuiDir_Left, 0.15f, nullptr, &dockMain);
ImGuiID dockRight = ImGui::DockBuilderSplitNode(dockMain, ImGuiDir_Right, 0.25f, nullptr, &dockMain);
ImGui::DockBuilderDockWindow("Hierarchy", dockLeft);
ImGui::DockBuilderDockWindow("Scene", dockMain);
ImGui::DockBuilderDockWindow("Game", dockMain);
ImGui::DockBuilderDockWindow("Inspector", dockRight);
ImGui::DockBuilderDockWindow("Console", dockBottom);
ImGui::DockBuilderDockWindow("Project", dockBottom);
ImGui::DockBuilderFinish(dockspaceId);
}
ImGui::End();
}
void Application::RenderUI() {
m_menuBar->Render();
m_hierarchyPanel->Render();
m_sceneViewPanel->Render();
m_gameViewPanel->Render();
m_inspectorPanel->Render();
m_consolePanel->Render();
m_projectPanel->Render();
}
}