mirror of
https://github.com/ocornut/imgui.git
synced 2026-03-27 23:37:03 -05:00
Textures: Added atlas's TexMinWidth/TexMinHeight/TexMaxWidth/TexMaxHeight.
Fixed ImFontAtlasBuildGetTextureSizeEstimate(). Basic error handling on OOM.
This commit is contained in:
4
imgui.h
4
imgui.h
@@ -3596,6 +3596,10 @@ struct ImFontAtlas
|
|||||||
ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_)
|
ImFontAtlasFlags Flags; // Build flags (see ImFontAtlasFlags_)
|
||||||
ImTextureFormat TexDesiredFormat; // Desired texture format (default to ImTextureFormat_RGBA32 but may be changed to ImTextureFormat_Alpha8).
|
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 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).
|
void* UserData; // Store your own atlas related user-data (if e.g. you have multiple font atlas).
|
||||||
|
|
||||||
// [Internal]
|
// [Internal]
|
||||||
|
|||||||
@@ -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_UNUSED ((ImU16)-1) // 0xFFFF
|
||||||
#define IM_FONTGLYPH_INDEX_NOT_FOUND ((ImU16)-2) // 0xFFFE
|
#define IM_FONTGLYPH_INDEX_NOT_FOUND ((ImU16)-2) // 0xFFFE
|
||||||
#define IM_FONTATLAS_DEFAULT_TEXTURE_SIZE ImVec2i(512, 128)
|
|
||||||
|
|
||||||
ImFontAtlas::ImFontAtlas()
|
ImFontAtlas::ImFontAtlas()
|
||||||
{
|
{
|
||||||
memset(this, 0, sizeof(*this));
|
memset(this, 0, sizeof(*this));
|
||||||
TexDesiredFormat = ImTextureFormat_RGBA32;
|
TexDesiredFormat = ImTextureFormat_RGBA32;
|
||||||
TexGlyphPadding = 1;
|
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.
|
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;
|
TexRef._TexData = NULL;// this;
|
||||||
TexNextUniqueID = 1;
|
TexNextUniqueID = 1;
|
||||||
@@ -3248,7 +3251,7 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas)
|
|||||||
if (atlas->Sources.Size == 0)
|
if (atlas->Sources.Size == 0)
|
||||||
atlas->AddFontDefault();
|
atlas->AddFontDefault();
|
||||||
|
|
||||||
// [LEGACY] For backends not supporting RendererHasTexUpdates: preload all glyphs
|
// [LEGACY] For backends not supporting RendererHasTextures: preload all glyphs
|
||||||
ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas);
|
ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas);
|
||||||
if (atlas->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures
|
if (atlas->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures
|
||||||
ImFontAtlasBuildPreloadAllGlyphRanges(atlas);
|
ImFontAtlasBuildPreloadAllGlyphRanges(atlas);
|
||||||
@@ -3268,7 +3271,7 @@ void ImFontAtlasBuildSetupFontLoader(ImFontAtlas* atlas, const ImFontLoader* fon
|
|||||||
return;
|
return;
|
||||||
IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!");
|
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);
|
ImVec2i new_tex_size = ImFontAtlasBuildGetTextureSizeEstimate(atlas);
|
||||||
ImFontAtlasBuildDestroy(atlas);
|
ImFontAtlasBuildDestroy(atlas);
|
||||||
|
|
||||||
@@ -3390,6 +3393,8 @@ static void ImFontAtlasBuildUpdateBasicTexData(ImFontAtlas* atlas, bool add_and_
|
|||||||
|
|
||||||
if (add_and_draw)
|
if (add_and_draw)
|
||||||
builder->PackIdMouseCursors = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y);
|
builder->PackIdMouseCursors = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y);
|
||||||
|
if (builder->PackIdMouseCursors < 0)
|
||||||
|
return;
|
||||||
ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdMouseCursors);
|
ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdMouseCursors);
|
||||||
|
|
||||||
// Draw to texture
|
// Draw to texture
|
||||||
@@ -3424,6 +3429,8 @@ static void ImFontAtlasBuildUpdateLinesTexData(ImFontAtlas* atlas, bool add_and_
|
|||||||
ImFontAtlasBuilder* builder = atlas->Builder;
|
ImFontAtlasBuilder* builder = atlas->Builder;
|
||||||
if (add_and_draw)
|
if (add_and_draw)
|
||||||
builder->PackIdLinesTexData = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y);
|
builder->PackIdLinesTexData = ImFontAtlasPackAddRect(atlas, pack_size.x, pack_size.y);
|
||||||
|
if (builder->PackIdLinesTexData < 0)
|
||||||
|
return;
|
||||||
ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdLinesTexData);
|
ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, builder->PackIdLinesTexData);
|
||||||
|
|
||||||
// Register texture region for thick lines
|
// 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: What to do when reaching limits exposed by backend?
|
||||||
// FIXME-NEWATLAS-V2: does ImFontAtlasFlags_NoPowerOfTwoHeight makes sense now? Allow 'lock' and 'compact' operations?
|
// 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(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.
|
// Grow texture so it follows roughly a square.
|
||||||
// FIXME-NEWATLAS-V1: Take account of RectsDiscardedSurface: may not need to grow.
|
// 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;
|
const int pack_padding = atlas->TexGlyphPadding;
|
||||||
new_tex_w = ImMax(new_tex_w, ImUpperPowerOfTwo(builder->MaxRectSize.x + pack_padding));
|
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_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);
|
ImFontAtlasBuildRepackTexture(atlas, new_tex_w, new_tex_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME-NEWATLAS: Expose atlas->TexMinWidth etc.
|
|
||||||
ImVec2i ImFontAtlasBuildGetTextureSizeEstimate(ImFontAtlas* atlas)
|
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)
|
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;
|
ImFontAtlasBuilder* builder = atlas->Builder;
|
||||||
const int min_w = ImMax(builder->MaxRectSize.x, 512);
|
min_w = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.x), min_w);
|
||||||
const int min_h = builder->MaxRectSize.y;
|
min_h = ImMax(ImUpperPowerOfTwo(builder->MaxRectSize.y), min_h);
|
||||||
const int surface_approx = atlas->_PackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack
|
const int surface_approx = atlas->_PackedSurface - builder->RectsDiscardedSurface; // Expected surface after repack
|
||||||
const int surface_sqrt = (int)sqrtf((float)surface_approx);
|
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_h = ImUpperPowerOfTwo(new_tex_h);
|
||||||
new_tex_w = ImMax(min_w, (int)((surface_approx + new_tex_h - 1) / 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);
|
return ImVec2i(new_tex_w, new_tex_h);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3894,7 +3909,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas)
|
|||||||
}
|
}
|
||||||
// Create initial texture size
|
// Create initial texture size
|
||||||
if (atlas->TexData == NULL)
|
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);
|
const bool builder_is_new = (builder == NULL);
|
||||||
if (builder_is_new)
|
if (builder_is_new)
|
||||||
@@ -4051,6 +4066,7 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon
|
|||||||
|
|
||||||
ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id)
|
ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id)
|
||||||
{
|
{
|
||||||
|
IM_ASSERT(id >= 0);
|
||||||
ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
|
ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
|
||||||
ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id];
|
ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id];
|
||||||
IM_ASSERT(index_entry->Used);
|
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 w = (x1 - x0 + oversample_h - 1);
|
||||||
const int h = (y1 - y0 + oversample_v - 1);
|
const int h = (y1 - y0 + oversample_v - 1);
|
||||||
ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h);
|
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);
|
ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
|
||||||
font->MetricsTotalSurface += w * h;
|
font->MetricsTotalSurface += w * h;
|
||||||
|
|
||||||
|
|||||||
@@ -3696,7 +3696,7 @@ struct ImFontAtlasBuilder
|
|||||||
ImFontAtlasRectId PackIdMouseCursors; // White pixel + mouse cursors. Also happen to be fallback in case of packing failure.
|
ImFontAtlasRectId PackIdMouseCursors; // White pixel + mouse cursors. Also happen to be fallback in case of packing failure.
|
||||||
ImFontAtlasRectId PackIdLinesTexData;
|
ImFontAtlasRectId PackIdLinesTexData;
|
||||||
|
|
||||||
ImFontAtlasBuilder() { memset(this, 0, sizeof(*this)); RectsIndexFreeListStart = -1; }
|
ImFontAtlasBuilder() { memset(this, 0, sizeof(*this)); RectsIndexFreeListStart = -1; PackIdMouseCursors = PackIdLinesTexData = -1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME-NEWATLAS: Cleanup
|
// FIXME-NEWATLAS: Cleanup
|
||||||
|
|||||||
@@ -509,6 +509,13 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon
|
|||||||
if (is_visible)
|
if (is_visible)
|
||||||
{
|
{
|
||||||
ImFontAtlasRectId pack_id = ImFontAtlasPackAddRect(atlas, w, h);
|
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);
|
ImFontAtlasRect* r = ImFontAtlasPackGetRect(atlas, pack_id);
|
||||||
font->MetricsTotalSurface += w * h;
|
font->MetricsTotalSurface += w * h;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user