Fonts: Fixed support for multiple contexts.

This commit is contained in:
ocornut
2024-12-27 11:23:22 +01:00
committed by ocornut
parent cec3e945f0
commit a2bc3d81c2
4 changed files with 44 additions and 42 deletions

View File

@@ -5184,6 +5184,7 @@ static void ImGui::UpdateTexturesNewFrame()
// FIXME-NEWATLAS: How to reach/target all atlas? // FIXME-NEWATLAS: How to reach/target all atlas?
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImFontAtlas* atlas = g.IO.Fonts; ImFontAtlas* atlas = g.IO.Fonts;
if (g.FontAtlasOwnedByContext)
ImFontAtlasUpdateNewFrame(atlas); ImFontAtlasUpdateNewFrame(atlas);
} }
@@ -5245,7 +5246,7 @@ void ImGui::NewFrame()
if (!atlas->TexIsBuilt && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) if (!atlas->TexIsBuilt && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures))
ImFontAtlasBuildMain(atlas); ImFontAtlasBuildMain(atlas);
else // Legacy backend 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 // Check and assert for various common IO and Configuration mistakes
ErrorCheckNewFrameSanityChecks(); ErrorCheckNewFrameSanityChecks();
@@ -15615,7 +15616,7 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
if (TreeNode("Loader", "Loader: \'%s\'", atlas->FontLoaderName ? atlas->FontLoaderName : "NULL")) if (TreeNode("Loader", "Loader: \'%s\'", atlas->FontLoaderName ? atlas->FontLoaderName : "NULL"))
{ {
const ImFontLoader* loader_current = atlas->FontLoader; const ImFontLoader* loader_current = atlas->FontLoader;
BeginDisabled(!atlas->DrawListSharedData || !atlas->DrawListSharedData->RendererHasTextures); BeginDisabled(!atlas->RendererHasTextures);
#ifdef IMGUI_ENABLE_STB_TRUETYPE #ifdef IMGUI_ENABLE_STB_TRUETYPE
const ImFontLoader* loader_stbtruetype = ImFontAtlasGetFontLoaderForStbTruetype(); const ImFontLoader* loader_stbtruetype = ImFontAtlasGetFontLoaderForStbTruetype();
if (RadioButton("stb_truetype", loader_current == loader_stbtruetype)) if (RadioButton("stb_truetype", loader_current == loader_stbtruetype))

View File

@@ -3603,6 +3603,7 @@ struct ImFontAtlas
ImTextureData* TexData; // Current texture 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! 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 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 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. 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) 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. //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 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 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 // [Internal] Font builder
ImFontAtlasBuilder* Builder; // Opaque interface to our data that doesn't need to be public ImFontAtlasBuilder* Builder; // Opaque interface to our data that doesn't need to be public

View File

@@ -390,7 +390,6 @@ ImDrawListSharedData::ImDrawListSharedData()
ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a)); ArcFastVtx[i] = ImVec2(ImCos(a), ImSin(a));
} }
ArcFastRadiusCutoff = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC_R(IM_DRAWLIST_ARCFAST_SAMPLE_MAX, CircleSegmentMaxError); 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() ImDrawListSharedData::~ImDrawListSharedData()
@@ -2580,6 +2579,7 @@ ImFontAtlas::ImFontAtlas()
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
TexDesiredFormat = ImTextureFormat_RGBA32; TexDesiredFormat = ImTextureFormat_RGBA32;
TexGlyphPadding = 1; 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; TexRef._TexData = NULL;// this;
TexNextUniqueID = 1; TexNextUniqueID = 1;
Builder = NULL; Builder = NULL;
@@ -2637,10 +2637,10 @@ void ImFontAtlas::ClearFonts()
ClearInputData(); ClearInputData();
Fonts.clear_delete(); Fonts.clear_delete();
TexIsBuilt = false; TexIsBuilt = false;
if (DrawListSharedData) for (ImDrawListSharedData* shared_data : DrawListSharedDatas)
{ {
DrawListSharedData->Font = NULL; shared_data->Font = NULL;
DrawListSharedData->FontScale = DrawListSharedData->FontSize = 0.0f; 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. // 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(). // - 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. // Whereas conversely, the portion of people using ImDrawList without ImGui is expected to be pathologically rare.
if (atlas->DrawListSharedData) for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
if (ImGuiContext* imgui_ctx = atlas->DrawListSharedData->Context) if (ImGuiContext* imgui_ctx = shared_data->Context)
atlas->DrawListSharedData->RendererHasTextures = (imgui_ctx->IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; {
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) void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas)
{ {
if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges) if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges)
{ {
ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); 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()."); "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) // 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) 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) if (shared_data->Font == old_font)
shared_data->Font = new_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(width > 0 && width <= 0xFFFF);
IM_ASSERT(height > 0 && height <= 0xFFFF); IM_ASSERT(height > 0 && height <= 0xFFFF);
if (DrawListSharedData && DrawListSharedData->RendererHasTextures) if (RendererHasTextures)
{ {
ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height); ImFontAtlasRectId r_id = ImFontAtlasPackAddRect(this, width, height);
ImFontAtlasRect* r = ImFontAtlasPackGetRect(this, r_id); ImFontAtlasRect* r = ImFontAtlasPackGetRect(this, r_id);
@@ -3220,7 +3223,7 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas)
// [LEGACY] For backends not supporting RendererHasTexUpdates: preload all glyphs // [LEGACY] For backends not supporting RendererHasTexUpdates: preload all glyphs
ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas);
if (atlas->DrawListSharedData && atlas->DrawListSharedData->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures if (atlas->RendererHasTextures == false) // ~ImGuiBackendFlags_RendererHasTextures
ImFontAtlasBuildPreloadAllGlyphRanges(atlas); ImFontAtlasBuildPreloadAllGlyphRanges(atlas);
atlas->TexIsBuilt = true; atlas->TexIsBuilt = true;
} }
@@ -3578,24 +3581,22 @@ void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font)
// Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData* // Those functions are designed to facilitate changing the underlying structures for ImFontAtlas to store an array of ImDrawListSharedData*
void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data) void ImFontAtlasAddDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data)
{ {
IM_ASSERT(atlas->DrawListSharedData == NULL && data->FontAtlas == NULL); IM_ASSERT(!atlas->DrawListSharedDatas.contains(data) && data->FontAtlas == NULL);
atlas->DrawListSharedData = data; atlas->DrawListSharedDatas.push_back(data);
data->FontAtlas = atlas; data->FontAtlas = atlas;
} }
void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data) void ImFontAtlasRemoveDrawListSharedData(ImFontAtlas* atlas, ImDrawListSharedData* data)
{ {
IM_ASSERT(atlas->DrawListSharedData == data && data->FontAtlas == atlas); IM_ASSERT(atlas->DrawListSharedDatas.contains(data) && data->FontAtlas == atlas);
atlas->DrawListSharedData = data; atlas->DrawListSharedDatas.find_erase(data);
data->FontAtlas = NULL; data->FontAtlas = NULL;
} }
// Update texture identifier in all active draw lists // Update texture identifier in all active draw lists
void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex) void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex, ImTextureRef new_tex)
{ {
ImDrawListSharedData* shared_data = atlas->DrawListSharedData; for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
if (shared_data == NULL)
return;
for (ImDrawList* draw_list : shared_data->DrawLists) for (ImDrawList* draw_list : shared_data->DrawLists)
{ {
// Replace in command-buffer // Replace in command-buffer
@@ -3614,13 +3615,13 @@ void ImFontAtlasUpdateDrawListsTextures(ImFontAtlas* atlas, ImTextureRef old_tex
// Update texture coordinates in all draw list shared context // Update texture coordinates in all draw list shared context
void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas) void ImFontAtlasUpdateDrawListsSharedData(ImFontAtlas* atlas)
{ {
ImDrawListSharedData* shared_data = atlas->DrawListSharedData; for (ImDrawListSharedData* shared_data : atlas->DrawListSharedDatas)
if (shared_data == NULL) {
return;
shared_data->FontAtlas = atlas; shared_data->FontAtlas = atlas;
shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel; shared_data->TexUvWhitePixel = atlas->TexUvWhitePixel;
shared_data->TexUvLines = atlas->TexUvLines; shared_data->TexUvLines = atlas->TexUvLines;
} }
}
// Set current texture. This is mostly called from AddTexture() + to handle a failed resize. // Set current texture. This is mostly called from AddTexture() + to handle a failed resize.
static void ImFontAtlasBuildSetTexture(ImFontAtlas* atlas, ImTextureData* tex) static void ImFontAtlasBuildSetTexture(ImFontAtlas* atlas, ImTextureData* tex)

View File

@@ -821,7 +821,6 @@ struct IMGUI_API ImDrawListSharedData
ImVec2 ArcFastVtx[IM_DRAWLIST_ARCFAST_TABLE_SIZE]; // Sample points on the quarter of the circle. 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() 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) 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();
~ImDrawListSharedData(); ~ImDrawListSharedData();