From 6d84637d7e34dbbda8a4192b17a274810a55adc3 Mon Sep 17 00:00:00 2001
From: jaseg <jaseg@jaseg.net>
Date: Thu, 2 Jan 2014 02:41:50 +0100
Subject: Consider it a memorial.

---
 host/matelight/Makefile |   6 ++
 host/matelight/font.c   | 223 ++++++++++++++++++++++++++++++++++++++++++++++++
 host/matelight/font.h   |  21 +++++
 host/matelight/main.c   | 106 +++++++++++++++++++++++
 4 files changed, 356 insertions(+)
 create mode 100644 host/matelight/Makefile
 create mode 100644 host/matelight/font.c
 create mode 100644 host/matelight/font.h
 create mode 100644 host/matelight/main.c

(limited to 'host')

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;
+}
-- 
cgit