Addendum to #2635. Add support for multi-viewports in SDL+DX!! example. making all Win32-centric back-ends handle PlatformHandleRaw. Using the field to use/store the HWND for internal purpose in SDL/GLFW back-ends. (#1542)

This commit is contained in:
omar 2019-06-18 23:35:48 +02:00
parent 3e8eebfbec
commit adbbd17cb6
11 changed files with 79 additions and 53 deletions

View File

@ -51,13 +51,25 @@ int main(int, char**)
IMGUI_CHECKVERSION(); IMGUI_CHECKVERSION();
ImGui::CreateContext(); ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io; ImGuiIO& io = ImGui::GetIO(); (void)io;
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad 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;
// Setup Dear ImGui style // Setup Dear ImGui style
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
//ImGui::StyleColorsClassic(); //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 bindings // Setup Platform/Renderer bindings
ImGui_ImplSDL2_InitForD3D(window); ImGui_ImplSDL2_InitForD3D(window);
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
@ -149,6 +161,13 @@ int main(int, char**)
g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, (float*)&clear_color); g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, (float*)&clear_color);
ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());
// Update and Render additional Platform Windows
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
ImGui::UpdatePlatformWindows();
ImGui::RenderPlatformWindowsDefault();
}
g_pSwapChain->Present(1, 0); // Present with vsync g_pSwapChain->Present(1, 0); // Present with vsync
//g_pSwapChain->Present(0, 0); // Present without vsync //g_pSwapChain->Present(0, 0); // Present without vsync
} }

View File

@ -553,7 +553,9 @@ static void ImGui_ImplDX10_CreateWindow(ImGuiViewport* viewport)
ImGuiViewportDataDx10* data = IM_NEW(ImGuiViewportDataDx10)(); ImGuiViewportDataDx10* data = IM_NEW(ImGuiViewportDataDx10)();
viewport->RendererUserData = data; viewport->RendererUserData = data;
HWND hwnd = (HWND)viewport->PlatformHandle; // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
// Some back-ends will leave PlatformHandleRaw NULL, in which case we assume PlatformHandle will contain the HWND.
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
IM_ASSERT(hwnd != 0); IM_ASSERT(hwnd != 0);
// Create swap chain // Create swap chain

View File

@ -564,13 +564,9 @@ static void ImGui_ImplDX11_CreateWindow(ImGuiViewport* viewport)
ImGuiViewportDataDx11* data = IM_NEW(ImGuiViewportDataDx11)(); ImGuiViewportDataDx11* data = IM_NEW(ImGuiViewportDataDx11)();
viewport->RendererUserData = data; viewport->RendererUserData = data;
// When using SDL, PlatformHandleRaw will be the HWND (because PlatformHandle would be the SDL_Window) // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
// If not using SDL, PlatformHandleRaw will be null and PlatformHandle will contain the HWND // Some back-end will leave PlatformHandleRaw NULL, in which case we assume PlatformHandle will contain the HWND.
HWND hwnd = (HWND)viewport->PlatformHandleRaw; HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
if (hwnd == 0)
{
hwnd = (HWND)viewport->PlatformHandle;
}
IM_ASSERT(hwnd != 0); IM_ASSERT(hwnd != 0);
// Create swap chain // Create swap chain

View File

