From c8d11459ec6a8d71f042e5b39cefd826e0cfab88 Mon Sep 17 00:00:00 2001 From: nick black Date: Thu, 21 Nov 2019 07:24:11 -0500 Subject: [PATCH] notcurses_render: set colors naively #5 --- src/bin/demo.c | 1 - src/lib/notcurses.c | 73 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/bin/demo.c b/src/bin/demo.c index 64743e3fb..01759ed2f 100644 --- a/src/bin/demo.c +++ b/src/bin/demo.c @@ -31,7 +31,6 @@ int main(void){ if(notcurses_render(nc)){ goto err; } - sleep(5); if(notcurses_stop(nc)){ return EXIT_FAILURE; } diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index 586b3e5b8..cf21c480c 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -30,7 +30,10 @@ // (pretty large) 500x200 terminal. At 80x43, it's less than 200KB. typedef struct cell { wchar_t cchar[CCHARW_MAX]; // 5 * 4b == 20b - uint64_t attrs; // 16 MSB of attr bits, 24 of fg, 24 of bg + // The attrword covers classic NCURSES attributes (16 bits), plus foreground + // and background color, stored as 3x8bits of RGB. At render time, these + // 24-bit values are quantized down to terminal capabilities, if necessary. + uint64_t attrs; uint32_t reserved; // 0 for now, serves to pad out struct } cell; @@ -91,6 +94,11 @@ const char* notcurses_version(void){ return NOTCURSES_VERSION; } +static inline int +fbcellidx(const ncplane* n, int row, int col){ + return row * n->lenx + col; +} + void ncplane_dimensions(const ncplane* n, int* rows, int* cols){ *rows = n->leny; *cols = n->lenx; @@ -350,29 +358,72 @@ erpchar(int c){ return EOF; } +#define CELL_RMASK 0x0000ff0000000000ull +#define CELL_GMASK 0x000000ff00000000ull +#define CELL_BMASK 0x00000000ff000000ull +#define CELL_RGBMASK (CELL_RMASK | CELL_GMASK | CELL_BMASK) + +static void +cell_set_fg(cell* c, unsigned r, unsigned g, unsigned b){ + uint64_t rgb = (r & 0xffull) << 40u; + rgb += (g & 0xffull) << 32u; + rgb += (b & 0xffull) << 24u; + c->attrs = (c->attrs & ~CELL_RGBMASK) | rgb; +} + +static void +cell_get_fb(const cell* c, unsigned* r, unsigned* g, unsigned* b){ + *r = (c->attrs & CELL_RMASK) >> 40u; + *g = (c->attrs & CELL_GMASK) >> 32; + *b = (c->attrs & CELL_BMASK) >> 24u; +} + int ncplane_fg_rgb8(ncplane* n, unsigned r, unsigned g, unsigned b){ if(r >= 256 || g >= 256 || b >= 256){ return -1; } - if(n->nc->setaf == NULL){ - return -1; - } + cell_set_fg(&n->fb[fbcellidx(n, n->y, n->x)], r, g, b); + return 0; +} + +static int +term_fg_rgb8(notcurses* nc, unsigned r, unsigned g, unsigned b){ // We typically want to use tputs() and tiperm() to acquire and write the // escapes, as these take into account terminal-specific delays, padding, // etc. For the case of DirectColor, there is no suitable terminfo entry, but // we're also in that case working with hopefully more robust terminals. // If it doesn't work, eh, it doesn't work. Fuck the world; save yourself. - static char rgbesc[] = "\x1b[38;2;%u;%u;%um"; - if(n->nc->RGBflag){ - if(write(n->nc->ttyfd, rgbesc, sizeof(rgbesc)) != sizeof(rgbesc)){ + if(nc->RGBflag){ + #define RGBESC "\x1b[38;2;" + // rrr;ggg;bbb;m + char rgbesc[] = RGBESC " "; + size_t len = strlen(RGBESC); + if(r > 99){ rgbesc[len++] = r / 100; } + if(r > 9){ rgbesc[len++] = (r % 100) / 10; } + rgbesc[len++] = r % 10; + rgbesc[len++] = ';'; + if(g > 99){ rgbesc[len++] = g / 100; } + if(g > 9){ rgbesc[len++] = (g % 100) / 10; } + rgbesc[len++] = g % 10; + rgbesc[len++] = ';'; + if(b > 99){ rgbesc[len++] = b / 100; } + if(b > 9){ rgbesc[len++] = (b % 100) / 10; } + rgbesc[len++] = b % 10; + rgbesc[len++] = ';'; + rgbesc[len++] = 'm'; + rgbesc[len] = '\0'; + ssize_t w; + if((w = write(nc->ttyfd, rgbesc, len)) < 0 || (size_t)w != len){ return -1; } }else{ + if(nc->setaf == NULL){ + return -1; + } // For 256-color indexed mode, start constructing a palette based off // the inputs *if we can change the palette*. If more than 256 are used on // a single screen, start... combining close ones? For 8-color mode, simple // interpolation. I have no idea what to do for 88 colors. FIXME - fprintf(stderr, "you need more colors, fool\n"); return -1; } return 0; @@ -399,7 +450,11 @@ int notcurses_render(notcurses* nc){ return -1; } for(y = 0 ; y < nc->stdscr->leny ; ++y){ - for(x = 0 ; x < nc->stdscr->lenx ; ++y){ + for(x = 0 ; x < nc->stdscr->lenx ; ++x){ + unsigned r, g, b; + // FIXME z-culling + cell_get_fb(&nc->stdscr->fb[fbcellidx(nc->stdscr, y, x)], &r, &g, &b); + term_fg_rgb8(nc, r, g, b); // FIXME blit those fuckers } }