DLT_Splitter/Src/Main.cpp
2025-11-10 18:54:24 +08:00

363 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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 "Global_Variables.hpp"
}
// 辅助函数声明
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, // 创建的窗体类名
L"DLT Splitter —— Dev by: LuChiChick", // 窗体标题
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);
}
// Our state
bool show_demo_window = true;
bool show_another_window = false;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
// 主事件循环
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();
// 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
if (show_demo_window)
ImGui::ShowDemoWindow(&show_demo_window);
// 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
{
static float f = 0.0f;
static int counter = 0;
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
ImGui::Checkbox("Another Window", &show_another_window);
ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
ImGui::ColorEdit3("clear color", (float *)&clear_color); // Edit 3 floats representing a color
if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
counter++;
ImGui::SameLine();
ImGui::Text("counter = %d", counter);
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
ImGui::End();
}
// 3. Show another simple window.
if (show_another_window)
{
ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
ImGui::Text("Hello from another window!");
if (ImGui::Button("Close Me"))
show_another_window = false;
ImGui::End();
}
// Rendering
ImGui::Render();
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};
g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr);
g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha);
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
// Update and Render additional Platform Windows
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
// Present
HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync
// HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync
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);
}