From 862d4595afbd0b055bc494a583290453ff082911 Mon Sep 17 00:00:00 2001 From: Caerind Date: Fri, 6 Feb 2026 15:41:39 +0100 Subject: [PATCH 1/3] ImGuiBackend: RendererHasTextures --- imgui-SFML.cpp | 116 +++++++++++++++++++++++++++++++++---------------- imgui-SFML.h | 12 ++--- 2 files changed, 85 insertions(+), 43 deletions(-) diff --git a/imgui-SFML.cpp b/imgui-SFML.cpp index 70c9b18..9a91470 100644 --- a/imgui-SFML.cpp +++ b/imgui-SFML.cpp @@ -243,9 +243,6 @@ struct WindowContext const sf::Window* window; ImGuiContext* imContext{ImGui::CreateContext()}; - std::optional fontTexture; // internal font atlas which is used if user doesn't set - // a custom sf::Texture. - bool windowHasFocus; bool mouseMoved{false}; bool mousePressed[3] = {false}; @@ -291,17 +288,18 @@ namespace ImGui { namespace SFML { -bool Init(sf::RenderWindow& window, bool loadDefaultFont) + +bool Init(sf::RenderWindow& window) { - return Init(window, window, loadDefaultFont); + return Init(window, window); } -bool Init(sf::Window& window, sf::RenderTarget& target, bool loadDefaultFont) +bool Init(sf::Window& window, sf::RenderTarget& target) { - return Init(window, sf::Vector2f(target.getSize()), loadDefaultFont); + return Init(window, sf::Vector2f(target.getSize())); } -bool Init(sf::Window& window, const sf::Vector2f& displaySize, bool loadDefaultFont) +bool Init(sf::Window& window, const sf::Vector2f& displaySize) { s_currWindowCtx = s_windowContexts.emplace_back(std::make_unique(&window)).get(); ImGui::SetCurrentContext(s_currWindowCtx->imContext); @@ -313,6 +311,7 @@ bool Init(sf::Window& window, const sf::Vector2f& displaySize, bool loadDefaultF io.BackendFlags |= ImGuiBackendFlags_HasGamepad; io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos; + io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures; io.BackendPlatformName = "imgui_impl_sfml"; s_currWindowCtx->joystickId = getConnectedJoystickId(); @@ -338,13 +337,6 @@ bool Init(sf::Window& window, const sf::Vector2f& displaySize, bool loadDefaultF loadMouseCursor(ImGuiMouseCursor_ResizeNWSE, sf::Cursor::Type::SizeTopLeftBottomRight); loadMouseCursor(ImGuiMouseCursor_Hand, sf::Cursor::Type::Hand); - if (loadDefaultFont) - { - // this will load default font automatically - // No need to call AddDefaultFont - return UpdateFontTexture(); - } - return true; } @@ -550,8 +542,7 @@ void Update(const sf::Vector2i& mousePos, const sf::Vector2f& displaySize, sf::T #endif #endif - assert(io.Fonts->Fonts.Size > 0); // You forgot to create and set up font - // atlas (see createFontTexture) + assert(io.Fonts->Fonts.Size > 0); // You forgot to create and set up font atlas // gamepad navigation if ((io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) && s_currWindowCtx->joystickId != NULL_JOYSTICK_ID) @@ -588,6 +579,14 @@ void Render() void Shutdown(const sf::Window& window) { const bool needReplacement = (s_currWindowCtx->window->getNativeHandle() == window.getNativeHandle()); + + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + { + if (tex->RefCount == 1) + { + DestroyTexture(tex); + } + } // remove window's context auto found = std::find_if(s_windowContexts.begin(), @@ -619,43 +618,82 @@ void Shutdown(const sf::Window& window) void Shutdown() { + for (ImTextureData* tex : ImGui::GetPlatformIO().Textures) + { + if (tex->RefCount == 1) + { + DestroyTexture(tex); + } + } + s_currWindowCtx = nullptr; ImGui::SetCurrentContext(nullptr); s_windowContexts.clear(); } -bool UpdateFontTexture() +void UpdateTexture(ImTextureData* tex) { assert(s_currWindowCtx); + if (tex->Status == ImTextureStatus_WantCreate) + { + assert(tex->Format == ImTextureFormat_RGBA32); + assert(tex->BytesPerPixel == 4); - ImGuiIO& io = ImGui::GetIO(); - unsigned char* pixels = nullptr; - int width = 0; - int height = 0; + auto* texture = new sf::Texture(); + texture->create(tex->Width, tex->Height); + texture->setSmooth(true); + texture->setRepeated(false); - io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); + const uint8_t* src = (uint8_t*)tex->GetPixels(); + int pitch = tex->GetPitch(); + std::vector contiguous(tex->Width * tex->Height * 4); - sf::Texture newTexture; - if (!newTexture.resize(sf::Vector2u(sf::Vector2(width, height)))) - { - return false; + for (int y = 0; y < tex->Height; ++y) + memcpy(&contiguous[y * tex->Width * 4], src + y * pitch, tex->Width * 4); + + texture->update(contiguous.data()); + + tex->BackendUserData = texture; + tex->SetTexID(convertGLTextureHandleToImTextureID(texture->getNativeHandle())); + tex->SetStatus(ImTextureStatus_OK); } + else if (tex->Status == ImTextureStatus_WantUpdates) + { + assert(tex->BackendUserData != nullptr); - newTexture.update(pixels); + auto* texture = static_cast(tex->BackendUserData); + int pitch = tex->GetPitch(); - ImTextureID texID = convertGLTextureHandleToImTextureID(newTexture.getNativeHandle()); - io.Fonts->SetTexID(texID); + std::vector block; + for (ImTextureRect& r : tex->Updates) + { + block.clear(); + block.resize(r.w * r.h * 4); - s_currWindowCtx->fontTexture = std::move(newTexture); + const uint8_t* src = (uint8_t*)tex->GetPixelsAt(r.x, r.y); - return true; + for (int y = 0; y < r.h; ++y) + memcpy(&block[y * r.w * 4], src + y * pitch, r.w * 4); + + texture->update(block.data(), r.w, r.h, r.x, r.y); + } + + tex->SetStatus(ImTextureStatus_OK); + } + else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) + { + DestroyTexture(tex); + } } -std::optional& GetFontTexture() +void DestroyTexture(ImTextureData* tex) { - assert(s_currWindowCtx); - return s_currWindowCtx->fontTexture; + assert(tex->BackendUserData != nullptr); + delete tex->BackendUserData; + tex->BackendUserData = nullptr; + tex->SetTexID(ImTextureID_Invalid); + tex->SetStatus(ImTextureStatus_Destroyed); } void SetActiveJoystickId(unsigned int joystickId) @@ -946,14 +984,17 @@ void SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height) // Rendering callback void RenderDrawLists(ImDrawData* draw_data) { - ImGui::GetDrawData(); + if (draw_data->Textures != nullptr) + for (ImTextureData* tex : *draw_data->Textures) + if (tex->Status != ImTextureStatus_OK) + UpdateTexture(tex); + if (draw_data->CmdListsCount == 0) { return; } const ImGuiIO& io = ImGui::GetIO(); - assert(io.Fonts->TexID != (ImTextureID) nullptr); // You forgot to create and set font texture // Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != // framebuffer coordinates) @@ -963,7 +1004,6 @@ void RenderDrawLists(ImDrawData* draw_data) return; draw_data->ScaleClipRects(io.DisplayFramebufferScale); - // Backup GL state // Backup GL state GLint last_texture = 0; glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture); diff --git a/imgui-SFML.h b/imgui-SFML.h index ee873f6..ffc29fc 100644 --- a/imgui-SFML.h +++ b/imgui-SFML.h @@ -22,13 +22,15 @@ class Texture; class Window; } // namespace sf +struct ImTextureData; + namespace ImGui { namespace SFML { -[[nodiscard]] IMGUI_SFML_API bool Init(sf::RenderWindow& window, bool loadDefaultFont = true); -[[nodiscard]] IMGUI_SFML_API bool Init(sf::Window& window, sf::RenderTarget& target, bool loadDefaultFont = true); -[[nodiscard]] IMGUI_SFML_API bool Init(sf::Window& window, const sf::Vector2f& displaySize, bool loadDefaultFont = true); +[[nodiscard]] IMGUI_SFML_API bool Init(sf::RenderWindow& window); +[[nodiscard]] IMGUI_SFML_API bool Init(sf::Window& window, sf::RenderTarget& target); +[[nodiscard]] IMGUI_SFML_API bool Init(sf::Window& window, const sf::Vector2f& displaySize); IMGUI_SFML_API void SetCurrentWindow(const sf::Window& window); IMGUI_SFML_API void ProcessEvent(const sf::Window& window, const sf::Event& event); @@ -45,8 +47,8 @@ IMGUI_SFML_API void Shutdown(const sf::Window& window); // Shuts down all ImGui contexts IMGUI_SFML_API void Shutdown(); -[[nodiscard]] IMGUI_SFML_API bool UpdateFontTexture(); -IMGUI_SFML_API std::optional& GetFontTexture(); +IMGUI_SFML_API void UpdateTexture(ImTextureData* tex); +IMGUI_SFML_API void DestroyTexture(ImTextureData* tex); // joystick functions IMGUI_SFML_API void SetActiveJoystickId(unsigned int joystickId); From fcff789d9893dd3233344700a2066343a41dafef Mon Sep 17 00:00:00 2001 From: Caerind Date: Fri, 6 Feb 2026 16:06:18 +0100 Subject: [PATCH 2/3] Fix invalid delete --- imgui-SFML.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/imgui-SFML.cpp b/imgui-SFML.cpp index 9a91470..7415418 100644 --- a/imgui-SFML.cpp +++ b/imgui-SFML.cpp @@ -690,7 +690,8 @@ void UpdateTexture(ImTextureData* tex) void DestroyTexture(ImTextureData* tex) { assert(tex->BackendUserData != nullptr); - delete tex->BackendUserData; + auto* texture = static_cast(tex->BackendUserData); + delete texture; tex->BackendUserData = nullptr; tex->SetTexID(ImTextureID_Invalid); tex->SetStatus(ImTextureStatus_Destroyed); From a3eb3c1c80dca4ed63f95401fd654949f3c8d2ad Mon Sep 17 00:00:00 2001 From: Caerind Date: Fri, 6 Feb 2026 20:49:56 +0100 Subject: [PATCH 3/3] Added missing Texture API update --- imgui-SFML.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui-SFML.cpp b/imgui-SFML.cpp index 7415418..69d98ac 100644 --- a/imgui-SFML.cpp +++ b/imgui-SFML.cpp @@ -1081,7 +1081,7 @@ void RenderDrawLists(ImDrawData* draw_data) (int)(clip_rect.w - clip_rect.y)); // Bind texture, Draw - const GLuint textureHandle = convertImTextureIDToGLTextureHandle(pcmd->GetTexID()); + const GLuint textureHandle = convertImTextureIDToGLTextureHandle(pcmd->TexRef.GetTexID()); glBindTexture(GL_TEXTURE_2D, textureHandle); glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount,