From 046b2b7a38ec66208c96be59c030294b6d10351b Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 16 Oct 2021 19:36:53 +0200 Subject: Add font rendering --- src/graphics/font.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 src/graphics/font.c (limited to 'src/graphics/font.c') diff --git a/src/graphics/font.c b/src/graphics/font.c new file mode 100644 index 0000000..9a1d637 --- /dev/null +++ b/src/graphics/font.c @@ -0,0 +1,119 @@ +#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; +} -- cgit v1.2.3