Skip to content

Commit

Permalink
Backends: SDL_Renderer2/SDL_Renderer3: and ImGui_ImplSDLRenderer2_Ren…
Browse files Browse the repository at this point in the history
…derDrawData() and ImGui_ImplSDLRenderer3_RenderDrawData() now takes a SDL_Renderer* parameter.
  • Loading branch information
ocornut committed May 15, 2024
1 parent af2fbf0 commit 5d973a8
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 49 deletions.
41 changes: 19 additions & 22 deletions backends/imgui_impl_sdlrenderer2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
// - Introduction, links and more at the top of imgui.cpp

// CHANGELOG
// 2024-05-14: *BREAKING CHANGE* ImGui_ImplSDLRenderer3_RenderDrawData() requires SDL_Renderer* passed as parameter.
// 2023-05-30: Renamed imgui_impl_sdlrenderer.h/.cpp to imgui_impl_sdlrenderer2.h/.cpp to accommodate for upcoming SDL3.
// 2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
// 2021-12-21: Update SDL_RenderGeometryRaw() format to work with SDL 2.0.19.
Expand Down Expand Up @@ -47,9 +48,9 @@
// SDL_Renderer data
struct ImGui_ImplSDLRenderer2_Data
{
SDL_Renderer* SDLRenderer;
SDL_Renderer* Renderer; // Main viewport's renderer
SDL_Texture* FontTexture;
ImGui_ImplSDLRenderer2_Data() { memset((void*)this, 0, sizeof(*this)); }
ImGui_ImplSDLRenderer2_Data() { memset((void*)this, 0, sizeof(*this)); }
};

// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
Expand All @@ -73,7 +74,7 @@ bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer)
io.BackendRendererName = "imgui_impl_sdlrenderer2";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.

bd->SDLRenderer = renderer;
bd->Renderer = renderer;

return true;
}
Expand All @@ -92,14 +93,12 @@ void ImGui_ImplSDLRenderer2_Shutdown()
IM_DELETE(bd);
}

static void ImGui_ImplSDLRenderer2_SetupRenderState()
static void ImGui_ImplSDLRenderer2_SetupRenderState(SDL_Renderer* renderer)
{
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();

// Clear out any viewports and cliprect set by the user
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
SDL_RenderSetViewport(bd->SDLRenderer, nullptr);
SDL_RenderSetClipRect(bd->SDLRenderer, nullptr);
SDL_RenderSetViewport(renderer, nullptr);
SDL_RenderSetClipRect(renderer, nullptr);
}

void ImGui_ImplSDLRenderer2_NewFrame()
Expand All @@ -111,16 +110,14 @@ void ImGui_ImplSDLRenderer2_NewFrame()
ImGui_ImplSDLRenderer2_CreateDeviceObjects();
}

void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data)
void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer)
{
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();

// 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
// to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
float rsx = 1.0f;
float rsy = 1.0f;
SDL_RenderGetScale(bd->SDLRenderer, &rsx, &rsy);
SDL_RenderGetScale(renderer, &rsx, &rsy);
ImVec2 render_scale;
render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;
Expand All @@ -139,16 +136,16 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data)
SDL_Rect ClipRect;
};
BackupSDLRendererState old = {};
old.ClipEnabled = SDL_RenderIsClipEnabled(bd->SDLRenderer) == SDL_TRUE;
SDL_RenderGetViewport(bd->SDLRenderer, &old.Viewport);
SDL_RenderGetClipRect(bd->SDLRenderer, &old.ClipRect);
old.ClipEnabled = SDL_RenderIsClipEnabled(renderer) == SDL_TRUE;
SDL_RenderGetViewport(renderer, &old.Viewport);
SDL_RenderGetClipRect(renderer, &old.ClipRect);

// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = render_scale;

// Render command lists
ImGui_ImplSDLRenderer2_SetupRenderState();
ImGui_ImplSDLRenderer2_SetupRenderState(renderer);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
Expand All @@ -163,7 +160,7 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data)
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplSDLRenderer2_SetupRenderState();
ImGui_ImplSDLRenderer2_SetupRenderState(renderer);
else
pcmd->UserCallback(cmd_list, pcmd);
}
Expand All @@ -180,7 +177,7 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data)
continue;

SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
SDL_RenderSetClipRect(bd->SDLRenderer, &r);
SDL_RenderSetClipRect(renderer, &r);

const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos));
const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, uv));
Expand All @@ -192,7 +189,7 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data)

