diff --git a/src/gui/Font.cc b/src/gui/Font.cc new file mode 100644 index 0000000..66381fd --- /dev/null +++ b/src/gui/Font.cc @@ -0,0 +1,91 @@ +#include "Font.h" + +#define round_up_26_6(val) (((val) + 63) >> 6u) + +static FT_Library ft_library_handle; +static bool ft_initialized; + +bool Initialize_FreeType() +{ + if (ft_initialized) + { + return true; + } + + if (FT_Init_FreeType(&ft_library_handle) != 0) + { + return false; + } + + ft_initialized = true; + return true; +} + +bool Font::load(const char * fname, int size) +{ + if (!Initialize_FreeType()) + { + return false; + } + + if (FT_New_Face(ft_library_handle, fname, 0, &m_face) != 0) + { + return false; + } + + FT_Set_Pixel_Sizes(m_face, 0, size); + + return preload_glyphs(); +} + +bool Font::preload_glyphs() +{ + static const char preload_glyph_list[] = "HMgjqxy_|^"; + + int max_top = -9999; + int min_bottom = 9999; + m_advance = 0; + + for (size_t i = 0u; i < sizeof(preload_glyph_list) - 1u; i++) + { + std::shared_ptr g = get_glyph(preload_glyph_list[i]); + if (g == NULL) + { + return false; + } + if (m_face->glyph->bitmap_top > max_top) + { + max_top = m_face->glyph->bitmap_top; + } + int bitmap_bottom = m_face->glyph->bitmap_top - m_face->glyph->bitmap.rows; + if (bitmap_bottom < min_bottom) + { + min_bottom = bitmap_bottom; + } + if (g->get_advance() > m_advance) + { + m_advance = g->get_advance(); + } + } + + m_line_height = round_up_26_6(m_face->size->metrics.height); + m_baseline_offset = (m_line_height - (max_top - min_bottom)) / 2 - min_bottom; + + return true; +} + +std::shared_ptr Font::get_glyph(FT_ULong character) +{ + auto it = m_glyphs.find(character); + if (it != m_glyphs.end()) + { + return it->second; + } + std::shared_ptr glyph = std::make_shared(); + if (!glyph->load(m_face, character)) + { + glyph = nullptr; + } + m_glyphs[character] = glyph; + return glyph; +} diff --git a/src/gui/Font.h b/src/gui/Font.h new file mode 100644 index 0000000..300c4b2 --- /dev/null +++ b/src/gui/Font.h @@ -0,0 +1,24 @@ +#ifndef FONT_H +#define FONT_H + +#include +#include +#include "Glyph.h" + +class Font +{ +public: + bool load(const char * fname, int size); + std::shared_ptr get_glyph(FT_ULong character); + +protected: + bool preload_glyphs(); + + FT_Face m_face; + std::unordered_map> m_glyphs; + int m_advance; + int m_line_height; + int m_baseline_offset; +}; + +#endif