aboutsummaryrefslogtreecommitdiff
path: root/host/matelight
diff options
context:
space:
mode:
Diffstat (limited to 'host/matelight')
-rw-r--r--host/matelight/Makefile6
-rw-r--r--host/matelight/font.c223
-rw-r--r--host/matelight/font.h21
-rw-r--r--host/matelight/main.c106
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, &current_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;
+}