diff options
Diffstat (limited to 'host/matelight')
-rw-r--r-- | host/matelight/Makefile | 6 | ||||
-rw-r--r-- | host/matelight/font.c | 223 | ||||
-rw-r--r-- | host/matelight/font.h | 21 | ||||
-rw-r--r-- | host/matelight/main.c | 106 |
4 files changed, 356 insertions, 0 deletions
diff --git a/host/matelight/Makefile b/host/matelight/Makefile new file mode 100644 index 0000000..2a7e971 --- /dev/null +++ b/host/matelight/Makefile @@ -0,0 +1,6 @@ + +all: main.c font.c font.h + gcc -std=gnu11 -Wall -lm -o matelight -g -O0 main.c font.c + +clean: + rm matelight diff --git a/host/matelight/font.c b/host/matelight/font.c new file mode 100644 index 0000000..753c442 --- /dev/null +++ b/host/matelight/font.c @@ -0,0 +1,223 @@ + +#include "font.h" +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void render_glyph(glyph_t *g, char *buf, unsigned int bufwidth, unsigned int offx, unsigned int offy){ + unsigned int bitmap_row_width = g->width/8; + uint8_t *bitmap = ((uint8_t *)g) + sizeof(glyph_t); + printf("READING GLYPH FROM %016lx (BITMAP %016lx) SIZE %d ROW WIDTH %d\n", g, bitmap, sizeof(glyph_t), bitmap_row_width); + char *p = bitmap; + for(int i=0; i<bitmap_row_width*g->height; i++){ + printf("%02x ", *p++); + } + printf("\n"); + for(unsigned int y=0; y < g->height; y++){ + long int data = 0; + for(unsigned int i=0; i<bitmap_row_width; i++){ + data <<= 8; + data |= bitmap[y*bitmap_row_width+i]; + } + uint8_t *p = buf + (offy+y)*bufwidth + offx; + printf("R %02d %04lx ", y, data); + for(unsigned int x=0; x < g->width; x++){ + if(data&1) + printf("█"); + else + printf(" "); + *p++ = (data&1) ? 1 : 0; + data >>= 1; + } + printf("\n"); + } +} + +int read_bdf(FILE *f, glyph_t **glyph_table, unsigned int glyph_table_size){ + char* line = 0; + size_t len = 0; + + glyph_t current_glyph = {-1, -1, -1, -1}; + unsigned int dwidth = -1; + unsigned int encoding = -1; + void *glyph_data = 0; + + // Clear glyph table before use + memset(glyph_table, 0, sizeof(*glyph_table)); + + for(;;){ + size_t read = getline(&line, &len, f); + if(read == -1){ + fprintf(stderr, "Could not read line from font file\n"); + goto error; + } + if(read < 2) // Ignore empty lines + continue; + line[read-1] = '\0'; + char *endptr; + char *args = strchr(line, ' '); + if(args){ + *args = 0; + args++; + } + + if(strcmp("ENDFONT", line) == 0){ + break; + }else if(strcmp("ENCODING", line) == 0){ + if(!args){ + fprintf(stderr, "Invalid ENCODING line: %s %s\n", line, args); + goto error; + } + + encoding = strtol(args, &endptr, 10); + if(args == endptr || *endptr != '\0'){ + fprintf(stderr, "Invalid ENCODING line: %s %s\n", line, args); + goto error; + } + if(encoding > glyph_table_size){ + fprintf(stderr, "Codepoint out of valid range (0-%d): %d", glyph_table_size, encoding); + goto error; + } + + }else if(strcmp("BBX", line) == 0){ + if(!args){ + fprintf(stderr, "Invalid ENCODING line: %s %s\n", line, args); + goto error; + } + + endptr = 0; + char *w = strtok_r(args, " ", &endptr); + char *h = strtok_r(NULL, " ", &endptr); + char *x = strtok_r(NULL, " ", &endptr); + char *y = strtok_r(NULL, " ", &endptr); + if(!w || !h || !x || !y){ + fprintf(stderr, "Invalid BBX line: %s %s\n", line, args); + goto error; + } + current_glyph.width = atoi(w); + current_glyph.height = atoi(h); + current_glyph.x = atoi(x); + current_glyph.y = atoi(y); + + }else if(strcmp("DWIDTH", line) == 0){ + if(!args){ + fprintf(stderr, "Invalid ENCODING line: %s %s\n", line, args); + goto error; + } + + endptr = 0; + char *w = strtok_r(args, " ", &endptr); + char *h = strtok_r(NULL, " ", &endptr); + if(!w || !h){ + fprintf(stderr, "Invalid DWIDTH line: %s %s\n", line, args); + goto error; + } + + dwidth = strtol(w, &endptr, 10); + if(w == endptr || *endptr != '\0'){ + fprintf(stderr, "Invalid DWIDTH line: %s %s\n", line, args); + goto error; + } + + }else if(strcmp("BITMAP", line) == 0){ + unsigned int row_bytes = dwidth/8; + glyph_data = malloc(sizeof(glyph_t) + row_bytes * current_glyph.height); + if(!glyph_data){ + fprintf(stderr, "Cannot malloc() memory.\n"); + goto error; + } + uint8_t *bitmap = (uint8_t *)glyph_data + sizeof(glyph_t); + + if(current_glyph.width < 0 || dwidth < 0 || encoding < 0){ + fprintf(stderr, "Invalid glyph: "); + if(current_glyph.width < 0) + fprintf(stderr, "No bounding box given."); + if(dwidth < 0) + fprintf(stderr, "No data width given."); + if(encoding < 0) + fprintf(stderr, "No codepoint given."); + fprintf(stderr, "\n"); + goto error; + } + + if(current_glyph.width != dwidth){ + fprintf(stderr, "Invalid glyph: bounding box width != dwidth\n"); + goto error; + } + + unsigned int i=0; + while(1){ + read = getline(&line, &len, f); + if(read == -1){ + fprintf(stderr, "Could not read line from font file\n"); + goto error; + } + if(read < 2) // Ignore empty lines + continue; + line[read-1] = '\0'; + + if(strncmp("ENDCHAR", line, read) == 0) + break; + + if(i >= current_glyph.height){ + fprintf(stderr, "Too many rows of bitmap data in glyph %d: %d > %d\n", encoding, i+1, current_glyph.height); + goto error; + } + + //XXX This limits the maximum character width to sizeof(long)*8 (normally 64) piccells. + long int data = strtol(line, &endptr, 16); + if(line == endptr || *endptr != '\0'){ + fprintf(stderr, "Invalid bitmap data in glyph %d: %s\n", encoding, line); + goto error; + } + + // Right-align data + data >>= ((read-1)*4 - dwidth); + // Copy rightmost bytes of data to destination buffer + if(encoding == 'A') + printf("%02d %04lx ", i, data); + for(unsigned int j=0; j<row_bytes; j++){ + if(encoding == 'A') + for(unsigned int bit=0; bit<8; bit++){ + if(data&(1<<bit)) + printf("█"); + else + printf(" "); + } + bitmap[(i+1)*row_bytes-j-1] = data&0xFF; + data >>= 8; + } + if(encoding == 'A') + printf("\n"); + i++; + } + if(encoding == 'A'){ + printf("WRITING GLYPH %d TO %016lx (BITMAP %016lx) SIZE %d ROW WIDTH %d\n", encoding, glyph_data, bitmap, sizeof(glyph_t), row_bytes); + char *p = bitmap; + for(int i=0; i<row_bytes*current_glyph.height; i++){ + printf("%02x ", *p++); + } + printf("\n"); + } + memcpy(glyph_data, ¤t_glyph, sizeof(glyph_t)); + glyph_table[encoding] = glyph_data; + + // Reset things for next iteration + current_glyph.width = -1; + current_glyph.height = -1; + current_glyph.x = -1; + current_glyph.y = -1; + dwidth = -1; + encoding = -1; + } + } + return 0; +error: + // Free malloc()ed glyphs + free(glyph_data); + for(unsigned int i=0; i<sizeof(glyph_table)/sizeof(glyph_t *); i++) + free(glyph_table[i]); + return 1; +} + diff --git a/host/matelight/font.h b/host/matelight/font.h new file mode 100644 index 0000000..6213eb4 --- /dev/null +++ b/host/matelight/font.h @@ -0,0 +1,21 @@ + +#include <stdint.h> +#include <stdio.h> + +// CAUTION: A glyph struct is always followed by the glyph's bitmap. +typedef struct { + uint8_t width; + uint8_t height; + int8_t x; + int8_t y; +} glyph_t; + +// Size of Unicode's basic multilingual plane +#define BLP_SIZE 65536 + +// We could also use some fancy hashtable here, but unifont includes about 57k glyphs so we would hardly save any memory. +int read_bdf(FILE *f, glyph_t **glyph_table, unsigned int glyph_table_size); + +// Requires buf to point to a buffer at least of size glyph->width*glyph->height. +void render_glyph(glyph_t *glyph, char *buf, unsigned int bufwidth, unsigned int offx, unsigned int offy); + diff --git a/host/matelight/main.c b/host/matelight/main.c new file mode 100644 index 0000000..d40ef29 --- /dev/null +++ b/host/matelight/main.c @@ -0,0 +1,106 @@ + +#include "font.h" +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <wchar.h> + +/* CAUTION: REQUIRES INPUT TO BE \0-TERMINATED */ +int console_render(char *s, glyph_t **glyph_table, unsigned int glyph_table_size){ + unsigned int len = strlen(s); + char *t = s; + wchar_t *buf = calloc(len, sizeof(wchar_t)); + if(buf == 0){ + fprintf(stderr, "Cannot calloc() %ld bytes.\n", len*sizeof(wchar_t)); + goto error; + } + mbsrtowcs(buf, &t, len, NULL); + + char *gbuf = NULL; + unsigned int gbufwidth = 0; + unsigned int gbufheight = 0; + for(wchar_t *c=buf; *c; c++){ + if(*c > glyph_table_size){ + fprintf(stderr, "Error rendering string: Codepoint 0x%lx out of valid range (0-%d).\n", (long int)c, glyph_table_size); + goto error; + } + + glyph_t *g = glyph_table[*c]; + if(!g){ + fprintf(stderr, "Error rendering string: Codepoint 0x%lx not in font.\n", (long int)c); + goto error; + } + + if(g->height > gbufheight) + gbufheight = g->height; + + gbufwidth += g->width; + } + // For easier rendering on the terminal, round up to multiples of two + gbufheight += gbufheight&1; + + unsigned int gbufsize = gbufwidth*gbufheight; + gbuf = malloc(gbufsize); + if(gbuf == 0){ + fprintf(stderr, "Cannot malloc() %d bytes.\n", gbufsize); + goto error; + } + + unsigned int x = 0; + for(wchar_t *c=buf; *c; c++){ + glyph_t *g = glyph_table[*c]; + render_glyph(g, gbuf, gbufwidth, x, 0); + x += g->width; + } + + for(unsigned int y=0; y < gbufheight; y++){ + for(unsigned int x=0; x < gbufwidth; x++){ + //Da magicks: ▀█▄ + if(gbuf[y*gbufwidth + x]) + printf("█"); + else + printf(" "); + /* + char c1 = gbuf[y*gbufwidth + x]; + char c2 = gbuf[(y+1)*gbufwidth + x]; + if(c1 && c2) + printf("█"); + else if(c1 && !c2) + printf("▀"); + else if(!c1 && c2) + printf("▄"); + else + printf(" "); + */ + } + printf("\n"); + } + return 0; +error: + free(gbuf); + free(buf); + return 1; +} + +int main(int argc, char **argv){ + FILE *f = fopen("unifont.bdf", "r"); + if(!f){ + fprintf(stderr, "Error opening font file: %s\n", strerror(errno)); + return 1; + } + glyph_t* glyph_table[BLP_SIZE]; + if(read_bdf(f, glyph_table, BLP_SIZE)){ + fprintf(stderr, "Error reading font file.\n"); + return 1; + } + for(unsigned int i=1; i<argc; i++){ + if(console_render(argv[i], glyph_table, BLP_SIZE)){ + fprintf(stderr, "Error rendering text.\n"); + return 1; + } + printf("\n"); + } + return 0; +} |