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 */