2023-11-27 21:38:00 +00:00
|
|
|
|
|
|
|
#include <toml.h>
|
|
|
|
|
|
|
|
#include "util.h"
|
|
|
|
#include "font.h"
|
|
|
|
|
2023-11-30 05:01:38 +00:00
|
|
|
int font_compare(const node_t *a, const node_t *b) {
|
|
|
|
const font_t *x = (const font_t *)a->data;
|
|
|
|
const font_t *y = (const font_t *)b->data;
|
2023-11-28 08:25:03 +00:00
|
|
|
|
|
|
|
return strcmp(x->name, y->name);
|
|
|
|
}
|
|
|
|
|
2023-11-30 05:01:38 +00:00
|
|
|
node_t *load_fonts(toml_table_t *table, const char *base_path) {
|
|
|
|
node_t *root = NULL;
|
2023-11-28 08:25:03 +00:00
|
|
|
|
|
|
|
// vast majority of projects should have only 1-2 fonts, but let's offer
|
|
|
|
// some room in case there's more.
|
|
|
|
for (int i = 0; i < 32; i++) {
|
|
|
|
const char *key = toml_key_in(table, i);
|
|
|
|
if (!key) break;
|
|
|
|
char fullname[200];
|
2023-11-30 05:01:38 +00:00
|
|
|
font_t font;
|
2023-11-28 08:25:03 +00:00
|
|
|
|
|
|
|
toml_datum_t filename = toml_string_in(table, key);
|
|
|
|
if (!filename.ok) {
|
|
|
|
error("couldn't load font ", key);
|
|
|
|
}
|
|
|
|
snprintf(fullname, 200, "%s/%s", base_path, filename.u.s);
|
2023-11-30 05:01:38 +00:00
|
|
|
font = font_create(key, fullname);
|
|
|
|
root = node_insert(root, &font, font_compare);
|
2023-11-28 08:25:03 +00:00
|
|
|
}
|
2023-11-30 05:01:38 +00:00
|
|
|
return root;
|
2023-11-28 08:25:03 +00:00
|
|
|
}
|
2023-11-30 05:01:38 +00:00
|
|
|
font_t *font_find(node_t *root, const char *key) {
|
|
|
|
font_t search = {.name = key};
|
|
|
|
node_t *node = node_search(root, &search, font_compare);
|
|
|
|
font_t *font = (font_t *)node->data;
|
2023-11-28 08:25:03 +00:00
|
|
|
|
2023-11-30 05:01:38 +00:00
|
|
|
if (font == NULL) {
|
2023-11-28 08:25:03 +00:00
|
|
|
error("couldn't find requested font ", key);
|
|
|
|
}
|
|
|
|
|
|
|
|
return font;
|
|
|
|
}
|
|
|
|
|
|
|
|
font_t font_create(const char *font_name, const char *filename) {
|
2023-11-27 21:38:00 +00:00
|
|
|
FILE *fp;
|
|
|
|
font_t font;
|
2023-11-27 23:33:40 +00:00
|
|
|
char errbuf[200];
|
|
|
|
map_t *map;
|
2023-11-27 21:38:00 +00:00
|
|
|
|
2023-11-28 06:40:36 +00:00
|
|
|
printf(" Processing %s...\n", font_name);
|
2023-11-27 21:38:00 +00:00
|
|
|
|
|
|
|
fp = fopen(filename, "r");
|
|
|
|
|
|
|
|
if (!fp) {
|
2023-11-27 23:33:40 +00:00
|
|
|
char str[200];
|
|
|
|
snprintf(str, 200, "can't open %s: ", filename);
|
|
|
|
error(str, strerror(errno));
|
2023-11-27 21:38:00 +00:00
|
|
|
}
|
2023-11-27 23:33:40 +00:00
|
|
|
toml_table_t *table = toml_parse_file(fp, errbuf, 200);
|
2023-11-27 21:38:00 +00:00
|
|
|
fclose(fp);
|
|
|
|
|
2023-11-27 23:33:40 +00:00
|
|
|
#define TOML_GET_KEY(var, key, func) toml_datum_t (var) = func(table, (key));\
|
2023-11-27 23:21:09 +00:00
|
|
|
if (!(var).ok) {\
|
2023-11-27 23:33:40 +00:00
|
|
|
char str[200];\
|
|
|
|
snprintf(str, 200, "key '%s' missing from", (key)); \
|
|
|
|
error(str, filename); \
|
2023-11-27 21:38:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TOML_GET_KEY(name, "name", toml_string_in)
|
|
|
|
TOML_GET_KEY(image_filename, "filename", toml_string_in)
|
|
|
|
TOML_GET_KEY(bpp, "bits_per_pixel", toml_int_in)
|
|
|
|
TOML_GET_KEY(width, "width", toml_int_in)
|
|
|
|
TOML_GET_KEY(height, "height", toml_int_in)
|
|
|
|
#undef TOML_GET_KEY
|
2023-11-27 23:33:40 +00:00
|
|
|
toml_table_t *mapping = toml_table_in(table, "map");
|
2023-11-27 21:38:00 +00:00
|
|
|
|
|
|
|
font.name = name.u.s;
|
2023-11-28 00:31:48 +00:00
|
|
|
font.image_filename = image_filename.u.s;
|
2023-11-27 23:33:40 +00:00
|
|
|
font.bits_per_pixel = bpp.u.i;
|
|
|
|
font.width = width.u.i;
|
|
|
|
font.height = height.u.i;
|
|
|
|
font.map_entries = map_create(mapping, &map);
|
2023-11-27 23:21:09 +00:00
|
|
|
font.map = map;
|
2023-11-27 21:38:00 +00:00
|
|
|
|
|
|
|
return font;
|
|
|
|
}
|
|
|
|
|
2023-11-27 23:21:09 +00:00
|
|
|
void font_destroy(font_t font) {
|
|
|
|
map_destroy(font.map);
|
|
|
|
free(font.name);
|
2023-11-28 00:43:49 +00:00
|
|
|
free(font.image_filename);
|
2023-11-27 23:21:09 +00:00
|
|
|
}
|
|
|
|
|
2023-11-27 21:38:00 +00:00
|
|
|
unsigned int map_create(toml_table_t *table, map_t **map) {
|
|
|
|
map_t *node;
|
|
|
|
map_t *next;
|
|
|
|
unsigned int nodes;
|
|
|
|
map_t *root = malloc(sizeof(map_t*));
|
|
|
|
toml_array_t *space = toml_array_in(table, " ");
|
|
|
|
toml_datum_t spcidx = toml_int_at(space, 0);
|
|
|
|
toml_datum_t spcwid = toml_int_at(space, 1);
|
|
|
|
if (!spcidx.ok) {
|
2023-11-27 23:33:40 +00:00
|
|
|
error("missing or inappropriate index for glyph: ' '", "");
|
2023-11-27 21:38:00 +00:00
|
|
|
}
|
|
|
|
if (!spcwid.ok) {
|
2023-11-27 23:33:40 +00:00
|
|
|
error("missing or inappropriate index for glyph: ' '", "");
|
2023-11-27 21:38:00 +00:00
|
|
|
}
|
|
|
|
node = root;
|
|
|
|
|
|
|
|
for (nodes = 1; ; nodes++) {
|
2023-11-27 23:33:40 +00:00
|
|
|
const char *key = toml_key_in(table, nodes);
|
2023-11-27 21:38:00 +00:00
|
|
|
if (!key) break;
|
|
|
|
toml_array_t *val = toml_array_in(table, key);
|
|
|
|
toml_datum_t index = toml_int_at(val, 0);
|
|
|
|
toml_datum_t width = toml_int_at(val, 1);
|
|
|
|
if (!index.ok) {
|
|
|
|
error("missing or inappropriate index for glyph: ", key);
|
|
|
|
}
|
|
|
|
if (!width.ok) {
|
|
|
|
error("missing or inappropriate width for glyph: ", key);
|
|
|
|
}
|
|
|
|
|
|
|
|
next = malloc(sizeof(map_t *));
|
|
|
|
next->glyph = key;
|
|
|
|
next->index = index.u.i;
|
|
|
|
next->width = width.u.i;
|
|
|
|
node->next = next;
|
|
|
|
node = next;
|
|
|
|
}
|
2023-11-27 23:21:09 +00:00
|
|
|
node->next = NULL;
|
|
|
|
|
|
|
|
*map = root;
|
|
|
|
return nodes;
|
|
|
|
}
|
|
|
|
|
|
|
|
void map_destroy(map_t *map) {
|
|
|
|
map_t *node = map;
|
|
|
|
map_t *next;
|
|
|
|
|
|
|
|
while ((next = node->next) != NULL) {
|
|
|
|
free(node);
|
|
|
|
node = next;
|
|
|
|
}
|
2023-11-27 21:38:00 +00:00
|
|
|
}
|