// Bind texture, Draw
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
SDL_RenderGeometryRaw(bd->SDLRenderer, tex,
SDL_RenderGeometryRaw(renderer, tex,
xy, (int)sizeof(ImDrawVert),
color, (int)sizeof(ImDrawVert),
uv, (int)sizeof(ImDrawVert),
Expand All @@ -203,8 +200,8 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data)
}

// Restore modified SDL_Renderer state
SDL_RenderSetViewport(bd->SDLRenderer, &old.Viewport);
SDL_RenderSetClipRect(bd->SDLRenderer, old.ClipEnabled ? &old.ClipRect : nullptr);
SDL_RenderSetViewport(renderer, &old.Viewport);
SDL_RenderSetClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr);
}

// Called by Init/NewFrame/Shutdown
Expand All @@ -220,7 +217,7 @@ bool ImGui_ImplSDLRenderer2_CreateFontsTexture()

// Upload texture to graphics system
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
bd->FontTexture = SDL_CreateTexture(bd->SDLRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height);
bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height);
if (bd->FontTexture == nullptr)
{
SDL_Log("error creating texture");
Expand Down
2 changes: 1 addition & 1 deletion backends/imgui_impl_sdlrenderer2.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct SDL_Renderer;
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer);
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_NewFrame();
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data);
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer);

// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateFontsTexture();
Expand Down
43 changes: 20 additions & 23 deletions backends/imgui_impl_sdlrenderer3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
// - Introduction, links and more at the top of imgui.cpp

// CHANGELOG
// 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.
// 2023-05-30: Initial version.

Expand All @@ -43,9 +44,9 @@
// SDL_Renderer data
struct ImGui_ImplSDLRenderer3_Data
{
SDL_Renderer* SDLRenderer;
SDL_Renderer* Renderer; // Main viewport's renderer
SDL_Texture* FontTexture;
ImGui_ImplSDLRenderer3_Data() { memset((void*)this, 0, sizeof(*this)); }
ImGui_ImplSDLRenderer3_Data() { memset((void*)this, 0, sizeof(*this)); }
};

// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
Expand All @@ -69,7 +70,7 @@ bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer)
io.BackendRendererName = "imgui_impl_sdlrenderer3";
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.

bd->SDLRenderer = renderer;
bd->Renderer = renderer;

return true;
}
Expand All @@ -88,14 +89,12 @@ void ImGui_ImplSDLRenderer3_Shutdown()
IM_DELETE(bd);
}

static void ImGui_ImplSDLRenderer3_SetupRenderState()
static void ImGui_ImplSDLRenderer3_SetupRenderState(SDL_Renderer* renderer)
{
ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData();

// Clear out any viewports and cliprect set by the user
// FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
SDL_SetRenderViewport(bd->SDLRenderer, nullptr);
SDL_SetRenderClipRect(bd->SDLRenderer, nullptr);
SDL_SetRenderViewport(renderer, nullptr);
SDL_SetRenderClipRect(renderer, nullptr);
}

void ImGui_ImplSDLRenderer3_NewFrame()
Expand All @@ -107,16 +106,14 @@ void ImGui_ImplSDLRenderer3_NewFrame()
ImGui_ImplSDLRenderer3_CreateDeviceObjects();
}

void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data)
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 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.
float rsx = 1.0f;
float rsy = 1.0f;
SDL_GetRenderScale(bd->SDLRenderer, &rsx, &rsy);
SDL_GetRenderScale(renderer, &rsx, &rsy);
ImVec2 render_scale;
render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;
Expand All @@ -136,17 +133,17 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data)
SDL_Rect ClipRect;
};
BackupSDLRendererState old = {};
old.ViewportEnabled = SDL_RenderViewportSet(bd->SDLRenderer) == SDL_TRUE;
old.ClipEnabled = SDL_RenderClipEnabled(bd->SDLRenderer) == SDL_TRUE;
SDL_GetRenderViewport(bd->SDLRenderer, &old.Viewport);
SDL_GetRenderClipRect(bd->SDLRenderer, &old.ClipRect);
old.ViewportEnabled = SDL_RenderViewportSet(renderer) == SDL_TRUE;
old.ClipEnabled = SDL_RenderClipEnabled(renderer) == SDL_TRUE;
SDL_GetRenderViewport(renderer, &old.Viewport);
SDL_GetRenderClipRect(renderer, &old.ClipRect);

// Will project scissor/clipping rectangles into framebuffer space
ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
ImVec2 clip_scale = render_scale;

