113 lines
3.4 KiB
C++
113 lines
3.4 KiB
C++
#include "Font.h"
|
|
#include <iostream>
|
|
#include <stdint.h>
|
|
|
|
#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;
|
|
}
|
|
}
|