From 4863c7e3df0673cb8f274362fd194bf18b9eba77 Mon Sep 17 00:00:00 2001 From: nick black Date: Wed, 1 Jul 2020 01:14:42 -0400 Subject: [PATCH] ncdirect_image_render: restore NCBLIT_2x2 #751 --- include/ncpp/Direct.hh | 4 +- include/notcurses/notcurses.h | 37 ++++++++++++---- python/src/notcurses/build_notcurses.py | 4 +- src/demo/demo.c | 16 +++---- src/lib/direct.cpp | 57 ++++++++++++++++++++++--- src/poc/dirgb.c | 2 +- 6 files changed, 92 insertions(+), 28 deletions(-) diff --git a/include/ncpp/Direct.hh b/include/ncpp/Direct.hh index b4d59d31a..a5392d9a6 100644 --- a/include/ncpp/Direct.hh +++ b/include/ncpp/Direct.hh @@ -44,7 +44,7 @@ namespace ncpp bool set_fg (unsigned r, unsigned g, unsigned b) const NOEXCEPT_MAYBE { - return error_guard (ncdirect_fg_rgb8 (direct, r, g, b), -1); + return error_guard (ncdirect_fg_rgb (direct, r, g, b), -1); } bool set_bg_default () const NOEXCEPT_MAYBE @@ -59,7 +59,7 @@ namespace ncpp bool set_bg (unsigned r, unsigned g, unsigned b) const NOEXCEPT_MAYBE { - return error_guard (ncdirect_bg_rgb8 (direct, r, g, b), -1); + return error_guard (ncdirect_bg_rgb (direct, r, g, b), -1); } int get_dim_x () const NOEXCEPT_MAYBE diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index 4b459f0d8..4dd8b3e3f 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -56,6 +56,13 @@ typedef enum { NCBLIT_SIXEL, // 6 rows, 1 col (RGB), spotty support among terminals } ncblitter_e; +// Alignment within a plane or terminal. Left/right-justified, or centered. +typedef enum { + NCALIGN_LEFT, + NCALIGN_CENTER, + NCALIGN_RIGHT, +} ncalign_e; + // How to scale an ncvisual during rendering. NCSCALE_NONE will apply no // scaling. NCSCALE_SCALE scales a visual to the plane's size, maintaining // aspect ratio. NCSCALE_STRETCH stretches and scales the image in an @@ -80,8 +87,19 @@ API struct ncdirect* ncdirect_init(const char* termtype, FILE* fp); API int ncdirect_fg(struct ncdirect* nc, unsigned rgb); API int ncdirect_bg(struct ncdirect* nc, unsigned rgb); +API int ncdirect_fg_palindex(struct ncdirect* nc, int pidx); +API int ncdirect_bg_palindex(struct ncdirect* nc, int pidx); + +// Returns the number of simultaneous colors claimed to be supported, or 1 if +// there is no color support. Note that several terminal emulators advertise +// more colors than they actually support, downsampling internally. +API int ncdirect_palette_size(const struct ncdirect* nc); + +// Output the EGC |egc| according to the channels |channels|. +API int ncdirect_putc(struct ncdirect* nc, uint64_t channels, const char* egc); + static inline int -ncdirect_bg_rgb8(struct ncdirect* nc, unsigned r, unsigned g, unsigned b){ +ncdirect_bg_rgb(struct ncdirect* nc, unsigned r, unsigned g, unsigned b){ if(r > 255 || g > 255 || b > 255){ return -1; } @@ -89,7 +107,7 @@ ncdirect_bg_rgb8(struct ncdirect* nc, unsigned r, unsigned g, unsigned b){ } static inline int -ncdirect_fg_rgb8(struct ncdirect* nc, unsigned r, unsigned g, unsigned b){ +ncdirect_fg_rgb(struct ncdirect* nc, unsigned r, unsigned g, unsigned b){ if(r > 255 || g > 255 || b > 255){ return -1; } @@ -127,6 +145,11 @@ API int ncdirect_cursor_yx(struct ncdirect* n, int* y, int* x); API int ncdirect_cursor_push(struct ncdirect* n); API int ncdirect_cursor_pop(struct ncdirect* n); +// Formatted printing (plus alignment relative to the terminal). +API int ncdirect_printf_aligned(struct ncdirect* n, int y, ncalign_e align, + const char* fmt, ...) + __attribute__ ((format (printf, 4, 5))); + // Display an image using the specified blitter and scaling. The image may // // be arbitrarily many rows -- the output will scroll -- but will only occupy // // the column of the cursor, and those to the right. @@ -1108,13 +1131,6 @@ notcurses_term_dim_yx(const struct notcurses* n, int* RESTRICT rows, int* RESTRI API char* notcurses_at_yx(struct notcurses* nc, int yoff, int xoff, uint32_t* attrword, uint64_t* channels); -// Alignment within the ncplane. Left/right-justified, or centered. -typedef enum { - NCALIGN_LEFT, - NCALIGN_CENTER, - NCALIGN_RIGHT, -} ncalign_e; - // Create a new ncplane at the specified offset (relative to the standard plane) // and the specified size. The number of rows and columns must both be positive. // This plane is initially at the top of the z-buffer, as if ncplane_move_top() @@ -1373,6 +1389,9 @@ ncplane_align(const struct ncplane* n, ncalign_e align, int c){ return 0; } int cols = ncplane_dim_x(n); + if(c > cols){ + return 0; + } if(align == NCALIGN_CENTER){ return (cols - c) / 2; }else if(align == NCALIGN_RIGHT){ diff --git a/python/src/notcurses/build_notcurses.py b/python/src/notcurses/build_notcurses.py index 6d3ab88f2..cbef55e14 100644 --- a/python/src/notcurses/build_notcurses.py +++ b/python/src/notcurses/build_notcurses.py @@ -486,8 +486,8 @@ int ncplane_putnstr_yx(struct ncplane* n, int y, int x, size_t s, const char* gc int ncplane_putnstr_aligned(struct ncplane* n, int y, ncalign_e align, size_t s, const char* gclustarr); int ncplane_qrcode(struct ncplane* n, ncblitter_e blitter, int* ymax, int* xmax, const void* data, size_t len); struct ncdirect* ncdirect_init(const char* termtype, FILE* fp); -int ncdirect_bg_rgb8(struct ncdirect* n, unsigned r, unsigned g, unsigned b); -int ncdirect_fg_rgb8(struct ncdirect* n, unsigned r, unsigned g, unsigned b); +int ncdirect_bg_rgb(struct ncdirect* n, unsigned r, unsigned g, unsigned b); +int ncdirect_fg_rgb(struct ncdirect* n, unsigned r, unsigned g, unsigned b); int ncdirect_fg(struct ncdirect* n, unsigned rgb); int ncdirect_bg(struct ncdirect* n, unsigned rgb); int ncdirect_styles_set(struct ncdirect* n, unsigned stylebits); diff --git a/src/demo/demo.c b/src/demo/demo.c index f7f4978a6..695a1c3e9 100644 --- a/src/demo/demo.c +++ b/src/demo/demo.c @@ -297,7 +297,7 @@ static int table_segment_color(struct ncdirect* nc, const char* str, const char* delim, unsigned color){ ncdirect_fg(nc, color); fputs(str, stdout); - ncdirect_fg_rgb8(nc, 178, 102, 255); + ncdirect_fg_rgb(nc, 178, 102, 255); fputs(delim, stdout); return 0; } @@ -309,12 +309,12 @@ table_segment(struct ncdirect* nc, const char* str, const char* delim){ static int table_printf(struct ncdirect* nc, const char* delim, const char* fmt, ...){ - ncdirect_fg_rgb8(nc, 0xD4, 0xAF, 0x37); + ncdirect_fg_rgb(nc, 0xD4, 0xAF, 0x37); va_list va; va_start(va, fmt); vfprintf(stdout, fmt, va); va_end(va); - ncdirect_fg_rgb8(nc, 178, 102, 255); + ncdirect_fg_rgb(nc, 178, 102, 255); fputs(delim, stdout); return 0; } @@ -371,11 +371,11 @@ summary_table(struct ncdirect* nc, const char* spec){ } ncdirect_fg(nc, rescolor); printf("%2zu", i); - ncdirect_fg_rgb8(nc, 178, 102, 255); + ncdirect_fg_rgb(nc, 178, 102, 255); printf("│"); ncdirect_fg(nc, rescolor); printf("%9s", demos[results[i].selector - 'a'].name); - ncdirect_fg_rgb8(nc, 178, 102, 255); + ncdirect_fg_rgb(nc, 178, 102, 255); printf("│%*ss│%7ju│%*s│ %*ss│%3jd│%7.1f│%7.1f║", PREFIXFMT(timebuf), (uintmax_t)(results[i].stats.renders), BPREFIXFMT(totalbuf), PREFIXFMT(rtimebuf), @@ -408,17 +408,17 @@ summary_table(struct ncdirect* nc, const char* spec){ table_printf(nc, "│", "%3ld", nsdelta ? totalrenderns * 100 / nsdelta : 0); table_printf(nc, "│", "%7.1f", nsdelta ? totalframes / ((double)nsdelta / GIG) : 0); printf("\n"); - ncdirect_fg_rgb8(nc, 0xff, 0xb0, 0xb0); + ncdirect_fg_rgb(nc, 0xff, 0xb0, 0xb0); fflush(stdout); // in case we print to stderr below, we want color from above if(failed){ fprintf(stderr, "\nError running demo.\nIs \"%s\" the correct data path? Supply it with -p.\n", datadir); } #ifdef DFSG_BUILD - ncdirect_fg_rgb8(nc, 0xfe, 0x20, 0x76); // PANTONE Strong Red C + 3x0x20 + ncdirect_fg_rgb(nc, 0xfe, 0x20, 0x76); // PANTONE Strong Red C + 3x0x20 fflush(stdout); // in case we print to stderr below, we want color from above fprintf(stderr, "\nDFSG version. Some demos are unavailable.\n"); #elif !defined(USE_MULTIMEDIA) // don't double-print for DFSG - ncdirect_fg_rgb8(nc, 0xfe, 0x20, 0x76); // PANTONE Strong Red C + 3x0x20 + ncdirect_fg_rgb(nc, 0xfe, 0x20, 0x76); // PANTONE Strong Red C + 3x0x20 fflush(stdout); // in case we print to stderr below, we want color from above fprintf(stderr, "\nNo multimedia support. Some demos are unavailable.\n"); #endif diff --git a/src/lib/direct.cpp b/src/lib/direct.cpp index 5c7a0f39f..18c00e03e 100644 --- a/src/lib/direct.cpp +++ b/src/lib/direct.cpp @@ -6,6 +6,24 @@ #include "visual-details.h" #include "internal.h" +int ncdirect_putc(ncdirect* nc, uint64_t channels, const char* egc){ + if(channels_fg_default_p(channels)){ + if(ncdirect_fg_default(nc)){ + return -1; + } + }else if(ncdirect_fg(nc, channels_fg(channels))){ + return -1; + } + if(channels_bg_default_p(channels)){ + if(ncdirect_bg_default(nc)){ + return -1; + } + }else if(ncdirect_bg(nc, channels_bg(channels))){ + return -1; + } + return fprintf(nc->ttyfp, "%s", egc); +} + int ncdirect_cursor_up(ncdirect* nc, int num){ if(num < 0){ return -1; @@ -106,8 +124,22 @@ int ncdirect_cursor_move_yx(ncdirect* n, int y, int x){ return -1; } +// verify that fp is actually a terminal, returning 1 if so +static int +verify_tty(FILE* fp){ + int fd = fileno(fp); + if(fd < 0){ + return -1; + } + return isatty(fd); +} + static int cursor_yx_get(FILE* outfp, FILE* infp, int* y, int* x){ + // we're never going to be getting an answer if it's not a terminal + if(!verify_tty(outfp)){ + return -1; + } if(fprintf(outfp, "\033[6n") != 4){ return -1; } @@ -232,13 +264,16 @@ ncdirect_dump_plane(ncdirect* n, const ncplane* np){ } ncdirect_fg(n, channels_fg(channels)); ncdirect_bg(n, channels_bg(channels)); -// fprintf(stderr, "%03d/%03d [%s]\n", y, x, egc); +//fprintf(stdout, "%03d/%03d [%s] (%03dx%03d)\n", y, x, egc, dimy, dimx); if(printf("%s", strlen(egc) == 0 ? " " : egc) < 0){ return -1; } } - ncdirect_cursor_down(n, 1); + // FIXME mystifyingly, we require this cursor_left() when using 2x2, but must + // not have it when using 2x1 (we insert blank lines otherwise). don't paper + // over it with a conditional, but instead get to the bottom of this FIXME. ncdirect_cursor_left(n, dimx); + ncdirect_cursor_down(n, 1); } return 0; } @@ -263,7 +298,7 @@ nc_err_e ncdirect_render_image(ncdirect* n, const char* file, ncblitter_e blitte return NCERR_DECODE; } //fprintf(stderr, "render %d/%d to %dx%d+%dx%d scaling: %d\n", ncv->rows, ncv->cols, begy, begx, leny, lenx, scale); - auto bset = rgba_blitter_low(n->utf8, scale, blitter, NCBLIT_DEFAULT); + auto bset = rgba_blitter_low(n->utf8, scale, true, blitter); if(!bset){ return NCERR_INVALID_ARG; } @@ -281,13 +316,15 @@ nc_err_e ncdirect_render_image(ncdirect* n, const char* file, ncblitter_e blitte leny = (leny / (double)ncv->rows) * ((double)disprows); lenx = (lenx / (double)ncv->cols) * ((double)dispcols); //fprintf(stderr, "render: %dx%d:%d+%d of %d/%d stride %u %p\n", begy, begx, leny, lenx, ncv->rows, ncv->cols, ncv->rowstride, ncv->data); - struct ncplane* faken = ncplane_create(NULL, NULL, disprows, dispcols, 0, 0, NULL); + struct ncplane* faken = ncplane_create(NULL, NULL, + disprows / encoding_y_scale(bset), + dispcols,// / encoding_x_scale(bset), + 0, 0, NULL); if(faken == NULL){ return NCERR_NOMEM; } if(ncvisual_blit(ncv, disprows, dispcols, faken, bset, - 0, 0, 0, 0, leny, lenx, - false)){ + 0, 0, 0, 0, leny, lenx, false)){ ncvisual_destroy(ncv); free_plane(faken); return NCERR_SYSTEM; @@ -314,3 +351,11 @@ int ncdirect_stop(ncdirect* nc){ } return ret; } + +int ncdirect_fg_palindex(ncdirect* nc, int pidx){ + return term_emit("setaf", tiparm(nc->tcache.setaf, pidx), nc->ttyfp, false); +} + +int ncdirect_bg_palindex(ncdirect* nc, int pidx){ + return term_emit("setab", tiparm(nc->tcache.setab, pidx), nc->ttyfp, false); +} diff --git a/src/poc/dirgb.c b/src/poc/dirgb.c index 06d6242fc..0fb257de1 100644 --- a/src/poc/dirgb.c +++ b/src/poc/dirgb.c @@ -11,7 +11,7 @@ print_b(struct ncdirect* nc, int r, int g, int total){ if(b > 255){ return 0; } - int ret = ncdirect_fg_rgb8(nc, r, g, b); + int ret = ncdirect_fg_rgb(nc, r, g, b); if(ret){ return -1; }