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;
}
|