#include "Backend.hpp" #if BUILD_CORE_WITH_DX11_BACKEND # include # include # include # include # include # include // Forward declare message handler from imgui_impl_win32.cpp extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); class DirectX11Backend : public RenderingBackend { private: HWND hWnd; WNDCLASSEX wc; ID3D11Device* mD3dDevice = nullptr; ID3D11DeviceContext* mD3dDeviceContext = nullptr; IDXGISwapChain* mSwapChain = nullptr; ID3D11RenderTargetView* mMainRenderTargetView = nullptr; public: DirectX11Backend() { ImGui_ImplWin32_EnableDpiAwareness(); wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_CLASSDC; wc.lpfnWndProc = &StaticWndProc; wc.cbClsExtra = 0L; wc.cbWndExtra = 0L; wc.hInstance = GetModuleHandle(nullptr); wc.hIcon = nullptr; wc.hCursor = nullptr; wc.hbrBackground = nullptr; wc.lpszMenuName = nullptr; wc.lpszClassName = _T("Cplt"); wc.hIconSm = nullptr; ::RegisterClassEx(&wc); hWnd = ::CreateWindow( wc.lpszClassName, _T("Cplt main window"), WS_OVERLAPPEDWINDOW, /* x */ 100, /* y */ 100, /* window width */ 1280, /* window height */ 800, nullptr, nullptr, wc.hInstance, this); if (!CreateDeviceD3D()) { CleanupDeviceD3D(); ::UnregisterClass(wc.lpszClassName, wc.hInstance); throw std::runtime_error("Failed to create d3d device."); } ::ShowWindow(hWnd, SW_SHOWDEFAULT); ::UpdateWindow(hWnd); IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGui_ImplWin32_Init(hWnd); ImGui_ImplDX11_Init(mD3dDevice, mD3dDeviceContext); } virtual ~DirectX11Backend() { ImGui_ImplDX11_Shutdown(); ImGui_ImplWin32_Shutdown(); ImGui::DestroyContext(); CleanupDeviceD3D(); ::DestroyWindow(hWnd); ::UnregisterClass(wc.lpszClassName, wc.hInstance); } virtual void RunUntilWindowClose(void (*windowContent)()) { while (true) { MSG msg; bool done = false; while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) { ::TranslateMessage(&msg); ::DispatchMessage(&msg); if (msg.message == WM_QUIT) { done = true; } } if (done) break; ImGui_ImplDX11_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); windowContent(); ImGui::Render(); const ImVec4 kClearColor = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); const float kClearColorWithAlpha[4] = { kClearColor.x * kClearColor.w, kClearColor.y * kClearColor.w, kClearColor.z * kClearColor.w, kClearColor.w }; mD3dDeviceContext->OMSetRenderTargets(1, &mMainRenderTargetView, nullptr); mD3dDeviceContext->ClearRenderTargetView(mMainRenderTargetView, kClearColorWithAlpha); ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); mSwapChain->Present(1, 0); // Present with vsync } } private: bool CreateDeviceD3D() { // Setup swap chain DXGI_SWAP_CHAIN_DESC sd; ZeroMemory(&sd, sizeof(sd)); sd.BufferCount = 2; sd.BufferDesc.Width = 0; sd.BufferDesc.Height = 0; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Denominator = 1; sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.OutputWindow = hWnd; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = 0; sd.Windowed = TRUE; sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; UINT createDeviceFlags = 0; //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; D3D_FEATURE_LEVEL featureLevel; const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, }; if (D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &mSwapChain, &mD3dDevice, &featureLevel, &mD3dDeviceContext) != S_OK) { return false; } CreateRenderTarget(); return true; } void CleanupDeviceD3D() { CleanupRenderTarget(); if (mSwapChain) { mSwapChain->Release(); mSwapChain = nullptr; } if (mD3dDeviceContext) { mD3dDeviceContext->Release(); mD3dDeviceContext = nullptr; } if (mD3dDevice) { mD3dDevice->Release(); mD3dDevice = nullptr; } } void CreateRenderTarget() { ID3D11Texture2D* pBackBuffer; mSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); mD3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &mMainRenderTargetView); pBackBuffer->Release(); } void CleanupRenderTarget() { if (mMainRenderTargetView) { mMainRenderTargetView->Release(); mMainRenderTargetView = nullptr; } } static LRESULT CALLBACK StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { DirectX11Backend* self; if (uMsg == WM_NCCREATE) { auto lpcs = reinterpret_cast(lParam); self = static_cast(lpcs->lpCreateParams); self->hWnd = hWnd; SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(self)); } else { self = reinterpret_cast(GetWindowLongPtr(hWnd, GWLP_USERDATA)); } if (self) { return self->WndProc(uMsg, wParam, lParam); } else { return DefWindowProc(hWnd, uMsg, wParam, lParam); } } LRESULT WndProc(UINT msg, WPARAM wParam, LPARAM lParam) { if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) { return true; } switch (msg) { case WM_SIZE: { if (mD3dDevice != nullptr && wParam != SIZE_MINIMIZED) { CleanupRenderTarget(); mSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0); CreateRenderTarget(); } return 0; } case WM_SYSCOMMAND: { // Disable ALT application menu if ((wParam & 0xfff0) == SC_KEYMENU) { return 0; } } break; case WM_DESTROY: { ::PostQuitMessage(0); return 0; } } return ::DefWindowProc(hWnd, msg, wParam, lParam); } }; std::unique_ptr RenderingBackend::CreateDx11Backend() { try { return std::make_unique(); } catch (std::exception& e) { return nullptr; } } #else // ^^ BUILD_CORE_WITH_DX11_BACKEND | BUILD_CORE_WITH_DX11_BACKEND vv std::unique_ptr RenderingBackend::CreateDx11Backend() { return nullptr; } #endif