diff --git a/src/Font.cc b/src/Font.cc index 66381fd..0ad0a03 100644 --- a/src/Font.cc +++ b/src/Font.cc @@ -21,7 +21,7 @@ bool Initialize_FreeType() return true; } -bool Font::load(const char * fname, int size) +bool Font::load(const char * fname, int size, int outline_size) { if (!Initialize_FreeType()) { @@ -35,6 +35,8 @@ bool Font::load(const char * fname, int size) FT_Set_Pixel_Sizes(m_face, 0, size); + m_outline_size = outline_size; + return preload_glyphs(); } @@ -82,7 +84,7 @@ std::shared_ptr Font::get_glyph(FT_ULong character) return it->second; } std::shared_ptr glyph = std::make_shared(); - if (!glyph->load(m_face, character)) + if (!glyph->load(ft_library_handle, m_face, character, m_outline_size)) { glyph = nullptr; } diff --git a/src/Font.h b/src/Font.h index 2590246..0018e94 100644 --- a/src/Font.h +++ b/src/Font.h @@ -8,7 +8,7 @@ class Font { public: - bool load(const char * fname, int size); + bool load(const char * fname, int size, int outline_size); std::shared_ptr get_glyph(FT_ULong character); int get_advance() { return m_advance; } int get_line_height() { return m_line_height; } @@ -22,6 +22,7 @@ protected: int m_advance; int m_line_height; int m_baseline_offset; + int m_outline_size; }; #endif diff --git a/src/Glyph.cc b/src/Glyph.cc index 8f0a40d..1dfb445 100644 --- a/src/Glyph.cc +++ b/src/Glyph.cc @@ -1,17 +1,34 @@ #include "Glyph.h" +#include FT_STROKER_H #define round_up_26_6(val) (((val) + 63) >> 6u) -bool Glyph::load(FT_Face face, FT_ULong char_code) +bool Glyph::load(FT_Library library, FT_Face face, FT_ULong char_code, int outline_size) { - if (FT_Load_Char(face, char_code, FT_LOAD_RENDER) != 0) - return false; + FT_Glyph glyph; + FT_BitmapGlyph bitmap_glyph; + + FT_UInt glyph_index = FT_Get_Char_Index(face, char_code); + + /* Load the glyph to the face object */ + FT_Load_Glyph(face, glyph_index, FT_LOAD_NO_BITMAP); + FT_Get_Glyph(face->glyph, &glyph); + + if (outline_size > 0) + { + FT_Stroker stroker; + FT_Stroker_New(library, &stroker); + FT_Stroker_Set(stroker, outline_size, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0); + FT_Glyph_StrokeBorder(&glyph, stroker, false, true); + } + FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, nullptr, true); + bitmap_glyph = reinterpret_cast(glyph); m_texture = glcxx::Texture::create(); m_texture->bind(GL_TEXTURE_2D); - int width = face->glyph->bitmap.width; + int width = bitmap_glyph->bitmap.width; int rounded_width = glcxx::Texture::next_power_of_2(width); - int height = face->glyph->bitmap.rows; + int height = bitmap_glyph->bitmap.rows; int rounded_height = glcxx::Texture::next_power_of_2(height); m_advance = round_up_26_6(face->glyph->advance.x); uint8_t * texture = new uint8_t[rounded_width * rounded_height]; @@ -19,7 +36,7 @@ bool Glyph::load(FT_Face face, FT_ULong char_code) for (int i = 0; i < height; i++) { memcpy(&texture[rounded_width * i], - &face->glyph->bitmap.buffer[width * (height - i - 1)], + &bitmap_glyph->bitmap.buffer[width * (height - i - 1)], width); } @@ -34,8 +51,8 @@ bool Glyph::load(FT_Face face, FT_ULong char_code) m_array = glcxx::Array::create(); m_array->bind(); - int left = face->glyph->bitmap_left; - int top = face->glyph->bitmap_top; + int left = bitmap_glyph->left; + int top = bitmap_glyph->top; float s_max = width / (float)rounded_width; float t_max = height / (float)rounded_height; m_buffer = glcxx::Buffer::create(GL_ARRAY_BUFFER, GL_STATIC_DRAW, { @@ -48,5 +65,7 @@ bool Glyph::load(FT_Face face, FT_ULong char_code) glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); + FT_Done_Glyph(glyph); + return true; } diff --git a/src/Glyph.h b/src/Glyph.h index 05913a8..8046678 100644 --- a/src/Glyph.h +++ b/src/Glyph.h @@ -8,7 +8,7 @@ class Glyph { public: - bool load(FT_Face face, FT_ULong char_code); + bool load(FT_Library library, FT_Face face, FT_ULong char_code, int outline_size); int get_advance() { return m_advance; } void render() { diff --git a/src/main.cc b/src/main.cc index 606e327..f6b3cfe 100644 --- a/src/main.cc +++ b/src/main.cc @@ -14,6 +14,7 @@ std::shared_ptr rect_shader; std::shared_ptr rect_array; std::shared_ptr rect_buffer; Font font; +Font outlined_font; #define WIDTH 800 #define HEIGHT 800 @@ -64,14 +65,20 @@ static void draw_string(int row) { static const char message[] = "Hello World! 0123456789_g*^#"; float color = row / 9.0; - text_shader->set_color(color, color, color, 1.0); int x = 0; int y = font.get_line_height() * row + font.get_baseline_offset(); for (size_t i = 0; i < sizeof(message) - 1; i++) { - auto g = font.get_glyph(message[i]); + auto g = outlined_font.get_glyph(message[i]); text_shader->set_position(x, y); + text_shader->set_color(1.0 - color, 1.0 - color, 1.0 - color, 1.0); g->render(); + + g = font.get_glyph(message[i]); + text_shader->set_position(x, y); + text_shader->set_color(color, color, color, 1.0); + g->render(); + x += g->get_advance(); } } @@ -148,7 +155,13 @@ int main(int argc, char *argv[]) return 2; } - if (!font.load(argv[1], HEIGHT / 10 * 7 / 10)) + if (!font.load(argv[1], HEIGHT / 10 * 7 / 10, 0)) + { + fprintf(stderr, "Error loading font from %s\n", argv[1]); + return 2; + } + + if (!outlined_font.load(argv[1], HEIGHT / 10 * 7 / 10, 128)) { fprintf(stderr, "Error loading font from %s\n", argv[1]); return 2;