|
@@ -142,24 +142,12 @@ namespace
|
|
|
// | |
|
|
|
// |------------- advanceX ----------->|
|
|
|
|
|
|
- // A structure that describe a glyph.
|
|
|
- struct GlyphInfo
|
|
|
- {
|
|
|
- int Width; // Glyph's width in pixels.
|
|
|
- int Height; // Glyph's height in pixels.
|
|
|
- FT_Int OffsetX; // The distance from the origin ("pen position") to the left of the glyph.
|
|
|
- FT_Int OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0.
|
|
|
- float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0.
|
|
|
- bool IsColored; // The glyph is colored
|
|
|
- };
|
|
|
-
|
|
|
// Stored in ImFontAtlas::FontLoaderData
|
|
|
struct ImGui_ImplFreeType_Data
|
|
|
{
|
|
|
- FT_Library Library;
|
|
|
- FT_MemoryRec_ MemoryManager;
|
|
|
-
|
|
|
- ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); }
|
|
|
+ FT_Library Library;
|
|
|
+ FT_MemoryRec_ MemoryManager;
|
|
|
+ ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); }
|
|
|
};
|
|
|
|
|
|
// Font parameters and metrics.
|
|
@@ -180,8 +168,7 @@ namespace
|
|
|
void CloseFont();
|
|
|
void SetPixelHeight(float pixel_height); // Change font pixel size.
|
|
|
const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint);
|
|
|
- const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info);
|
|
|
- void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = nullptr);
|
|
|
+ void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch);
|
|
|
ImGui_ImplFreeType_FontSrcData() { memset((void*)this, 0, sizeof(*this)); }
|
|
|
~ImGui_ImplFreeType_FontSrcData() { CloseFont(); }
|
|
|
|
|
@@ -316,25 +303,7 @@ namespace
|
|
|
return &slot->metrics;
|
|
|
}
|
|
|
|
|
|
- const FT_Bitmap* ImGui_ImplFreeType_FontSrcData::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info)
|
|
|
- {
|
|
|
- FT_GlyphSlot slot = FtFace->glyph;
|
|
|
- FT_Error error = FT_Render_Glyph(slot, RenderMode);
|
|
|
- if (error != 0)
|
|
|
- return nullptr;
|
|
|
-
|
|
|
- FT_Bitmap* ft_bitmap = &FtFace->glyph->bitmap;
|
|
|
- out_glyph_info->Width = (int)ft_bitmap->width;
|
|
|
- out_glyph_info->Height = (int)ft_bitmap->rows;
|
|
|
- out_glyph_info->OffsetX = FtFace->glyph->bitmap_left;
|
|
|
- out_glyph_info->OffsetY = -FtFace->glyph->bitmap_top;
|
|
|
- out_glyph_info->AdvanceX = (float)slot->advance.x / FT_SCALEFACTOR;
|
|
|
- out_glyph_info->IsColored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA);
|
|
|
-
|
|
|
- return ft_bitmap;
|
|
|
- }
|
|
|
-
|
|
|
- void ImGui_ImplFreeType_FontSrcData::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table)
|
|
|
+ void ImGui_ImplFreeType_FontSrcData::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch)
|
|
|
{
|
|
|
IM_ASSERT(ft_bitmap != nullptr);
|
|
|
const uint32_t w = ft_bitmap->width;
|
|
@@ -346,24 +315,13 @@ namespace
|
|
|
{
|
|
|
case FT_PIXEL_MODE_GRAY: // Grayscale image, 1 byte per pixel.
|
|
|
{
|
|
|
- if (multiply_table == nullptr)
|
|
|
- {
|
|
|
- for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
|
|
- for (uint32_t x = 0; x < w; x++)
|
|
|
- dst[x] = IM_COL32(255, 255, 255, src[x]);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
|
|
- for (uint32_t x = 0; x < w; x++)
|
|
|
- dst[x] = IM_COL32(255, 255, 255, multiply_table[src[x]]);
|
|
|
- }
|
|
|
+ for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
|
|
+ for (uint32_t x = 0; x < w; x++)
|
|
|
+ dst[x] = IM_COL32(255, 255, 255, src[x]);
|
|
|
break;
|
|
|
}
|
|
|
case FT_PIXEL_MODE_MONO: // Monochrome image, 1 bit per pixel. The bits in each byte are ordered from MSB to LSB.
|
|
|
{
|
|
|
- uint8_t color0 = multiply_table ? multiply_table[0] : 0;
|
|
|
- uint8_t color1 = multiply_table ? multiply_table[255] : 255;
|
|
|
for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
|
|
{
|
|
|
uint8_t bits = 0;
|
|
@@ -372,7 +330,7 @@ namespace
|
|
|
{
|
|
|
if ((x & 7) == 0)
|
|
|
bits = *bits_ptr++;
|
|
|
- dst[x] = IM_COL32(255, 255, 255, (bits & 0x80) ? color1 : color0);
|
|
|
+ dst[x] = IM_COL32(255, 255, 255, (bits & 0x80) ? 255 : 0);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
@@ -381,26 +339,12 @@ namespace
|
|
|
{
|
|
|
// FIXME: Converting pre-multiplied alpha to straight. Doesn't smell good.
|
|
|
#define DE_MULTIPLY(color, alpha) ImMin((ImU32)(255.0f * (float)color / (float)(alpha + FLT_MIN) + 0.5f), 255u)
|
|
|
- if (multiply_table == nullptr)
|
|
|
- {
|
|
|
- for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
|
|
- for (uint32_t x = 0; x < w; x++)
|
|
|
- {
|
|
|
- uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3];
|
|
|
- dst[x] = IM_COL32(DE_MULTIPLY(r, a), DE_MULTIPLY(g, a), DE_MULTIPLY(b, a), a);
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
|
|
+ for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch)
|
|
|
+ for (uint32_t x = 0; x < w; x++)
|
|
|
{
|
|
|
- for (uint32_t x = 0; x < w; x++)
|
|
|
- {
|
|
|
- uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3];
|
|
|
- dst[x] = IM_COL32(multiply_table[DE_MULTIPLY(r, a)], multiply_table[DE_MULTIPLY(g, a)], multiply_table[DE_MULTIPLY(b, a)], multiply_table[a]);
|
|
|
- }
|
|
|
+ uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3];
|
|
|
+ dst[x] = IM_COL32(DE_MULTIPLY(r, a), DE_MULTIPLY(g, a), DE_MULTIPLY(b, a), a);
|
|
|
}
|
|
|
- }
|
|
|
#undef DE_MULTIPLY
|
|
|
break;
|
|
|
}
|
|
@@ -410,376 +354,6 @@ namespace
|
|
|
}
|
|
|
} // namespace
|
|
|
|
|
|
-#if 0
|
|
|
-
|
|
|
-#ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
|
|
|
-#ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
|
|
|
-#define STBRP_ASSERT(x) do { IM_ASSERT(x); } while (0)
|
|
|
-#define STBRP_STATIC
|
|
|
-#define STB_RECT_PACK_IMPLEMENTATION
|
|
|
-#endif
|
|
|
-#ifdef IMGUI_STB_RECT_PACK_FILENAME
|
|
|
-#include IMGUI_STB_RECT_PACK_FILENAME
|
|
|
-#else
|
|
|
-#include "imstb_rectpack.h"
|
|
|
-#endif
|
|
|
-#endif
|
|
|
-
|
|
|
-struct ImFontBuildSrcGlyphFT
|
|
|
-{
|
|
|
- GlyphInfo Info;
|
|
|
- uint32_t Codepoint;
|
|
|
- unsigned int* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array
|
|
|
-
|
|
|
- ImFontBuildSrcGlyphFT() { memset((void*)this, 0, sizeof(*this)); }
|
|
|
-};
|
|
|
-
|
|
|
-struct ImFontBuildSrcDataFT
|
|
|
-{
|
|
|
- FreeTypeFont Font;
|
|
|
- stbrp_rect* Rects; // Rectangle to pack. We first fill in their size and the packer will give us their position.
|
|
|
- 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)
|
|
|
- ImBitVector GlyphsSet; // Glyph bit map (random access, 1-bit per codepoint. This will be a maximum of 8KB)
|
|
|
- ImVector<ImFontBuildSrcGlyphFT> GlyphsList;
|
|
|
-};
|
|
|
-
|
|
|
-// Temporary data for one destination ImFont* (multiple source fonts can be merged into one destination ImFont)
|
|
|
-struct ImFontBuildDstDataFT
|
|
|
-{
|
|
|
- int SrcCount; // Number of source fonts targeting this destination font.
|
|
|
- int GlyphsHighest;
|
|
|
- int GlyphsCount;
|
|
|
- ImBitVector GlyphsSet; // This is used to resolve collision when multiple sources are merged into a same destination font.
|
|
|
-};
|
|
|
-
|
|
|
-bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, unsigned int extra_flags)
|
|
|
-{
|
|
|
- IM_ASSERT(atlas->Sources.Size > 0);
|
|
|
-
|
|
|
- ImFontAtlasBuildInit(atlas);
|
|
|
-
|
|
|
- // Clear atlas
|
|
|
- atlas->TexID._TexID = 0;
|
|
|
- atlas->TexWidth = atlas->TexHeight = 0;
|
|
|
- atlas->TexUvScale = ImVec2(0.0f, 0.0f);
|
|
|
- atlas->TexUvWhitePixel = ImVec2(0.0f, 0.0f);
|
|
|
- atlas->ClearTexData();
|
|
|
-
|
|
|
- // Temporary storage for building
|
|
|
- bool src_load_color = false;
|
|
|
- ImVector<ImFontBuildSrcDataFT> src_tmp_array;
|
|
|
- ImVector<ImFontBuildDstDataFT> dst_tmp_array;
|
|
|
- src_tmp_array.resize(atlas->Sources.Size);
|
|
|
- dst_tmp_array.resize(atlas->Fonts.Size);
|
|
|
- memset((void*)src_tmp_array.Data, 0, (size_t)src_tmp_array.size_in_bytes());
|
|
|
- memset((void*)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->Sources.Size; src_i++)
|
|
|
- {
|
|
|
- ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
|
|
- ImFontConfig& src = atlas->Sources[src_i];
|
|
|
- FreeTypeFont& font_face = src_tmp.Font;
|
|
|
- IM_ASSERT(src.DstFont && (!src.DstFont->IsLoaded() || src.DstFont->ContainerAtlas == atlas));
|
|
|
-
|
|
|
- // Find index from src.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 (src.DstFont == atlas->Fonts[output_i])
|
|
|
- src_tmp.DstIndex = output_i;
|
|
|
- IM_ASSERT(src_tmp.DstIndex != -1); // src.DstFont not pointing within atlas->Fonts[] array?
|
|
|
- if (src_tmp.DstIndex == -1)
|
|
|
- return false;
|
|
|
-
|
|
|
- // Load font
|
|
|
- if (!font_face.InitFont(ft_library, src, extra_flags))
|
|
|
- return false;
|
|
|
-
|
|
|
- // Measure highest codepoints
|
|
|
- src_load_color |= (src.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0;
|
|
|
- ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
|
|
- src_tmp.SrcRanges = src.GlyphRanges ? src.GlyphRanges : atlas->GetGlyphRangesDefault();
|
|
|
- for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
|
|
- {
|
|
|
- // Check for valid range. This may also help detect *some* dangling pointers, because a common
|
|
|
- // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent,
|
|
|
- // or to forget to zero-terminate the glyph range array.
|
|
|
- IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?");
|
|
|
- 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++)
|
|
|
- {
|
|
|
- ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
|
|
- ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex];
|
|
|
- src_tmp.GlyphsSet.Create(src_tmp.GlyphsHighest + 1);
|
|
|
- if (dst_tmp.GlyphsSet.Storage.empty())
|
|
|
- dst_tmp.GlyphsSet.Create(dst_tmp.GlyphsHighest + 1);
|
|
|
-
|
|
|
- for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
|
|
|
- for (int codepoint = src_range[0]; codepoint <= (int)src_range[1]; codepoint++)
|
|
|
- {
|
|
|
- if (dst_tmp.GlyphsSet.TestBit(codepoint)) // Don't overwrite existing glyphs. We could make this an option (e.g. MergeOverwrite)
|
|
|
- continue;
|
|
|
- uint32_t glyph_index = FT_Get_Char_Index(src_tmp.Font.Face, codepoint); // It is actually in the font? (FIXME-OPT: We are not storing the glyph_index..)
|
|
|
- if (glyph_index == 0)
|
|
|
- continue;
|
|
|
-
|
|
|
- // Add to avail set/counters
|
|
|
- src_tmp.GlyphsCount++;
|
|
|
- dst_tmp.GlyphsCount++;
|
|
|
- src_tmp.GlyphsSet.SetBit(codepoint);
|
|
|
- dst_tmp.GlyphsSet.SetBit(codepoint);
|
|
|
- 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++)
|
|
|
- {
|
|
|
- ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
|
|
- src_tmp.GlyphsList.reserve(src_tmp.GlyphsCount);
|
|
|
-
|
|
|
- IM_ASSERT(sizeof(src_tmp.GlyphsSet.Storage.Data[0]) == sizeof(ImU32));
|
|
|
- const ImU32* it_begin = src_tmp.GlyphsSet.Storage.begin();
|
|
|
- const ImU32* it_end = src_tmp.GlyphsSet.Storage.end();
|
|
|
- for (const ImU32* it = it_begin; it < it_end; it++)
|
|
|
- if (ImU32 entries_32 = *it)
|
|
|
- for (ImU32 bit_n = 0; bit_n < 32; bit_n++)
|
|
|
- if (entries_32 & ((ImU32)1 << bit_n))
|
|
|
- {
|
|
|
- ImFontBuildSrcGlyphFT src_glyph;
|
|
|
- src_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n);
|
|
|
- //src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it..
|
|
|
- src_tmp.GlyphsList.push_back(src_glyph);
|
|
|
- }
|
|
|
- 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)
|
|
|
- // (We technically don't need to zero-clear buf_rects, but let's do it for the sake of sanity)
|
|
|
- ImVector<stbrp_rect> buf_rects;
|
|
|
- buf_rects.resize(total_glyphs_count);
|
|
|
- memset(buf_rects.Data, 0, (size_t)buf_rects.size_in_bytes());
|
|
|
-
|
|
|
- // Allocate temporary rasterization data buffers.
|
|
|
- // We could not find a way to retrieve accurate glyph size without rendering them.
|
|
|
- // (e.g. slot->metrics->width not always matching bitmap->width, especially considering the Oblique transform)
|
|
|
- // We allocate in chunks of 256 KB to not waste too much extra memory ahead. Hopefully users of FreeType won't mind the temporary allocations.
|
|
|
- const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024;
|
|
|
- int buf_bitmap_current_used_bytes = 0;
|
|
|
- ImVector<unsigned char*> buf_bitmap_buffers;
|
|
|
- buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
|
|
|
-
|
|
|
- // 4. Gather glyphs sizes so we can pack them in our virtual canvas.
|
|
|
- // 8. Render/rasterize font characters into the texture
|
|
|
- int total_surface = 0;
|
|
|
- int buf_rects_out_n = 0;
|
|
|
- const int pack_padding = atlas->TexGlyphPadding;
|
|
|
- for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
|
|
- {
|
|
|
- ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
|
|
- ImFontConfig& src = atlas->Sources[src_i];
|
|
|
- if (src_tmp.GlyphsCount == 0)
|
|
|
- continue;
|
|
|
-
|
|
|
- src_tmp.Rects = &buf_rects[buf_rects_out_n];
|
|
|
- buf_rects_out_n += src_tmp.GlyphsCount;
|
|
|
-
|
|
|
- // Compute multiply table if requested
|
|
|
- const bool multiply_enabled = (src.RasterizerMultiply != 1.0f);
|
|
|
- unsigned char multiply_table[256];
|
|
|
- if (multiply_enabled)
|
|
|
- ImFontAtlasBuildMultiplyCalcLookupTable(multiply_table, src.RasterizerMultiply);
|
|
|
-
|
|
|
- // Gather the sizes of all rectangles we will need to pack
|
|
|
- for (int glyph_i = 0; glyph_i < src_tmp.GlyphsList.Size; glyph_i++)
|
|
|
- {
|
|
|
- ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
|
|
|
-
|
|
|
- const FT_Glyph_Metrics* metrics = src_tmp.Font.LoadGlyph(src_glyph.Codepoint);
|
|
|
- if (metrics == nullptr)
|
|
|
- continue;
|
|
|
-
|
|
|
- // Render glyph into a bitmap (currently held by FreeType)
|
|
|
- const FT_Bitmap* ft_bitmap = src_tmp.Font.RenderGlyphAndGetInfo(&src_glyph.Info);
|
|
|
- if (ft_bitmap == nullptr)
|
|
|
- continue;
|
|
|
-
|
|
|
- // Allocate new temporary chunk if needed
|
|
|
- const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height * 4;
|
|
|
- if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE)
|
|
|
- {
|
|
|
- buf_bitmap_current_used_bytes = 0;
|
|
|
- buf_bitmap_buffers.push_back((unsigned char*)IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
|
|
|
- }
|
|
|
- IM_ASSERT(buf_bitmap_current_used_bytes + bitmap_size_in_bytes <= BITMAP_BUFFERS_CHUNK_SIZE); // We could probably allocate custom-sized buffer instead.
|
|
|
-
|
|
|
- // Blit rasterized pixels to our temporary buffer and keep a pointer to it.
|
|
|
- src_glyph.BitmapData = (unsigned int*)(buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes);
|
|
|
- buf_bitmap_current_used_bytes += bitmap_size_in_bytes;
|
|
|
- src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width, multiply_enabled ? multiply_table : nullptr);
|
|
|
-
|
|
|
- src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + pack_padding);
|
|
|
- src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + pack_padding);
|
|
|
- total_surface += src_tmp.Rects[glyph_i].w * src_tmp.Rects[glyph_i].h;
|
|
|
- }
|
|
|
- }
|
|
|
- for (int i = 0; i < atlas->CustomRects.Size; i++)
|
|
|
- total_surface += (atlas->CustomRects[i].Width + pack_padding) * (atlas->CustomRects[i].Height + pack_padding);
|
|
|
-
|
|
|
- // 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;
|
|
|
- const int num_nodes_for_packing_algorithm = atlas->TexWidth - atlas->TexGlyphPadding;
|
|
|
- ImVector<stbrp_node> pack_nodes;
|
|
|
- pack_nodes.resize(num_nodes_for_packing_algorithm);
|
|
|
- stbrp_context pack_context;
|
|
|
- stbrp_init_target(&pack_context, atlas->TexWidth - atlas->TexGlyphPadding, TEX_HEIGHT_MAX - atlas->TexGlyphPadding, pack_nodes.Data, pack_nodes.Size);
|
|
|
- ImFontAtlasBuildPackCustomRects(atlas, &pack_context);
|
|
|
-
|
|
|
- // 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++)
|
|
|
- {
|
|
|
- ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
|
|
- if (src_tmp.GlyphsCount == 0)
|
|
|
- continue;
|
|
|
-
|
|
|
- stbrp_pack_rects(&pack_context, 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->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight);
|
|
|
- if (src_load_color)
|
|
|
- {
|
|
|
- size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 4;
|
|
|
- atlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(tex_size);
|
|
|
- memset(atlas->TexPixelsRGBA32, 0, tex_size);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- size_t tex_size = (size_t)atlas->TexWidth * atlas->TexHeight * 1;
|
|
|
- atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(tex_size);
|
|
|
- memset(atlas->TexPixelsAlpha8, 0, tex_size);
|
|
|
- }
|
|
|
-
|
|
|
- // 8. Copy rasterized font characters back into the main texture
|
|
|
- // 9. Setup ImFont and glyphs for runtime
|
|
|
- bool tex_use_colors = false;
|
|
|
- for (int src_i = 0; src_i < src_tmp_array.Size; src_i++)
|
|
|
- {
|
|
|
- ImFontBuildSrcDataFT& src_tmp = src_tmp_array[src_i];
|
|
|
-
|
|
|
- // When merging fonts with MergeMode=true:
|
|
|
- // - We can have multiple input fonts writing into a same destination font.
|
|
|
- // - dst_font->Sources is != from src which is our source configuration.
|
|
|
- ImFontConfig& src = atlas->Sources[src_i];
|
|
|
- ImFont* dst_font = src.DstFont;
|
|
|
-
|
|
|
- const float ascent = src_tmp.Font.Info.Ascender;
|
|
|
- const float descent = src_tmp.Font.Info.Descender;
|
|
|
- ImFontAtlasBuildSetupFont(atlas, dst_font, &src, ascent, descent);
|
|
|
-
|
|
|
- if (src_tmp.GlyphsCount == 0)
|
|
|
- continue;
|
|
|
- const float font_off_x = src.GlyphOffset.x;
|
|
|
- const float font_off_y = src.GlyphOffset.y + IM_ROUND(dst_font->Ascent);
|
|
|
-
|
|
|
- const int padding = atlas->TexGlyphPadding;
|
|
|
- for (int glyph_i = 0; glyph_i < src_tmp.GlyphsCount; glyph_i++)
|
|
|
- {
|
|
|
- ImFontBuildSrcGlyphFT& src_glyph = src_tmp.GlyphsList[glyph_i];
|
|
|
- stbrp_rect& pack_rect = src_tmp.Rects[glyph_i];
|
|
|
- IM_ASSERT(pack_rect.was_packed);
|
|
|
- if (pack_rect.w == 0 && pack_rect.h == 0)
|
|
|
- continue;
|
|
|
-
|
|
|
- GlyphInfo& info = src_glyph.Info;
|
|
|
- IM_ASSERT(info.Width + padding <= pack_rect.w);
|
|
|
- IM_ASSERT(info.Height + padding <= pack_rect.h);
|
|
|
- const int tx = pack_rect.x + padding;
|
|
|
- const int ty = pack_rect.y + padding;
|
|
|
-
|
|
|
- // Register glyph
|
|
|
- float x0 = info.OffsetX * src_tmp.Font.InvRasterizationDensity + font_off_x;
|
|
|
- float y0 = info.OffsetY * src_tmp.Font.InvRasterizationDensity + font_off_y;
|
|
|
- float x1 = x0 + info.Width * src_tmp.Font.InvRasterizationDensity;
|
|
|
- float y1 = y0 + info.Height * src_tmp.Font.InvRasterizationDensity;
|
|
|
- float u0 = (tx) / (float)atlas->TexWidth;
|
|
|
- float v0 = (ty) / (float)atlas->TexHeight;
|
|
|
- float u1 = (tx + info.Width) / (float)atlas->TexWidth;
|
|
|
- float v1 = (ty + info.Height) / (float)atlas->TexHeight;
|
|
|
- dst_font->AddGlyph(&src, (ImWchar)src_glyph.Codepoint, x0, y0, x1, y1, u0, v0, u1, v1, info.AdvanceX * src_tmp.Font.InvRasterizationDensity);
|
|
|
-
|
|
|
- ImFontGlyph* dst_glyph = &dst_font->Glyphs.back();
|
|
|
- IM_ASSERT(dst_glyph->Codepoint == src_glyph.Codepoint);
|
|
|
- if (src_glyph.Info.IsColored)
|
|
|
- dst_glyph->Colored = tex_use_colors = true;
|
|
|
-
|
|
|
- // Blit from temporary buffer to final texture
|
|
|
- size_t blit_src_stride = (size_t)src_glyph.Info.Width;
|
|
|
- size_t blit_dst_stride = (size_t)atlas->TexWidth;
|
|
|
- unsigned int* blit_src = src_glyph.BitmapData;
|
|
|
- if (atlas->TexPixelsAlpha8 != nullptr)
|
|
|
- {
|
|
|
- unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx;
|
|
|
- for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
|
|
|
- for (int x = 0; x < info.Width; x++)
|
|
|
- blit_dst[x] = (unsigned char)((blit_src[x] >> IM_COL32_A_SHIFT) & 0xFF);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- unsigned int* blit_dst = atlas->TexPixelsRGBA32 + (ty * blit_dst_stride) + tx;
|
|
|
- for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
|
|
|
- for (int x = 0; x < info.Width; x++)
|
|
|
- blit_dst[x] = blit_src[x];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- src_tmp.Rects = nullptr;
|
|
|
- }
|
|
|
- atlas->TexPixelsUseColors = tex_use_colors;
|
|
|
-
|
|
|
- // Cleanup
|
|
|
- for (int buf_i = 0; buf_i < buf_bitmap_buffers.Size; buf_i++)
|
|
|
- IM_FREE(buf_bitmap_buffers[buf_i]);
|
|
|
- src_tmp_array.clear_destruct();
|
|
|
-
|
|
|
- ImFontAtlasBuildFinish(atlas);
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
// FreeType memory allocation callbacks
|
|
|
static void* FreeType_Alloc(FT_Memory /*memory*/, long size)
|
|
|
{
|
|
@@ -941,7 +515,7 @@ bool ImGui_ImplFreeType_FontAddGlyph(ImFontAtlas* atlas, ImFont* font, ImFontCon
|
|
|
// Render pixels to our temporary buffer
|
|
|
atlas->Builder->TempBuffer.resize(w * h * 4);
|
|
|
uint32_t* temp_buffer = (uint32_t*)atlas->Builder->TempBuffer.Data;
|
|
|
- bd_font_data->BlitGlyph(ft_bitmap, temp_buffer, w, nullptr);// multiply_enabled ? multiply_table : nullptr);
|
|
|
+ bd_font_data->BlitGlyph(ft_bitmap, temp_buffer, w);
|
|
|
|
|
|
float font_off_x = src->GlyphOffset.x;
|
|
|
float font_off_y = src->GlyphOffset.y + IM_ROUND(font->Ascent);
|