13.4 KB、311行 生 Blame 履歴
1// Dear ImGui: standalone example application for Windows API + DirectX 10
2
3// Learn about Dear ImGui:
4// - FAQ https://dearimgui.com/faq
5// - Getting Started https://dearimgui.com/getting-started
6// - Documentation https://dearimgui.com/docs (same as your local docs/ folder).
7// - Introduction, links and more at the top of imgui.cpp
8
9#include "imgui.h"
10#include "imgui_impl_win32.h"
11#include "imgui_impl_dx10.h"
12#include <d3d10_1.h>
13#include <d3d10.h>
14#include <tchar.h>
15
16// Data
17static ID3D10Device* g_pd3dDevice = nullptr;
18static IDXGISwapChain* g_pSwapChain = nullptr;
19static bool g_SwapChainOccluded = false;
20static UINT g_ResizeWidth = 0, g_ResizeHeight = 0;
21static ID3D10RenderTargetView* g_mainRenderTargetView = nullptr;
22
23// Forward declarations of helper functions
24bool CreateDeviceD3D(HWND hWnd);
25void CleanupDeviceD3D();
26void CreateRenderTarget();
27void CleanupRenderTarget();
28LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
29
30// Main code
31int main(int, char**)
32{
33 // Make process DPI aware and obtain main monitor scale
34 ImGui_ImplWin32_EnableDpiAwareness();
35 float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
36
37 // Create application window
38 WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr };
39 ::RegisterClassExW(&wc);
40 HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX10 Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr);
41
42 // Initialize Direct3D
43 if (!CreateDeviceD3D(hwnd))
44 {
45 CleanupDeviceD3D();
46 ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
47 return 1;
48 }
49
50 // Show the window
51 ::ShowWindow(hwnd, SW_SHOWDEFAULT);
52 ::UpdateWindow(hwnd);
53
54 // Setup Dear ImGui context
55 IMGUI_CHECKVERSION();
56 ImGui::CreateContext();
57 ImGuiIO& io = ImGui::GetIO(); (void)io;
58 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
59 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
60 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
61 io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
62 //io.ConfigViewportsNoAutoMerge = true;
63 //io.ConfigViewportsNoTaskBarIcon = true;
64
65 // Setup Dear ImGui style
66 ImGui::StyleColorsDark();
67 //ImGui::StyleColorsLight();
68
69 // Setup scaling
70 ImGuiStyle& style = ImGui::GetStyle();
71 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)
72 style.FontScaleDpi = main_scale; // Set initial font scale. (in docking branch: using io.ConfigDpiScaleFonts=true automatically overrides this for every window depending on the current monitor)
73 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.
74 io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
75
76 // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
77 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
78 {
79 style.WindowRounding = 0.0f;
80 style.Colors[ImGuiCol_WindowBg].w = 1.0f;
81 }
82
83 // Setup Platform/Renderer backends
84 ImGui_ImplWin32_Init(hwnd);
85 ImGui_ImplDX10_Init(g_pd3dDevice);
86
87 // Load Fonts
88 // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap().
89 // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold.
90 // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
91 // - If a file cannot be loaded, AddFont functions will return a nullptr. Please handle those errors in your code (e.g. use an assertion, display an error and quit).
92 // - Read 'docs/FONTS.md' for more instructions and details.
93 // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering.
94 // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
95 //style.FontSizeBase = 20.0f;
96 //io.Fonts->AddFontDefaultVector();
97 //io.Fonts->AddFontDefaultBitmap();
98 //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf");
99 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf");
100 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf");
101 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf");
102 //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf");
103 //IM_ASSERT(font != nullptr);
104
105 // Our state
106 bool show_demo_window = true;
107 bool show_another_window = false;
108 ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
109
110 // Main loop
111 bool done = false;
112 while (!done)
113 {
114 // Poll and handle messages (inputs, window resize, etc.)
115 // See the WndProc() function below for our to dispatch events to the Win32 backend.
116 MSG msg;
117 while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE))
118 {
119 ::TranslateMessage(&msg);
120 ::DispatchMessage(&msg);
121 if (msg.message == WM_QUIT)
122 done = true;
123 }
124 if (done)
125 break;
126
127 // Handle window being minimized or screen locked
128 if (g_SwapChainOccluded && g_pSwapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED)
129 {
130 ::Sleep(10);
131 continue;
132 }
133 g_SwapChainOccluded = false;
134
135 // Handle window resize (we don't resize directly in the WM_SIZE handler)
136 if (g_ResizeWidth != 0 && g_ResizeHeight != 0)
137 {
138 CleanupRenderTarget();
139 g_pSwapChain->ResizeBuffers(0, g_ResizeWidth, g_ResizeHeight, DXGI_FORMAT_UNKNOWN, 0);
140 g_ResizeWidth = g_ResizeHeight = 0;
141 CreateRenderTarget();
142 }
143
144 // Start the Dear ImGui frame
145 ImGui_ImplDX10_NewFrame();
146 ImGui_ImplWin32_NewFrame();
147 ImGui::NewFrame();
148
149 // 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!).
150 if (show_demo_window)
151 ImGui::ShowDemoWindow(&show_demo_window);
152
153 // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
154 {
155 static float f = 0.0f;
156 static int counter = 0;
157
158 ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
159
160 ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
161 ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
162 ImGui::Checkbox("Another Window", &show_another_window);
163
164 ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
165 ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
166
167 if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
168 counter++;
169 ImGui::SameLine();
170 ImGui::Text("counter = %d", counter);
171
172 ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
173 ImGui::End();
174 }
175
176 // 3. Show another simple window.
177 if (show_another_window)
178 {
179 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)
180 ImGui::Text("Hello from another window!");
181 if (ImGui::Button("Close Me"))
182 show_another_window = false;
183 ImGui::End();
184 }
185
186 // Rendering
187 ImGui::Render();
188 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 };
189 g_pd3dDevice->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr);
190 g_pd3dDevice->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha);
191 ImGui_ImplDX10_RenderDrawData(ImGui::GetDrawData());
192
193 // Update and Render additional Platform Windows
194 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
195 {
196 ImGui::UpdatePlatformWindows();
197 ImGui::RenderPlatformWindowsDefault();
198 }
199
200 // Present
201 HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync
202 //HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync
203 g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED);
204 }
205
206 // Cleanup
207 ImGui_ImplDX10_Shutdown();
208 ImGui_ImplWin32_Shutdown();
209 ImGui::DestroyContext();
210
211 CleanupDeviceD3D();
212 ::DestroyWindow(hwnd);
213 ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
214
215 return 0;
216}
217
218// Helper functions
219bool CreateDeviceD3D(HWND hWnd)
220{
221 // Setup swap chain
222 // This is a basic setup. Optimally could use handle fullscreen mode differently. See #8979 for suggestions.
223 DXGI_SWAP_CHAIN_DESC sd;
224 ZeroMemory(&sd, sizeof(sd));
225 sd.BufferCount = 2;
226 sd.BufferDesc.Width = 0;
227 sd.BufferDesc.Height = 0;
228 sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
229 sd.BufferDesc.RefreshRate.Numerator = 60;
230 sd.BufferDesc.RefreshRate.Denominator = 1;
231 sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
232 sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
233 sd.OutputWindow = hWnd;
234 sd.SampleDesc.Count = 1;
235 sd.SampleDesc.Quality = 0;
236 sd.Windowed = TRUE;
237 sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
238
239 UINT createDeviceFlags = 0;
240 //createDeviceFlags |= D3D10_CREATE_DEVICE_DEBUG;
241 HRESULT res = D3D10CreateDeviceAndSwapChain(nullptr, D3D10_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice);
242 if (res == DXGI_ERROR_UNSUPPORTED) // Try high-performance WARP software driver if hardware is not available.
243 res = D3D10CreateDeviceAndSwapChain(nullptr, D3D10_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, D3D10_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice);
244 if (res != S_OK)
245 return false;
246
247 // Disable DXGI's default Alt+Enter fullscreen behavior.
248 // - You are free to leave this enabled, but it will not work properly with multiple viewports.
249 // - This must be done for all windows associated to the device. Our DX11 backend does this automatically for secondary viewports that it creates.
250 IDXGIFactory* pSwapChainFactory;
251 if (SUCCEEDED(g_pSwapChain->GetParent(IID_PPV_ARGS(&pSwapChainFactory))))
252 {
253 pSwapChainFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER);
254 pSwapChainFactory->Release();
255 }
256
257 CreateRenderTarget();
258 return true;
259}
260
261void CleanupDeviceD3D()
262{
263 CleanupRenderTarget();
264 if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = nullptr; }
265 if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = nullptr; }
266}
267
268void CreateRenderTarget()
269{
270 ID3D10Texture2D* pBackBuffer;
271 g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
272 g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_mainRenderTargetView);
273 pBackBuffer->Release();
274}
275
276void CleanupRenderTarget()
277{
278 if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = nullptr; }
279}
280
281// Forward declare message handler from imgui_impl_win32.cpp
282extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
283
284// Win32 message handler
285// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
286// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
287// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
288// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
289LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
290{
291 if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
292 return true;
293
294 switch (msg)
295 {
296 case WM_SIZE:
297 if (wParam == SIZE_MINIMIZED)
298 return 0;
299 g_ResizeWidth = (UINT)LOWORD(lParam); // Queue resize
300 g_ResizeHeight = (UINT)HIWORD(lParam);
301 return 0;
302 case WM_SYSCOMMAND:
303 if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu
304 return 0;
305 break;
306 case WM_DESTROY:
307 ::PostQuitMessage(0);
308 return 0;
309 }
310 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
311}