#include "Font.h" #include #include #define round_up_26_6(val) (((val) + 63) >> 6u) namespace jes { Font::Font() { m_loaded = false; } Font::~Font() { if (m_loaded) { FT_Done_Face(m_face); } } bool Font::load(FT_Library ft, const char * fname, size_t size) { if (FT_New_Face(ft, fname, 0, &m_face) != 0) { std::cerr << "Could not load font " << fname << std::endl; return false; } FT_Set_Pixel_Sizes(m_face, 0, size); GlyphRef x_glyph = load_glyph('x'); if (x_glyph == NULL) { std::cerr << "Could not load 'x' glyph from font" << fname << std::endl; return false; } m_glyphs['x'] = x_glyph; m_advance = x_glyph->get_advance(); m_line_height = round_up_26_6(m_face->size->metrics.height); m_baseline_offset = round_up_26_6((m_face->size->metrics.height - (m_face->size->metrics.ascender - m_face->size->metrics.descender)) / 2 - m_face->size->metrics.descender); m_loaded = true; return true; } Font::GlyphRef Font::load_glyph(FT_ULong char_code) { GlyphRef glyph = new Glyph(); if (glyph->load(m_face, char_code)) return glyph; return NULL; } Font::Glyph::Glyph() { m_loaded = false; } Font::Glyph::~Glyph() { if (m_loaded) { glDeleteTextures(1, &m_texture_id); } } bool Font::Glyph::load(FT_Face face, FT_ULong char_code) { if (FT_Load_Char(face, char_code, FT_LOAD_RENDER) != 0) return false; int width = face->glyph->bitmap.width; int height = face->glyph->bitmap.rows; int left = face->glyph->bitmap_left; int top = face->glyph->bitmap_top; m_advance = round_up_26_6(face->glyph->advance.x); uint8_t * texture = new uint8_t[width * height]; for (int i = 0; i < height; i++) { memcpy(&texture[width * i], &face->glyph->bitmap.buffer[width * (height - i - 1)], width); } glGenTextures(1, &m_texture_id); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_texture_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, texture); delete[] texture; float s = 1.0 / (width * 2); float t = 1.0 / (height * 2); GLfloat box[4][4] = { {(GLfloat)left, (GLfloat)(top - height), s, t}, {(GLfloat)(left + width - 1), (GLfloat)(top - height), 1 - s, t}, {(GLfloat)left, (GLfloat)(top - 1), s, 1 - t}, {(GLfloat)(left + width - 1), (GLfloat)(top - 1), 1 - s, 1 - t}, }; glGenBuffers(1, &m_vbo_id); glBindBuffer(GL_ARRAY_BUFFER, m_vbo_id); glBufferData(GL_ARRAY_BUFFER, sizeof(box), box, GL_STATIC_DRAW); m_loaded = true; return true; } }