commit db34bc9
uint
·
2026-10-17 13:09:55 +0000 UTC
parent a875246
add unicode texture loading, decoding glyph widths
3 files changed,
+113,
-11
+1,
-2
1@@ -3,8 +3,7 @@
2
3 #include "types.h"
4
5-i8 font_load(const char* path);
6+i8 font_load(const char* dir);
7 void font_destroy(void);
8
9 #endif /* FONT_H */
10-
+111,
-8
1@@ -1,19 +1,122 @@
2+#include <stdio.h>
3+#include <string.h>
4+
5 #include "client/font.h"
6 #include "renderer/renderer.h"
7
8-static MGTexture texture;
9+#define PATH_SIZE 4096
10+#define PAGES_CNT 256
11+
12+static i32 glyph_width(u16 c);
13+static u8 load_glyph_sizes(const char* path);
14+static MGTexture load_page(u8 page);
15+static u8 make_path(char* path, size_t size, const char* suffix);
16
17-i8 font_load(const char* path)
18+static MGTexture ascii;
19+static MGTexture unicode_pages[PAGES_CNT];
20+static u8 glyph_sizes[65536];
21+static char root[PATH_SIZE];
22+
23+/* the glyph bounds are stored in a byte:
24+ high nibble is the start
25+ low nibble is the end
26+ of the glyph (in half pixels). the width is found by
27+ (end - start + 1) / 2 + 1. */
28+static i32 glyph_width(u16 c)
29 {
30- texture = renderer_texture_load(path);
31- return texture != MGTEXTURE_INVALID;
32+ u8 size = glyph_sizes[c];
33+ i32 high = size >> 4; /* high nibble */
34+ i32 low = size & 15; /* low nibble */
35+
36+ if (!size)
37+ return 0;
38+
39+ return (low - high + 1) / 2 + 1;
40 }
41
42-void font_destroy(void)
43+/* load the glyph sizes from a binary file */
44+static u8 load_glyph_sizes(const char* path)
45+{
46+ FILE* file = fopen(path, "rb");
47+ size_t cnt = 0;
48+
49+ if (!file)
50+ return 0;
51+
52+ cnt = fread(glyph_sizes, 1, sizeof(glyph_sizes), file);
53+ fclose(file);
54+
55+ return cnt == sizeof(glyph_sizes);
56+}
57+
58+/* load a unicode page texture */
59+static MGTexture load_page(u8 page)
60+{
61+ char path[PATH_SIZE] = { 0 };
62+ int n = 0;
63+
64+ if (unicode_pages[page] != MGTEXTURE_INVALID)
65+ return unicode_pages[page];
66+
67+ n = snprintf(path, sizeof(path), "%s/textures/font/unicode_page_%02x.png", root, (unsigned)page);
68+ if (n < 0 || (size_t)n >= sizeof(path))
69+ return MGTEXTURE_INVALID;
70+
71+ unicode_pages[page] = renderer_texture_load(path);
72+ return unicode_pages[page];
73+}
74+
75+/* concatenating the root and a suffix */
76+static u8 make_path(char* path, size_t size, const char* suffix)
77+{
78+ int n = snprintf(path, size, "%s/%s", root, suffix);
79+ return n >= 0 && (size_t)n < size;
80+}
81+
82+i8 font_load(const char* dir)
83 {
84- if (texture != MGTEXTURE_INVALID)
85- renderer_texture_destroy(texture);
86+ char path[PATH_SIZE];
87+ size_t len;
88+
89+ font_destroy();
90+ if (!dir)
91+ return 0;
92+
93+ len = strlen(dir);
94+ if (len >= sizeof(root))
95+ return 0;
96+ memcpy(root, dir, len + 1);
97+
98+ if (!make_path(path, sizeof(path), "textures/font/ascii.png"))
99+ goto fail;
100+ ascii = renderer_texture_load(path);
101+ if (ascii == MGTEXTURE_INVALID)
102+ goto fail;
103
104- texture = MGTEXTURE_INVALID;
105+ if (!make_path(path, sizeof(path), "font/glyph_sizes.bin") || !load_glyph_sizes(path))
106+ goto fail;
107+
108+ return 1;
109+
110+fail:
111+ font_destroy();
112+ return 0;
113 }
114
115+void font_destroy(void)
116+{
117+ i32 i;
118+
119+ if (ascii != MGTEXTURE_INVALID)
120+ renderer_texture_destroy(ascii);
121+ ascii = MGTEXTURE_INVALID;
122+
123+ for (i = 0; i < PAGES_CNT; i++) {
124+ if (unicode_pages[i] != MGTEXTURE_INVALID)
125+ renderer_texture_destroy(unicode_pages[i]);
126+ unicode_pages[i] = MGTEXTURE_INVALID;
127+ }
128+
129+ memset(glyph_sizes, 0, sizeof(glyph_sizes));
130+ root[0] = '\0';
131+}
+1,
-1
1@@ -127,7 +127,7 @@ static void game_init(int argc, char** argv)
2 if (!game.client)
3 create_local_world();
4
5- font_load("assets/resourcepacks/1.8.9/assets/minecraft/textures/font/ascii.png");
6+ font_load("assets/resourcepacks/1.8.9/assets/minecraft");
7 }
8
9 /* run main loop */