// Render command lists
ImGui_ImplSDLRenderer3_SetupRenderState();
ImGui_ImplSDLRenderer3_SetupRenderState(renderer);
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
Expand All @@ -161,7 +158,7 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data)
// User callback, registered via ImDrawList::AddCallback()
// (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
ImGui_ImplSDLRenderer3_SetupRenderState();
ImGui_ImplSDLRenderer3_SetupRenderState(renderer);
else
pcmd->UserCallback(cmd_list, pcmd);
}
Expand All @@ -178,15 +175,15 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data)
continue;

SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
SDL_SetRenderClipRect(bd->SDLRenderer, &r);
SDL_SetRenderClipRect(renderer, &r);

const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos));
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+

// Bind texture, Draw
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
SDL_RenderGeometryRaw(bd->SDLRenderer, tex,
SDL_RenderGeometryRaw(renderer, tex,
xy, (int)sizeof(ImDrawVert),
color, (int)sizeof(ImDrawVert),
uv, (int)sizeof(ImDrawVert),
Expand All @@ -197,8 +194,8 @@ void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data)
}

// Restore modified SDL_Renderer state
SDL_SetRenderViewport(bd->SDLRenderer, old.ViewportEnabled ? &old.Viewport : nullptr);
SDL_SetRenderClipRect(bd->SDLRenderer, old.ClipEnabled ? &old.ClipRect : nullptr);
SDL_SetRenderViewport(renderer, old.ViewportEnabled ? &old.Viewport : nullptr);
SDL_SetRenderClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr);
}

// Called by Init/NewFrame/Shutdown
Expand All @@ -214,7 +211,7 @@ bool ImGui_ImplSDLRenderer3_CreateFontsTexture()

// Upload texture to graphics system
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
bd->FontTexture = SDL_CreateTexture(bd->SDLRenderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height);
bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height);
if (bd->FontTexture == nullptr)
{
SDL_Log("error creating texture");
Expand Down
2 changes: 1 addition & 1 deletion backends/imgui_impl_sdlrenderer3.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct SDL_Renderer;
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_Init(SDL_Renderer* renderer);
IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_NewFrame();
IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data);
IMGUI_IMPL_API void ImGui_ImplSDLRenderer3_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer);

// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer3_CreateFontsTexture();
Expand Down
4 changes: 4 additions & 0 deletions docs/CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ HOW TO UPDATE?

Breaking changes:

- Backends: SDL_Renderer2/SDL_Renderer3: and ImGui_ImplSDLRenderer2_RenderDrawData() and
ImGui_ImplSDLRenderer3_RenderDrawData() now takes a SDL_Renderer* parameter. This was previously
overlooked from the API but it will facilitate eventual support for multi-viewports.

Other changes:

- Nav: fixed holding Ctrl or gamepad L1 from not slowing down keyboard/gamepad tweak speed.
Expand Down
2 changes: 1 addition & 1 deletion examples/example_sdl2_sdlrenderer2/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ int main(int, char**)
SDL_RenderSetScale(renderer, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
SDL_SetRenderDrawColor(renderer, (Uint8)(clear_color.x * 255), (Uint8)(clear_color.y * 255), (Uint8)(clear_color.z * 255), (Uint8)(clear_color.w * 255));
SDL_RenderClear(renderer);
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData());
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), renderer);
SDL_RenderPresent(renderer);
}

Expand Down
2 changes: 1 addition & 1 deletion examples/example_sdl3_sdlrenderer3/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ int main(int, char**)
//SDL_RenderSetScale(renderer, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
SDL_SetRenderDrawColor(renderer, (Uint8)(clear_color.x * 255), (Uint8)(clear_color.y * 255), (Uint8)(clear_color.z * 255), (Uint8)(clear_color.w * 255));
SDL_RenderClear(renderer);
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData());
ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData(), renderer);
SDL_RenderPresent(renderer);
}

Expand Down
1 change: 1 addition & 0 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ CODE
When you are not sure about an old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
You can read releases logs https://github.com/ocornut/imgui/releases for more details.

- 2024/05/14 (1.90.7) - backends: SDL_Renderer2 and SDL_Renderer3 backend now take a SDL_Renderer* in their RenderDrawData() functions.
- 2024/04/18 (1.90.6) - TreeNode: Fixed a layout inconsistency when using an empty/hidden label followed by a SameLine() call. (#7505, #282)
- old: TreeNode("##Hidden"); SameLine(); Text("Hello"); // <-- This was actually incorrect! BUT appeared to look ok with the default style where ItemSpacing.x == FramePadding.x * 2 (it didn't look aligned otherwise).
- new: TreeNode("##Hidden"); SameLine(0, 0); Text("Hello"); // <-- This is correct for all styles values.
Expand Down

0 comments on commit 5d973a8

Please sign in to comment.