12.4 KB、294行 生 Blame 履歴
1// Dear ImGui: standalone example application for Windows API + DirectX 9
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_dx9.h"
11#include "imgui_impl_win32.h"
12#include <d3d9.h>
13#include <tchar.h>
14
15// Data
16static LPDIRECT3D9 g_pD3D = nullptr;
17static LPDIRECT3DDEVICE9 g_pd3dDevice = nullptr;
18static bool g_DeviceLost = false;
19static UINT g_ResizeWidth = 0, g_ResizeHeight = 0;
20static D3DPRESENT_PARAMETERS g_d3dpp = {};
21
22// Forward declarations of helper functions
23bool CreateDeviceD3D(HWND hWnd);
24void CleanupDeviceD3D();
25void ResetDevice();
26LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
27
28// Main code
29int main(int, char**)
30{
31 // Make process DPI aware and obtain main monitor scale
32 ImGui_ImplWin32_EnableDpiAwareness();
33 float main_scale = ImGui_ImplWin32_GetDpiScaleForMonitor(::MonitorFromPoint(POINT{ 0, 0 }, MONITOR_DEFAULTTOPRIMARY));
34
35 // Create application window
36 WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr };
37 ::RegisterClassExW(&wc);
38 HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX9 Example", WS_OVERLAPPEDWINDOW, 100, 100, (int)(1280 * main_scale), (int)(800 * main_scale), nullptr, nullptr, wc.hInstance, nullptr);
39
40 // Initialize Direct3D
41 if (!CreateDeviceD3D(hwnd))
42 {
43 CleanupDeviceD3D();
44 ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
45 return 1;
46 }
47
48 // Show the window
49 ::ShowWindow(hwnd, SW_SHOWDEFAULT);
50 ::UpdateWindow(hwnd);
51
52 // Setup Dear ImGui context
53 IMGUI_CHECKVERSION();
54 ImGui::CreateContext();
55 ImGuiIO& io = ImGui::GetIO(); (void)io;
56 io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
57 io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
58 io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
59 io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
60 //io.ConfigViewportsNoAutoMerge = true;
61 //io.ConfigViewportsNoTaskBarIcon = true;
62
63 // Setup Dear ImGui style
64 ImGui::StyleColorsDark();
65 //ImGui::StyleColorsLight();
66
67 // Setup scaling
68 ImGuiStyle& style = ImGui::GetStyle();
69 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)
70 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)
71 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.
72 io.ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
73
74 // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones.
75 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
76 {
77 style.WindowRounding = 0.0f;
78 style.Colors[ImGuiCol_WindowBg].w = 1.0f;
79 }
80
81 // Setup Platform/Renderer backends
82 ImGui_ImplWin32_Init(hwnd);
83 ImGui_ImplDX9_Init(g_pd3dDevice);
84
85 // Load Fonts
86 // - If fonts are not explicitly loaded, Dear ImGui will select an embedded font: either AddFontDefaultVector() or AddFontDefaultBitmap().
87 // This selection is based on (style.FontSizeBase * style.FontScaleMain * style.FontScaleDpi) reaching a small threshold.
88 // - You can load multiple fonts and use ImGui::PushFont()/PopFont() to select them.
89 // - 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).
90 // - Read 'docs/FONTS.md' for more instructions and details.
91 // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use FreeType for higher quality font rendering.
92 // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ !
93 //style.FontSizeBase = 20.0f;
94 //io.Fonts->AddFontDefaultVector();
95 //io.Fonts->AddFontDefaultBitmap();
96 //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf");
97 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf");
98 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf");
99 //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf");
100 //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf");
101 //IM_ASSERT(font != nullptr);
102
103 // Our state
104 bool show_demo_window = true;
105 bool show_another_window = false;
106 ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
107
108 // Main loop
109 bool done = false;
110 while (!done)
111 {
112 // Poll and handle messages (inputs, window resize, etc.)
113 // See the WndProc() function below for our to dispatch events to the Win32 backend.
114 MSG msg;
115 while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE))
116 {
117 ::TranslateMessage(&msg);
118 ::DispatchMessage(&msg);
119 if (msg.message == WM_QUIT)
120 done = true;
121 }
122 if (done)
123 break;
124
125 // Handle lost D3D9 device
126 if (g_DeviceLost)
127 {
128 HRESULT hr = g_pd3dDevice->TestCooperativeLevel();
129 if (hr == D3DERR_DEVICELOST)
130 {
131 ::Sleep(10);
132 continue;
133 }
134 if (hr == D3DERR_DEVICENOTRESET)
135 ResetDevice();
136 g_DeviceLost = false;
137 }
138
139 // Handle window resize (we don't resize directly in the WM_SIZE handler)
140 if (g_ResizeWidth != 0 && g_ResizeHeight != 0)
141 {
142 g_d3dpp.BackBufferWidth = g_ResizeWidth;
143 g_d3dpp.BackBufferHeight = g_ResizeHeight;
144 g_ResizeWidth = g_ResizeHeight = 0;
145 ResetDevice();
146 }
147
148 // Start the Dear ImGui frame
149 ImGui_ImplDX9_NewFrame();
150 ImGui_ImplWin32_NewFrame();
151 ImGui::NewFrame();
152
153 // 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!).
154 if (show_demo_window)
155 ImGui::ShowDemoWindow(&show_demo_window);
156
157 // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
158 {
159 static float f = 0.0f;
160 static int counter = 0;
161
162 ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
163
164 ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
165 ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state
166 ImGui::Checkbox("Another Window", &show_another_window);
167
168 ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f
169 ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color
170
171 if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated)
172 counter++;
173 ImGui::SameLine();
174 ImGui::Text("counter = %d", counter);
175
176 ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
177 ImGui::End();
178 }
179
180 // 3. Show another simple window.
181 if (show_another_window)
182 {
183 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)
184 ImGui::Text("Hello from another window!");
185 if (ImGui::Button("Close Me"))
186 show_another_window = false;
187 ImGui::End();
188 }
189
190 // Rendering
191 ImGui::EndFrame();
192 g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
193 g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
194 g_pd3dDevice->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE);
195 D3DCOLOR clear_col_dx = D3DCOLOR_RGBA((int)(clear_color.x*clear_color.w*255.0f), (int)(clear_color.y*clear_color.w*255.0f), (int)(clear_color.z*clear_color.w*255.0f), (int)(clear_color.w*255.0f));
196 g_pd3dDevice->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, clear_col_dx, 1.0f, 0);
197 if (g_pd3dDevice->BeginScene() >= 0)
198 {
199 ImGui::Render();
200 ImGui_ImplDX9_RenderDrawData(ImGui::GetDrawData());
201 g_pd3dDevice->EndScene();
202 }
203
204 // Update and Render additional Platform Windows
205 if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
206 {
207 ImGui::UpdatePlatformWindows();
208 ImGui::RenderPlatformWindowsDefault();
209 }
210
211 HRESULT result = g_pd3dDevice->Present(nullptr, nullptr, nullptr, nullptr);
212 if (result == D3DERR_DEVICELOST)
213 g_DeviceLost = true;
214 }
215
216 // Cleanup
217 ImGui_ImplDX9_Shutdown();
218 ImGui_ImplWin32_Shutdown();
219 ImGui::DestroyContext();
220
221 CleanupDeviceD3D();
222 ::DestroyWindow(hwnd);
223 ::UnregisterClassW(wc.lpszClassName, wc.hInstance);
224
225 return 0;
226}
227
228// Helper functions
229bool CreateDeviceD3D(HWND hWnd)
230{
231 if ((g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)) == nullptr)
232 return false;
233
234 // Create the D3DDevice
235 ZeroMemory(&g_d3dpp, sizeof(g_d3dpp));
236 g_d3dpp.Windowed = TRUE;
237 g_d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
238 g_d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; // Need to use an explicit format with alpha if needing per-pixel alpha composition.
239 g_d3dpp.EnableAutoDepthStencil = TRUE;
240 g_d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
241 g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE; // Present with vsync
242 //g_d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Present without vsync, maximum unthrottled framerate
243 if (g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &g_d3dpp, &g_pd3dDevice) < 0)
244 return false;
245
246 return true;
247}
248
249void CleanupDeviceD3D()
250{
251 if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = nullptr; }
252 if (g_pD3D) { g_pD3D->Release(); g_pD3D = nullptr; }
253}
254
255void ResetDevice()
256{
257 ImGui_ImplDX9_InvalidateDeviceObjects();
258 HRESULT hr = g_pd3dDevice->Reset(&g_d3dpp);
259 if (hr == D3DERR_INVALIDCALL)
260 IM_ASSERT(0);
261 ImGui_ImplDX9_CreateDeviceObjects();
262}
263
264// Forward declare message handler from imgui_impl_win32.cpp
265extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
266
267// Win32 message handler
268// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
269// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
270// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
271// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
272LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
273{
274 if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
275 return true;
276
277 switch (msg)
278 {
279 case WM_SIZE:
280 if (wParam == SIZE_MINIMIZED)
281 return 0;
282 g_ResizeWidth = (UINT)LOWORD(lParam); // Queue resize
283 g_ResizeHeight = (UINT)HIWORD(lParam);
284 return 0;
285 case WM_SYSCOMMAND:
286 if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu
287 return 0;
288 break;
289 case WM_DESTROY:
290 ::PostQuitMessage(0);
291 return 0;
292 }
293 return ::DefWindowProcW(hWnd, msg, wParam, lParam);
294}