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