#include "font.h" #include "color.h" #include #include #include #include #include #include #include #include /* 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); uint8_t *gbuf = NULL; unsigned int gbufwidth = 0; unsigned int gbufheight = 0; char *p = s; wchar_t c; mbstate_t ps = {0}; memset(&ps, 0, sizeof(mbstate_t)); if(!setlocale(LC_CTYPE, "en_US.utf8")){ fprintf(stderr, "Cannot set locale\n"); goto error; } for(;;){ size_t inc = mbrtowc(&c, p, MB_CUR_MAX, &ps); // MB_CUR_MAX is safe since p is \0-terminated if(inc == -1 || inc == -2){ fprintf(stderr, "Error rendering string: No valid UTF-8 input.\n"); goto error; } if(inc == 0) // Reached end of string break; p += inc; 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; // gbuf uses 3 bytes per color for r, g and b unsigned int gbufsize = gbufwidth*3*gbufheight; gbuf = malloc(gbufsize); if(gbuf == 0){ fprintf(stderr, "Cannot malloc() %d bytes.\n", gbufsize); goto error; } memset(gbuf, 0, gbufsize); unsigned int x = 0; p = s; memset(&ps, 0, sizeof(mbstate_t)); struct { color_t fg; color_t bg; int blink:4; int bold:1; // TODO int underline:1; int strikethrough:1; int fraktur:1; // TODO See: Flat10 Fraktur font int invert:1; } style = { colortable[DEFAULT_FG_COLOR], colortable[DEFAULT_BG_COLOR], 0, 0, 0, 0, 0, 0 }; for(;;){ // NOTE: This nested escape sequence parsing does not contain any unicode-awareness whatsoever if(*p == '\033'){ // Escape sequence YAY char *sequence_start = p++; if(*p == '['){ // This was a CSI! long elems[MAX_CSI_ELEMENTS]; int nelems; for(nelems = 0; nelemsy usually is a negative index of the glyph's baseline measured from the glyph's bottom int uly = gbufheight + g->y; for(int i=0; iwidth; i++){ if(style.strikethrough) *((color_t *)(gbuf + (sty*gbufwidth + i)*3)) = fg; if(style.underline) *((color_t *)(gbuf + (uly*gbufwidth + i)*3)) = fg; } } x += g->width; } for(unsigned int y=0; y < gbufheight; y++){ for(unsigned int x=0; x < gbufwidth; x++){ color_t c = *((color_t *)(gbuf + (y*gbufwidth + x)*3)); //printf("\033[0m%02x,%02x,%02x-%02x\033[38;5;%dm█", c.r, c.g, c.b, xterm_color_index(c), xterm_color_index(c)); printf("\033[38;5;%dm█", xterm_color_index(c)); } printf("\n"); } return 0; color_t lastfg = {0, 0, 0}, lastbg = {0, 0, 0}; printf("\e[38;5;0;48;5;0m"); for(unsigned int y=0; y < gbufheight; y+=2){ for(unsigned int x=0; x < gbufwidth; x++){ //Da magicks: ▀█▄ color_t ct = *((color_t *)(gbuf + (y*gbufwidth + x)*3)); // Top pixel color_t cb = *((color_t *)(gbuf + ((y+1)*gbufwidth + x)*3)); // Bottom pixel if(!memcmp(&ct, &lastfg, sizeof(color_t))){ if(!memcmp(&cb, &lastbg, sizeof(color_t))){ printf("▀"); }else if(!memcmp(&cb, &lastfg, sizeof(color_t))){ printf("█"); }else{ printf("\033[48;5;%dm▀", xterm_color_index(cb)); lastbg = cb; } }else if(!memcmp(&ct, &lastbg, sizeof(color_t))){ if(!memcmp(&cb, &lastfg, sizeof(color_t))){ printf("▄"); }else if(!memcmp(&cb, &lastbg, sizeof(color_t))){ printf(" "); }else{ printf("\033[38;5;%dm▄", xterm_color_index(cb)); lastfg = cb; } }else{ // No matches for the upper pixel if(!memcmp(&cb, &lastfg, sizeof(color_t))){ printf("\033[48;5;%dm▄", xterm_color_index(ct)); lastbg = ct; }else if(!memcmp(&cb, &lastbg, sizeof(color_t))){ printf("\033[38;5;%dm▀", xterm_color_index(ct)); lastfg = ct; }else{ printf("\033[38;5;%d;48;5;%dm▀", xterm_color_index(ct), xterm_color_index(cb)); lastfg = ct; lastbg = cb; } } } printf("\n"); } return 0; error: free(gbuf); 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