Skip to content

Instantly share code, notes, and snippets.

@rygorous
Last active October 31, 2023 00:45
Show Gist options
  • Save rygorous/6f2779a451d2040371e3acb79e16eaff to your computer and use it in GitHub Desktop.
Save rygorous/6f2779a451d2040371e3acb79e16eaff to your computer and use it in GitHub Desktop.
HarfBuzz->stb_truetype
// ---- loading a font
static void load_font(void)
{
hb_blob_t *blob;
hb_face_t *face;
size_t filelen = 0;
void *filedata = stb_file("c:/windows/fonts/arial.ttf", &filelen);
if (filedata == 0) stbpg_fatal("Couldn't load font");
if (!stbtt_InitFont(&font, filedata, stbtt_GetFontOffsetForIndex(filedata,0))) stbpg_fatal("Couldn't parse font");
font_scale = stbtt_ScaleForPixelHeight(&font, 32);
blob = hb_blob_create((const char *)filedata, (unsigned int)filelen, HB_MEMORY_MODE_READONLY, NULL, NULL);
if (!blob) stbpg_fatal("Font blob create failed");
face = hb_face_create(blob, 0);
if (!face) stbpg_fatal("Font face create failed");
hb_blob_destroy(blob); // face keeps its ref.
hb_font = hb_font_create(face);
if (!hb_font) stbpg_fatal("Font create failed");
hb_face_destroy(face); // font keeps ref
// stb_truetype only does TrueType/OpenType which HB supports natively
hb_ot_font_set_funcs(hb_font);
}
static void cleanup_font(void)
{
hb_font_destroy(hb_font);
}
// ---- shaping and rendering
static void print_message_shaped(int x, int y, const char *msg)
{
hb_buffer_t *buf;
hb_glyph_info_t *ginf;
hb_glyph_position_t *gpos;
unsigned int len = 0;
unsigned int i;
int j;
buf = hb_buffer_create();
if (!buf) stbpg_fatal("no buf");
// set up the buffer
hb_buffer_set_flags(buf, HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT); // beginning and end of text both
hb_buffer_add_utf8(buf, msg, -1, 0, -1);
hb_buffer_guess_segment_properties(buf);
// shape it
hb_shape(hb_font, buf, NULL, 0);
ginf = hb_buffer_get_glyph_infos(buf, &len);
gpos = hb_buffer_get_glyph_positions(buf, &len);
if ((!ginf || !gpos) && len) stbpg_fatal("no glyph info");
// make sure we have the glyphs
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
for (i = 0; i < len; ++i) {
int glyph = ginf[i].codepoint;
if (!glyphs[glyph].init)
bake_glyph(&font, font_scale, glyph);
}
// render the text
glBegin(GL_QUADS);
for (i = 0; i < len; ++i) {
hb_glyph_info_t *gi = &ginf[i];
hb_glyph_position_t *gp = &gpos[i];
glyph_quad *gq = &glyphs[gi->codepoint];
float xb, yb;
xb = x + gp->x_offset*font_scale;
yb = y - gp->y_offset*font_scale; // our +y goes down, glyph +y goes up
for (j = 0; j < 4; ++j) {
int k = j ^ (j >> 1);
int xd = ((k&1) ? gq->w : 0);
int yd = ((k&2) ? gq->h : 0);
glTexCoord2f(1.0f * (gq->x0 + xd) / FONT_W, 1.0f * (gq->y0 + yd) / FONT_H);
glVertex2f(xb + (gq->xo + xd)/((float) OVERSAMPLE), yb + (gq->yo + yd)/((float)OVERSAMPLE));
}
x += gp->x_advance*font_scale;
}
glEnd();
hb_buffer_destroy(buf);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment