static void *font_renderer_stb_init(const char *font_path, float font_size) { int ascent, descent, line_gap; stbtt_fontinfo info; uint8_t *font_data = NULL; stb_font_renderer_t *self = (stb_font_renderer_t*) calloc(1, sizeof(*self)); /* See https://github.com/nothings/stb/blob/master/stb_truetype.h#L539 */ font_size = STBTT_POINT_SIZE(font_size); if (!self) goto error; if (!filestream_read_file(font_path, (void**)&font_data, NULL)) goto error; if (!font_renderer_stb_create_atlas(self, font_data, font_size, 512, 512)) goto error; if (!stbtt_InitFont(&info, font_data, stbtt_GetFontOffsetForIndex(font_data, 0))) goto error; stbtt_GetFontVMetrics(&info, &ascent, &descent, &line_gap); self->line_height = ascent - descent; if (font_size < 0) self->line_height *= stbtt_ScaleForMappingEmToPixels(&info, -font_size); else self->line_height *= stbtt_ScaleForPixelHeight(&info, font_size); free(font_data); return self; error: if (font_data) free(font_data); if (self) font_renderer_stb_free(self); return NULL; }
static void *font_renderer_stb_init(const char *font_path, float font_size) { uint8_t *font_data = NULL; int ascent, descent, line_gap; stbtt_fontinfo info; stb_font_renderer_t *self = (stb_font_renderer_t*) calloc(1, sizeof(*self)); /* prevent warnings */ (void)rect_width_compare; if (!self) goto error; if (!read_file(font_path, (void**)&font_data, NULL)) goto error; if (!font_renderer_stb_create_atlas(self, font_data, font_size)) goto error; if (!stbtt_InitFont(&info, font_data, stbtt_GetFontOffsetForIndex(font_data, 0))) goto error; stbtt_GetFontVMetrics(&info, &ascent, &descent, &line_gap); self->line_height = ascent - descent;// + line_gap; if (font_size < 0) self->line_height *= stbtt_ScaleForMappingEmToPixels(&info, -font_size); else self->line_height *= stbtt_ScaleForPixelHeight(&info, font_size); free(font_data); return self; error: if (font_data) free(font_data); font_renderer_stb_free(self); return NULL; }
static bool font_renderer_stb_create_atlas(stb_font_renderer_t *self, uint8_t *font_data, float font_size, unsigned width, unsigned height) { int i; stbtt_pack_context pc = {NULL}; stbtt_packedchar chardata[256]; if (width > 2048 || height > 2048) { RARCH_WARN("[stb] Font atlas too big: %ux%u\n", width, height); goto error; } if (self->atlas.buffer) free(self->atlas.buffer); self->atlas.buffer = (uint8_t*)calloc(height, width); self->atlas.width = width; self->atlas.height = height; if (!self->atlas.buffer) goto error; stbtt_PackBegin(&pc, self->atlas.buffer, self->atlas.width, self->atlas.height, self->atlas.width, 1, NULL); stbtt_PackFontRange(&pc, font_data, 0, font_size, 0, 256, chardata); stbtt_PackEnd(&pc); for (i = 0; i < 256; ++i) { struct font_glyph *g = &self->glyphs[i]; stbtt_packedchar *c = &chardata[i]; g->advance_x = c->xadvance; g->atlas_offset_x = c->x0; g->atlas_offset_y = c->y0; g->draw_offset_x = c->xoff; g->draw_offset_y = c->yoff; g->width = c->x1 - c->x0; g->height = c->y1 - c->y0; /* Make sure important characters fit */ if (isalnum(i) && (!g->width || !g->height)) { int new_width = width * 1.2; int new_height = height * 1.2; /* Limit growth to 2048x2048 unless we already reached that */ if (width < 2048 || height < 2048) { new_width = MIN(new_width, 2048); new_height = MIN(new_height, 2048); } return font_renderer_stb_create_atlas(self, font_data, font_size, new_width, new_height); } } return true; error: self->atlas.width = self->atlas.height = 0; if (self->atlas.buffer) free(self->atlas.buffer); self->atlas.buffer = NULL; return false; }