422 lines
18 KiB
C++
422 lines
18 KiB
C++
// IMGUI相关库包含
|
||
#include "imgui.h"
|
||
#include "imgui_impl_win32.h"
|
||
#include "imgui_impl_dx11.h"
|
||
|
||
// ImNodes相关
|
||
#include "imnodes.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布局相关
|
||
#include "Command_Solve.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)
|
||
{
|
||
// 命令行前置处理
|
||
Pre_Command_Solve();
|
||
|
||
// 启用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)(MAIN_FRAME_SIZE_WIDTH_MIN * main_scale), // 窗体长
|
||
(int)(MAIN_FRAME_SIZE_HEIGHT_MIN * main_scale), // 窗体宽
|
||
nullptr, // 父窗体句柄
|
||
nullptr, // 菜单句柄
|
||
wc.hInstance, // 创建实例句柄
|
||
nullptr); // 额外的事件参数指针
|
||
|
||
// 在窗体内创建 Direct 3D 设备
|
||
if (!CreateDeviceD3D(hwnd))
|
||
{
|
||
// 未创建完成时清理 Direct 3D 设备并清理窗体注册类
|
||
CleanupDeviceD3D();
|
||
UnregisterClassW(wc.lpszClassName, wc.hInstance);
|
||
|
||
// 返回错误代码
|
||
return -1;
|
||
}
|
||
|
||
// 启用文件拖拽输入
|
||
DragAcceptFiles(hwnd, TRUE);
|
||
|
||
// 显示窗体并强制更新一次窗体
|
||
ShowWindow(hwnd, SW_SHOWDEFAULT);
|
||
UpdateWindow(hwnd);
|
||
|
||
// 检查版本
|
||
IMGUI_CHECKVERSION();
|
||
|
||
// 建立 Dear ImGui 上下文
|
||
ImGui::CreateContext();
|
||
|
||
// 建立ImNodes 上下文
|
||
ImNodes::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 上下文
|
||
ImNodes::DestroyContext(); // 销毁 ImNodes 上下文
|
||
|
||
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_DROPFILES: // 文件拖拽事件
|
||
{
|
||
HDROP hDrop = (HDROP)wParam; // 拖拽数据句柄
|
||
// 获取拖拽的文件总数
|
||
UINT fileCount = DragQueryFileW(hDrop, 0xFFFFFFFF, NULL, 0);
|
||
|
||
// 添加到文件列表
|
||
for (UINT count = 0; count < fileCount; count++)
|
||
{
|
||
wchar_t filePath[MAX_PATH] = {L'\0'};
|
||
DragQueryFileW(
|
||
hDrop, // 拖拽句柄
|
||
count, // 文件索引(0 表示第一个文件)
|
||
filePath, // 存储路径的缓冲区
|
||
MAX_PATH // 缓冲区大小
|
||
);
|
||
|
||
char file_path_multi_byte[MAX_PATH] = {'\0'};
|
||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, filePath, -1, NULL, 0, NULL, NULL);
|
||
WideCharToMultiByte(CP_UTF8, 0, filePath, -1, file_path_multi_byte, size_needed, NULL, NULL);
|
||
|
||
/**
|
||
* @todo 文件类型筛选
|
||
*/
|
||
|
||
// 重复文件剔除
|
||
bool duplicated = false;
|
||
for (Input_File_Node *p_file_node = input_dlt_file_list_head; p_file_node != nullptr; p_file_node = p_file_node->p_next)
|
||
if (!strcmp(p_file_node->file_name_str, file_path_multi_byte))
|
||
{
|
||
duplicated = true;
|
||
break;
|
||
}
|
||
if (duplicated)
|
||
continue;
|
||
|
||
// 开辟新文件节点
|
||
Input_File_Node *p_new_file_node = (Input_File_Node *)malloc(sizeof(Input_File_Node));
|
||
p_new_file_node->file_name_str = (char *)malloc(strlen(file_path_multi_byte) + 1);
|
||
memset(p_new_file_node->file_name_str, '\0', strlen(file_path_multi_byte) + 1);
|
||
memcpy(p_new_file_node->file_name_str, file_path_multi_byte, strlen(file_path_multi_byte));
|
||
p_new_file_node->p_next = nullptr;
|
||
|
||
// 插入文件列表
|
||
if (input_dlt_file_list_head == nullptr)
|
||
input_dlt_file_list_head = p_new_file_node;
|
||
else
|
||
{
|
||
Input_File_Node *p_target_node = input_dlt_file_list_head;
|
||
for (size_t count = 1; count < input_dlt_file_count; count++)
|
||
p_target_node = p_target_node->p_next;
|
||
|
||
p_target_node->p_next = p_new_file_node;
|
||
}
|
||
|
||
input_dlt_file_count++;
|
||
}
|
||
|
||
// 释放拖拽资源(必须调用,否则内存泄漏)
|
||
DragFinish(hDrop);
|
||
return 0;
|
||
}
|
||
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);
|
||
}
|