Procházet zdrojové kódy

Textures: Added atlas's TexMinWidth/TexMinHeight/TexMaxWidth/TexMaxHeight.

Fixed ImFontAtlasBuildGetTextureSizeEstimate().
Basic error handling on OOM.
ocornut před 8 měsíci
rodič
revize
2137b3448b
4 změnil soubory, kde provedl 43 přidání a 9 odebrání
  1. 4 0
      imgui.h
  2. 31 8
      imgui_draw.cpp
  3. 1 1
      imgui_internal.h
  4. 7 0
      misc/freetype/imgui_freetype.cpp

+ 4 - 0
imgui.h

@@ -3596,6 +3596,10 @@ struct ImFontAtlas
     ImFontAtlasFlags            Flags;              // Build flags (see ImFontAtlasFlags_)
     ImTextureFormat             TexDesiredFormat;   // Desired texture format (default to ImTextureFormat_RGBA32 but may be changed to ImTextureFormat_Alpha8).
     int                         TexGlyphPadding;    // FIXME: Should be called "TexPackPadding". Padding between glyphs within texture in pixels. Defaults to 1. If your rendering method doesn't rely on bilinear filtering you may set this to 0 (will also need to set AntiAliasedLinesUseTex = false).
+    int                         TexMinWidth;        // Minimum desired texture width. Must be a power of two. Default to 512.
+    int                         TexMinHeight;       // Minimum desired texture height. Must be a power of two. Default to 128.
+    int                         TexMaxWidth;        // Maximum desired texture width. Must be a power of two. Default to 8192.
+    int                         TexMaxHeight;       // Maximum desired texture height. Must be a power of two. Default to 8192.
     void*                       UserData;           // Store your own atlas related user-data (if e.g. you have multiple font atlas).
 
     // [Internal]

+ 31 - 8
imgui_draw.cpp

@@ -2576,13 +2576,16 @@ static const ImVec2 FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[ImGuiMouseCursor_COUNT][3
 
 #define IM_FONTGLYPH_INDEX_UNUSED           ((ImU16)-1) // 0xFFFF
 #define IM_FONTGLYPH_INDEX_NOT_FOUND        ((ImU16)-2) // 0xFFFE
-#define IM_FONTATLAS_DEFAULT_TEXTURE_SIZE   ImVec2i(512, 128)
 
 ImFontAtlas::ImFontAtlas()
 {
     memset(this, 0, sizeof(*this));
     TexDesiredFormat = ImTextureFormat_RGBA32;
     TexGlyphPadding = 1;
+    TexMinWidth = 512;
+    TexMinHeight = 128;
+    TexMaxWidth = 8192;
+    TexMaxHeight = 8192;
     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;
@@ -3248,7 +3251,7 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas)
     if (atlas->Sources.Size == 0)
         atlas->AddFontDefault();
 
-    // [LEGACY] For backends not supporting RendererHasTexUpdates: preload all glyphs
+    // [LEGACY] For backends not supporting RendererHasTextures: preload all glyphs
     ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas);
     if (atlas->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures
         ImFontAtlasBuildPreloadAllGlyphRanges(atlas);
@@ -3268,7 +3271,7 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon
         return;
     IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!");
 
-    // Note that texture size estimate is likely incorrect in this situation, as Freetype backend doesn't use oversampling.
+    // Note that texture size estimate is likely incorrect in this situation, as FreeType backend doesn't use oversampling.
     ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas);
     ImFontAtlasBuildDestroy(atlas);
 
@@ -3390,6 +3393,8 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_
 
     if (add_and_draw)
         builder->PackIdMouseCursors = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y);
+    if (builder->PackIdMouseCursors < 0)
+        return;
     ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdMouseCursors);
 
     // Draw to texture
@@ -3424,6 +3429,8 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_
     ImFontAtlasBuilder* builder = atlas->Builder;
     if (add_and_draw)
         builder->PackIdLinesTexData = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y);
+    if (builder->PackIdLinesTexData < 0)
+        return;
     ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdLinesTexData);
 
     // Register texture region for thick lines
@@ -3813,6 +3820,7 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_
     // FIXME-NEWATLAS-V2: What to do when reaching limits exposed by backend?
     // FIXME-NEWATLAS-V2: does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations?
     IM_ASSERT(ImIsPowerOfTwo(old_tex_w) && ImIsPowerOfTwo(old_tex_h));
+    IM_ASSERT(ImIsPowerOfTwo(atlas->TexMinWidth) && ImIsPowerOfTwo(atlas->TexMaxWidth) && ImIsPowerOfTwo(atlas->TexMinHeight) && ImIsPowerOfTwo(atlas->TexMaxHeight));
 
     // Grow texture so it follows roughly a square.
     // FIXME-NEWATLAS-V1: Take account of RectsDiscardedSurface: may not need to grow.
