From 9ef5c135e894b2da95940e2556f4df9ce2205552 Mon Sep 17 00:00:00 2001 From: jaseg Date: Fri, 3 Jan 2014 13:19:44 +0100 Subject: Re-organized the host software directory layout --- host/main.c | 357 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 357 insertions(+) create mode 100644 host/main.c (limited to 'host/main.c') diff --git a/host/main.c b/host/main.c new file mode 100644 index 0000000..48532f7 --- /dev/null +++ b/host/main.c @@ -0,0 +1,357 @@ + +#include "font.h" +#include "color.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// CAUTION: REQUIRES INPUT TO BE \0-TERMINATED +// ...also, it does a hardcodes setlocale of LC_CTYPE to en_US.utf8 for... reasons. +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; + + // Calculate screen width of string prior to allocating memory for the frame buffer + 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(;;){ + while(*p == '\033'){ + p++; + // Jump over escape sequences + for(;;p++){ + if(!(*p == ';' || *p == '[' || ('0' <= *p && *p <= '9'))){ + p++; + break; + } + } + memset(&ps, 0, sizeof(mbstate_t)); + } + + 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; + unsigned int blink:4; + unsigned int bold:1; // TODO + unsigned int underline:1; + unsigned int strikethrough:1; + unsigned int fraktur:1; // TODO See: Flat10 Fraktur font + unsigned int invert:1; + } style = { + colortable[DEFAULT_FG_COLOR], colortable[DEFAULT_BG_COLOR], 0, 0, 0, 0, 0, 0 + }; + // Render glyphs (now with escape sequence rendering!) + 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! + // Disassemble the list of numbers, only accept SGR sequences (those ending with 'm') + 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 + x + i)*3)) = fg; + if(style.underline) + *((color_t *)(gbuf + (uly*gbufwidth + x + i)*3)) = fg; + } + } + x += g->width; + } + + // Render framebuffer to terminal, two pixels per character using Unicode box drawing stuff + 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 + // The following, rather convoluted logic tries to "save" escape sequences when rendering. + 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(;;){ + printf("\033[2J"); + for(unsigned int i=1; i