From 4d5fd3c4658c1b5644d4514545a33e47536c0a7f Mon Sep 17 00:00:00 2001 From: nick black Date: Mon, 8 Mar 2021 11:22:32 -0500 Subject: [PATCH] add kitty_blit, divert to it in kitty #1095 --- src/lib/blit.c | 122 ++++++++++++++++++++++++--------------------- src/lib/blitset.h | 2 + src/lib/direct.cpp | 8 +-- src/lib/fill.c | 4 +- src/lib/internal.h | 52 ++++++++++--------- src/lib/kitty.c | 7 +++ src/lib/plot.h | 8 +-- src/lib/terminfo.c | 3 ++ src/lib/visual.cpp | 8 +-- 9 files changed, 120 insertions(+), 94 deletions(-) create mode 100644 src/lib/kitty.c diff --git a/src/lib/blit.c b/src/lib/blit.c index 3bed2d528..ad032fbe8 100644 --- a/src/lib/blit.c +++ b/src/lib/blit.c @@ -826,7 +826,7 @@ braille_blit(ncplane* nc, int placey, int placex, int linesize, // NCBLIT_DEFAULT is not included, as it has no defined properties. It ought // be replaced with some real blitter implementation by the calling widget. -static const struct blitset notcurses_blitters[] = { +static struct blitset notcurses_blitters[] = { { .geom = NCBLIT_8x1, .width = 1, .height = 8, .egcs = L" ▁▂▃▄▅▆▇█", .blit = tria_blit, .name = "eightstep", .fill = false, }, { .geom = NCBLIT_1x1, .width = 1, .height = 1, .egcs = L" █", @@ -847,29 +847,83 @@ static const struct blitset notcurses_blitters[] = { .blit = NULL, .name = NULL, .fill = false, }, }; -int notcurses_lex_blitter(const char* op, ncblitter_e* blitter){ +void set_pixel_blitter(blitter blitfxn){ + struct blitset* b = notcurses_blitters; + while(b->geom != NCBLIT_PIXEL){ + ++b; + } + b->blit = blitfxn; +} + +const struct blitset* lookup_blitset(const tinfo* tcache, ncblitter_e setid, bool may_degrade) { + if(setid == NCBLIT_DEFAULT){ // ought have resolved NCBLIT_DEFAULT before now + return NULL; + } + // without braille support, NCBLIT_BRAILLE decays to NCBLIT_3x2 + if(!tcache->braille && setid == NCBLIT_BRAILLE){ + if(may_degrade){ + setid = NCBLIT_3x2; + }else{ + return NULL; + } + } + // without pixel support, NCBLIT_PIXEL decays to NCBLIT_3x2 + if(!tcache->sixel_supported && setid == NCBLIT_PIXEL){ + if(may_degrade){ + setid = NCBLIT_3x2; + }else{ + return NULL; + } + } + // without sextant support, NCBLIT_3x2 decays to NCBLIT_2x2 + if(!tcache->sextants && setid == NCBLIT_3x2){ + if(may_degrade){ + setid = NCBLIT_2x2; + }else{ + return NULL; + } + } + // the only viable blitter in ASCII is NCBLIT_1x1 + if(!tcache->utf8 && setid != NCBLIT_1x1){ + if(may_degrade){ + setid = NCBLIT_1x1; + }else{ + return NULL; + } + } + const struct blitset* bset = notcurses_blitters; + while(bset->egcs){ + if(bset->geom == setid){ + return bset; + } + ++bset; + } + return NULL; +} + +int notcurses_lex_blitter(const char* op, ncblitter_e* blitfxn){ const struct blitset* bset = notcurses_blitters; while(bset->name){ if(strcasecmp(bset->name, op) == 0){ - *blitter = bset->geom; + *blitfxn = bset->geom; return 0; } ++bset; } if(strcasecmp("default", op) == 0){ - *blitter = NCBLIT_DEFAULT; + *blitfxn = NCBLIT_DEFAULT; return 0; } return -1; } -const char* notcurses_str_blitter(ncblitter_e blitter){ - if(blitter == NCBLIT_DEFAULT){ +const char* notcurses_str_blitter(ncblitter_e blitfxn){ + if(blitfxn == NCBLIT_DEFAULT){ return "default"; } const struct blitset* bset = notcurses_blitters; while(bset->name){ - if(bset->geom == blitter){ + if(bset->geom == blitfxn){ return bset->name; } ++bset; @@ -909,15 +963,15 @@ int ncblit_rgba(const void* data, int linesize, const struct ncvisual_options* v if(begy < 0 || begx < 0 || lenx < -1 || leny < -1){ return -1; } - ncblitter_e blitter; + ncblitter_e blitfxn; if(!vopts || vopts->blitter == NCBLIT_DEFAULT){ - blitter = ncvisual_media_defblitter(ncplane_notcurses(nc), NCSCALE_NONE); + blitfxn = ncvisual_media_defblitter(ncplane_notcurses(nc), NCSCALE_NONE); }else{ - blitter = vopts->blitter; + blitfxn = vopts->blitter; } const bool degrade = !(vopts->flags & NCVISUAL_OPTION_NODEGRADE); const notcurses* notc = ncplane_notcurses(nc); - const struct blitset* bset = lookup_blitset(¬c->tcache, blitter, degrade); + const struct blitset* bset = lookup_blitset(¬c->tcache, blitfxn, degrade); if(bset == NULL){ return -1; } @@ -926,52 +980,6 @@ int ncblit_rgba(const void* data, int linesize, const struct ncvisual_options* v leny, lenx, blend); } -const struct blitset* lookup_blitset(const tinfo* tcache, ncblitter_e setid, bool may_degrade) { - if(setid == NCBLIT_DEFAULT){ // ought have resolved NCBLIT_DEFAULT before now - return NULL; - } - // without braille support, NCBLIT_BRAILLE decays to NCBLIT_3x2 - if(!tcache->braille && setid == NCBLIT_BRAILLE){ - if(may_degrade){ - setid = NCBLIT_3x2; - }else{ - return NULL; - } - } - // without pixel support, NCBLIT_PIXEL decays to NCBLIT_3x2 - if(!tcache->sixel_supported && setid == NCBLIT_PIXEL){ - if(may_degrade){ - setid = NCBLIT_3x2; - }else{ - return NULL; - } - } - // without sextant support, NCBLIT_3x2 decays to NCBLIT_2x2 - if(!tcache->sextants && setid == NCBLIT_3x2){ - if(may_degrade){ - setid = NCBLIT_2x2; - }else{ - return NULL; - } - } - // the only viable blitter in ASCII is NCBLIT_1x1 - if(!tcache->utf8 && setid != NCBLIT_1x1){ - if(may_degrade){ - setid = NCBLIT_1x1; - }else{ - return NULL; - } - } - const struct blitset* bset = notcurses_blitters; - while(bset->egcs){ - if(bset->geom == setid){ - return bset; - } - ++bset; - } - return NULL; -} - ncblitter_e ncvisual_media_defblitter(const notcurses* nc, ncscale_e scale){ return rgba_blitter_default(&nc->tcache, scale); } diff --git a/src/lib/blitset.h b/src/lib/blitset.h index c91a09d3b..bff928a8d 100644 --- a/src/lib/blitset.h +++ b/src/lib/blitset.h @@ -44,4 +44,6 @@ ncplot_defblitter(const notcurses* nc){ return NCBLIT_1x1; } +void set_pixel_blitter(blitter blitfxn); + #endif diff --git a/src/lib/direct.cpp b/src/lib/direct.cpp index 4cb7e8568..a92e5f022 100644 --- a/src/lib/direct.cpp +++ b/src/lib/direct.cpp @@ -457,7 +457,7 @@ int ncdirect_raster_frame(ncdirect* n, ncdirectv* ncdv, ncalign_e align){ } ncdirectv* ncdirect_render_frame(ncdirect* n, const char* file, - ncblitter_e blitter, ncscale_e scale){ + ncblitter_e blitfxn, ncscale_e scale){ struct ncvisual* ncv = ncvisual_from_file(file); if(ncv == nullptr){ return nullptr; @@ -470,7 +470,7 @@ ncdirectv* ncdirect_render_frame(ncdirect* n, const char* file, return nullptr; } //fprintf(stderr, "render %d/%d to %d+%d scaling: %d\n", ncv->rows, ncv->cols, leny, lenx, scale); - auto bset = rgba_blitter_low(&n->tcache, scale, true, blitter); + auto bset = rgba_blitter_low(&n->tcache, scale, true, blitfxn); if(!bset){ ncvisual_destroy(ncv); return nullptr; @@ -524,8 +524,8 @@ ncdirectv* ncdirect_render_frame(ncdirect* n, const char* file, } int ncdirect_render_image(ncdirect* n, const char* file, ncalign_e align, - ncblitter_e blitter, ncscale_e scale){ - auto faken = ncdirect_render_frame(n, file, blitter, scale); + ncblitter_e blitfxn, ncscale_e scale){ + auto faken = ncdirect_render_frame(n, file, blitfxn, scale); if(!faken){ return -1; } diff --git a/src/lib/fill.c b/src/lib/fill.c index 259d6fe91..152cbbd1f 100644 --- a/src/lib/fill.c +++ b/src/lib/fill.c @@ -574,7 +574,7 @@ qrcode_cols(int version){ } int ncplane_qrcode(ncplane* n, int* ymax, int* xmax, const void* data, size_t len){ - const ncblitter_e blitter = NCBLIT_2x1; + const ncblitter_e blitfxn = NCBLIT_2x1; const int MAX_QR_VERSION = 40; // QR library only supports up to 40 if(*ymax <= 0 || *xmax <= 0){ return -1; @@ -639,7 +639,7 @@ int ncplane_qrcode(ncplane* n, int* ymax, int* xmax, const void* data, size_t le ret = square; struct ncvisual_options vopts = { .n = n, - .blitter = blitter, + .blitter = blitfxn, }; if(ncvisual_render(ncplane_notcurses(n), ncv, &vopts) == n){ ret = square; diff --git a/src/lib/internal.h b/src/lib/internal.h index 1a18c54b2..b4cef3902 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -380,6 +380,10 @@ typedef struct notcurses { unsigned stdio_blocking_save; // was stdio blocking at entry? restore on stop. } notcurses; +typedef int (*blitter)(struct ncplane* n, int placey, int placex, + int linesize, const void* data, int begy, int begx, + int leny, int lenx, unsigned blendcolors); + // a system for rendering RGBA pixels as text glyphs struct blitset { ncblitter_e geom; @@ -390,9 +394,7 @@ struct blitset { // quickly, i.e. it can be indexed as height arrays of 1 + height glyphs. i.e. // the first five braille EGCs are all 0 on the left, [0..4] on the right. const wchar_t* egcs; - int (*blit)(struct ncplane* n, int placey, int placex, - int linesize, const void* data, int begy, int begx, - int leny, int lenx, unsigned blendcolors); + blitter blit; const char* name; bool fill; }; @@ -719,26 +721,6 @@ memdup(const void* src, size_t len){ ALLOC void* bgra_to_rgba(const void* data, int rows, int rowstride, int cols); -API const struct blitset* lookup_blitset(const tinfo* tcache, ncblitter_e setid, bool may_degrade); - -static inline const struct blitset* -rgba_blitter_low(const tinfo* tcache, ncscale_e scale, bool maydegrade, - ncblitter_e blitrec) { - if(blitrec == NCBLIT_DEFAULT){ - blitrec = rgba_blitter_default(tcache, scale); - } - return lookup_blitset(tcache, blitrec, maydegrade); -} - -// RGBA visuals all use NCBLIT_2x1 by default (or NCBLIT_1x1 if not in -// UTF-8 mode), but an alternative can be specified. -static inline const struct blitset* -rgba_blitter(const struct notcurses* nc, const struct ncvisual_options* opts) { - const bool maydegrade = !(opts && (opts->flags & NCVISUAL_OPTION_NODEGRADE)); - const ncscale_e scale = opts ? opts->scaling : NCSCALE_NONE; - return rgba_blitter_low(&nc->tcache, scale, maydegrade, opts ? opts->blitter : NCBLIT_DEFAULT); -} - // find the "center" cell of two lengths. in the case of even rows/columns, we // place the center on the top/left. in such a case there will be one more // cell to the bottom/right of the center. @@ -1214,9 +1196,15 @@ int sixel_blit(ncplane* nc, int placey, int placex, int linesize, const void* data, int begy, int begx, int leny, int lenx, unsigned cellpixx); +int kitty_blit(ncplane* nc, int placey, int placex, int linesize, + const void* data, int begy, int begx, + int leny, int lenx, unsigned cellpixx); + int term_fg_rgb8(bool RGBflag, const char* setaf, int colors, FILE* out, unsigned r, unsigned g, unsigned b); +API const struct blitset* lookup_blitset(const tinfo* tcache, ncblitter_e setid, bool may_degrade); + static inline int rgba_blit_dispatch(ncplane* nc, const struct blitset* bset, int placey, int placex, int linesize, const void* data, int begy, @@ -1225,6 +1213,24 @@ rgba_blit_dispatch(ncplane* nc, const struct blitset* bset, int placey, leny, lenx, blendcolors); } +static inline const struct blitset* +rgba_blitter_low(const tinfo* tcache, ncscale_e scale, bool maydegrade, + ncblitter_e blitrec) { + if(blitrec == NCBLIT_DEFAULT){ + blitrec = rgba_blitter_default(tcache, scale); + } + return lookup_blitset(tcache, blitrec, maydegrade); +} + +// RGBA visuals all use NCBLIT_2x1 by default (or NCBLIT_1x1 if not in +// UTF-8 mode), but an alternative can be specified. +static inline const struct blitset* +rgba_blitter(const struct notcurses* nc, const struct ncvisual_options* opts) { + const bool maydegrade = !(opts && (opts->flags & NCVISUAL_OPTION_NODEGRADE)); + const ncscale_e scale = opts ? opts->scaling : NCSCALE_NONE; + return rgba_blitter_low(&nc->tcache, scale, maydegrade, opts ? opts->blitter : NCBLIT_DEFAULT); +} + typedef struct ncvisual_implementation { int (*visual_init)(int loglevel); void (*visual_printbanner)(const struct notcurses* nc); diff --git a/src/lib/kitty.c b/src/lib/kitty.c new file mode 100644 index 000000000..6b912e3f8 --- /dev/null +++ b/src/lib/kitty.c @@ -0,0 +1,7 @@ +#include "internal.h" + +int kitty_blit(ncplane* nc, int placey, int placex, int linesize, + const void* data, int begy, int begx, + int leny, int lenx, unsigned cellpixx){ + return 0; +} diff --git a/src/lib/plot.h b/src/lib/plot.h index 7f146aa26..d20ec7cf6 100644 --- a/src/lib/plot.h +++ b/src/lib/plot.h @@ -43,12 +43,12 @@ class ncppplot { return false; } const notcurses* notc = ncplane_notcurses(n); - ncblitter_e blitter = opts ? opts->gridtype : NCBLIT_DEFAULT; - if(blitter == NCBLIT_DEFAULT){ - blitter = ncplot_defblitter(notc); + ncblitter_e blitfxn = opts ? opts->gridtype : NCBLIT_DEFAULT; + if(blitfxn == NCBLIT_DEFAULT){ + blitfxn = ncplot_defblitter(notc); } bool degrade_blitter = !(opts && (opts->flags & NCPLOT_OPTION_NODEGRADE)); - auto bset = lookup_blitset(¬c->tcache, blitter, degrade_blitter); + auto bset = lookup_blitset(¬c->tcache, blitfxn, degrade_blitter); if(bset == nullptr){ ncplane_destroy(n); return false; diff --git a/src/lib/terminfo.c b/src/lib/terminfo.c index cabc9f08d..f225a6a9f 100644 --- a/src/lib/terminfo.c +++ b/src/lib/terminfo.c @@ -58,6 +58,9 @@ apply_term_heuristics(tinfo* ti, const char* termname){ // be RGB(0, 0, 0) (the default). we could also just set it, i guess. ti->bg_collides_default = 0x1000000; ti->sextants = true; // work since bugfix in 0.19.3 + ti->pixel_query_done = true; + ti->sixel_supported = true; + set_pixel_blitter(kitty_blit); /*}else if(strstr(termname, "alacritty")){ ti->sextants = true; // alacritty https://github.com/alacritty/alacritty/issues/4409 */ }else if(strstr(termname, "vte") || strstr(termname, "gnome") || strstr(termname, "xfce")){ diff --git a/src/lib/visual.cpp b/src/lib/visual.cpp index e06dc9dbc..8e2d33d1d 100644 --- a/src/lib/visual.cpp +++ b/src/lib/visual.cpp @@ -72,14 +72,14 @@ auto ncvisual_geom(const notcurses* nc, const ncvisual* n, const struct ncvisual_options* vopts, int* y, int* x, int* toy, int* tox) -> int { const ncscale_e scale = vopts ? vopts->scaling : NCSCALE_NONE; - ncblitter_e blitter; + ncblitter_e blitfxn; if(!vopts || vopts->blitter == NCBLIT_DEFAULT){ - blitter = ncvisual_media_defblitter(nc, scale); + blitfxn = ncvisual_media_defblitter(nc, scale); }else{ - blitter = vopts->blitter; + blitfxn = vopts->blitter; } const bool maydegrade = !(vopts && (vopts->flags & NCVISUAL_OPTION_NODEGRADE)); - const struct blitset* bset = lookup_blitset(&nc->tcache, blitter, maydegrade); + const struct blitset* bset = lookup_blitset(&nc->tcache, blitfxn, maydegrade); if(!bset){ return -1; }