Add outlining around glyphs

This commit is contained in:
Josh Holtrop 2018-01-24 09:33:05 -05:00
parent c8325da7ed
commit fbe4b21e5e
5 changed files with 50 additions and 15 deletions

View File

@ -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<Glyph> Font::get_glyph(FT_ULong character)
return it->second;
}
std::shared_ptr<Glyph> glyph = std::make_shared<Glyph>();
if (!glyph->load(m_face, character))
if (!glyph->load(ft_library_handle, m_face, character, m_outline_size))
{
glyph = nullptr;
}

View File

@ -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<Glyph> 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

View File

@ -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<FT_BitmapGlyph>(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;
}

View File

@ -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()
{

View File

@ -14,6 +14,7 @@ std::shared_ptr<RectShader> rect_shader;
std::shared_ptr<glcxx::Array> rect_array;
std::shared_ptr<glcxx::Buffer> 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;