Compare commits

...

2 Commits

  1. 112
      backends/imgui_impl_sdlrenderer3.cpp
  2. 3
      backends/imgui_impl_sdlrenderer3.h
  3. 15
      examples/example_sdl3_sdlrenderer3/main.cpp
  4. 20
      examples/imgui_examples.sln

@ -10,8 +10,9 @@
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! // [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. // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
// Missing features: // [X] Renderer: Multi-viewport support (multiple windows).
// [ ] 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. // 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. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
@ -22,6 +23,7 @@
// - Introduction, links and more at the top of imgui.cpp // - Introduction, links and more at the top of imgui.cpp
// CHANGELOG // CHANGELOG
// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface. (#5835)
// 2024-05-14: *BREAKING CHANGE* ImGui_ImplSDLRenderer3_RenderDrawData() requires SDL_Renderer* passed as parameter. // 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. // 2024-02-12: Amend to query SDL_RenderViewportSet() and restore viewport accordingly.
// 2023-05-30: Initial version. // 2023-05-30: Initial version.
@ -48,6 +50,9 @@ struct ImGui_ImplSDLRenderer3_Data
{ {
SDL_Renderer* Renderer; // Main viewport's renderer SDL_Renderer* Renderer; // Main viewport's renderer
SDL_Texture* FontTexture; SDL_Texture* FontTexture;
ImVector<ImVec2> PosBuffer; // Transformed pos buffer (for multi-viewports only)
ImGui_ImplSDLRenderer3_Data() { memset((void*)this, 0, sizeof(*this)); } ImGui_ImplSDLRenderer3_Data() { memset((void*)this, 0, sizeof(*this)); }
}; };
@ -58,6 +63,10 @@ static ImGui_ImplSDLRenderer3_Data* ImGui_ImplSDLRenderer3_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
} }
// Forward Declarations
static void ImGui_ImplSDLRenderer3_InitPlatformInterface();
static void ImGui_ImplSDLRenderer3_ShutdownPlatformInterface();
// Functions // Functions
bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer) bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer)
{ {
@ -71,9 +80,13 @@ bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer)
io.BackendRendererUserData = (void*)bd; io.BackendRendererUserData = (void*)bd;
io.BackendRendererName = "imgui_impl_sdlrenderer3"; io.BackendRendererName = "imgui_impl_sdlrenderer3";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes. 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; bd->Renderer = renderer;
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
ImGui_ImplSDLRenderer3_InitPlatformInterface();
return true; return true;
} }
@ -83,6 +96,7 @@ void ImGui_ImplSDLRenderer3_Shutdown()
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
ImGuiIO& io = ImGui::GetIO(); ImGuiIO& io = ImGui::GetIO();
ImGui_ImplSDLRenderer3_ShutdownPlatformInterface();
ImGui_ImplSDLRenderer3_DestroyDeviceObjects(); ImGui_ImplSDLRenderer3_DestroyDeviceObjects();
io.BackendRendererName = nullptr; io.BackendRendererName = nullptr;
@ -110,6 +124,8 @@ void ImGui_ImplSDLRenderer3_NewFrame()
void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer) void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer)
{ {
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();
// If there's a scale factor set by the user, use that instead // If there's a scale factor set by the user, use that instead
// If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass // If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
// to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here. // to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
@ -180,13 +196,32 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
SDL_SetRenderClipRect(renderer, &r); SDL_SetRenderClipRect(renderer, &r);
const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos)); const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos));
int xy_stride = (int)sizeof(ImDrawVert);
const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, uv)); const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, uv));
const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.19+ const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.19+
// FIXME-OPT: Transform position manually
// FIXME-OPT: Note that SDL_RenderGeometryRaw() does another transform for colors..
if (draw_data->DisplayPos.x != 0.0f || draw_data->DisplayPos.y != 0.0f)
{
const float off_x = draw_data->DisplayPos.x;
const float off_y = draw_data->DisplayPos.y;
bd->PosBuffer.resize(pcmd->ElemCount);
const ImDrawVert* p_in = vtx_buffer + pcmd->VtxOffset;
ImVec2* p_out = bd->PosBuffer.Data;
for (int remaining = pcmd->ElemCount; remaining > 0; remaining--, p_out++, p_in++)
{
p_out->x = p_in->pos.x - off_x;
p_out->y = p_in->pos.y - off_y;
}
xy = (const float*)bd->PosBuffer.Data;
xy_stride = (int)sizeof(ImVec2);
}
// Bind texture, Draw // Bind texture, Draw
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
SDL_RenderGeometryRaw(renderer, tex, SDL_RenderGeometryRaw(renderer, tex,
xy, (int)sizeof(ImDrawVert), xy, xy_stride,
color, (int)sizeof(ImDrawVert), color, (int)sizeof(ImDrawVert),
uv, (int)sizeof(ImDrawVert), uv, (int)sizeof(ImDrawVert),
cmd_list->VtxBuffer.Size - pcmd->VtxOffset, cmd_list->VtxBuffer.Size - pcmd->VtxOffset,
@ -251,6 +286,77 @@ void ImGui_ImplSDLRenderer3_DestroyDeviceObjects()
ImGui_ImplSDLRenderer3_DestroyFontsTexture(); 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__) #if defined(__clang__)

@ -10,8 +10,7 @@
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID! // [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. // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
// Missing features: // [X] Renderer: Multi-viewport support (multiple windows).
// [ ] 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. // 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. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.

@ -35,13 +35,17 @@ int main(int, char**)
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1"); SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
// Create window with SDL_Renderer graphics context // 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); SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", 1280, 720, window_flags);
if (window == nullptr) if (window == nullptr)
{ {
printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError());
return -1; 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_Renderer* renderer = SDL_CreateRenderer(window, nullptr);
SDL_SetRenderVSync(renderer, 1); SDL_SetRenderVSync(renderer, 1);
if (renderer == nullptr) if (renderer == nullptr)
@ -59,6 +63,7 @@ int main(int, char**)
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_DockingEnable; // Enable Docking
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
// Setup Dear ImGui style // Setup Dear ImGui style
ImGui::StyleColorsDark(); ImGui::StyleColorsDark();
@ -164,6 +169,14 @@ int main(int, char**)
SDL_SetRenderDrawColorFloat(renderer, clear_color.x, clear_color.y, clear_color.z, clear_color.w); SDL_SetRenderDrawColorFloat(renderer, clear_color.x, clear_color.y, clear_color.z, clear_color.w);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), 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); SDL_RenderPresent(renderer);
} }

