You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
3.7 KiB

#include "TextRasterizer.h"
#include <cmath>
#include <limits>
#include <iostream>
TextRasterizer::TextRasterizer(std::string fontPath, int size, int resolution) {
FT_Init_FreeType(&lib);
face = std::unique_ptr<FT_Face>(new FT_Face);
if (FT_New_Face(lib, fontPath.c_str(), 0, face.get())) {
std::cout << "Could not open font" << std::endl;
return;
}
if (!isUnicodeBMP(*face)) {
std::cout << "Font is not Unicode BMP" << std::endl;
return;
}
if (FT_Set_Char_Size(*face, 0, size * 64, resolution, resolution)) {
std::cout << "Could not set font size" << std::endl;
return;
}
font = hb_ft_font_create(*face, NULL);
buffer = hb_buffer_create();
if (!hb_buffer_allocation_successful(buffer)) {
std::cout << "Could not create HarfBuzz buffer" << std::endl;
return;
}
}
TextRasterizer::~TextRasterizer() {
hb_buffer_destroy(buffer);
hb_font_destroy(font);
FT_Done_FreeType(lib);
}
std::unique_ptr<Glyph[]> TextRasterizer::rasterize(std::string text, int x, int y, unsigned int &glyphCount) {
hb_buffer_reset(buffer);
hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
hb_buffer_set_language(buffer, hb_language_from_string("en", 2));
hb_buffer_add_utf8(buffer, "Hello, World!", text.length(), 0, text.length());
hb_feature_t KerningOn = { HB_TAG('k', 'e', 'r', 'n'), 1, 0, std::numeric_limits<unsigned int>::max() };
hb_shape(font, buffer, &KerningOn, 1);
hb_glyph_info_t *glyphInfo = hb_buffer_get_glyph_infos(buffer, &glyphCount);
hb_glyph_position_t *glyphPos = hb_buffer_get_glyph_positions(buffer, &glyphCount);
std::unique_ptr<Glyph[]> glyphs = std::unique_ptr<Glyph[]>(new Glyph[glyphCount]);
for (int i = 0; i < glyphCount; i++) {
if (FT_Load_Glyph(*face, glyphInfo[i].codepoint, FT_LOAD_DEFAULT)) {
std::cout << "Could not load glyph" << std::endl;
return nullptr;
}
FT_GlyphSlot slot = (*face)->glyph;
if (FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL)) {
std::cout << "Could not render glyph" << std::endl;
return nullptr;
}
FT_Bitmap ftBitmap = slot->bitmap;
glyphs[i].textureWidth = pow(2, ceil(log(ftBitmap.width) / log(2)));
glyphs[i].textureHeight = pow(2, ceil(log(ftBitmap.rows) / log(2)));
glyphs[i].textureData = std::unique_ptr<unsigned char[]>(new unsigned char[glyphs[i].textureWidth * glyphs[i].textureHeight]);
for (int iy = 0; iy < ftBitmap.rows; iy++) {
memcpy(glyphs[i].textureData.get() + iy * glyphs[i].textureWidth, ftBitmap.buffer + iy * ftBitmap.width, ftBitmap.width);
}
float xa = (float) glyphPos[i].x_advance / 64;
float ya = (float) glyphPos[i].y_advance / 64;
float xo = (float) glyphPos[i].x_offset / 64;
float yo = (float) glyphPos[i].y_offset / 64;
glyphs[i].x0 = x + xo + slot->bitmap_left;
glyphs[i].y0 = floor(y + yo + slot->bitmap_top);
glyphs[i].x1 = glyphs[i].x0 + ftBitmap.width;
glyphs[i].y1 = floor(glyphs[i].y0 - ftBitmap.rows);
glyphs[i].s0 = 0.0f;
glyphs[i].t0 = 0.0f;
glyphs[i].s1 = (float) ftBitmap.width / glyphs[i].textureWidth;
glyphs[i].t1 = (float) ftBitmap.rows / glyphs[i].textureHeight;
x += xa;
y += ya;
}
return glyphs;
}
bool TextRasterizer::isUnicodeBMP(FT_Face face) {
for (int i = 0; i < face->num_charmaps; i++) {
if (((face->charmaps[i]->platform_id == 0) && (face->charmaps[i]->encoding_id == 3)) || ((face->charmaps[i]->platform_id == 3) && (face->charmaps[i]->encoding_id == 1))) {
FT_Set_Charmap(face, face->charmaps[i]);
return true;
}
}
return false;
}