29 #include FT_FREETYPE_H // <freetype/freetype.h>
30 #include FT_MODULE_H // <freetype/ftmodapi.h>
31 #include FT_GLYPH_H // <freetype/ftglyph.h>
32 #include FT_SYNTHESIS_H // <freetype/ftsynth.h>
35 #pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
39 #pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
40 #pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
94 float MaxAdvanceWidth;
101 bool InitFont(FT_Library ft_library,
const ImFontConfig& cfg,
unsigned int extra_user_flags);
103 void SetPixelHeight(
int pixel_height);
104 const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint);
105 const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info);
106 void BlitGlyph(
const FT_Bitmap* ft_bitmap, uint8_t*
dst, uint32_t dst_pitch,
unsigned char* multiply_table =
NULL);
107 ~FreeTypeFont() { CloseFont(); }
112 unsigned int UserFlags;
114 FT_Render_Mode RenderMode;
118 #define FT_CEIL(X) (((X + 63) & -64) / 64)
120 bool FreeTypeFont::InitFont(FT_Library ft_library,
const ImFontConfig& cfg,
unsigned int extra_user_flags)
125 error = FT_Select_Charmap(Face, FT_ENCODING_UNICODE);
134 LoadFlags = FT_LOAD_NO_BITMAP;
136 LoadFlags |= FT_LOAD_NO_HINTING;
138 LoadFlags |= FT_LOAD_NO_AUTOHINT;
140 LoadFlags |= FT_LOAD_FORCE_AUTOHINT;
142 LoadFlags |= FT_LOAD_TARGET_LIGHT;
144 LoadFlags |= FT_LOAD_TARGET_MONO;
146 LoadFlags |= FT_LOAD_TARGET_NORMAL;
149 RenderMode = FT_RENDER_MODE_MONO;
151 RenderMode = FT_RENDER_MODE_NORMAL;
156 void FreeTypeFont::CloseFont()
165 void FreeTypeFont::SetPixelHeight(
int pixel_height)
170 FT_Size_RequestRec
req;
171 req.type = FT_SIZE_REQUEST_TYPE_REAL_DIM;
173 req.height = (uint32_t)pixel_height * 64;
174 req.horiResolution = 0;
175 req.vertResolution = 0;
176 FT_Request_Size(Face, &
req);
179 FT_Size_Metrics metrics = Face->size->metrics;
180 Info.PixelHeight = (uint32_t)pixel_height;
182 Info.Descender = (float)
FT_CEIL(metrics.descender);
184 Info.LineGap = (float)
FT_CEIL(metrics.height - metrics.ascender + metrics.descender);
185 Info.MaxAdvanceWidth = (float)
FT_CEIL(metrics.max_advance);
188 const FT_Glyph_Metrics* FreeTypeFont::LoadGlyph(uint32_t codepoint)
190 uint32_t glyph_index = FT_Get_Char_Index(Face, codepoint);
191 if (glyph_index == 0)
193 FT_Error
error = FT_Load_Glyph(Face, glyph_index, LoadFlags);
198 FT_GlyphSlot slot = Face->glyph;
199 IM_ASSERT(slot->format == FT_GLYPH_FORMAT_OUTLINE);
203 FT_GlyphSlot_Embolden(slot);
206 FT_GlyphSlot_Oblique(slot);
213 return &slot->metrics;
216 const FT_Bitmap* FreeTypeFont::RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info)
218 FT_GlyphSlot slot = Face->glyph;
219 FT_Error
error = FT_Render_Glyph(slot, RenderMode);
223 FT_Bitmap* ft_bitmap = &Face->glyph->bitmap;
224 out_glyph_info->Width = (int)ft_bitmap->width;
225 out_glyph_info->Height = (
int)ft_bitmap->rows;
226 out_glyph_info->OffsetX = Face->glyph->bitmap_left;
227 out_glyph_info->OffsetY = -Face->glyph->bitmap_top;
228 out_glyph_info->AdvanceX = (float)
FT_CEIL(slot->advance.x);
233 void FreeTypeFont::BlitGlyph(
const FT_Bitmap* ft_bitmap, uint8_t*
dst, uint32_t dst_pitch,
unsigned char* multiply_table)
236 const uint32_t
w = ft_bitmap->width;
237 const uint32_t
h = ft_bitmap->rows;
238 const uint8_t*
src = ft_bitmap->buffer;
239 const uint32_t src_pitch = ft_bitmap->pitch;
241 switch (ft_bitmap->pixel_mode)
243 case FT_PIXEL_MODE_GRAY:
245 if (multiply_table ==
NULL)
247 for (uint32_t
y = 0;
y <
h;
y++,
src += src_pitch,
dst += dst_pitch)
252 for (uint32_t
y = 0;
y <
h;
y++,
src += src_pitch,
dst += dst_pitch)
253 for (uint32_t
x = 0;
x <
w;
x++)
258 case FT_PIXEL_MODE_MONO:
260 uint8_t color0 = multiply_table ? multiply_table[0] : 0;
261 uint8_t color1 = multiply_table ? multiply_table[255] : 255;
262 for (uint32_t
y = 0;
y <
h;
y++,
src += src_pitch,
dst += dst_pitch)
265 const uint8_t* bits_ptr =
src;
266 for (uint32_t
x = 0;
x <
w;
x++, bits <<= 1)
270 dst[
x] = (bits & 0x80) ? color1 : color0;
276 IM_ASSERT(0 &&
"FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!");
281 #ifndef STB_RECT_PACK_IMPLEMENTATION // in case the user already have an implementation in the _same_ compilation unit (e.g. unity builds)
282 #ifndef IMGUI_DISABLE_STB_RECT_PACK_IMPLEMENTATION
283 #define STBRP_ASSERT(x) IM_ASSERT(x)
285 #define STB_RECT_PACK_IMPLEMENTATION
287 #ifdef IMGUI_STB_RECT_PACK_FILENAME
288 #include IMGUI_STB_RECT_PACK_FILENAME
348 FreeTypeFont& font_face = src_tmp.
Font;
353 for (
int output_i = 0; output_i < atlas->
Fonts.
Size && src_tmp.
DstIndex == -1; output_i++)
361 if (!font_face.InitFont(ft_library, cfg, extra_flags))
367 for (
const ImWchar* src_range = src_tmp.
SrcRanges; src_range[0] && src_range[1]; src_range += 2)
374 int total_glyphs_count = 0;
375 for (
int src_i = 0; src_i < src_tmp_array.
Size; src_i++)
383 for (
const ImWchar* src_range = src_tmp.
SrcRanges; src_range[0] && src_range[1]; src_range += 2)
384 for (
int codepoint = src_range[0]; codepoint <= src_range[1]; codepoint++)
388 uint32_t glyph_index = FT_Get_Char_Index(src_tmp.
Font.Face, codepoint);
389 if (glyph_index == 0)
397 total_glyphs_count++;
402 for (
int src_i = 0; src_i < src_tmp_array.
Size; src_i++)
410 for (
const ImU32*
it = it_begin;
it < it_end;
it++)
412 for (
ImU32 bit_n = 0; bit_n < 32; bit_n++)
413 if (entries_32 & ((
ImU32)1 << bit_n))
416 memset(&src_glyph, 0,
sizeof(src_glyph));
424 for (
int dst_i = 0; dst_i < dst_tmp_array.
Size; dst_i++)
425 dst_tmp_array[dst_i].GlyphsSet.Clear();
426 dst_tmp_array.
clear();
431 buf_rects.
resize(total_glyphs_count);
438 const int BITMAP_BUFFERS_CHUNK_SIZE = 256 * 1024;
439 int buf_bitmap_current_used_bytes = 0;
441 buf_bitmap_buffers.
push_back((
unsigned char*)
IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
445 int total_surface = 0;
446 int buf_rects_out_n = 0;
447 for (
int src_i = 0; src_i < src_tmp_array.
Size; src_i++)
454 src_tmp.
Rects = &buf_rects[buf_rects_out_n];
459 unsigned char multiply_table[256];
460 if (multiply_enabled)
465 for (
int glyph_i = 0; glyph_i < src_tmp.
GlyphsList.
Size; glyph_i++)
469 const FT_Glyph_Metrics* metrics = src_tmp.
Font.LoadGlyph(src_glyph.
Codepoint);
475 const FT_Bitmap* ft_bitmap = src_tmp.
Font.RenderGlyphAndGetInfo(&src_glyph.
Info);
479 const int bitmap_size_in_bytes = src_glyph.
Info.Width * src_glyph.
Info.Height;
480 if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE)
482 buf_bitmap_current_used_bytes = 0;
483 buf_bitmap_buffers.
push_back((
unsigned char*)
IM_ALLOC(BITMAP_BUFFERS_CHUNK_SIZE));
487 src_glyph.
BitmapData = buf_bitmap_buffers.
back() + buf_bitmap_current_used_bytes;
488 buf_bitmap_current_used_bytes += bitmap_size_in_bytes;
489 src_tmp.
Font.BlitGlyph(ft_bitmap, src_glyph.
BitmapData, src_glyph.
Info.Width * 1, multiply_enabled ? multiply_table :
NULL);
493 total_surface += src_tmp.
Rects[glyph_i].
w * src_tmp.
Rects[glyph_i].
h;
500 const int surface_sqrt = (int)
ImSqrt((
float)total_surface) + 1;
505 atlas->
TexWidth = (surface_sqrt >= 4096*0.7f) ? 4096 : (surface_sqrt >= 2048*0.7
f) ? 2048 : (surface_sqrt >= 1024*0.7f) ? 1024 : 512;
509 const int TEX_HEIGHT_MAX = 1024 * 32;
512 pack_nodes.
resize(num_nodes_for_packing_algorithm);
518 for (
int src_i = 0; src_i < src_tmp_array.
Size; src_i++)
528 for (
int glyph_i = 0; glyph_i < src_tmp.
GlyphsCount; glyph_i++)
541 for (
int src_i = 0; src_i < src_tmp_array.
Size; src_i++)
550 const float ascent = src_tmp.
Font.Info.Ascender;
551 const float descent = src_tmp.
Font.Info.Descender;
557 for (
int glyph_i = 0; glyph_i < src_tmp.
GlyphsCount; glyph_i++)
563 GlyphInfo& info = src_glyph.
Info;
564 IM_ASSERT(info.Width + padding <= pack_rect.
w);
565 IM_ASSERT(info.Height + padding <= pack_rect.
h);
566 const int tx = pack_rect.
x + padding;
567 const int ty = pack_rect.
y + padding;
570 size_t blit_src_stride = (size_t)src_glyph.
Info.Width;
571 size_t blit_dst_stride = (
size_t)atlas->
TexWidth;
572 unsigned char* blit_src = src_glyph.
BitmapData;
573 unsigned char* blit_dst = atlas->
TexPixelsAlpha8 + (ty * blit_dst_stride) + tx;
574 for (
int y = info.Height;
y > 0;
y--, blit_dst += blit_dst_stride, blit_src += blit_src_stride)
575 memcpy(blit_dst, blit_src, blit_src_stride);
577 float char_advance_x_org = info.AdvanceX;
579 float char_off_x = font_off_x;
580 if (char_advance_x_org != char_advance_x_mod)
581 char_off_x += cfg.
PixelSnapH ?
IM_FLOOR((char_advance_x_mod - char_advance_x_org) * 0.5
f) : (char_advance_x_mod - char_advance_x_org) * 0.5
f;
584 float x0 = info.OffsetX + char_off_x;
585 float y0 = info.OffsetY + font_off_y;
586 float x1 = x0 + info.Width;
587 float y1 = y0 + info.Height;
588 float u0 = (tx) / (
float)atlas->
TexWidth;
590 float u1 = (tx + info.Width) / (
float)atlas->
TexWidth;
591 float v1 = (ty + info.Height) / (
float)atlas->
TexHeight;
599 for (
int buf_i = 0; buf_i < buf_bitmap_buffers.
Size; buf_i++)
600 IM_FREE(buf_bitmap_buffers[buf_i]);
601 for (
int src_i = 0; src_i < src_tmp_array.
Size; src_i++)
641 if (new_size > cur_size)
644 memcpy(new_block, block, (
size_t)cur_size);
655 FT_MemoryRec_ memory_rec = {};
656 memory_rec.user =
NULL;
662 FT_Library ft_library;
663 FT_Error
error = FT_New_Library(&memory_rec, &ft_library);
668 FT_Add_Default_Modules(ft_library);
671 FT_Done_Library(ft_library);