Consider it a memorial.
This commit is contained in:
parent
21b9596a98
commit
6d84637d7e
4 changed files with 356 additions and 0 deletions
6
host/matelight/Makefile
Normal file
6
host/matelight/Makefile
Normal file
|
|
@ -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
|
||||
223
host/matelight/font.c
Normal file
223
host/matelight/font.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
|
||||
21
host/matelight/font.h
Normal file
21
host/matelight/font.h
Normal file
|
|
@ -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);
|
||||
|
||||
106
host/matelight/main.c
Normal file
106
host/matelight/main.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue