Browse Source

Fonts: Fixed support for multiple contexts.

ocornut 8 months ago
parent
commit
a2bc3d81c2
4 changed files with 45 additions and 43 deletions
  1. 4 3
      imgui.cpp
  2. 2 1
      imgui.h
  3. 39 38
      imgui_draw.cpp
  4. 0 1
      imgui_internal.h

+ 4 - 3
imgui.cpp

@@ -5184,7 +5184,8 @@ static void ImGui::UpdateTexturesNewFrame()
     // FIXME-NEWATLAS: How to reach/target all atlas?
     ImGuiContext& g = *GImGui;
     ImFontAtlas* atlas = g.IO.Fonts;
-    ImFontAtlasUpdateNewFrame(atlas);
+    if (g.FontAtlasOwnedByContext)
+        ImFontAtlasUpdateNewFrame(atlas);
 }
 
 // Build a single texture list
@@ -5245,7 +5246,7 @@ void ImGui::NewFrame()
     if (!atlas->TexIsBuilt && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures))
         ImFontAtlasBuildMain(atlas);
     else // Legacy backend
-        IM_ASSERT(atlas->TexIsBuilt && "Backend does not support ImGuiBackendFlags_RendererHasTexUpdates, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8().");
+        IM_ASSERT(atlas->TexIsBuilt && "Backend does not support ImGuiBackendFlags_RendererHasTextures, and font atlas is not built! Update backend OR make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8().");
 
     // Check and assert for various common IO and Configuration mistakes
     ErrorCheckNewFrameSanityChecks();
@@ -15615,7 +15616,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
     if (TreeNode("Loader", "Loader: \'%s\'", atlas->FontLoaderName ? atlas->FontLoaderName : "NULL"))
     {
         const ImFontLoader* loader_current = atlas->FontLoader;
-        BeginDisabled(!atlas->DrawListSharedData || !atlas->DrawListSharedData->RendererHasTextures);
+        BeginDisabled(!atlas->RendererHasTextures);
 #ifdef IMGUI_ENABLE_STB_TRUETYPE
         const ImFontLoader* loader_stbtruetype = ImFontAtlasGetFontLoaderForStbTruetype();
         if (RadioButton("stb_truetype", loader_current == loader_stbtruetype))

+ 2 - 1
imgui.h

@@ -3603,6 +3603,7 @@ struct ImFontAtlas
     ImTextureData*              TexData;            // Current texture
     ImVector<ImTextureData*>    TexList;            // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE GetDrawData().Textures[]/GetPlatformIO().Textures[] instead!
     bool                        Locked;             // Marked as Locked by ImGui::NewFrame() so attempt to modify the atlas will assert.
+    bool                        RendererHasTextures;// Copy of (BackendFlags & ImGuiBackendFlags_RendererHasTextures) from supporting context.
     bool                        TexIsBuilt;         // Set when texture was built matching current font input
     bool                        TexPixelsUseColors; // Tell whether our texture data is known to use colors (rather than just alpha channel), in order to help backend select a format or conversion process.
     ImVec2                      TexUvScale;         // = (1.0f/TexData->TexWidth, 1.0f/TexData->TexHeight)
@@ -3612,7 +3613,7 @@ struct ImFontAtlas
     //ImVector<ImFontAtlasCustomRect> CustomRects;  // Rectangles for packing custom texture data into the atlas.
     ImVec4                      TexUvLines[IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1];  // UVs for baked anti-aliased lines
     int                         TexNextUniqueID;    // Next value to be stored in TexData->UniqueID
-    ImDrawListSharedData*       DrawListSharedData; // In principle this could become an array (e.g. multiple contexts using same atlas)
+    ImVector<ImDrawListSharedData*> DrawListSharedDatas;
 
     // [Internal] Font builder
     ImFontAtlasBuilder*         Builder;            // Opaque interface to our data that doesn't need to be public

+ 39 - 38
imgui_draw.cpp

@@ -390,7 +390,6 @@ ImDrawListSharedData::ImDrawListSharedData()
         ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a));
     }
     ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError);
