#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 glyph = load_glyph('g'); if (glyph == NULL) { std::cerr << "Could not load 'g' glyph from font" << fname << std::endl; return false; } m_glyphs['g'] = glyph; m_advance = glyph->get_advance(); m_line_height = round_up_26_6(m_face->size->metrics.height); #if 0 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); #endif m_baseline_offset = 1 - m_face->glyph->bitmap_top + m_face->glyph->bitmap.rows; 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; } 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); } glActiveTexture(GL_TEXTURE0); m_texture = new GLTexture(); m_texture->create(width, height); 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); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_ALPHA, GL_UNSIGNED_BYTE, texture); delete[] texture; float s_max = width / (float)m_texture->get_width(); float t_max = height / (float)m_texture->get_height(); GLfloat box[4][4] = { {(GLfloat)left, (GLfloat)(top - height), 0.0, 0.0}, {(GLfloat)(left + width), (GLfloat)(top - height), s_max, 0.0}, {(GLfloat)left, (GLfloat)top, 0.0, t_max}, {(GLfloat)(left + width), (GLfloat)top, s_max, t_max}, }; 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; } }