@ -29,6 +29,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_win32_opengl3", "ex
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl2_sdlrenderer2", "example_sdl2_sdlrenderer2\example_sdl2_sdlrenderer2.vcxproj", "{0C0B2BEA-311F-473C-9652-87923EF639E3}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl2_sdlrenderer2", "example_sdl2_sdlrenderer2\example_sdl2_sdlrenderer2.vcxproj", "{0C0B2BEA-311F-473C-9652-87923EF639E3}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_sdlrenderer3", "example_sdl3_sdlrenderer3\example_sdl3_sdlrenderer3.vcxproj", "{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_opengl3", "example_sdl3_opengl3\example_sdl3_opengl3.vcxproj", "{84AAA301-84FE-428B-9E3E-817BC8123C0C}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 Debug|Win32 = Debug|Win32
@ -141,6 +145,22 @@ Global
{0C0B2BEA-311F-473C-9652-87923EF639E3}.Release|Win32.Build.0 = Release|Win32 {0C0B2BEA-311F-473C-9652-87923EF639E3}.Release|Win32.Build.0 = Release|Win32
{0C0B2BEA-311F-473C-9652-87923EF639E3}.Release|x64.ActiveCfg = Release|x64 {0C0B2BEA-311F-473C-9652-87923EF639E3}.Release|x64.ActiveCfg = Release|x64
{0C0B2BEA-311F-473C-9652-87923EF639E3}.Release|x64.Build.0 = Release|x64 {0C0B2BEA-311F-473C-9652-87923EF639E3}.Release|x64.Build.0 = Release|x64
{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Debug|Win32.ActiveCfg = Debug|Win32
{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Debug|Win32.Build.0 = Debug|Win32
{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Debug|x64.ActiveCfg = Debug|x64
{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Debug|x64.Build.0 = Debug|x64
{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|Win32.ActiveCfg = Release|Win32
{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|Win32.Build.0 = Release|Win32
{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|x64.ActiveCfg = Release|x64
{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|x64.Build.0 = Release|x64
{84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|Win32.ActiveCfg = Debug|Win32
{84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|Win32.Build.0 = Debug|Win32
{84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|x64.ActiveCfg = Debug|x64
{84AAA301-84FE-428B-9E3E-817BC8123C0C}.Debug|x64.Build.0 = Debug|x64
{84AAA301-84FE-428B-9E3E-817BC8123C0C}.Release|Win32.ActiveCfg = Release|Win32
{84AAA301-84FE-428B-9E3E-817BC8123C0C}.Release|Win32.Build.0 = Release|Win32
{84AAA301-84FE-428B-9E3E-817BC8123C0C}.Release|x64.ActiveCfg = Release|x64
{84AAA301-84FE-428B-9E3E-817BC8123C0C}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

Loading…
Cancel
Save