Add outlining around glyphs
This commit is contained in:
parent
c8325da7ed
commit
fbe4b21e5e
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
35
src/Glyph.cc
35
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<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;
|
||||
}
|
||||
|
@ -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()
|
||||
{
|
||||
|
19
src/main.cc
19
src/main.cc
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user