From 4bc51c6ff4da5b84f26402761a9ad98d8e3a5a75 Mon Sep 17 00:00:00 2001 From: Mark Jansen Date: Wed, 19 Apr 2023 16:46:22 +0200 Subject: [PATCH] Examples: Extend Win32/Winapi + OpenGL example for multi-viewport. (#3218, #5170 and #6086, #2772, #2600, #2359, #2022, #1553) --- backends/imgui_impl_win32.cpp | 9 ++- examples/example_win32_opengl3/main.cpp | 77 +++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 0229e014f..ed9f92bec 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -87,7 +87,7 @@ typedef DWORD (WINAPI *PFN_XInputGetState)(DWORD, XINPUT_STATE*); // 2016-11-12: Inputs: Only call Win32 ::SetCursor(nullptr) when io.MouseDrawCursor is set. // Forward Declarations -static void ImGui_ImplWin32_InitPlatformInterface(); +static void ImGui_ImplWin32_InitPlatformInterface(bool platformHasOwnDC); static void ImGui_ImplWin32_ShutdownPlatformInterface(); static void ImGui_ImplWin32_UpdateMonitors(); @@ -153,8 +153,7 @@ static bool ImGui_ImplWin32_InitEx(void* hwnd, bool platform_has_own_dc) ImGuiViewport* main_viewport = ImGui::GetMainViewport(); main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (void*)bd->hWnd; if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - ImGui_ImplWin32_InitPlatformInterface(); - IM_UNUSED(platform_has_own_dc); // Used in 'docking' branch + ImGui_ImplWin32_InitPlatformInterface(platform_has_own_dc); // Dynamically load XInput library #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD @@ -1166,11 +1165,11 @@ static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow(HWND hWnd, return DefWindowProc(hWnd, msg, wParam, lParam); } -static void ImGui_ImplWin32_InitPlatformInterface() +static void ImGui_ImplWin32_InitPlatformInterface(bool platformHasOwnDC) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.style = CS_HREDRAW | CS_VREDRAW | (platformHasOwnDC ? CS_OWNDC : 0); wcex.lpfnWndProc = ImGui_ImplWin32_WndProcHandler_PlatformWindow; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; diff --git a/examples/example_win32_opengl3/main.cpp b/examples/example_win32_opengl3/main.cpp index 7b89a0a12..33b021e52 100644 --- a/examples/example_win32_opengl3/main.cpp +++ b/examples/example_win32_opengl3/main.cpp @@ -29,6 +29,48 @@ void CleanupDeviceWGL(HWND hWnd, WGL_WindowData* data); void ResetDeviceWGL(); LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); + +static void Win32_CreateWindow(ImGuiViewport* viewport) +{ + assert(viewport->RendererUserData == NULL); + + WGL_WindowData* data = IM_NEW(WGL_WindowData); + CreateDeviceWGL((HWND)viewport->PlatformHandle, data); + viewport->RendererUserData = data; +} + +static void Win32_DestroyWindow(ImGuiViewport* viewport) +{ + if (viewport->RendererUserData != NULL) + { + WGL_WindowData* data = (WGL_WindowData*)viewport->RendererUserData; + CleanupDeviceWGL((HWND)viewport->PlatformHandle, data); + IM_DELETE(data); + viewport->RendererUserData = NULL; + } +} + +static void Win32_RenderWindow(ImGuiViewport* viewport, void*) +{ + WGL_WindowData* data = (WGL_WindowData*)viewport->RendererUserData; + + if (data) + { + // Activate the platform window DC in the OpenGL rendering context + wglMakeCurrent(data->hDC, g_hRC); + } +} + +static void Win32_SwapBuffers(ImGuiViewport* viewport, void*) +{ + WGL_WindowData* data = (WGL_WindowData*)viewport->RendererUserData; + + if (data) + { + SwapBuffers(data->hDC); + } +} + // Main code int main(int, char**) { @@ -58,15 +100,41 @@ int main(int, char**) ImGuiIO& io = ImGui::GetIO(); (void)io; 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 // Setup Dear ImGui style ImGui::StyleColorsDark(); //ImGui::StyleColorsClassic(); + // When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. + ImGuiStyle& style = ImGui::GetStyle(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + style.WindowRounding = 0.0f; + style.Colors[ImGuiCol_WindowBg].w = 1.0f; + } + // Setup Platform/Renderer backends ImGui_ImplWin32_InitForOpenGL(hwnd); ImGui_ImplOpenGL3_Init(); + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + + // Store the hdc for this new window + assert(platform_io.Renderer_CreateWindow == NULL); + platform_io.Renderer_CreateWindow = Win32_CreateWindow; + assert(platform_io.Renderer_DestroyWindow == NULL); + platform_io.Renderer_DestroyWindow = Win32_DestroyWindow; + assert(platform_io.Renderer_SwapBuffers == NULL); + platform_io.Renderer_SwapBuffers = Win32_SwapBuffers; + + // We need to activate the context before drawing + assert(platform_io.Platform_RenderWindow == NULL); + platform_io.Platform_RenderWindow = Win32_RenderWindow; + } // 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. @@ -154,6 +222,15 @@ int main(int, char**) glClear(GL_COLOR_BUFFER_BIT); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); + // Update and Render additional Platform Windows + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); + // Restore the OpenGL rendering context to the main window DC, since platform windows might have changed it. + wglMakeCurrent(g_MainWindow.hDC, g_hRC); + } + // Present ::SwapBuffers(g_MainWindow.hDC); }