diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 45a69baab..9e4d5011b 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -12,8 +12,9 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. -// Missing features: -// [ ] Renderer: Multi-viewport support (multiple windows). +// [X] Renderer: Multi-viewport support (multiple windows). +// FIXME: Missing way to share textures betweens renderers: shttps://github.com/libsdl-org/SDL/issues/6742 +// FIXME: Missing way to specify a projection matrix, so our vertices in absolute coordinates are not displayed correctly in multi-viewports mode. // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. @@ -24,6 +25,7 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG +// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. (#5835) // 2024-07-01: Update for SDL3 api changes: SDL_RenderGeometryRaw() uint32 version was removed (SDL#9009). // 2024-05-14: *BREAKING CHANGE* ImGui_ImplSDLRenderer3_RenderDrawData() requires SDL_Renderer* passed as parameter. // 2024-02-12: Amend to query SDL_RenderViewportSet() and restore viewport accordingly. @@ -63,6 +65,10 @@ static ImGui_ImplSDLRenderer3_Data* ImGui_ImplSDLRenderer3_GetBackendData() return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } +// Forward Declarations +static void ImGui_ImplSDLRenderer3_InitPlatformInterface(); +static void ImGui_ImplSDLRenderer3_ShutdownPlatformInterface(); + // Functions bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer) { @@ -76,9 +82,13 @@ bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer) io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_sdlrenderer3"; io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. + io.BackendFlags |= ImGuiBackendFlags_RendererHasViewports; // We can create multi-viewports on the Renderer side (optional) bd->Renderer = renderer; + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + ImGui_ImplSDLRenderer3_InitPlatformInterface(); + return true; } @@ -88,6 +98,7 @@ void ImGui_ImplSDLRenderer3_Shutdown() IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGui_ImplSDLRenderer3_ShutdownPlatformInterface(); ImGui_ImplSDLRenderer3_DestroyDeviceObjects(); io.BackendRendererName = nullptr; @@ -276,6 +287,77 @@ void ImGui_ImplSDLRenderer3_DestroyDeviceObjects() ImGui_ImplSDLRenderer3_DestroyFontsTexture(); } +//-------------------------------------------------------------------------------------------------------- +// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT +// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously. +// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first.. +//-------------------------------------------------------------------------------------------------------- + +// Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. +struct ImGui_ImplSDLRenderer3_ViewportData +{ + SDL_Renderer* Renderer; + + ImGui_ImplSDLRenderer3_ViewportData() { Renderer = nullptr; } + ~ImGui_ImplSDLRenderer3_ViewportData() { IM_ASSERT(Renderer == nullptr); } +}; + +static void ImGui_ImplSDLRenderer3_CreateWindow(ImGuiViewport* viewport) +{ + //ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); + ImGui_ImplSDLRenderer3_ViewportData* vd = IM_NEW(ImGui_ImplSDLRenderer3_ViewportData)(); + viewport->RendererUserData = vd; + + SDL_Window* window = (SDL_Window*)viewport->PlatformHandle; + vd->Renderer = SDL_CreateRenderer(window, nullptr); + SDL_SetRenderVSync(vd->Renderer, 0); + IM_ASSERT(vd->Renderer != NULL); +} + +static void ImGui_ImplSDLRenderer3_DestroyWindow(ImGuiViewport* viewport) +{ + // The main viewport (owned by the application) will always have RendererUserData == nullptr since we didn't create the data for it. + if (ImGui_ImplSDLRenderer3_ViewportData* vd = (ImGui_ImplSDLRenderer3_ViewportData*)viewport->RendererUserData) + { + SDL_DestroyRenderer(vd->Renderer); + vd->Renderer = nullptr; + IM_DELETE(vd); + } + viewport->RendererUserData = nullptr; +} + +static void ImGui_ImplSDLRenderer3_RenderWindow(ImGuiViewport* viewport, void*) +{ + ImGui_ImplSDLRenderer3_ViewportData* vd = (ImGui_ImplSDLRenderer3_ViewportData*)viewport->RendererUserData; + if (!(viewport->Flags & ImGuiViewportFlags_NoRendererClear)) + { + ImVec4 clear_color = ImVec4(0.0f, 0.0f, 0.0f, 1.0f); + SDL_SetRenderDrawColor(vd->Renderer, (Uint8)(clear_color.x * 255), (Uint8)(clear_color.y * 255), (Uint8)(clear_color.z * 255), (Uint8)(clear_color.w * 255)); + SDL_RenderClear(vd->Renderer); + } + ImGui_ImplSDLRenderer3_RenderDrawData(viewport->DrawData, vd->Renderer); +} + +static void ImGui_ImplSDLRenderer3_SwapBuffers(ImGuiViewport* viewport, void*) +{ + ImGui_ImplSDLRenderer3_ViewportData* vd = (ImGui_ImplSDLRenderer3_ViewportData*)viewport->RendererUserData; + SDL_RenderPresent(vd->Renderer); +} + +static void ImGui_ImplSDLRenderer3_InitPlatformInterface() +{ + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + platform_io.Renderer_CreateWindow = ImGui_ImplSDLRenderer3_CreateWindow; + platform_io.Renderer_DestroyWindow = ImGui_ImplSDLRenderer3_DestroyWindow; + platform_io.Renderer_RenderWindow = ImGui_ImplSDLRenderer3_RenderWindow; + platform_io.Renderer_SwapBuffers = ImGui_ImplSDLRenderer3_SwapBuffers; +} + +static void ImGui_ImplSDLRenderer3_ShutdownPlatformInterface() +{ + ImGui::DestroyPlatformWindows(); +} + //----------------------------------------------------------------------------- #if defined(__clang__) diff --git a/backends/imgui_impl_sdlrenderer3.h b/backends/imgui_impl_sdlrenderer3.h index 4ae96dc73..a1f4348e7 100644 --- a/backends/imgui_impl_sdlrenderer3.h +++ b/backends/imgui_impl_sdlrenderer3.h @@ -12,8 +12,7 @@ // Implemented features: // [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. -// Missing features: -// [ ] Renderer: Multi-viewport support (multiple windows). +// [X] Renderer: Multi-viewport support (multiple windows). // You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. diff --git a/examples/example_sdl3_sdlrenderer3/main.cpp b/examples/example_sdl3_sdlrenderer3/main.cpp index 9ebf850fc..77b2cc2d4 100644 --- a/examples/example_sdl3_sdlrenderer3/main.cpp +++ b/examples/example_sdl3_sdlrenderer3/main.cpp @@ -32,13 +32,17 @@ int main(int, char**) } // Create window with SDL_Renderer graphics context - Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN; + Uint32 window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN; SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", 1280, 720, window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); return -1; } + + for (int n = 0; n < SDL_GetNumRenderDrivers(); n++) + printf("- render driver %d: %s\n", n, SDL_GetRenderDriver(n)); + SDL_Renderer* renderer = SDL_CreateRenderer(window, nullptr); SDL_SetRenderVSync(renderer, 1); if (renderer == nullptr) @@ -56,6 +60,7 @@ int main(int, char**) 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(); @@ -166,6 +171,14 @@ int main(int, char**) SDL_SetRenderDrawColorFloat(renderer, clear_color.x, clear_color.y, clear_color.z, clear_color.w); SDL_RenderClear(renderer); ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer); + + // Update and Render additional Platform Windows + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); + } + SDL_RenderPresent(renderer); } #ifdef __EMSCRIPTEN__