mirror of
https://github.com/ocornut/imgui.git
synced 2025-09-05 19:08:19 +00:00
Backends: SDL_Renderer2: added ImGuiBackendFlags_RendererHasTextures support.
This commit is contained in:
@@ -10,8 +10,9 @@
|
|||||||
// and it might be difficult to step out of those boundaries.
|
// and it might be difficult to step out of those boundaries.
|
||||||
|
|
||||||
// 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 texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||||
|
// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures).
|
||||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||||
|
|
||||||
// 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.
|
||||||
@@ -23,6 +24,7 @@
|
|||||||
// - Introduction, links and more at the top of imgui.cpp
|
// - Introduction, links and more at the top of imgui.cpp
|
||||||
|
|
||||||
// CHANGELOG
|
// CHANGELOG
|
||||||
|
// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLRenderer2_CreateFontsTexture() and ImGui_ImplSDLRenderer2_DestroyFontsTexture().
|
||||||
// 2025-01-18: Use endian-dependent RGBA32 texture format, to match SDL_Color.
|
// 2025-01-18: Use endian-dependent RGBA32 texture format, to match SDL_Color.
|
||||||
// 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer2_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks.
|
// 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer2_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks.
|
||||||
// 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.
|
||||||
@@ -54,7 +56,7 @@
|
|||||||
struct ImGui_ImplSDLRenderer2_Data
|
struct ImGui_ImplSDLRenderer2_Data
|
||||||
{
|
{
|
||||||
SDL_Renderer* Renderer; // Main viewport's renderer
|
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)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -78,6 +80,7 @@ bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer)
|
|||||||
io.BackendRendererUserData = (void*)bd;
|
io.BackendRendererUserData = (void*)bd;
|
||||||
io.BackendRendererName = "imgui_impl_sdlrenderer2";
|
io.BackendRendererName = "imgui_impl_sdlrenderer2";
|
||||||
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_RendererHasTextures; // We can honor ImGuiPlatformIO::Textures[] requests during render.
|
||||||
|
|
||||||
bd->Renderer = renderer;
|
bd->Renderer = renderer;
|
||||||
|
|
||||||
@@ -94,7 +97,7 @@ void ImGui_ImplSDLRenderer2_Shutdown()
|
|||||||
|
|
||||||
io.BackendRendererName = nullptr;
|
io.BackendRendererName = nullptr;
|
||||||
io.BackendRendererUserData = nullptr;
|
io.BackendRendererUserData = nullptr;
|
||||||
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
|
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
||||||
IM_DELETE(bd);
|
IM_DELETE(bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,9 +113,7 @@ void ImGui_ImplSDLRenderer2_NewFrame()
|
|||||||
{
|
{
|
||||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||||
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLRenderer2_Init()?");
|
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLRenderer2_Init()?");
|
||||||
|
IM_UNUSED(bd);
|
||||||
if (!bd->FontTexture)
|
|
||||||
ImGui_ImplSDLRenderer2_CreateDeviceObjects();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer)
|
void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer)
|
||||||
@@ -133,6 +134,13 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
|
|||||||
if (fb_width == 0 || fb_height == 0)
|
if (fb_width == 0 || fb_height == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Catch up with texture updates. Most of the times, the list will have 1 element with an OK status, aka nothing to do.
|
||||||
|
// (This almost always points to ImGui::GetPlatformIO().Textures[] but is part of ImDrawData to allow overriding or disabling texture updates).
|
||||||
|
if (draw_data->Textures != nullptr)
|
||||||
|
for (ImTextureData* tex : *draw_data->Textures)
|
||||||
|
if (tex->Status != ImTextureStatus_OK)
|
||||||
|
ImGui_ImplSDLRenderer2_UpdateTexture(tex);
|
||||||
|
|
||||||
// Backup SDL_Renderer state that will be modified to restore it afterwards
|
// Backup SDL_Renderer state that will be modified to restore it afterwards
|
||||||
struct BackupSDLRendererState
|
struct BackupSDLRendererState
|
||||||
{
|
{
|
||||||
@@ -218,55 +226,67 @@ void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer*
|
|||||||
SDL_RenderSetClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr);
|
SDL_RenderSetClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by Init/NewFrame/Shutdown
|
void ImGui_ImplSDLRenderer2_UpdateTexture(ImTextureData* tex)
|
||||||
bool ImGui_ImplSDLRenderer2_CreateFontsTexture()
|
|
||||||
{
|
{
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
||||||
|
|
||||||
// Build texture atlas
|
if (tex->Status == ImTextureStatus_WantCreate)
|
||||||
unsigned char* pixels;
|
|
||||||
int width, height;
|
|
||||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.
|
|
||||||
|
|
||||||
// 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->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, width, height);
|
|
||||||
if (bd->FontTexture == nullptr)
|
|
||||||
{
|
{
|
||||||
SDL_Log("error creating texture");
|
// Create and upload new texture to graphics system
|
||||||
return false;
|
//IMGUI_DEBUG_LOG("UpdateTexture #%03d: WantCreate %dx%d\n", tex->UniqueID, tex->Width, tex->Height);
|
||||||
|
IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
|
||||||
|
IM_ASSERT(tex->Format == ImTextureFormat_RGBA32);
|
||||||
|
|
||||||
|
// Create texture
|
||||||
|
// (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
|
||||||
|
SDL_Texture* sdl_texture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STATIC, tex->Width, tex->Height);
|
||||||
|
IM_ASSERT(sdl_texture != nullptr && "Backend failed to create texture!");
|
||||||
|
SDL_UpdateTexture(sdl_texture, nullptr, tex->GetPixels(), tex->GetPitch());
|
||||||
|
SDL_SetTextureBlendMode(sdl_texture, SDL_BLENDMODE_BLEND);
|
||||||
|
SDL_SetTextureScaleMode(sdl_texture, SDL_ScaleModeLinear);
|
||||||
|
|
||||||
|
// Store identifiers
|
||||||
|
tex->SetTexID((ImTextureID)(intptr_t)sdl_texture);
|
||||||
|
tex->SetStatus(ImTextureStatus_OK);
|
||||||
}
|
}
|
||||||
SDL_UpdateTexture(bd->FontTexture, nullptr, pixels, 4 * width);
|
else if (tex->Status == ImTextureStatus_WantUpdates)
|
||||||
SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND);
|
|
||||||
SDL_SetTextureScaleMode(bd->FontTexture, SDL_ScaleModeLinear);
|
|
||||||
|
|
||||||
// Store our identifier
|
|
||||||
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_ImplSDLRenderer2_DestroyFontsTexture()
|
|
||||||
{
|
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
|
|
||||||
if (bd->FontTexture)
|
|
||||||
{
|
{
|
||||||
io.Fonts->SetTexID(0);
|
// Update selected blocks. We only ever write to textures regions which have never been used before!
|
||||||
SDL_DestroyTexture(bd->FontTexture);
|
// This backend choose to use tex->Updates[] but you can use tex->UpdateRect to upload a single region.
|
||||||
bd->FontTexture = nullptr;
|
SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID;
|
||||||
|
for (ImTextureRect& r : tex->Updates)
|
||||||
|
{
|
||||||
|
SDL_Rect sdl_r = { r.x, r.y, r.w, r.h };
|
||||||
|
SDL_UpdateTexture(sdl_texture, &sdl_r, tex->GetPixelsAt(r.x, r.y), tex->GetPitch());
|
||||||
|
}
|
||||||
|
tex->SetStatus(ImTextureStatus_OK);
|
||||||
|
}
|
||||||
|
else if (tex->Status == ImTextureStatus_WantDestroy)
|
||||||
|
{
|
||||||
|
SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID;
|
||||||
|
if (sdl_texture == nullptr)
|
||||||
|
return;
|
||||||
|
SDL_DestroyTexture(sdl_texture);
|
||||||
|
|
||||||
|
// Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running)
|
||||||
|
tex->SetTexID(ImTextureID_Invalid);
|
||||||
|
tex->SetStatus(ImTextureStatus_Destroyed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImGui_ImplSDLRenderer2_CreateDeviceObjects()
|
void ImGui_ImplSDLRenderer2_CreateDeviceObjects()
|
||||||
{
|
{
|
||||||
return ImGui_ImplSDLRenderer2_CreateFontsTexture();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_ImplSDLRenderer2_DestroyDeviceObjects()
|
void ImGui_ImplSDLRenderer2_DestroyDeviceObjects()
|
||||||
{
|
{
|
||||||
ImGui_ImplSDLRenderer2_DestroyFontsTexture();
|
// Destroy all textures
|
||||||
|
for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
|
||||||
|
if (tex->RefCount == 1)
|
||||||
|
{
|
||||||
|
tex->SetStatus(ImTextureStatus_WantDestroy);
|
||||||
|
ImGui_ImplSDLRenderer2_UpdateTexture(tex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@@ -10,8 +10,9 @@
|
|||||||
// and it might be difficult to step out of those boundaries.
|
// and it might be difficult to step out of those boundaries.
|
||||||
|
|
||||||
// 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 texture identifier. Read the FAQ about ImTextureID/ImTextureRef!
|
||||||
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
||||||
|
// [X] Renderer: Texture updates support for dynamic font system (ImGuiBackendFlags_RendererHasTextures).
|
||||||
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
// [X] Renderer: Expose selected render state for draw callbacks to use. Access in '(ImGui_ImplXXXX_RenderState*)GetPlatformIO().Renderer_RenderState'.
|
||||||
|
|
||||||
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
|
||||||
@@ -35,11 +36,12 @@ IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_NewFrame();
|
|||||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer);
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer);
|
||||||
|
|
||||||
// Called by Init/NewFrame/Shutdown
|
// Called by Init/NewFrame/Shutdown
|
||||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateFontsTexture();
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_CreateDeviceObjects();
|
||||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyFontsTexture();
|
|
||||||
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_CreateDeviceObjects();
|
|
||||||
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyDeviceObjects();
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_DestroyDeviceObjects();
|
||||||
|
|
||||||
|
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
|
||||||
|
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_UpdateTexture(ImTextureData* tex);
|
||||||
|
|
||||||
// [BETA] Selected render state data shared with callbacks.
|
// [BETA] Selected render state data shared with callbacks.
|
||||||
// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplSDLRenderer2_RenderDrawData() call.
|
// This is temporarily stored in GetPlatformIO().Renderer_RenderState during the ImGui_ImplSDLRenderer2_RenderDrawData() call.
|
||||||
// (Please open an issue if you feel you need access to more data)
|
// (Please open an issue if you feel you need access to more data)
|
||||||
|
Reference in New Issue
Block a user