aboutsummaryrefslogtreecommitdiff
path: root/src/graphics/font.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/graphics/font.c')
-rw-r--r--src/graphics/font.c119
1 files changed, 119 insertions, 0 deletions
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 <stdio.h>
+
+#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;
+}