// IMGUI相关库包含 #include "imgui.h" #include "imgui_impl_win32.h" #include "imgui_impl_dx11.h" extern "C" { // Mingw 相关库 #include "d3d11.h" #include "tchar.h" #include "wchar.h" } // 自定义头文件 #include "Config.hpp" // 配置文件 #include "Global_Variables.hpp" // 全局变量相关 #include "UI_Layout.hpp" // UI布局相关 // 辅助函数声明 bool CreateDeviceD3D(HWND hWnd); // 创建 Direct 3D 设备 void CleanupDeviceD3D(); // 清理 Direct3D 设备 void CreateRenderTarget(); // 创建渲染目标 void CleanupRenderTarget(); // 清理渲染目标 // Windows窗体事件处理函数声明 LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // 重定义窗体消息处理函数 >> imgui_impl_win32.cpp extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // 入口主函数 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { // 启用DPI响应并获取主显示器分辨率 ImGui_ImplWin32_EnableDpiAwareness(); float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(MonitorFromPoint(POINT{0, 0}, MONITOR_DEFAULTTOPRIMARY)); // 窗体类结构体 WNDCLASSEXW wc; // Windows 扩展窗体类 wc.cbSize = sizeof(wc); // 类结构大小 wc.style = CS_CLASSDC; // 绘制样式使用类设备上下文 Class Device Context wc.lpfnWndProc = WndProc; // 窗体事件处理回调函数 wc.cbClsExtra = 0L; // 为窗口类额外分配的字节数,通常为 0 wc.cbWndExtra = 0L; // 为窗口实例额外分配的字节数,通常为 0 wc.hInstance = hInstance; // 应用程序实例的句柄。 wc.hIcon = LoadIconW(hInstance, IDI_APPLICATION); // 应用图标样式 wc.hCursor = LoadCursorW(hInstance, IDC_ARROW); // 应用光标样式 wc.hbrBackground = (HBRUSH)COLOR_WINDOWFRAME; // 窗体背景颜色刷 wc.lpszMenuName = nullptr; // 窗体菜单名称 wc.lpszClassName = L"DLT_Splitter_Base_Window_Class"; // 窗体注册类名 wc.hIconSm = LoadIconW(hInstance, IDI_APPLICATION); // 应用小图标样式 // 注册窗体类 RegisterClassExW(&wc); // 创建窗体 HWND hwnd = CreateWindowW(wc.lpszClassName, // 创建的窗体类名 MAIN_FRAME_TITTLE, // 窗体标题 WS_OVERLAPPEDWINDOW, // 窗体风格为标准可重叠的顶层窗口 100, // 起始坐标x 100, // 起始坐标y (int)(1280 * main_scale), // 窗体长 (int)(720 * main_scale), // 窗体宽 nullptr, // 父窗体句柄 nullptr, // 菜单句柄 wc.hInstance, // 创建实例句柄 nullptr); // 额外的事件参数指针 // 在窗体内创建 Direct 3D 设备 if (!CreateDeviceD3D(hwnd)) { // 未创建完成时清理 Direct 3D 设备并清理窗体注册类 CleanupDeviceD3D(); UnregisterClassW(wc.lpszClassName, wc.hInstance); // 返回错误代码 return -1; } // 显示窗体并强制更新一次窗体 ShowWindow(hwnd, SW_SHOWDEFAULT); UpdateWindow(hwnd); // 检查版本 IMGUI_CHECKVERSION(); // 建立 Dear ImGui 上下文 ImGui::CreateContext(); // 获取ImGui IO 设备配置结构体 ImGuiIO &io = ImGui::GetIO(); io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows // io.ConfigViewportsNoAutoMerge = true; // io.ConfigViewportsNoTaskBarIcon = true; // io.ConfigDockingAlwaysTabBar = true; // io.ConfigDockingTransparentPayload = true; io.IniFilename = nullptr; // 不生成ini布局配置文件 // 主题为亮/暗 ImGui::StyleColorsLight(); // ImGui::StyleColorsDark(); // Setup scaling // 获取风格渲染配置并整缩放比例 ImGuiStyle &style = ImGui::GetStyle(); style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) io.ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now. io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes. // 调整视窗移动出主窗体范围外时的风格以匹配原生风格 // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { style.WindowRounding = 0.0f; style.Colors[ImGuiCol_WindowBg].w = 1.0f; } // 初始化渲染器后端(Renderer backends) ImGui_ImplWin32_Init(hwnd); ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); // 字体配置相关 { // Load Fonts // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. // - Read 'docs/FONTS.md' for more instructions and details. If you like the default font but want it to scale better, consider using the 'ProggyVector' from the same author! // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! // style.FontSizeBase = 20.0f; // io.Fonts->AddFontDefault(); // io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); // io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); // io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); // io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); // ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); // IM_ASSERT(font != nullptr); // 加载字体为微软雅黑 io.Fonts->AddFontFromFileTTF("c:/windows/Fonts/msyh.ttc", 15.0f * main_scale, NULL, io.Fonts->GetGlyphRangesChineseFull()); } // 主事件循环 bool done = false; while (!done) { // 非阻塞式获取所有窗体消息,Pick消息后从消息队列删除,并转译和派发消息 MSG msg; while (PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) { TranslateMessage(&msg); // 转译 DispatchMessageW(&msg); // 派发 // 窗体关闭事件 if (msg.message == WM_QUIT) done = true; } if (done) break; // 处理窗体最小化或屏幕被锁定 if (g_SwapChainOccluded && g_pSwapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED) { // 休眠10ms并跳过渲染 continue; } g_SwapChainOccluded = false; // 开始创建当前绘制帧(创建顺序:DirectX -> Win32 -> ImGui) ImGui_ImplDX11_NewFrame(); ImGui_ImplWin32_NewFrame(); ImGui::NewFrame(); // 此处进行UI布局 UI_Layout(); // 渲染部分 { // 调用 ImGui 渲染器进行预渲染 ImGui::Render(); // 设置D3D渲染目标 g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr); // 创建一个带透明度通道的RGB色 ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); const float clear_color_with_alpha[4] = {clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w}; // 使用创建的RGB色擦除D3D渲染画布 g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); // 渲染 ImGui 原始画面 ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); // 启用脱离窗口渲染时更新主窗体外的部分 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); } // 呈现当前帧到画布 // HRESULT hr = g_pSwapChain->Present(0, 0); // 非垂直同步 HRESULT hr = g_pSwapChain->Present(1, 0); // 垂直同步 // HRESULT hr = g_pSwapChain->Present(2, 0); // 等待双倍的垂直同步时间 // 更新交换链阻塞状态 g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED); } } // 收尾清理工作 ImGui_ImplDX11_Shutdown(); // 关闭 ImGui DX11 组件 ImGui_ImplWin32_Shutdown(); // 关闭 ImGui Win32 组件 ImGui::DestroyContext(); // 销毁 ImGui 上下文 CleanupDeviceD3D(); // 清理 Direct 3D 设备 DestroyWindow(hwnd); // 销毁窗体 UnregisterClassW(wc.lpszClassName, wc.hInstance); // 取消窗体注册类 return 0; } // 创建 Direct 3D 设备 bool CreateDeviceD3D(HWND hWnd) { // 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, }; HRESULT res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); if (res == DXGI_ERROR_UNSUPPORTED) // Try high-performance WARP software driver if hardware is not available. res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); if (res != S_OK) return false; // Disable DXGI's default Alt+Enter fullscreen behavior. // - You are free to leave this enabled, but it will not work properly with multiple viewports. // - This must be done for all windows associated to the device. Our DX11 backend does this automatically for secondary viewports that it creates. IDXGIFactory *pSwapChainFactory; if (SUCCEEDED(g_pSwapChain->GetParent(IID_PPV_ARGS(&pSwapChainFactory)))) pSwapChainFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER); CreateRenderTarget(); return true; } // 清理 Direct3D 设备 void CleanupDeviceD3D() { CleanupRenderTarget(); if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = nullptr; } if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = nullptr; } if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = nullptr; } } // 创建渲染目标 void CreateRenderTarget() { ID3D11Texture2D *pBackBuffer; g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_mainRenderTargetView); pBackBuffer->Release(); } // 清理渲染目标 void CleanupRenderTarget() { if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = nullptr; } } // Windows窗体事件处理函数 LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { // 优先让ImGui处理消息 if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) return true; // 筛查并处理余下的消息事件 switch (msg) { case WM_SIZE: // 窗体大小变事件 if (wParam != SIZE_MINIMIZED) // 窗体未处于最小化时进行重绘 { // 清理渲染器并重新创建对应窗体大小的渲染器目标 低字为宽,高字为长 CleanupRenderTarget(); g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0); CreateRenderTarget(); } return 0; case WM_SYSCOMMAND: // 系统指令事件 if ((wParam & 0xfff0) == SC_KEYMENU) // 禁用ALT键菜单响应,交给IMGUI实现 Disable ALT return 0; break; case WM_DESTROY: // 窗体销毁事件 PostQuitMessage(0); // 派发应用退出(Quit)消息 return 0; } // 剩余的消息交给默认的消息处理函数 return DefWindowProcW(hWnd, msg, wParam, lParam); }