mirror of
https://github.com/ocornut/imgui.git
synced 2025-04-16 18:25:01 +00:00
WIP - Fonts: encode additional data in ImFontAtlasRectId to detect invalid id + added Rects debug browser.
This commit is contained in:
parent
72bbb44dc5
commit
72ee77b919
4 changed files with 94 additions and 17 deletions
41
imgui.cpp
41
imgui.cpp
|
@ -21361,17 +21361,47 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
|
|||
Text("Packed rects: %d, area: about %d px ~%dx%d px", atlas->Builder->RectsPackedCount, atlas->Builder->RectsPackedSurface, packed_surface_sqrt, packed_surface_sqrt);
|
||||
Text("incl. Discarded rects: %d, area: about %d px ~%dx%d px", atlas->Builder->RectsDiscardedCount, atlas->Builder->RectsDiscardedSurface, discarded_surface_sqrt, discarded_surface_sqrt);
|
||||
|
||||
ImFontAtlasRectId highlight_r_id = ImFontAtlasRectId_Invalid;
|
||||
if (TreeNode("Rects Index", "Rects Index (%d)", atlas->Builder->RectsPackedCount)) // <-- Use count of used rectangles
|
||||
{
|
||||
PushStyleVar(ImGuiStyleVar_ImageBorderSize, 1.0f);
|
||||
if (BeginTable("##table", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_ScrollY, ImVec2(0.0f, GetTextLineHeightWithSpacing() * 12)))
|
||||
{
|
||||
for (const ImFontAtlasRectEntry& entry : atlas->Builder->RectsIndex)
|
||||
if (entry.IsUsed)
|
||||
{
|
||||
ImFontAtlasRectId id = ImFontAtlasRectId_Make(atlas->Builder->RectsIndex.index_from_ptr(&entry), entry.Generation);
|
||||
ImFontAtlasRect r = {};
|
||||
atlas->GetCustomRect(id, &r);
|
||||
const char* buf;
|
||||
ImFormatStringToTempBuffer(&buf, NULL, "ID:%08X, used:%d, { w:%3d, h:%3d } { x:%4d, y:%4d }", id, entry.IsUsed, r.w, r.h, r.x, r.y);
|
||||
TableNextColumn();
|
||||
Selectable(buf);
|
||||
if (IsItemHovered())
|
||||
highlight_r_id = id;
|
||||
TableNextColumn();
|
||||
Image(atlas->TexID, ImVec2(r.w, r.h), r.uv0, r.uv1);
|
||||
}
|
||||
EndTable();
|
||||
}
|
||||
PopStyleVar();
|
||||
TreePop();
|
||||
}
|
||||
|
||||
// Texture list
|
||||
// (ensure the last texture always use the same ID, so we can keep it open neatly)
|
||||
ImFontAtlasRect highlight_r;
|
||||
if (highlight_r_id != ImFontAtlasRectId_Invalid)
|
||||
atlas->GetCustomRect(highlight_r_id, &highlight_r);
|
||||
for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++)
|
||||
{
|
||||
if (tex_n == atlas->TexList.Size - 1)
|
||||
SetNextItemOpen(true, ImGuiCond_Once);
|
||||
DebugNodeTexture(atlas->TexList[tex_n], atlas->TexList.Size - 1 - tex_n);
|
||||
DebugNodeTexture(atlas->TexList[tex_n], atlas->TexList.Size - 1 - tex_n, (highlight_r_id != ImFontAtlasRectId_Invalid) ? &highlight_r : NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id)
|
||||
void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRect* highlight_rect)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
PushID(int_id);
|
||||
|
@ -21387,6 +21417,13 @@ void ImGui::DebugNodeTexture(ImTextureData* tex, int int_id)
|
|||
ImageWithBg(tex->GetTexRef(), ImVec2((float)tex->Width, (float)tex->Height), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), ImVec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
if (cfg->ShowTextureUsedRect)
|
||||
GetWindowDrawList()->AddRect(ImVec2(p.x + tex->UsedRect.x, p.y + tex->UsedRect.y), ImVec2(p.x + tex->UsedRect.x + tex->UsedRect.w, p.y + tex->UsedRect.y + tex->UsedRect.h), IM_COL32(255, 0, 255, 255));
|
||||
if (highlight_rect != NULL)
|
||||
{
|
||||
ImRect r_outer(p.x, p.y, p.x + tex->Width, p.y + tex->Height);
|
||||
ImRect r_inner(p.x + highlight_rect->x, p.y + highlight_rect->y, p.x + highlight_rect->x + highlight_rect->w, p.y + highlight_rect->y + highlight_rect->h);
|
||||
RenderRectFilledWithHole(GetWindowDrawList(), r_outer, r_inner, IM_COL32(0, 0, 0, 100), 0.0f);
|
||||
GetWindowDrawList()->AddRect(r_inner.Min - ImVec2(1, 1), r_inner.Max + ImVec2(1, 1), IM_COL32(255, 255, 0, 255));
|
||||
}
|
||||
PopStyleVar();
|
||||
|
||||
char texid_desc[20];
|
||||
|
|
2
imgui.h
2
imgui.h
|
@ -3616,7 +3616,7 @@ struct ImFontGlyphRangesBuilder
|
|||
IMGUI_API void BuildRanges(ImVector<ImWchar>* out_ranges); // Output new ranges
|
||||
};
|
||||
|
||||
// An identifier to a rectangle in the atlas. -1 when invalid.
|
||||
// An opaque identifier to a rectangle in the atlas. -1 when invalid.
|
||||
// The rectangle may move and UV may be invalidated, use GetCustomRect() to retrieve it.
|
||||
typedef int ImFontAtlasRectId;
|
||||
#define ImFontAtlasRectId_Invalid -1
|
||||
|
|
|
@ -3244,7 +3244,8 @@ ImFontAtlasRectId ImFontAtlas::AddCustomRect(int width, int height, ImFontAtlasR
|
|||
|
||||
void ImFontAtlas::RemoveCustomRect(ImFontAtlasRectId id)
|
||||
{
|
||||
IM_ASSERT(id != ImFontAtlasRectId_Invalid);
|
||||
if (ImFontAtlasPackGetRectSafe(this, id) == NULL)
|
||||
return;
|
||||
ImFontAtlasPackDiscardRect(this, id);
|
||||
}
|
||||
|
||||
|
@ -3300,10 +3301,12 @@ int ImFontAtlas::AddCustomRectFontGlyphForSize(ImFont* font, float font_size, Im
|
|||
|
||||
bool ImFontAtlas::GetCustomRect(ImFontAtlasRectId id, ImFontAtlasRect* out_r) const
|
||||
{
|
||||
ImTextureRect* r = ImFontAtlasPackGetRect((ImFontAtlas*)this, id);
|
||||
ImTextureRect* r = ImFontAtlasPackGetRectSafe((ImFontAtlas*)this, id);
|
||||
if (r == NULL)
|
||||
return false;
|
||||
IM_ASSERT(TexData->Width > 0 && TexData->Height > 0); // Font atlas needs to be built before we can calculate UV coordinates
|
||||
if (out_r == NULL)
|
||||
return true;
|
||||
out_r->x = r->x;
|
||||
out_r->y = r->y;
|
||||
out_r->w = r->w;
|
||||
|
@ -4007,7 +4010,7 @@ void ImFontAtlasBuildRepackTexture(ImFontAtlas* atlas, int w, int h)
|
|||
ImFontAtlasBuildGrowTexture(atlas, w, h); // Recurse
|
||||
return;
|
||||
}
|
||||
IM_ASSERT(new_r_id == builder->RectsIndex.index_from_ptr(&index_entry));
|
||||
IM_ASSERT(ImFontAtlasRectId_GetIndex(new_r_id) == builder->RectsIndex.index_from_ptr(&index_entry));
|
||||
ImTextureRect* new_r = ImFontAtlasPackGetRect(atlas, new_r_id);
|
||||
ImFontAtlasTextureBlockCopy(old_tex, old_r.x, old_r.y, new_tex, new_r->x, new_r->y, new_r->w, new_r->h);
|
||||
}
|
||||
|
@ -4236,17 +4239,18 @@ static ImFontAtlasRectId ImFontAtlasPackAllocRectEntry(ImFontAtlas* atlas, int r
|
|||
builder->RectsIndex.resize(builder->RectsIndex.Size + 1);
|
||||
index_idx = builder->RectsIndex.Size - 1;
|
||||
index_entry = &builder->RectsIndex[index_idx];
|
||||
memset(index_entry, 0, sizeof(*index_entry));
|
||||
}
|
||||
else
|
||||
{
|
||||
index_idx = builder->RectsIndexFreeListStart;
|
||||
index_entry = &builder->RectsIndex[index_idx];
|
||||
IM_ASSERT(index_entry->IsUsed == false);
|
||||
IM_ASSERT(index_entry->IsUsed == false && index_entry->Generation > 0); // Generation is incremented during DiscardRect
|
||||
builder->RectsIndexFreeListStart = index_entry->TargetIndex;
|
||||
}
|
||||
index_entry->TargetIndex = rect_idx;
|
||||
index_entry->IsUsed = 1;
|
||||
return (ImFontAtlasRectId)index_idx;
|
||||
return ImFontAtlasRectId_Make(index_idx, index_entry->Generation);
|
||||
}
|
||||
|
||||
// Overwrite existing entry
|
||||
|
@ -4254,23 +4258,29 @@ static ImFontAtlasRectId ImFontAtlasPackReuseRectEntry(ImFontAtlas* atlas, ImFon
|
|||
{
|
||||
IM_ASSERT(index_entry->IsUsed);
|
||||
index_entry->TargetIndex = atlas->Builder->Rects.Size - 1;
|
||||
return atlas->Builder->RectsIndex.index_from_ptr(index_entry);
|
||||
int index_idx = atlas->Builder->RectsIndex.index_from_ptr(index_entry);
|
||||
return ImFontAtlasRectId_Make(index_idx, index_entry->Generation);
|
||||
}
|
||||
|
||||
// This is expected to be called in batches and followed by a repack
|
||||
void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id)
|
||||
{
|
||||
IM_ASSERT(id != ImFontAtlasRectId_Invalid);
|
||||
ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
|
||||
ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id];
|
||||
IM_ASSERT(index_entry->IsUsed && index_entry->TargetIndex >= 0);
|
||||
|
||||
ImTextureRect* rect = ImFontAtlasPackGetRect(atlas, id);
|
||||
if (rect == NULL)
|
||||
return;
|
||||
|
||||
ImFontAtlasBuilder* builder = atlas->Builder;
|
||||
int index_idx = ImFontAtlasRectId_GetIndex(id);
|
||||
ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx];
|
||||
IM_ASSERT(index_entry->IsUsed && index_entry->TargetIndex >= 0);
|
||||
index_entry->IsUsed = false;
|
||||
index_entry->TargetIndex = builder->RectsIndexFreeListStart;
|
||||
index_entry->Generation++;
|
||||
|
||||
const int pack_padding = atlas->TexGlyphPadding;
|
||||
builder->RectsIndexFreeListStart = id;
|
||||
builder->RectsIndexFreeListStart = index_idx;
|
||||
builder->RectsDiscardedCount++;
|
||||
builder->RectsDiscardedSurface += (rect->w + pack_padding) * (rect->h + pack_padding);
|
||||
rect->w = rect->h = 0; // Clear rectangle so it won't be packed again
|
||||
|
@ -4325,16 +4335,36 @@ ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFon
|
|||
return ImFontAtlasPackAllocRectEntry(atlas, builder->Rects.Size - 1);
|
||||
}
|
||||
|
||||
// Important: return pointer is valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers.
|
||||
// Generally for non-user facing functions: assert on invalid ID.
|
||||
ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id)
|
||||
{
|
||||
IM_ASSERT(id != ImFontAtlasRectId_Invalid);
|
||||
int index_idx = ImFontAtlasRectId_GetIndex(id);
|
||||
int generation = ImFontAtlasRectId_GetGeneration(id);
|
||||
ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
|
||||
ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[id];
|
||||
ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx];
|
||||
IM_ASSERT(index_entry->Generation == generation);
|
||||
IM_ASSERT(index_entry->IsUsed);
|
||||
return &builder->Rects[index_entry->TargetIndex];
|
||||
}
|
||||
|
||||
// For user-facing functions: return NULL on invalid ID.
|
||||
// Important: return pointer is valid until next call to AddRect(), e.g. FindGlyph(), CalcTextSize() can all potentially invalidate previous pointers.
|
||||
ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId id)
|
||||
{
|
||||
if (id == ImFontAtlasRectId_Invalid)
|
||||
return NULL;
|
||||
int index_idx = ImFontAtlasRectId_GetIndex(id);
|
||||
int generation = ImFontAtlasRectId_GetGeneration(id);
|
||||
ImFontAtlasBuilder* builder = (ImFontAtlasBuilder*)atlas->Builder;
|
||||
if (index_idx >= builder->RectsIndex.Size)
|
||||
return NULL;
|
||||
ImFontAtlasRectEntry* index_entry = &builder->RectsIndex[index_idx];
|
||||
if (index_entry->Generation != generation || !index_entry->IsUsed)
|
||||
return NULL;
|
||||
return &builder->Rects[index_entry->TargetIndex];
|
||||
}
|
||||
|
||||
// Important! This assume by ImFontConfig::GlyphFilter is a SMALL ARRAY (e.g. <10 entries)
|
||||
static bool ImFontAtlasBuildAcceptCodepointForSource(ImFontConfig* src, ImWchar codepoint)
|
||||
{
|
||||
|
|
|
@ -3923,7 +3923,7 @@ namespace ImGui
|
|||
IMGUI_API void DebugNodeDrawCmdShowMeshAndBoundingBox(ImDrawList* out_draw_list, const ImDrawList* draw_list, const ImDrawCmd* draw_cmd, bool show_mesh, bool show_aabb);
|
||||
IMGUI_API void DebugNodeFont(ImFont* font);
|
||||
IMGUI_API void DebugNodeFontGlyph(ImFont* font, const ImFontGlyph* glyph);
|
||||
IMGUI_API void DebugNodeTexture(ImTextureData* tex, int int_id); // ID used to facilitate persisting the "current" texture.
|
||||
IMGUI_API void DebugNodeTexture(ImTextureData* tex, int int_id, const ImFontAtlasRect* highlight_rect = NULL); // ID used to facilitate persisting the "current" texture.
|
||||
IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label);
|
||||
IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label);
|
||||
IMGUI_API void DebugNodeTable(ImGuiTable* table);
|
||||
|
@ -3991,6 +3991,14 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype();
|
|||
// [SECTION] ImFontAtlas internal API
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Refer to ImFontAtlasPackGetRect() to better understand how this works.
|
||||
#define ImFontAtlasRectId_IndexMask_ (0x000FFFFF) // 20-bits: index to access builder->RectsIndex[].
|
||||
#define ImFontAtlasRectId_GenerationMask_ (0x3FF00000) // 10-bits: entry generation, so each ID is unique and get can safely detected old identifiers.
|
||||
#define ImFontAtlasRectId_GenerationShift_ (20)
|
||||
inline int ImFontAtlasRectId_GetIndex(ImFontAtlasRectId id) { return id & ImFontAtlasRectId_IndexMask_; }
|
||||
inline int ImFontAtlasRectId_GetGeneration(ImFontAtlasRectId id) { return (id & ImFontAtlasRectId_GenerationMask_) >> ImFontAtlasRectId_GenerationShift_; }
|
||||
inline ImFontAtlasRectId ImFontAtlasRectId_Make(int index_idx, int gen_idx) { IM_ASSERT(index_idx < ImFontAtlasRectId_IndexMask_ && gen_idx < (ImFontAtlasRectId_GenerationMask_ >> ImFontAtlasRectId_GenerationShift_)); return (ImFontAtlasRectId)(index_idx | (gen_idx << ImFontAtlasRectId_GenerationShift_)); }
|
||||
|
||||
// Packed rectangle lookup entry (we need an indirection to allow removing/reordering rectangles)
|
||||
// User are returned ImFontAtlasRectId values which are meant to be persistent.
|
||||
// We handle this with an indirection. While Rects[] may be in theory shuffled, compacted etc., RectsIndex[] cannot it is keyed by ImFontAtlasRectId.
|
||||
|
@ -3998,7 +4006,8 @@ IMGUI_API const ImFontLoader* ImFontAtlasGetFontLoaderForStbTruetype();
|
|||
// Having this also makes it easier to e.g. sort rectangles during repack.
|
||||
struct ImFontAtlasRectEntry
|
||||
{
|
||||
int TargetIndex : 31; // When Used: ImFontAtlasRectId -> into Rects[]. When unused: index to next unused RectsIndex[] slot to consume free-list.
|
||||
int TargetIndex : 20; // When Used: ImFontAtlasRectId -> into Rects[]. When unused: index to next unused RectsIndex[] slot to consume free-list.
|
||||
int Generation : 10; // Increased each time the entry is reused for a new rectangle.
|
||||
unsigned int IsUsed : 1;
|
||||
};
|
||||
|
||||
|
@ -4089,6 +4098,7 @@ IMGUI_API ImGuiID ImFontAtlasBakedGetId(ImGuiID font_id, float baked_s
|
|||
IMGUI_API void ImFontAtlasPackInit(ImFontAtlas* atlas);
|
||||
IMGUI_API ImFontAtlasRectId ImFontAtlasPackAddRect(ImFontAtlas* atlas, int w, int h, ImFontAtlasRectEntry* overwrite_entry = NULL);
|
||||
IMGUI_API ImTextureRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id);
|
||||
IMGUI_API ImTextureRect* ImFontAtlasPackGetRectSafe(ImFontAtlas* atlas, ImFontAtlasRectId id);
|
||||
IMGUI_API void ImFontAtlasPackDiscardRect(ImFontAtlas* atlas, ImFontAtlasRectId id);
|
||||
|
||||
IMGUI_API void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count);
|
||||
|
|
Loading…
Add table
Reference in a new issue