-    RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update.
 }
 
 ImDrawListSharedData::~ImDrawListSharedData()
@@ -2580,6 +2579,7 @@ ImFontAtlas::ImFontAtlas()
     memset(this, 0, sizeof(*this));
     TexDesiredFormat = ImTextureFormat_RGBA32;
     TexGlyphPadding = 1;
+    RendererHasTextures = false; // Assumed false by default, as apps can call e.g Atlas::Build() after backend init and before ImGui can update.
     TexRef._TexData = NULL;// this;
     TexNextUniqueID = 1;
     Builder = NULL;
@@ -2637,10 +2637,10 @@ void ImFontAtlas::ClearFonts()
     ClearInputData();
     Fonts.clear_delete();
     TexIsBuilt = false;
-    if (DrawListSharedData)
+    for (ImDrawListSharedData* shared_data : DrawListSharedDatas)
     {
-        DrawListSharedData->Font = NULL;
-        DrawListSharedData->FontScale = DrawListSharedData->FontSize = 0.0f;
+        shared_data->Font = NULL;
+        shared_data->FontScale = shared_data->FontSize = 0.0f;
     }
 }
 
@@ -2681,18 +2681,21 @@ static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* at
     //   time of an early call to Build(), it would be impossible for us to tell if the backend supports texture update.
     // - Without this hack, we would have quite a pitfall as many legacy codebases have an early call to Build().
     //   Whereas conversely, the portion of people using ImDrawList without ImGui is expected to be pathologically rare.
-    if (atlas->DrawListSharedData)
-        if (ImGuiContext* imgui_ctx = atlas->DrawListSharedData->Context)
-            atlas->DrawListSharedData->RendererHasTextures = (imgui_ctx->IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0;
+    for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
+        if (ImGuiContext* imgui_ctx = shared_data->Context)
+        {
+            atlas->RendererHasTextures = (imgui_ctx->IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0;
+            break;
+        }
 }
 
-// Called by NewFrame()
+// Called by NewFrame(). When multiple context own the atlas, only the first one calls this.
 void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas)
 {
     if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges)
     {
         ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas);
-        IM_ASSERT_USER_ERROR(atlas->DrawListSharedData->RendererHasTextures == false,
+        IM_ASSERT_USER_ERROR(atlas->RendererHasTextures == false,
             "Called ImFontAtlas::Build() before ImGuiBackendFlags_RendererHasTextures got set! With new backends: you don't need to call Build().");
     }
 
@@ -3050,7 +3053,7 @@ ImFont* ImFontAtlas::AddFontFromMemoryCompressedBase85TTF(const char* compressed
 // We allow old_font == new_font which forces updating all values (e.g. sizes)
 static void ImFontAtlasBuildNotifySetFont(ImFontAtlas* atlas, ImFont* old_font, ImFont* new_font)
 {
-    if (ImDrawListSharedData* shared_data = atlas->DrawListSharedData)
+    for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
     {
         if (shared_data->Font == old_font)
             shared_data->Font = new_font;
@@ -3124,7 +3127,7 @@ int ImFontAtlas::AddCustomRectRegular(int width, int height)
     IM_ASSERT(width > 0 && width <= 0xFFFF);
     IM_ASSERT(height > 0 && height <= 0xFFFF);
 
-    if (DrawListSharedData && DrawListSharedData->RendererHasTextures)
+    if (RendererHasTextures)
     {
         ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height);
         ImFontAtlasRect* r = ImFontAtlasPackGetRect(this, r_id);
@@ -3220,7 +3223,7 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas)
 
     // [LEGACY] For backends not supporting RendererHasTexUpdates: preload all glyphs
     ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas);
-    if (atlas->DrawListSharedData && atlas->DrawListSharedData->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures
+    if (atlas->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures
         ImFontAtlasBuildPreloadAllGlyphRanges(atlas);
     atlas->TexIsBuilt = true;
 }
@@ -3578,48 +3581,46 @@ void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font)
 // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData*
 void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data)
 {
-    IM_ASSERT(atlas->DrawListSharedData == NULL && data->FontAtlas == NULL);
-    atlas->DrawListSharedData = data;
+    IM_ASSERT(!atlas->DrawListSharedDatas.contains(data) && data->FontAtlas == NULL);
+    atlas->DrawListSharedDatas.push_back(data);
     data->FontAtlas = atlas;
 }
 
 void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data)
 {
-    IM_ASSERT(atlas->DrawListSharedData == data && data->FontAtlas == atlas);
-    atlas->DrawListSharedData = data;
+    IM_ASSERT(atlas->DrawListSharedDatas.contains(data) && data->FontAtlas == atlas);
+    atlas->DrawListSharedDatas.find_erase(data);
     data->FontAtlas = NULL;
 }
 
 // Update texture identifier in all active draw lists
 void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex)
 {
-    ImDrawListSharedData* shared_data = atlas->DrawListSharedData;
-    if (shared_data == NULL)
-        return;
-    for (ImDrawList* draw_list : shared_data->DrawLists)
-    {
-        // Replace in command-buffer
-        // (there is not need to replace in ImDrawListSplitter: current channel is in ImDrawList's CmdBuffer[],
-        //  other channels will be on SetCurrentChannel() which already needs to compare CmdHeader anyhow)
-        if (draw_list->CmdBuffer.Size > 0 && draw_list->_CmdHeader.TexRef == old_tex)
-            draw_list->_SetTexture(new_tex);
-
-        // Replace in stack
-        for (ImTextureRef& stacked_tex : draw_list->_TextureStack)
-            if (stacked_tex == old_tex)
-                stacked_tex = new_tex;
-    }
+    for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
+        for (ImDrawList* draw_list : shared_data->DrawLists)
+        {
+            // Replace in command-buffer
+            // (there is not need to replace in ImDrawListSplitter: current channel is in ImDrawList's CmdBuffer[],
+            //  other channels will be on SetCurrentChannel() which already needs to compare CmdHeader anyhow)
+            if (draw_list->CmdBuffer.Size > 0 && draw_list->_CmdHeader.TexRef == old_tex)
+                draw_list->_SetTexture(new_tex);
+
+            // Replace in stack
+            for (ImTextureRef& stacked_tex : draw_list->_TextureStack)
+                if (stacked_tex == old_tex)
+                    stacked_tex = new_tex;
+        }
 }
 
 // Update texture coordinates in all draw list shared context
 void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas)
 {
-    ImDrawListSharedData* shared_data = atlas->DrawListSharedData;
-    if (shared_data == NULL)
-        return;
-    shared_data->FontAtlas = atlas;
-    shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel;
-    shared_data->TexUvLines = atlas->TexUvLines;
+    for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
+    {
+        shared_data->FontAtlas = atlas;
+        shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel;
+        shared_data->TexUvLines = atlas->TexUvLines;
+    }
 }
 
 // Set current texture. This is mostly called from AddTexture() + to handle a failed resize.

+ 0 - 1
imgui_internal.h

@@ -821,7 +821,6 @@ struct IMGUI_API ImDrawListSharedData
     ImVec2          ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle.
     float           ArcFastRadiusCutoff;                        // Cutoff radius after which arc drawing will fallback to slower PathArcTo()
     ImU8            CircleSegmentCounts[64];    // Precomputed segment count for given radius before we calculate it dynamically (to avoid calculation overhead)
-    bool            RendererHasTextures;        // Copy of (GetIO().BackendFlags & ImGuiBackendFlags_RendererHasTextures).
 
     ImDrawListSharedData();
     ~ImDrawListSharedData();