@ -4,7 +4,8 @@
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. // [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
// Issues: // Missing features, issues:
// [ ] Renderer: Missing multi-viewport support.
// [ ] 64-bit only for now! (Because sizeof(ImTextureId) == sizeof(void*)). See github.com/ocornut/imgui/pull/301 // [ ] 64-bit only for now! (Because sizeof(ImTextureId) == sizeof(void*)). See github.com/ocornut/imgui/pull/301
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.
@ -680,7 +681,9 @@ static void ImGui_ImplDX12_CreateWindow(ImGuiViewport* viewport)
/* /*
// FIXME-PLATFORM // FIXME-PLATFORM
HWND hwnd = (HWND)viewport->PlatformHandle; // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
// Some back-ends will leave PlatformHandleRaw NULL, in which case we assume PlatformHandle will contain the HWND.
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
IM_ASSERT(hwnd != 0); IM_ASSERT(hwnd != 0);
// Create swap chain // Create swap chain

View File

@ -4,7 +4,8 @@
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp. // [X] Renderer: User texture binding. Use 'D3D12_GPU_DESCRIPTOR_HANDLE' as ImTextureID. Read the FAQ about ImTextureID in imgui.cpp.
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
// Issues: // Missing features, issues:
// [ ] Renderer: Missing multi-viewport support.
// [ ] 64-bit only for now! (Because sizeof(ImTextureId) == sizeof(void*)). See github.com/ocornut/imgui/pull/301 // [ ] 64-bit only for now! (Because sizeof(ImTextureId) == sizeof(void*)). See github.com/ocornut/imgui/pull/301
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.

View File

@ -319,8 +319,10 @@ static void ImGui_ImplDX9_CreateWindow(ImGuiViewport* viewport)
ImGuiViewportDataDx9* data = IM_NEW(ImGuiViewportDataDx9)(); ImGuiViewportDataDx9* data = IM_NEW(ImGuiViewportDataDx9)();
viewport->RendererUserData = data; viewport->RendererUserData = data;
HWND hWnd = (HWND)viewport->PlatformHandle; // PlatformHandleRaw should always be a HWND, whereas PlatformHandle might be a higher-level handle (e.g. GLFWWindow*, SDL_Window*).
IM_ASSERT(hWnd != 0); // Some back-ends will leave PlatformHandleRaw NULL, in which case we assume PlatformHandle will contain the HWND.
HWND hwnd = viewport->PlatformHandleRaw ? (HWND)viewport->PlatformHandleRaw : (HWND)viewport->PlatformHandle;
IM_ASSERT(hwnd != 0);
ZeroMemory(&data->d3dpp, sizeof(D3DPRESENT_PARAMETERS)); ZeroMemory(&data->d3dpp, sizeof(D3DPRESENT_PARAMETERS));
data->d3dpp.Windowed = TRUE; data->d3dpp.Windowed = TRUE;
@ -328,7 +330,7 @@ static void ImGui_ImplDX9_CreateWindow(ImGuiViewport* viewport)
data->d3dpp.BackBufferWidth = (UINT)viewport->Size.x; data->d3dpp.BackBufferWidth = (UINT)viewport->Size.x;
data->d3dpp.BackBufferHeight = (UINT)viewport->Size.y; data->d3dpp.BackBufferHeight = (UINT)viewport->Size.y;
data->d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; data->d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
data->d3dpp.hDeviceWindow = hWnd; data->d3dpp.hDeviceWindow = hwnd;
data->d3dpp.EnableAutoDepthStencil = FALSE; data->d3dpp.EnableAutoDepthStencil = FALSE;
data->d3dpp.AutoDepthStencilFormat = D3DFMT_D16; data->d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
data->d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Present without vsync data->d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; // Present without vsync

View File

@ -202,6 +202,9 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
// Our mouse update function expect PlatformHandle to be filled for the main viewport // Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport* main_viewport = ImGui::GetMainViewport(); ImGuiViewport* main_viewport = ImGui::GetMainViewport();
main_viewport->PlatformHandle = (void*)g_Window; main_viewport->PlatformHandle = (void*)g_Window;
#ifdef _WIN32
main_viewport->PlatformHandleRaw = glfwGetWin32Window(g_Window);
#endif
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
ImGui_ImplGlfw_InitPlatformInterface(); ImGui_ImplGlfw_InitPlatformInterface();
@ -444,6 +447,9 @@ static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport)
data->Window = glfwCreateWindow((int)viewport->Size.x, (int)viewport->Size.y, "No Title Yet", NULL, share_window); data->Window = glfwCreateWindow((int)viewport->Size.x, (int)viewport->Size.y, "No Title Yet", NULL, share_window);
data->WindowOwned = true; data->WindowOwned = true;
viewport->PlatformHandle = (void*)data->Window; viewport->PlatformHandle = (void*)data->Window;
#ifdef _WIN32
viewport->PlatformHandleRaw = glfwGetWin32Window(data->Window);
#endif
glfwSetWindowPos(data->Window, (int)viewport->Pos.x, (int)viewport->Pos.y); glfwSetWindowPos(data->Window, (int)viewport->Pos.x, (int)viewport->Pos.y);
// Install callbacks for secondary viewports // Install callbacks for secondary viewports
@ -468,7 +474,7 @@ static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport)
if (data->WindowOwned) if (data->WindowOwned)
{ {
#if GLFW_HAS_GLFW_HOVERED && defined(_WIN32) #if GLFW_HAS_GLFW_HOVERED && defined(_WIN32)
HWND hwnd = glfwGetWin32Window(data->Window); HWND hwnd = (HWND)viewport->PlatformHandleRaw;
::RemovePropA(hwnd, "IMGUI_VIEWPORT"); ::RemovePropA(hwnd, "IMGUI_VIEWPORT");
#endif #endif
glfwDestroyWindow(data->Window); glfwDestroyWindow(data->Window);
@ -504,7 +510,7 @@ static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport)
#if defined(_WIN32) #if defined(_WIN32)
// GLFW hack: Hide icon from task bar // GLFW hack: Hide icon from task bar
HWND hwnd = glfwGetWin32Window(data->Window); HWND hwnd = (HWND)viewport->PlatformHandleRaw;
if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon) if (viewport->Flags & ImGuiViewportFlags_NoTaskBarIcon)
{ {
LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
@ -633,8 +639,7 @@ static void ImGui_ImplGlfw_SwapBuffers(ImGuiViewport* viewport, void*)
static void ImGui_ImplWin32_SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos) static void ImGui_ImplWin32_SetImeInputPos(ImGuiViewport* viewport, ImVec2 pos)
{ {
COMPOSITIONFORM cf = { CFS_FORCE_POSITION, { (LONG)(pos.x - viewport->Pos.x), (LONG)(pos.y - viewport->Pos.y) }, { 0, 0, 0, 0 } }; COMPOSITIONFORM cf = { CFS_FORCE_POSITION, { (LONG)(pos.x - viewport->Pos.x), (LONG)(pos.y - viewport->Pos.y) }, { 0, 0, 0, 0 } };
if (ImGuiViewportDataGlfw* data = (ImGuiViewportDataGlfw*)viewport->PlatformUserData) if (HWND hwnd = (HWND)viewport->PlatformHandleRaw)
if (HWND hwnd = glfwGetWin32Window(data->Window))
if (HIMC himc = ::ImmGetContext(hwnd)) if (HIMC himc = ::ImmGetContext(hwnd))
{ {
::ImmSetCompositionWindow(himc, &cf); ::ImmSetCompositionWindow(himc, &cf);

View File

@ -200,6 +200,12 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, void* sdl_gl_context)
// Our mouse update function expect PlatformHandle to be filled for the main viewport // Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport* main_viewport = ImGui::GetMainViewport(); ImGuiViewport* main_viewport = ImGui::GetMainViewport();
main_viewport->PlatformHandle = (void*)window; main_viewport->PlatformHandle = (void*)window;
#if defined(_WIN32)
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
if (SDL_GetWindowWMInfo(window, &info))
main_viewport->PlatformHandleRaw = info.info.win.window;
#endif
// We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports. // We need SDL_CaptureMouse(), SDL_GetGlobalMouseState() from SDL 2.0.4+ to support multiple viewports.
// We left the call to ImGui_ImplSDL2_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings. // We left the call to ImGui_ImplSDL2_InitPlatformInterface() outside of #ifdef to avoid unused-function warnings.
@ -455,16 +461,13 @@ static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport)
} }
if (use_opengl && backup_context) if (use_opengl && backup_context)
SDL_GL_MakeCurrent(data->Window, backup_context); SDL_GL_MakeCurrent(data->Window, backup_context);
viewport->PlatformHandle = (void*)data->Window;
viewport->PlatformHandle = (void*)data->Window;
#if defined(_WIN32) #if defined(_WIN32)
// save the window handle for render that needs it (directX)
SDL_SysWMinfo info; SDL_SysWMinfo info;
SDL_VERSION(&info.version); SDL_VERSION(&info.version);
if (SDL_GetWindowWMInfo(data->Window, &info)) if (SDL_GetWindowWMInfo(data->Window, &info))
{
viewport->PlatformHandleRaw = info.info.win.window; viewport->PlatformHandleRaw = info.info.win.window;
}
#endif #endif
} }
@ -487,11 +490,7 @@ static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
{ {
ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData; ImGuiViewportDataSDL2* data = (ImGuiViewportDataSDL2*)viewport->PlatformUserData;
#if defined(_WIN32) #if defined(_WIN32)
SDL_SysWMinfo info; HWND hwnd = (HWND)viewport->PlatformHandleRaw;
SDL_VERSION(&info.version);
if (SDL_GetWindowWMInfo(data->Window, &info))
{
HWND hwnd = info.info.win.window;
// SDL hack: Hide icon from task bar // SDL hack: Hide icon from task bar
// Note: SDL 2.0.6+ has a SDL_WINDOW_SKIP_TASKBAR flag which is supported under Windows but the way it create the window breaks our seamless transition. // Note: SDL 2.0.6+ has a SDL_WINDOW_SKIP_TASKBAR flag which is supported under Windows but the way it create the window breaks our seamless transition.
@ -509,7 +508,6 @@ static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
::ShowWindow(hwnd, SW_SHOWNA); ::ShowWindow(hwnd, SW_SHOWNA);
return; return;
} }
}
#endif #endif
SDL_ShowWindow(data->Window); SDL_ShowWindow(data->Window);

View File

@ -3,8 +3,8 @@
// Implemented features: // Implemented features:
// [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices. // [X] Renderer: Support for large meshes (64k+ vertices) with 16-bits indices.
// [x] Platform: Multi-viewport / platform windows. With issues (flickering when creating a new viewport).
// Missing features: // Missing features:
// [ ] Platform: Multi-viewport / platform windows.
// [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this binding! See https://github.com/ocornut/imgui/pull/914 // [ ] Renderer: User texture binding. Changes of ImTextureID aren't supported by this binding! See https://github.com/ocornut/imgui/pull/914
// You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this. // You can copy and use unmodified imgui_impl_* files in your project. See main.cpp for an example of using this.

View File

@ -73,7 +73,7 @@ bool ImGui_ImplWin32_Init(void* hwnd)
// Our mouse update function expect PlatformHandle to be filled for the main viewport // Our mouse update function expect PlatformHandle to be filled for the main viewport
g_hWnd = (HWND)hwnd; g_hWnd = (HWND)hwnd;
ImGuiViewport* main_viewport = ImGui::GetMainViewport(); ImGuiViewport* main_viewport = ImGui::GetMainViewport();
main_viewport->PlatformHandle = (void*)g_hWnd; main_viewport->PlatformHandle = main_viewport->PlatformHandleRaw = (void*)g_hWnd;
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
ImGui_ImplWin32_InitPlatformInterface(); ImGui_ImplWin32_InitPlatformInterface();
@ -547,7 +547,7 @@ static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport)
parent_window, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param parent_window, NULL, ::GetModuleHandle(NULL), NULL); // Parent window, Menu, Instance, Param
data->HwndOwned = true; data->HwndOwned = true;
viewport->PlatformRequestResize = false; viewport->PlatformRequestResize = false;
viewport->PlatformHandle = data->Hwnd; viewport->PlatformHandle = viewport->PlatformHandleRaw = data->Hwnd;
} }
static void ImGui_ImplWin32_DestroyWindow(ImGuiViewport* viewport) static void ImGui_ImplWin32_DestroyWindow(ImGuiViewport* viewport)

View File

@ -2398,8 +2398,8 @@ struct ImGuiViewport
void* RendererUserData; // void* to hold custom data structure for the renderer (e.g. swap chain, frame-buffers etc.) void* RendererUserData; // void* to hold custom data structure for the renderer (e.g. swap chain, frame-buffers etc.)
void* PlatformUserData; // void* to hold custom data structure for the OS / platform (e.g. windowing info, render context) void* PlatformUserData; // void* to hold custom data structure for the OS / platform (e.g. windowing info, render context)
void* PlatformHandle; // void* for FindViewportByPlatformHandle(). (e.g. suggested to use natural platform handle such as HWND, GlfwWindow*, SDL_Window*) void* PlatformHandle; // void* for FindViewportByPlatformHandle(). (e.g. suggested to use natural platform handle such as HWND, GLFWWindow*, SDL_Window*)
void* PlatformHandleRaw; // void* to hold the platfor-native windows handle (e.g. the HWND) when using an abstraction layer like SDL (where PlatformHandle would be a SDL_Window*) void* PlatformHandleRaw; // void* to hold low-level, platform-native window handle (e.g. the HWND) when using an abstraction layer like GLFW or SDL (where PlatformHandle would be a SDL_Window*)
bool PlatformRequestClose; // Platform window requested closure (e.g. window was moved by the OS / host window manager, e.g. pressing ALT-F4) bool PlatformRequestClose; // Platform window requested closure (e.g. window was moved by the OS / host window manager, e.g. pressing ALT-F4)
bool PlatformRequestMove; // Platform window requested move (e.g. window was moved by the OS / host window manager, authoritative position will be OS window position) bool PlatformRequestMove; // Platform window requested move (e.g. window was moved by the OS / host window manager, authoritative position will be OS window position)
bool PlatformRequestResize; // Platform window requested resize (e.g. window was resized by the OS / host window manager, authoritative size will be OS window size) bool PlatformRequestResize; // Platform window requested resize (e.g. window was resized by the OS / host window manager, authoritative size will be OS window size)