70{
72
73 if (
const FT_Error err = FT_Set_Pixel_Sizes(face, 0,
m_pixel_size); err != 0) {
75 "FT_Set_Pixel_Sizes({}) failed: {}",
m_pixel_size,
static_cast<int>(err));
76 return false;
77 }
78
79 if (const FT_Error err = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER); err != 0) {
81 "FT_Load_Glyph({}) failed: {}", glyph_index, static_cast<int>(err));
82 return false;
83 }
84
85 const FT_Bitmap& bmp = face->glyph->bitmap;
86 const uint32_t gw = bmp.width;
87 const uint32_t gh = bmp.rows;
88
89 constexpr uint32_t k_pad = 1;
90
95 }
96
99 "GlyphAtlas full at pixel_size={} atlas_size={}. "
100 "Construct with a larger atlas_size.",
102 return false;
103 }
104
108 "GlyphAtlas: TextureContainer pixel_bytes returned empty span");
109 return false;
110 }
111
113
114 for (uint32_t row = 0; row < gh; ++row) {
115 const uint8_t* src = bmp.buffer + static_cast<size_t>(row * static_cast<uint32_t>(std::abs(bmp.pitch)));
117 std::memcpy(dst, src, gw);
118 }
119
120 const float inv = 1.F /
static_cast<float>(
m_atlas_size);
121
122 GlyphMetrics m;
123 m.uv_x0 =
static_cast<float>(
m_cursor_x) * inv;
124 m.uv_y0 =
static_cast<float>(
m_cursor_y) * inv;
125 m.uv_x1 =
static_cast<float>(
m_cursor_x + gw) * inv;
126 m.uv_y1 =
static_cast<float>(
m_cursor_y + gh) * inv;
127 m.bearing_x = face->glyph->bitmap_left;
128 m.bearing_y = face->glyph->bitmap_top;
129 m.width = gw;
130 m.height = gh;
131 m.advance_x = static_cast<int32_t>(face->glyph->advance.x >> 6);
132
133 m_cache.emplace(glyph_index, m);
134
138 }
139
141 return true;
142}
#define MF_ERROR(comp, ctx,...)
const std::vector< float > * pixels
FT_Face get_face() const
Raw FT_Face handle for use by GlyphAtlas.
std::unique_ptr< Kakshya::TextureContainer > m_texture
std::unordered_map< FT_UInt, GlyphMetrics > m_cache
@ API
API calls from external code.
@ Portal
High-level user-facing API layer.