aboutsummaryrefslogtreecommitdiff
path: root/src/graphics/font.c
blob: 9a1d637d093792596bb99e4073879fda2714795f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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;
}