@@ -3823,19 +3831,24 @@ void ImFontAtlasBuildGrowTexture(ImFontAtlas* atlas, int old_tex_w, int old_tex_
     const int pack_padding = atlas->TexGlyphPadding;
     new_tex_w = ImMax(new_tex_w, ImUpperPowerOfTwo(builder->MaxRectSize.x + pack_padding));
     new_tex_h = ImMax(new_tex_h, ImUpperPowerOfTwo(builder->MaxRectSize.y + pack_padding));
+    new_tex_w = ImClamp(new_tex_w, atlas->TexMinWidth, atlas->TexMaxWidth);
+    new_tex_h = ImClamp(new_tex_h, atlas->TexMinHeight, atlas->TexMaxHeight);
+    if (new_tex_w == old_tex_w && new_tex_h == old_tex_h)
+        return;
 
     ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h);
 }
 
-// FIXME-NEWATLAS: Expose atlas->TexMinWidth etc.
 ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas)
 {
+    int min_w = ImUpperPowerOfTwo(atlas->TexMinWidth);
+    int min_h = ImUpperPowerOfTwo(atlas->TexMinHeight);
     if (atlas->Builder == NULL || atlas->TexData == NULL || atlas->TexData->Status == ImTextureStatus_WantDestroy)
-        return IM_FONTATLAS_DEFAULT_TEXTURE_SIZE;
+        return ImVec2i(min_w, min_h);
 
     ImFontAtlasBuilder* builder = atlas->Builder;
-    const int min_w = ImMax(builder->MaxRectSize.x, 512);
-    const int min_h = builder->MaxRectSize.y;
+    min_w = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.x), min_w);
+    min_h = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.y), min_h);
     const int surface_approx = atlas->_PackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack
     const int surface_sqrt = (int)sqrtf((float)surface_approx);
 
@@ -3855,6 +3868,8 @@ ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas)
             new_tex_h = ImUpperPowerOfTwo(new_tex_h);
         new_tex_w = ImMax(min_w, (int)((surface_approx + new_tex_h - 1) / new_tex_h));
     }
+
+    IM_ASSERT(ImIsPowerOfTwo(new_tex_w) && ImIsPowerOfTwo(new_tex_h));
     return ImVec2i(new_tex_w, new_tex_h);
 }
 
@@ -3894,7 +3909,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas)
     }
     // Create initial texture size
     if (atlas->TexData == NULL)
-        ImFontAtlasBuildAddTexture(atlas, IM_FONTATLAS_DEFAULT_TEXTURE_SIZE.x, IM_FONTATLAS_DEFAULT_TEXTURE_SIZE.y);
+        ImFontAtlasBuildAddTexture(atlas, ImUpperPowerOfTwo(atlas->TexMinWidth), ImUpperPowerOfTwo(atlas->TexMinHeight));
 
     const bool builder_is_new = (builder == NULL);
     if (builder_is_new)
@@ -4051,6 +4066,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon
 
 ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id)
 {
+    IM_ASSERT(id >= 0);
     ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
     ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id];
     IM_ASSERT(index_entry->Used);
@@ -4255,6 +4271,13 @@ static bool ImGui_ImplStbTrueType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font,
         const int w = (x1 - x0 + oversample_h - 1);
         const int h = (y1 - y0 + oversample_v - 1);
         ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h);
+        if (pack_id < 0)
+        {
+            // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?)
+            IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory.");
+            return false;
+        }
+
         ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
         font->MetricsTotalSurface += w * h;
 

+ 1 - 1
imgui_internal.h

@@ -3696,7 +3696,7 @@ struct ImFontAtlasBuilder
     ImFontAtlasRectId           PackIdMouseCursors;     // White pixel + mouse cursors. Also happen to be fallback in case of packing failure.
     ImFontAtlasRectId           PackIdLinesTexData;
 
-    ImFontAtlasBuilder()        { memset(this, 0, sizeof(*this)); RectsIndexFreeListStart = -1; }
+    ImFontAtlasBuilder()        { memset(this, 0, sizeof(*this)); RectsIndexFreeListStart = -1; PackIdMouseCursors = PackIdLinesTexData = -1; }
 };
 
 // FIXME-NEWATLAS: Cleanup

+ 7 - 0
misc/freetype/imgui_freetype.cpp

@@ -509,6 +509,13 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon
     if (is_visible)
     {
         ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h);
+        if (pack_id < 0)
+        {
+            // Pathological out of memory case (TexMaxWidth/TexMaxHeight set too small?)
+            IM_ASSERT_USER_ERROR(pack_id >= 0, "Out of texture memory.");
+            return false;
+        }
+
         ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
         font->MetricsTotalSurface += w * h;