mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-11-03 22:51:06 +01:00 
			
		
		
		
	ImFontAtlas: Rewrote stb_truetype based builder.
- Atlas width is now properly based on total surface rather than glyph count (unless overridden with TexDesiredWidth). - Fixed atlas builder so missing glyphs won't influence the atlas texture width. (#2233) - Fixed atlas builder so duplicate glyphs (when merging fonts) won't be included in the rasterized atlas.
This commit is contained in:
		@@ -72,6 +72,9 @@ Other Changes:
 | 
				
			|||||||
  Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen.
 | 
					  Missing calls to End(), past the assert, should not lead to crashes or to the fallback Debug window appearing on screen.
 | 
				
			||||||
  Those changes makes it easier to integrate dear imgui with a scripting language allowing, given asserts are redirected
 | 
					  Those changes makes it easier to integrate dear imgui with a scripting language allowing, given asserts are redirected
 | 
				
			||||||
  into e.g. an error log and stopping the script execution.
 | 
					  into e.g. an error log and stopping the script execution.
 | 
				
			||||||
 | 
					- ImFontAtlas: Stb: Atlas width is now properly based on total surface rather than glyph count (unless overridden with TexDesiredWidth).
 | 
				
			||||||
 | 
					- ImFontAtlas: Stb: Fixed atlas builder so missing glyphs won't influence the atlas texture width. (#2233)
 | 
				
			||||||
 | 
					- ImFontAtlas: Stb: Fixed atlas builder so duplicate glyphs (when merging fonts) won't be included in the rasterized atlas.
 | 
				
			||||||
- ImDrawList: Optimized some of the functions for performance of debug builds where non-inline function call cost are non-negligible.
 | 
					- ImDrawList: Optimized some of the functions for performance of debug builds where non-inline function call cost are non-negligible.
 | 
				
			||||||
  (Our test UI scene on VS2015 Debug Win64 with /RTC1 went ~5.9 ms -> ~4.9 ms. In Release same scene stays at ~0.3 ms.)
 | 
					  (Our test UI scene on VS2015 Debug Win64 with /RTC1 went ~5.9 ms -> ~4.9 ms. In Release same scene stays at ~0.3 ms.)
 | 
				
			||||||
- IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends.
 | 
					- IO: Added BackendPlatformUserData, BackendRendererUserData, BackendLanguageUserData void* for storage use by back-ends.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -235,9 +235,7 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
 | 
				
			|||||||
 - pie menus patterns (#434)
 | 
					 - pie menus patterns (#434)
 | 
				
			||||||
 - markup: simple markup language for color change? (#902)
 | 
					 - markup: simple markup language for color change? (#902)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
!- font: need handling of missing glyphs by not packing/rasterizing glyph 0 of a given font.
 | 
					 - font: MergeMode: flags to select overwriting or not (this is now very easy with refactored ImFontAtlasBuildWithStbTruetype)
 | 
				
			||||||
 - font: MergeMode: flags to select overwriting or not.
 | 
					 | 
				
			||||||
 - font: MergeMode: duplicate glyphs are stored in the atlas texture which is suboptimal.
 | 
					 | 
				
			||||||
 - font: free the Alpha buffer if user only requested RGBA.
 | 
					 - font: free the Alpha buffer if user only requested RGBA.
 | 
				
			||||||
!- font: better CalcTextSizeA() API, at least for simple use cases. current one is horrible (perhaps have simple vs extended versions).
 | 
					!- font: better CalcTextSizeA() API, at least for simple use cases. current one is horrible (perhaps have simple vs extended versions).
 | 
				
			||||||
 - font: a CalcTextHeight() helper could run faster than CalcTextSize().y
 | 
					 - font: a CalcTextHeight() helper could run faster than CalcTextSize().y
 | 
				
			||||||
@@ -252,7 +250,6 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i
 | 
				
			|||||||
 - font/draw: vertical and/or rotated text renderer (#705) - vertical is easier clipping wise
 | 
					 - font/draw: vertical and/or rotated text renderer (#705) - vertical is easier clipping wise
 | 
				
			||||||
 - font/draw: need to be able to specify wrap start position.
 | 
					 - font/draw: need to be able to specify wrap start position.
 | 
				
			||||||
 - font/draw: better reserve policy for large horizontal block of text (shouldn't reserve for all clipped lines)
 | 
					 - font/draw: better reserve policy for large horizontal block of text (shouldn't reserve for all clipped lines)
 | 
				
			||||||
 - font: imgui_freetype.h alternative renderer (#618)
 | 
					 | 
				
			||||||
 - font: optimization: for monospace font (like the default one) we can trim IndexXAdvance as long as trailing value is == FallbackXAdvance (need to make sure TAB is still correct).
 | 
					 - font: optimization: for monospace font (like the default one) we can trim IndexXAdvance as long as trailing value is == FallbackXAdvance (need to make sure TAB is still correct).
 | 
				
			||||||
 - font: add support for kerning, probably optional. A) perhaps default to (32..128)^2 matrix ~ 9K entries = 36KB, then hash for non-ascii?. B) or sparse lookup into per-char list?
 | 
					 - font: add support for kerning, probably optional. A) perhaps default to (32..128)^2 matrix ~ 9K entries = 36KB, then hash for non-ascii?. B) or sparse lookup into per-char list?
 | 
				
			||||||
 - font: add a simpler CalcTextSizeA() api? current one ok but not welcome if user needs to call it directly (without going through ImGui::CalcTextSize)
 | 
					 - font: add a simpler CalcTextSizeA() api? current one ok but not welcome if user needs to call it directly (without going through ImGui::CalcTextSize)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								imgui.h
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								imgui.h
									
									
									
									
									
								
							@@ -2047,7 +2047,7 @@ struct ImFontAtlas
 | 
				
			|||||||
    ImFontAtlasFlags            Flags;              // Build flags (see ImFontAtlasFlags_)
 | 
					    ImFontAtlasFlags            Flags;              // Build flags (see ImFontAtlasFlags_)
 | 
				
			||||||
    ImTextureID                 TexID;              // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure.
 | 
					    ImTextureID                 TexID;              // User data to refer to the texture once it has been uploaded to user's graphic systems. It is passed back to you during rendering via the ImDrawCmd structure.
 | 
				
			||||||
    int                         TexDesiredWidth;    // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
 | 
					    int                         TexDesiredWidth;    // Texture width desired by user before Build(). Must be a power-of-two. If have many glyphs your graphics API have texture size restrictions you may want to increase texture width to decrease height.
 | 
				
			||||||
    int                         TexGlyphPadding;    // Padding between glyphs within texture in pixels. Defaults to 1.
 | 
					    int                         TexGlyphPadding;    // 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // [Internal]
 | 
					    // [Internal]
 | 
				
			||||||
    // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you.
 | 
					    // NB: Access texture data via GetTexData*() calls! Which will setup a default font for you.
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										388
									
								
								imgui_draw.cpp
									
									
									
									
									
								
							
							
						
						
									
										388
									
								
								imgui_draw.cpp
									
									
									
									
									
								
							@@ -1541,11 +1541,11 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
 | 
				
			|||||||
    if (!font_cfg->MergeMode)
 | 
					    if (!font_cfg->MergeMode)
 | 
				
			||||||
        Fonts.push_back(IM_NEW(ImFont));
 | 
					        Fonts.push_back(IM_NEW(ImFont));
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        IM_ASSERT(!Fonts.empty()); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
 | 
					        IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ConfigData.push_back(*font_cfg);
 | 
					    ConfigData.push_back(*font_cfg);
 | 
				
			||||||
    ImFontConfig& new_font_cfg = ConfigData.back();
 | 
					    ImFontConfig& new_font_cfg = ConfigData.back();
 | 
				
			||||||
    if (!new_font_cfg.DstFont)
 | 
					    if (new_font_cfg.DstFont == NULL)
 | 
				
			||||||
        new_font_cfg.DstFont = Fonts.back();
 | 
					        new_font_cfg.DstFont = Fonts.back();
 | 
				
			||||||
    if (!new_font_cfg.FontDataOwnedByAtlas)
 | 
					    if (!new_font_cfg.FontDataOwnedByAtlas)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@@ -1733,139 +1733,220 @@ void    ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsig
 | 
				
			|||||||
            data[i] = table[data[i]];
 | 
					            data[i] = table[data[i]];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Temporary data for one source font (multiple source fonts can be merged into one destination ImFont)
 | 
				
			||||||
 | 
					// (C++03 doesn't allow instancing ImVector<> with function-local types so we declare the type here.)
 | 
				
			||||||
 | 
					struct ImFontBuildSrcData
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    stbtt_fontinfo      FontInfo;
 | 
				
			||||||
 | 
					    stbtt_pack_range    PackRange;          // Hold the list of codepoints to pack (essentially points to Codepoints.Data)
 | 
				
			||||||
 | 
					    stbrp_rect*         Rects;              // Rectangle to pack. We first fill in their size and the packer will give us their position.
 | 
				
			||||||
 | 
					    stbtt_packedchar*   PackedChars;        // Output glyphs
 | 
				
			||||||
 | 
					    const ImWchar*      SrcRanges;          // Ranges as requested by user (user is allowed to request too much, e.g. 0x0020..0xFFFF)
 | 
				
			||||||
 | 
					    int                 DstIndex;           // Index into atlas->Fonts[] and dst_tmp_array[]
 | 
				
			||||||
 | 
					    int                 GlyphsHighest;      // Highest requested codepoint
 | 
				
			||||||
 | 
					    int                 GlyphsCount;        // Glyph count (excluding missing glyphs and glyphs already set by an earlier source font)
 | 
				
			||||||
 | 
					    ImBoolVector        GlyphsSet;          // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
 | 
				
			||||||
 | 
					    ImVector<int>       GlyphsList;         // Glyph codepoints list (flattened version of GlyphsMap)
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
 | 
				
			||||||
 | 
					struct ImFontBuildDstData
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int                 SrcCount;           // Number of source fonts targeting this destination font.
 | 
				
			||||||
 | 
					    int                 GlyphsHighest;
 | 
				
			||||||
 | 
					    int                 GlyphsCount;
 | 
				
			||||||
 | 
					    ImBoolVector        GlyphsSet;          // This is used to resolve collision when multiple sources are merged into a same destination font.
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void UnpackBoolVectorToFlatIndexList(const ImBoolVector* in, ImVector<int>* out)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    IM_ASSERT(sizeof(in->Storage.Data[0]) == sizeof(int));
 | 
				
			||||||
 | 
					    const int* it_begin = in->Storage.begin();
 | 
				
			||||||
 | 
					    const int* it_end = in->Storage.end();
 | 
				
			||||||
 | 
					    for (const int* it = it_begin; it < it_end; it++)
 | 
				
			||||||
 | 
					        if (int entries_32 = *it)
 | 
				
			||||||
 | 
					            for (int bit_n = 0; bit_n < 32; bit_n++)
 | 
				
			||||||
 | 
					                if (entries_32 & (1 << bit_n))
 | 
				
			||||||
 | 
					                    out->push_back((int)((it - it_begin) << 5) + bit_n);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool    ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
 | 
					bool    ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    IM_ASSERT(atlas->ConfigData.Size > 0);
 | 
					    IM_ASSERT(atlas->ConfigData.Size > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
 | 
					    ImFontAtlasBuildRegisterDefaultCustomRects(atlas);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Clear atlas
 | 
				
			||||||
    atlas->TexID = (ImTextureID)NULL;
 | 
					    atlas->TexID = (ImTextureID)NULL;
 | 
				
			||||||
    atlas->TexWidth = atlas->TexHeight = 0;
 | 
					    atlas->TexWidth = atlas->TexHeight = 0;
 | 
				
			||||||
    atlas->TexUvScale = ImVec2(0.0f, 0.0f);
 | 
					    atlas->TexUvScale = ImVec2(0.0f, 0.0f);
 | 
				
			||||||
    atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
 | 
					    atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
 | 
				
			||||||
    atlas->ClearTexData();
 | 
					    atlas->ClearTexData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Count glyphs/ranges
 | 
					    // Temporary storage for building
 | 
				
			||||||
    int total_glyphs_count = 0;
 | 
					    ImVector<ImFontBuildSrcData> src_tmp_array;
 | 
				
			||||||
    int total_ranges_count = 0;
 | 
					    ImVector<ImFontBuildDstData> dst_tmp_array;
 | 
				
			||||||
    for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
 | 
					    src_tmp_array.resize(atlas->ConfigData.Size);
 | 
				
			||||||
 | 
					    dst_tmp_array.resize(atlas->Fonts.Size);
 | 
				
			||||||
 | 
					    memset(src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
 | 
				
			||||||
 | 
					    memset(dst_tmp_array.Data, 0, (size_t)dst_tmp_array.size_in_bytes());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 1. Initialize font loading structure, check font data validity
 | 
				
			||||||
 | 
					    for (int src_i = 0; src_i < atlas->ConfigData.Size; src_i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ImFontConfig& cfg = atlas->ConfigData[input_i];
 | 
					        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
 | 
				
			||||||
        if (!cfg.GlyphRanges)
 | 
					        ImFontConfig& cfg = atlas->ConfigData[src_i];
 | 
				
			||||||
            cfg.GlyphRanges = atlas->GetGlyphRangesDefault();
 | 
					 | 
				
			||||||
        for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, total_ranges_count++)
 | 
					 | 
				
			||||||
            total_glyphs_count += (in_range[1] - in_range[0]) + 1;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // We need a width for the skyline algorithm. Using a dumb heuristic here to decide of width. User can override TexDesiredWidth and TexGlyphPadding if they wish.
 | 
					 | 
				
			||||||
    // Width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
 | 
					 | 
				
			||||||
    atlas->TexWidth = (atlas->TexDesiredWidth > 0) ? atlas->TexDesiredWidth : (total_glyphs_count > 4000) ? 4096 : (total_glyphs_count > 2000) ? 2048 : (total_glyphs_count > 1000) ? 1024 : 512;
 | 
					 | 
				
			||||||
    atlas->TexHeight = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Start packing
 | 
					 | 
				
			||||||
    const int max_tex_height = 1024*32;
 | 
					 | 
				
			||||||
    stbtt_pack_context spc = {};
 | 
					 | 
				
			||||||
    if (!stbtt_PackBegin(&spc, NULL, atlas->TexWidth, max_tex_height, 0, atlas->TexGlyphPadding, NULL))
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    stbtt_PackSetOversampling(&spc, 1, 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
 | 
					 | 
				
			||||||
    ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Initialize font information (so we can error without any cleanup)
 | 
					 | 
				
			||||||
    struct ImFontTempBuildData
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        stbtt_fontinfo      FontInfo;
 | 
					 | 
				
			||||||
        stbrp_rect*         Rects;
 | 
					 | 
				
			||||||
        int                 RectsCount;
 | 
					 | 
				
			||||||
        stbtt_pack_range*   Ranges;
 | 
					 | 
				
			||||||
        int                 RangesCount;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    ImFontTempBuildData* tmp_array = (ImFontTempBuildData*)ImGui::MemAlloc((size_t)atlas->ConfigData.Size * sizeof(ImFontTempBuildData));
 | 
					 | 
				
			||||||
    for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        ImFontConfig& cfg = atlas->ConfigData[input_i];
 | 
					 | 
				
			||||||
        ImFontTempBuildData& tmp = tmp_array[input_i];
 | 
					 | 
				
			||||||
        IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
 | 
					        IM_ASSERT(cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Find index from cfg.DstFont (we allow the user to set cfg.DstFont. Also it makes casual debugging nicer than when storing indices)
 | 
				
			||||||
 | 
					        src_tmp.DstIndex = -1;
 | 
				
			||||||
 | 
					        for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
 | 
				
			||||||
 | 
					            if (cfg.DstFont == atlas->Fonts[output_i])
 | 
				
			||||||
 | 
					                src_tmp.DstIndex = output_i;
 | 
				
			||||||
 | 
					        IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
 | 
				
			||||||
 | 
					        if (src_tmp.DstIndex == -1)
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Initialize helper structure for font loading and verify that the TTF/OTF data is correct
 | 
				
			||||||
        const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
 | 
					        const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
 | 
				
			||||||
        IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
 | 
					        IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
 | 
				
			||||||
        if (!stbtt_InitFont(&tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
 | 
					        if (!stbtt_InitFont(&src_tmp.FontInfo, (unsigned char*)cfg.FontData, font_offset))
 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            atlas->TexWidth = atlas->TexHeight = 0; // Reset output on failure
 | 
					 | 
				
			||||||
            ImGui::MemFree(tmp_array);
 | 
					 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					
 | 
				
			||||||
 | 
					        // Measure highest codepoints
 | 
				
			||||||
 | 
					        ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
 | 
				
			||||||
 | 
					        src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault();
 | 
				
			||||||
 | 
					        for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
 | 
				
			||||||
 | 
					            src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
 | 
				
			||||||
 | 
					        dst_tmp.SrcCount++;
 | 
				
			||||||
 | 
					        dst_tmp.GlyphsHighest = ImMax(dst_tmp.GlyphsHighest, src_tmp.GlyphsHighest);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 2. For every requested codepoint, check for their presence in the font data, and handle redundancy or overlaps between source fonts to avoid unused glyphs.
 | 
				
			||||||
 | 
					    int total_glyphs_count = 0;
 | 
				
			||||||
 | 
					    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
 | 
				
			||||||
 | 
					        ImFontBuildDstData& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
 | 
				
			||||||
 | 
					        ImFontConfig& cfg = atlas->ConfigData[src_i];
 | 
				
			||||||
 | 
					        src_tmp.GlyphsSet.Resize(src_tmp.GlyphsHighest);
 | 
				
			||||||
 | 
					        if (dst_tmp.SrcCount > 1 && dst_tmp.GlyphsSet.Storage.empty())
 | 
				
			||||||
 | 
					            dst_tmp.GlyphsSet.Resize(dst_tmp.GlyphsHighest);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
 | 
				
			||||||
 | 
					            for (int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (cfg.MergeMode && dst_tmp.GlyphsSet.GetBit(codepoint))   // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                if (!stbtt_FindGlyphIndex(&src_tmp.FontInfo, codepoint))    // It is actually in the font?
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                // Add to avail set/counters
 | 
				
			||||||
 | 
					                src_tmp.GlyphsCount++;
 | 
				
			||||||
 | 
					                dst_tmp.GlyphsCount++;
 | 
				
			||||||
 | 
					                src_tmp.GlyphsSet.SetBit(codepoint, true);
 | 
				
			||||||
 | 
					                if (dst_tmp.SrcCount > 1)
 | 
				
			||||||
 | 
					                    dst_tmp.GlyphsSet.SetBit(codepoint, true);
 | 
				
			||||||
 | 
					                total_glyphs_count++;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 3. Unpack our bit map into a flat list (we now have all the Unicode points that we know are requested _and_ available _and_ not overlapping another)
 | 
				
			||||||
 | 
					    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
 | 
				
			||||||
 | 
					        src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
 | 
				
			||||||
 | 
					        UnpackBoolVectorToFlatIndexList(&src_tmp.GlyphsSet, &src_tmp.GlyphsList);
 | 
				
			||||||
 | 
					        src_tmp.GlyphsSet.Clear();
 | 
				
			||||||
 | 
					        IM_ASSERT(src_tmp.GlyphsList.Size == src_tmp.GlyphsCount);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    for (int dst_i = 0; dst_i < dst_tmp_array.Size; dst_i++)
 | 
				
			||||||
 | 
					        dst_tmp_array[dst_i].GlyphsSet.Clear();
 | 
				
			||||||
 | 
					    dst_tmp_array.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
 | 
					    // Allocate packing character data and flag packed characters buffer as non-packed (x0=y0=x1=y1=0)
 | 
				
			||||||
    int buf_packedchars_n = 0, buf_rects_n = 0, buf_ranges_n = 0;
 | 
					    // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
 | 
				
			||||||
    stbtt_packedchar* buf_packedchars = (stbtt_packedchar*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbtt_packedchar));
 | 
					    ImVector<stbrp_rect> buf_rects;
 | 
				
			||||||
    stbrp_rect* buf_rects = (stbrp_rect*)ImGui::MemAlloc(total_glyphs_count * sizeof(stbrp_rect));
 | 
					    ImVector<stbtt_packedchar> buf_packedchars;
 | 
				
			||||||
    stbtt_pack_range* buf_ranges = (stbtt_pack_range*)ImGui::MemAlloc(total_ranges_count * sizeof(stbtt_pack_range));
 | 
					    buf_rects.resize(total_glyphs_count);
 | 
				
			||||||
    memset(buf_packedchars, 0, total_glyphs_count * sizeof(stbtt_packedchar));
 | 
					    buf_packedchars.resize(total_glyphs_count);
 | 
				
			||||||
    memset(buf_rects, 0, total_glyphs_count * sizeof(stbrp_rect));              // Unnecessary but let's clear this for the sake of sanity.
 | 
					    memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
 | 
				
			||||||
    memset(buf_ranges, 0, total_ranges_count * sizeof(stbtt_pack_range));
 | 
					    memset(buf_packedchars.Data, 0, (size_t)buf_packedchars.size_in_bytes());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // First font pass: pack all glyphs (no rendering at this point, we are working with rectangles in an infinitely tall texture at this point)
 | 
					    // 4. Gather glyphs sizes so we can pack them in our virtual canvas.
 | 
				
			||||||
    for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
 | 
					    int total_surface = 0;
 | 
				
			||||||
 | 
					    int buf_rects_out_n = 0;
 | 
				
			||||||
 | 
					    int buf_packedchars_out_n = 0;
 | 
				
			||||||
 | 
					    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ImFontConfig& cfg = atlas->ConfigData[input_i];
 | 
					        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
 | 
				
			||||||
        ImFontTempBuildData& tmp = tmp_array[input_i];
 | 
					        if (src_tmp.GlyphsCount == 0)
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Setup ranges
 | 
					        src_tmp.Rects = &buf_rects[buf_rects_out_n];
 | 
				
			||||||
        int font_glyphs_count = 0;
 | 
					        src_tmp.PackedChars = &buf_packedchars[buf_packedchars_out_n];
 | 
				
			||||||
        int font_ranges_count = 0;
 | 
					        buf_rects_out_n += src_tmp.GlyphsCount;
 | 
				
			||||||
        for (const ImWchar* in_range = cfg.GlyphRanges; in_range[0] && in_range[1]; in_range += 2, font_ranges_count++)
 | 
					        buf_packedchars_out_n += src_tmp.GlyphsCount;
 | 
				
			||||||
            font_glyphs_count += (in_range[1] - in_range[0]) + 1;
 | 
					
 | 
				
			||||||
        tmp.Ranges = buf_ranges + buf_ranges_n;
 | 
					        // Convert our ranges in the format stb_truetype wants
 | 
				
			||||||
        tmp.RangesCount = font_ranges_count;
 | 
					        ImFontConfig& cfg = atlas->ConfigData[src_i];
 | 
				
			||||||
        buf_ranges_n += font_ranges_count;
 | 
					        src_tmp.PackRange.font_size = cfg.SizePixels;
 | 
				
			||||||
        for (int i = 0; i < font_ranges_count; i++)
 | 
					        src_tmp.PackRange.first_unicode_codepoint_in_range = 0;
 | 
				
			||||||
 | 
					        src_tmp.PackRange.array_of_unicode_codepoints = src_tmp.GlyphsList.Data;
 | 
				
			||||||
 | 
					        src_tmp.PackRange.num_chars = src_tmp.GlyphsList.Size;
 | 
				
			||||||
 | 
					        src_tmp.PackRange.chardata_for_range = src_tmp.PackedChars;
 | 
				
			||||||
 | 
					        src_tmp.PackRange.h_oversample = (unsigned char)cfg.OversampleH;
 | 
				
			||||||
 | 
					        src_tmp.PackRange.v_oversample = (unsigned char)cfg.OversampleV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Gather the sizes of all rectangles we will need to pack (this loop is based on stbtt_PackFontRangesGatherRects)
 | 
				
			||||||
 | 
					        const float scale = (cfg.SizePixels > 0) ? stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels) : stbtt_ScaleForMappingEmToPixels(&src_tmp.FontInfo, -cfg.SizePixels);
 | 
				
			||||||
 | 
					        const int padding = atlas->TexGlyphPadding;
 | 
				
			||||||
 | 
					        for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            const ImWchar* in_range = &cfg.GlyphRanges[i * 2];
 | 
					            int x0, y0, x1, y1;
 | 
				
			||||||
            stbtt_pack_range& range = tmp.Ranges[i];
 | 
					            const int glyph_index_in_font = stbtt_FindGlyphIndex(&src_tmp.FontInfo, src_tmp.GlyphsList[glyph_i]);
 | 
				
			||||||
            range.font_size = cfg.SizePixels;
 | 
					            IM_ASSERT(glyph_index_in_font != 0);
 | 
				
			||||||
            range.first_unicode_codepoint_in_range = in_range[0];
 | 
					            stbtt_GetGlyphBitmapBoxSubpixel(&src_tmp.FontInfo, glyph_index_in_font, scale * cfg.OversampleH, scale * cfg.OversampleV, 0, 0, &x0, &y0, &x1, &y1);
 | 
				
			||||||
            range.num_chars = (in_range[1] - in_range[0]) + 1;
 | 
					            src_tmp.Rects[glyph_i].w = (stbrp_coord)(x1 - x0 + padding + cfg.OversampleH - 1);
 | 
				
			||||||
            range.chardata_for_range = buf_packedchars + buf_packedchars_n;
 | 
					            src_tmp.Rects[glyph_i].h = (stbrp_coord)(y1 - y0 + padding + cfg.OversampleV - 1);
 | 
				
			||||||
            buf_packedchars_n += range.num_chars;
 | 
					            total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Gather the sizes of all rectangle we need
 | 
					 | 
				
			||||||
        tmp.Rects = buf_rects + buf_rects_n;
 | 
					 | 
				
			||||||
        tmp.RectsCount = font_glyphs_count;
 | 
					 | 
				
			||||||
        buf_rects_n += font_glyphs_count;
 | 
					 | 
				
			||||||
        stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
 | 
					 | 
				
			||||||
        int n = stbtt_PackFontRangesGatherRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
 | 
					 | 
				
			||||||
        IM_ASSERT(n == font_glyphs_count);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Detect missing glyphs and replace them with a zero-sized box instead of relying on the default glyphs
 | 
					 | 
				
			||||||
        // This allows us merging overlapping icon fonts more easily.
 | 
					 | 
				
			||||||
        int rect_i = 0;
 | 
					 | 
				
			||||||
        for (int range_i = 0; range_i < tmp.RangesCount; range_i++)
 | 
					 | 
				
			||||||
            for (int char_i = 0; char_i < tmp.Ranges[range_i].num_chars; char_i++, rect_i++)
 | 
					 | 
				
			||||||
                if (stbtt_FindGlyphIndex(&tmp.FontInfo, tmp.Ranges[range_i].first_unicode_codepoint_in_range + char_i) == 0)
 | 
					 | 
				
			||||||
                    tmp.Rects[rect_i].w = tmp.Rects[rect_i].h = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Pack
 | 
					 | 
				
			||||||
        stbrp_pack_rects((stbrp_context*)spc.pack_info, tmp.Rects, n);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Extend texture height
 | 
					 | 
				
			||||||
        // Also mark missing glyphs as non-packed so we don't attempt to render into them
 | 
					 | 
				
			||||||
        for (int i = 0; i < n; i++)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (tmp.Rects[i].w == 0 && tmp.Rects[i].h == 0)
 | 
					 | 
				
			||||||
                tmp.Rects[i].was_packed = 0;
 | 
					 | 
				
			||||||
            if (tmp.Rects[i].was_packed)
 | 
					 | 
				
			||||||
                atlas->TexHeight = ImMax(atlas->TexHeight, tmp.Rects[i].y + tmp.Rects[i].h);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    IM_ASSERT(buf_rects_n == total_glyphs_count);
 | 
					 | 
				
			||||||
    IM_ASSERT(buf_packedchars_n == total_glyphs_count);
 | 
					 | 
				
			||||||
    IM_ASSERT(buf_ranges_n == total_ranges_count);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Create texture
 | 
					    // We need a width for the skyline algorithm, any width!
 | 
				
			||||||
 | 
					    // The exact width doesn't really matter much, but some API/GPU have texture size limitations and increasing width can decrease height.
 | 
				
			||||||
 | 
					    // User can override TexDesiredWidth and TexGlyphPadding if they wish, otherwise we use a simple heuristic to select the width based on expected surface.
 | 
				
			||||||
 | 
					    const int surface_sqrt = (int)ImSqrt((float)total_surface) + 1;
 | 
				
			||||||
 | 
					    atlas->TexHeight = 0;
 | 
				
			||||||
 | 
					    if (atlas->TexDesiredWidth > 0)
 | 
				
			||||||
 | 
					        atlas->TexWidth = atlas->TexDesiredWidth;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        atlas->TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 5. Start packing
 | 
				
			||||||
 | 
					    // Pack our extra data rectangles first, so it will be on the upper-left corner of our texture (UV will have small values).
 | 
				
			||||||
 | 
					    const int TEX_HEIGHT_MAX = 1024 * 32;
 | 
				
			||||||
 | 
					    stbtt_pack_context spc = {};
 | 
				
			||||||
 | 
					    stbtt_PackBegin(&spc, NULL, atlas->TexWidth, TEX_HEIGHT_MAX, 0, atlas->TexGlyphPadding, NULL);
 | 
				
			||||||
 | 
					    ImFontAtlasBuildPackCustomRects(atlas, spc.pack_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 6. Pack each source font. No rendering yet, we are working with rectangles in an infinitely tall texture at this point.
 | 
				
			||||||
 | 
					    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
 | 
				
			||||||
 | 
					        if (src_tmp.GlyphsCount == 0)
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stbrp_pack_rects((stbrp_context*)spc.pack_info, src_tmp.Rects, src_tmp.GlyphsCount);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Extend texture height and mark missing glyphs as non-packed so we won't render them.
 | 
				
			||||||
 | 
					        // FIXME: We are not handling packing failure here (would happen if we got off TEX_HEIGHT_MAX or if a single if larger than TexWidth?)
 | 
				
			||||||
 | 
					        for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
 | 
				
			||||||
 | 
					            if (src_tmp.Rects[glyph_i].was_packed)
 | 
				
			||||||
 | 
					                atlas->TexHeight = ImMax(atlas->TexHeight, src_tmp.Rects[glyph_i].y + src_tmp.Rects[glyph_i].h);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 7. Allocate texture
 | 
				
			||||||
    atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
 | 
					    atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight);
 | 
				
			||||||
    atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
 | 
					    atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
 | 
				
			||||||
    atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
 | 
					    atlas->TexPixelsAlpha8 = (unsigned char*)ImGui::MemAlloc(atlas->TexWidth * atlas->TexHeight);
 | 
				
			||||||
@@ -1873,41 +1954,46 @@ bool    ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
 | 
				
			|||||||
    spc.pixels = atlas->TexPixelsAlpha8;
 | 
					    spc.pixels = atlas->TexPixelsAlpha8;
 | 
				
			||||||
    spc.height = atlas->TexHeight;
 | 
					    spc.height = atlas->TexHeight;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Second pass: render font characters
 | 
					    // 8. Render/rasterize font characters into the texture
 | 
				
			||||||
    for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
 | 
					    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ImFontConfig& cfg = atlas->ConfigData[input_i];
 | 
					        ImFontConfig& cfg = atlas->ConfigData[src_i];
 | 
				
			||||||
        ImFontTempBuildData& tmp = tmp_array[input_i];
 | 
					        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
 | 
				
			||||||
        stbtt_PackSetOversampling(&spc, cfg.OversampleH, cfg.OversampleV);
 | 
					        if (src_tmp.GlyphsCount == 0)
 | 
				
			||||||
        stbtt_PackFontRangesRenderIntoRects(&spc, &tmp.FontInfo, tmp.Ranges, tmp.RangesCount, tmp.Rects);
 | 
					            continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stbtt_PackFontRangesRenderIntoRects(&spc, &src_tmp.FontInfo, &src_tmp.PackRange, 1, src_tmp.Rects);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Apply multiply operator
 | 
				
			||||||
        if (cfg.RasterizerMultiply != 1.0f)
 | 
					        if (cfg.RasterizerMultiply != 1.0f)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            unsigned char multiply_table[256];
 | 
					            unsigned char multiply_table[256];
 | 
				
			||||||
            ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
 | 
					            ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, cfg.RasterizerMultiply);
 | 
				
			||||||
            for (const stbrp_rect* r = tmp.Rects; r != tmp.Rects + tmp.RectsCount; r++)
 | 
					            stbrp_rect* r = &src_tmp.Rects[0];
 | 
				
			||||||
 | 
					            for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++, r++)
 | 
				
			||||||
                if (r->was_packed)
 | 
					                if (r->was_packed)
 | 
				
			||||||
                    ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, spc.pixels, r->x, r->y, r->w, r->h, spc.stride_in_bytes);
 | 
					                    ImFontAtlasBuildMultiplyRectAlpha8(multiply_table, atlas->TexPixelsAlpha8, r->x, r->y, r->w, r->h, atlas->TexWidth * 1);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        tmp.Rects = NULL;
 | 
					        src_tmp.Rects = NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // End packing
 | 
					    // End packing
 | 
				
			||||||
    stbtt_PackEnd(&spc);
 | 
					    stbtt_PackEnd(&spc);
 | 
				
			||||||
    ImGui::MemFree(buf_rects);
 | 
					    buf_rects.clear();
 | 
				
			||||||
    buf_rects = NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Third pass: setup ImFont and glyphs for runtime
 | 
					    // 9. Setup ImFont and glyphs for runtime
 | 
				
			||||||
    for (int input_i = 0; input_i < atlas->ConfigData.Size; input_i++)
 | 
					    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        ImFontConfig& cfg = atlas->ConfigData[input_i];
 | 
					        ImFontBuildSrcData& src_tmp = src_tmp_array[src_i];
 | 
				
			||||||
        ImFontTempBuildData& tmp = tmp_array[input_i];
 | 
					        if (src_tmp.GlyphsCount == 0)
 | 
				
			||||||
        ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
 | 
					            continue;
 | 
				
			||||||
        if (cfg.MergeMode)
 | 
					 | 
				
			||||||
            dst_font->BuildLookupTable();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const float font_scale = stbtt_ScaleForPixelHeight(&tmp.FontInfo, cfg.SizePixels);
 | 
					        ImFontConfig& cfg = atlas->ConfigData[src_i];
 | 
				
			||||||
 | 
					        ImFont* dst_font = cfg.DstFont; // We can have multiple input fonts writing into a same destination font (when using MergeMode=true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const float font_scale = stbtt_ScaleForPixelHeight(&src_tmp.FontInfo, cfg.SizePixels);
 | 
				
			||||||
        int unscaled_ascent, unscaled_descent, unscaled_line_gap;
 | 
					        int unscaled_ascent, unscaled_descent, unscaled_line_gap;
 | 
				
			||||||
        stbtt_GetFontVMetrics(&tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
 | 
					        stbtt_GetFontVMetrics(&src_tmp.FontInfo, &unscaled_ascent, &unscaled_descent, &unscaled_line_gap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
 | 
					        const float ascent = ImFloor(unscaled_ascent * font_scale + ((unscaled_ascent > 0.0f) ? +1 : -1));
 | 
				
			||||||
        const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
 | 
					        const float descent = ImFloor(unscaled_descent * font_scale + ((unscaled_descent > 0.0f) ? +1 : -1));
 | 
				
			||||||
@@ -1915,40 +2001,30 @@ bool    ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
 | 
				
			|||||||
        const float font_off_x = cfg.GlyphOffset.x;
 | 
					        const float font_off_x = cfg.GlyphOffset.x;
 | 
				
			||||||
        const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
 | 
					        const float font_off_y = cfg.GlyphOffset.y + (float)(int)(dst_font->Ascent + 0.5f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (int i = 0; i < tmp.RangesCount; i++)
 | 
					        for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            stbtt_pack_range& range = tmp.Ranges[i];
 | 
					            const int codepoint = src_tmp.GlyphsList[glyph_i];
 | 
				
			||||||
            for (int char_idx = 0; char_idx < range.num_chars; char_idx += 1)
 | 
					            const stbtt_packedchar& pc = src_tmp.PackedChars[glyph_i];
 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                const stbtt_packedchar& pc = range.chardata_for_range[char_idx];
 | 
					 | 
				
			||||||
                if (!pc.x0 && !pc.x1 && !pc.y0 && !pc.y1)
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const int codepoint = range.first_unicode_codepoint_in_range + char_idx;
 | 
					            const float char_advance_x_org = pc.xadvance;
 | 
				
			||||||
                if (cfg.MergeMode && dst_font->FindGlyphNoFallback((ImWchar)codepoint))
 | 
					            const float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
 | 
				
			||||||
                    continue;
 | 
					            float char_off_x = font_off_x;
 | 
				
			||||||
 | 
					            if (char_advance_x_org != char_advance_x_mod)
 | 
				
			||||||
 | 
					                char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
                float char_advance_x_org = pc.xadvance;
 | 
					            // Register glyph
 | 
				
			||||||
                float char_advance_x_mod = ImClamp(char_advance_x_org, cfg.GlyphMinAdvanceX, cfg.GlyphMaxAdvanceX);
 | 
					            stbtt_aligned_quad q;
 | 
				
			||||||
                float char_off_x = font_off_x;
 | 
					            float dummy_x = 0.0f, dummy_y = 0.0f;
 | 
				
			||||||
                if (char_advance_x_org != char_advance_x_mod)
 | 
					            stbtt_GetPackedQuad(src_tmp.PackedChars, atlas->TexWidth, atlas->TexHeight, glyph_i, &dummy_x, &dummy_y, &q, 0);
 | 
				
			||||||
                    char_off_x += cfg.PixelSnapH ? (float)(int)((char_advance_x_mod - char_advance_x_org) * 0.5f) : (char_advance_x_mod - char_advance_x_org) * 0.5f;
 | 
					            dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod);
 | 
				
			||||||
 | 
					 | 
				
			||||||
                stbtt_aligned_quad q;
 | 
					 | 
				
			||||||
                float dummy_x = 0.0f, dummy_y = 0.0f;
 | 
					 | 
				
			||||||
                stbtt_GetPackedQuad(range.chardata_for_range, atlas->TexWidth, atlas->TexHeight, char_idx, &dummy_x, &dummy_y, &q, 0);
 | 
					 | 
				
			||||||
                dst_font->AddGlyph((ImWchar)codepoint, q.x0 + char_off_x, q.y0 + font_off_y, q.x1 + char_off_x, q.y1 + font_off_y, q.s0, q.t0, q.s1, q.t1, char_advance_x_mod);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Cleanup temporaries
 | 
					    // Cleanup temporary (ImVector doesn't honor destructor)
 | 
				
			||||||
    ImGui::MemFree(buf_packedchars);
 | 
					    for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
 | 
				
			||||||
    ImGui::MemFree(buf_ranges);
 | 
					        src_tmp_array[src_i].~ImFontBuildSrcData();
 | 
				
			||||||
    ImGui::MemFree(tmp_array);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImFontAtlasBuildFinish(atlas);
 | 
					    ImFontAtlasBuildFinish(atlas);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1976,16 +2052,16 @@ void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* f
 | 
				
			|||||||
    font->ConfigDataCount++;
 | 
					    font->ConfigDataCount++;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* pack_context_opaque)
 | 
					void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    stbrp_context* pack_context = (stbrp_context*)pack_context_opaque;
 | 
					    stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects;
 | 
					    ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects;
 | 
				
			||||||
    IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
 | 
					    IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ImVector<stbrp_rect> pack_rects;
 | 
					    ImVector<stbrp_rect> pack_rects;
 | 
				
			||||||
    pack_rects.resize(user_rects.Size);
 | 
					    pack_rects.resize(user_rects.Size);
 | 
				
			||||||
    memset(pack_rects.Data, 0, sizeof(stbrp_rect) * user_rects.Size);
 | 
					    memset(pack_rects.Data, 0, (size_t)pack_rects.size_in_bytes());
 | 
				
			||||||
    for (int i = 0; i < user_rects.Size; i++)
 | 
					    for (int i = 0; i < user_rects.Size; i++)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        pack_rects[i].w = user_rects[i].Width;
 | 
					        pack_rects[i].w = user_rects[i].Width;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1452,7 +1452,7 @@ namespace ImGui
 | 
				
			|||||||
IMGUI_API bool              ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas);
 | 
					IMGUI_API bool              ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas);
 | 
				
			||||||
IMGUI_API void              ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas);
 | 
					IMGUI_API void              ImFontAtlasBuildRegisterDefaultCustomRects(ImFontAtlas* atlas);
 | 
				
			||||||
IMGUI_API void              ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent);
 | 
					IMGUI_API void              ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent);
 | 
				
			||||||
IMGUI_API void              ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* spc);
 | 
					IMGUI_API void              ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque);
 | 
				
			||||||
IMGUI_API void              ImFontAtlasBuildFinish(ImFontAtlas* atlas);
 | 
					IMGUI_API void              ImFontAtlasBuildFinish(ImFontAtlas* atlas);
 | 
				
			||||||
IMGUI_API void              ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);
 | 
					IMGUI_API void              ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);
 | 
				
			||||||
IMGUI_API void              ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);
 | 
					IMGUI_API void              ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user