#include "../../include/mgl/graphics/font.h" #include "../../include/mgl/system/fileutils.h" #include #define STB_RECT_PACK_IMPLEMENTATION #include "../../external/stb_rect_pack.h" #define STB_TRUETYPE_IMPLEMENTATION #include "../../external/stb_truetype.h" /* TODO: Test and fix .tcc files */ int mgl_font_load_from_file(mgl_font *self, const char *filepath, unsigned int font_size) { self->texture.id = 0; self->font_atlas.atlas = NULL; self->font_atlas.width = 0; self->font_atlas.height = 0; self->size = font_size; self->packed_chars = NULL; self->num_packed_chars = 0; mgl_filedata filedata; if(mgl_load_file(filepath, &filedata) != 0) { fprintf(stderr, "Error: failed to load font %s, error: mgl_load_file failed\n", filepath); return -1; } stbtt_fontinfo font; if(!stbtt_InitFont(&font, filedata.data, stbtt_GetFontOffsetForIndex(filedata.data, 0))) { fprintf(stderr, "Error: failed to load font %s, error: stbtt_InitFont failed\n", filepath); mgl_filedata_free(&filedata); return -1; } /* TODO: Optimize */ self->font_atlas.width = 1024; self->font_atlas.height = 1024; self->font_atlas.atlas = malloc(self->font_atlas.width * self->font_atlas.height); if(!self->font_atlas.atlas) { fprintf(stderr, "Error: failed to load font %s, error: out of memory\n", filepath); mgl_filedata_free(&filedata); mgl_font_unload(self); return -1; } self->num_packed_chars = 256; self->packed_chars = malloc(self->num_packed_chars * sizeof(stbtt_packedchar)); if(!self->packed_chars) { fprintf(stderr, "Error: failed to load font %s, error: out of memory\n", filepath); mgl_filedata_free(&filedata); mgl_font_unload(self); return -1; } stbtt_pack_context pc; if(!stbtt_PackBegin(&pc, self->font_atlas.atlas, self->font_atlas.width, self->font_atlas.height, self->font_atlas.width, 1, NULL)) { fprintf(stderr, "Error: failed to load font %s, error: stbtt_PackBegin failed\n", filepath); mgl_filedata_free(&filedata); mgl_font_unload(self); return -1; } if(!stbtt_PackFontRange(&pc, filedata.data, 0, self->size, 0, self->num_packed_chars, self->packed_chars)) { fprintf(stderr, "Error: failed to load font %s, error: stbtt_PackFontRange failed\n", filepath); mgl_filedata_free(&filedata); mgl_font_unload(self); stbtt_PackEnd(&pc); return -1; } stbtt_PackEnd(&pc); if(mgl_texture_load_from_memory(&self->texture, self->font_atlas.atlas, self->font_atlas.width, self->font_atlas.height, MGL_TEXTURE_ALPHA, NULL) != 0) { fprintf(stderr, "Error: failed to load font %s, error: mgl_texture_load_from_memory failed\n", filepath); mgl_filedata_free(&filedata); mgl_font_unload(self); return -1; } /* TODO: Use stbtt_GetCodepointSDF */ /* TODO: Use stbtt_PackSetOversampling */ mgl_filedata_free(&filedata); return 0; } void mgl_font_unload(mgl_font *self) { mgl_texture_unload(&self->texture); free(self->font_atlas.atlas); self->font_atlas.atlas = NULL; self->font_atlas.width = 0; self->font_atlas.height = 0; free(self->packed_chars); self->packed_chars = NULL; self->num_packed_chars = 0; } int mgl_font_get_glyph(mgl_font *self, uint32_t codepoint, mgl_font_glyph *glyph) { stbtt_packedchar *packed_chars = self->packed_chars; if(codepoint >= self->num_packed_chars) return -1; float x = 0.0f; float y = 0.0f; stbtt_aligned_quad quad; stbtt_GetPackedQuad(packed_chars, self->font_atlas.width, self->font_atlas.height, codepoint, &x, &y, &quad, 1); glyph->position = (mgl_vec2f){ quad.x0, quad.y0 }; glyph->size = (mgl_vec2f){ quad.x1 - quad.x0, quad.y1 - quad.y0 }; glyph->texture_position = (mgl_vec2f){ quad.s0, quad.t0 }; glyph->texture_size = (mgl_vec2f){ quad.s1 - quad.s0, quad.t1 - quad.t0 }; glyph->advance = x; return 0; }