diff --git a/imgui.cpp b/imgui.cpp index 8f56e8956..3e261ddbb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -5335,13 +5335,16 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags(const ImVec2& mouse_pos) io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false; } +// FIXME-NEWATLAS-V2: If we aim to support multiple atlases used by same context: how to reach/target all atlases? static void ImGui::UpdateTexturesNewFrame() { - // FIXME-NEWATLAS-V2: If we aim to support multiple atlases used by same context: how to reach/target all atlases? ImGuiContext& g = *GImGui; ImFontAtlas* atlas = g.IO.Fonts; if (g.FontAtlasOwnedByContext) + { + atlas->RendererHasTextures = (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) != 0; ImFontAtlasUpdateNewFrame(atlas); + } } // Build a single texture list @@ -5397,13 +5400,6 @@ void ImGui::NewFrame() CallContextHooks(&g, ImGuiContextHookType_NewFramePre); - // Check that font atlas was built or backend support texture reload in which case we can build now - ImFontAtlas* atlas = g.IO.Fonts; - if (!atlas->TexIsBuilt && (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures)) - ImFontAtlasBuildMain(atlas); - else // Legacy backend - 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 g.ConfigFlagsLastFrame = g.ConfigFlagsCurrFrame; ErrorCheckNewFrameSanityChecks(); @@ -5437,11 +5433,7 @@ void ImGui::NewFrame() // Setup current font and draw list shared data if ((g.IO.BackendFlags & ImGuiBackendFlags_RendererHasTextures) == 0) - { g.IO.Fonts->Locked = true; - for (ImFont* font : g.IO.Fonts->Fonts) - font->LockDisableLoading = true; - } SetupDrawListSharedData(); SetCurrentFont(GetDefaultFont()); IM_ASSERT(g.Font->IsLoaded()); diff --git a/imgui.h b/imgui.h index 690f35263..c8c193244 100644 --- a/imgui.h +++ b/imgui.h @@ -3432,7 +3432,7 @@ struct ImDrawData }; //----------------------------------------------------------------------------- -// [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureDataUpdate, ImTextureData +// [SECTION] Texture API (ImTextureFormat, ImTextureStatus, ImTextureRect, ImTextureData //----------------------------------------------------------------------------- // We intentionally support a limited amount of texture formats to limit burden on CPU-side code and extension. @@ -3614,17 +3614,20 @@ struct ImFontAtlas IMGUI_API void ClearTexData(); // [OBSOLETE] Clear output texture data (CPU side). Saves RAM once the texture has been copied to graphics memory. #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - // Build atlas, retrieve pixel data. - // User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). - // The pitch is always = Width * BytesPerPixels (1 or 4) - // Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into - // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. - IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. - IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel - IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel - void SetTexID(ImTextureID id) { TexRef._TexData = NULL; TexRef._TexID = id; } // Called by legacy backends. - void SetTexID(ImTextureRef id) { TexRef = id; } // Called by legacy backends. - bool IsBuilt() const { return Fonts.Size > 0 && TexIsBuilt; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent... + // Legacy path for build atlas + retrieving pixel data. + // - User is in charge of copying the pixels into graphics memory (e.g. create a texture with your engine). Then store your texture handle with SetTexID(). + // - The pitch is always = Width * BytesPerPixels (1 or 4) + // - Building in RGBA32 format is provided for convenience and compatibility, but note that unless you manually manipulate or copy color data into + // the texture (e.g. when using the AddCustomRect*** api), then the RGB pixels emitted will always be white (~75% of memory/bandwidth waste. + // - From 1.92 with backends supporting ImGuiBackendFlags_RendererHasTextures: + // - Calling Build(), GetTexDataAsAlpha8(), GetTexDataAsRGBA32() is not needed. + // - In backend: replace calls to ImFontAtlas::SetTexID() with calls to ImTextureData::SetTexID() after honoring texture creation. + IMGUI_API bool Build(); // Build pixels data. This is called automatically for you by the GetTexData*** functions. + IMGUI_API void GetTexDataAsAlpha8(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 1 byte per-pixel + IMGUI_API void GetTexDataAsRGBA32(unsigned char** out_pixels, int* out_width, int* out_height, int* out_bytes_per_pixel = NULL); // 4 bytes-per-pixel + void SetTexID(ImTextureID id) { IM_ASSERT(TexRef._TexID == ImTextureID_Invalid); TexRef._TexData->TexID = id; } // Called by legacy backends. May be called before texture creation. + void SetTexID(ImTextureRef id) { IM_ASSERT(TexRef._TexID == ImTextureID_Invalid && id._TexData == NULL); TexRef._TexData->TexID = id._TexID; } // Called by legacy backends. + bool IsBuilt() const { return Fonts.Size > 0 && TexIsBuilt; } // Bit ambiguous: used to detect when user didn't build texture but effectively we should check TexID != 0 except that would be backend dependent.. #endif //------------------------------------------- @@ -3685,7 +3688,7 @@ struct ImFontAtlas ImVector TexList; // Texture list (most often TexList.Size == 1). TexData is always == TexList.back(). DO NOT USE DIRECTLY, USE 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 TexIsBuilt; // Set when texture was built matching current font input. Mostly useful for legacy IsBuilt() call. 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 TexUvWhitePixel; // Texture coordinates to a white pixel diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0faa5104f..34100d85b 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2487,6 +2487,7 @@ void ImTextureData::DestroyPixels() // - ImFontAtlas::CalcCustomRectUV() // - ImFontAtlasGetMouseCursorTexData() //----------------------------------------------------------------------------- +// - ImFontAtlasBuildMain() // - ImFontAtlasBuildSetupFontLoader() // - ImFontAtlasBuildPreloadAllGlyphRanges() // - ImFontAtlasBuildUpdatePointers() @@ -2687,15 +2688,24 @@ static void ImFontAtlasBuildUpdateRendererHasTexturesFromContext(ImFontAtlas* at } // Called by NewFrame(). When multiple context own the atlas, only the first one calls this. +// If you are calling this yourself, ensure atlas->RendererHasTexUpdates is et. void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas) { - if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges) + // Check that font atlas was built or backend support texture reload in which case we can build now + if (atlas->RendererHasTextures) { - ImFontAtlasBuildUpdateRendererHasTexturesFromContext(atlas); - 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()."); + atlas->TexIsBuilt = true; + if (atlas->Builder == NULL) // This will only happen if fonts were not already loaded. + ImFontAtlasBuildMain(atlas); } + else // Legacy backend + { + IM_ASSERT_USER_ERROR(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()."); + } + if (atlas->TexIsBuilt && atlas->Builder->PreloadedAllGlyphsRanges) + 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()."); + // Update texture status for (int tex_n = 0; tex_n < atlas->TexList.Size; tex_n++) { ImTextureData* tex = atlas->TexList[tex_n]; @@ -2868,6 +2878,7 @@ void ImFontAtlasTextureBlockQueueUpload(ImFontAtlas* atlas, ImTextureData* tex, tex->UpdateRect.y = ImMin(tex->UpdateRect.y, req.y); tex->UpdateRect.w = (unsigned short)(new_x1 - tex->UpdateRect.x); tex->UpdateRect.h = (unsigned short)(new_y1 - tex->UpdateRect.y); + atlas->TexIsBuilt = false; // No need to queue if status is _WantCreate if (tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantUpdates) @@ -3209,6 +3220,7 @@ bool ImFontAtlasGetMouseCursorTexData(ImFontAtlas* atlas, ImGuiMouseCursor curso return true; } +// When atlas->RendererHasTexUpdates == true, this is only called if no font were loaded. void ImFontAtlasBuildMain(ImFontAtlas* atlas) { IM_ASSERT(!atlas->Locked && "Cannot modify a locked ImFontAtlas!"); @@ -3592,6 +3604,7 @@ void ImFontAtlasBuildReloadFont(ImFontAtlas* atlas, ImFont* font) atlas->FontLoader->FontSrcInit(atlas, src); ImFontAtlasBuildSetupFontSpecialGlyphs(atlas, src); // Technically this is called for each source sub-font, tho 99.9% of the time the first one fills everything. + atlas->TexIsBuilt = false; } // Notify external systems @@ -3687,6 +3700,7 @@ ImTextureData* ImFontAtlasBuildAddTexture(ImFontAtlas* atlas, int w, int h) new_tex->Create(atlas->TexDesiredFormat, w, h); new_tex->Status = ImTextureStatus_WantCreate; + atlas->TexIsBuilt = false; ImFontAtlasBuildSetTexture(atlas, new_tex); @@ -4040,12 +4054,12 @@ ImFontAtlasRect* ImFontAtlasPackGetRect(ImFontAtlas* atlas, ImFontAtlasRectId id ImFontGlyph* ImFont::BuildLoadGlyph(ImWchar codepoint) { - if (LockDisableLoading) + ImFontAtlas* atlas = ContainerAtlas; + if (LockDisableLoading || atlas->Locked) return NULL; //char utf8_buf[5]; //IMGUI_DEBUG_LOG("[font] BuildAddGlyph U+%04X (%s)\n", (unsigned int)codepoint, ImTextCharToUtf8(utf8_buf, (unsigned int)codepoint)); - ImFontAtlas* atlas = ContainerAtlas; // Load from single source or all sources? int srcs_count = (LockSingleSrcConfigIdx != -1) ? 1 : SourcesCount;