From fc4c0a2d9c2578daf146d4577c84dcffe7611ec0 Mon Sep 17 00:00:00 2001 From: nick black Date: Sat, 20 Mar 2021 04:44:40 -0400 Subject: [PATCH] [kitty] most of sprite_kitty_cell_wipe() --- src/lib/internal.h | 17 +++++++++-------- src/lib/kitty.c | 39 +++++++++++++++++++++++++++++++++++---- src/lib/render.c | 7 +------ src/lib/sprite.c | 6 +++++- src/lib/visual.c | 6 +++--- src/tests/pixel.cpp | 12 ++++++------ 6 files changed, 59 insertions(+), 28 deletions(-) diff --git a/src/lib/internal.h b/src/lib/internal.h index 2987578fc..c15eb9ba5 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -53,15 +53,15 @@ struct ncvisual_details; typedef struct sprixel { char* glyph; // glyph; can be quite large int id; // embedded into glusters field of nccell - struct ncplane* n; // associated ncplane, provides location and size + struct ncplane* n; // associated ncplane enum { SPRIXEL_NOCHANGE, SPRIXEL_INVALIDATED, SPRIXEL_HIDE, } invalidated; struct sprixel* next; - int y, x; // only defined when being hidden (n is NULL) - int dimy, dimx; // likewise only defined when being hidden + int y, x; + int dimy, dimx; } sprixel; // A plane is memory for some rectilinear virtual window, plus current cursor @@ -318,7 +318,7 @@ typedef struct tinfo { // wipe out a cell's worth of pixels from within a sprixel. for sixel, this // means leaving out the pixels (and likely resizes the string). for kitty, // this means dialing down their alpha to 0 (in equivalent space). - int (*pixel_cell_wipe)(sprixel* s, int y, int x); + int (*pixel_cell_wipe)(struct notcurses* nc, sprixel* s, int y, int x); bool pixel_query_done; // have we yet performed pixel query? bool sextants; // do we have (good, vetted) Unicode 13 sextant support? bool braille; // do we have Braille support? (linux console does not) @@ -699,7 +699,8 @@ plane_debug(const ncplane* n, bool details){ void sprixel_free(sprixel* s); void sprixel_hide(sprixel* s); -sprixel* sprixel_create(ncplane* n, const char* s, int bytes, int sprixelid); +// dimy and dimx are cell geometry, not pixel +sprixel* sprixel_create(ncplane* n, const char* s, int bytes, int sprixelid, int dimy, int dimx); int sprite_kitty_annihilate(notcurses* nc, const ncpile* p, FILE* out, sprixel* s); int sprite_sixel_annihilate(notcurses* nc, const ncpile* p, FILE* out, sprixel* s); @@ -1097,7 +1098,7 @@ egc_rtl(const char* egc, int* bytes){ static inline int plane_blit_sixel(ncplane* n, const char* s, int bytes, int leny, int lenx, int sprixelid){ - sprixel* spx = sprixel_create(n, s, bytes, sprixelid); + sprixel* spx = sprixel_create(n, s, bytes, sprixelid, leny, lenx); if(spx == NULL){ return -1; } @@ -1261,8 +1262,8 @@ ncdirect_bg_default_p(const struct ncdirect* nc){ return channels_bg_default_p(ncdirect_channels(nc)); } -int sprite_sixel_cell_wipe(sprixel* s, int y, int x); -int sprite_kitty_cell_wipe(sprixel* s, int y, int x); +int sprite_sixel_cell_wipe(notcurses* nc, sprixel* s, int y, int x); +int sprite_kitty_cell_wipe(notcurses* nc, sprixel* s, int y, int x); int sixel_blit(ncplane* nc, int linesize, const void* data, int begy, int begx, int leny, int lenx, const blitterargs* bargs); diff --git a/src/lib/kitty.c b/src/lib/kitty.c index e2a56112a..8ad31261d 100644 --- a/src/lib/kitty.c +++ b/src/lib/kitty.c @@ -1,5 +1,40 @@ #include "internal.h" +#define RGBA_MAXLEN 768 // 768 base64-encoded pixels in 4096 bytes +int sprite_kitty_cell_wipe(notcurses* nc, sprixel* s, int ycell, int xcell){ + if(ycell >= s->dimy){ + return -1; + } + if(xcell >= s->dimx){ + return -1; + } + int xpixels = nc->tcache.cellpixx; + int ypixels = nc->tcache.cellpixy; + int xpx = xpixels * xcell; // pixel coordinates where we start erasing + int ypx = ypixels * ycell; + char* c = s->glyph; + // every pixel was 4 source bytes, 32 bits, 6.33 base64 bytes. every 3 input pixels is + // 12 bytes (96 bits), an even 16 base64 bytes. there is chunking to worry about. there + // are up to 768 pixels in a chunk. + int chunks = (xcell + s->dimx * ycell) / RGBA_MAXLEN; + do{ + while(*c != ';'){ + ++c; + } + ++c; + if(chunks == 0){ + // we're in the proper chunk. find the pixel offset of the first + // pixel (within the chunk). + int offset = (xpx + s->dimx * ypx) % RGBA_MAXLEN; + // skip the 16-byte pixel triples + int bytes = (offset / 3) * 16; + // FIXME + return 0; + } + }while(--chunks); + return -1; +} + static unsigned const char b64subs[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; @@ -64,12 +99,10 @@ base64_rgba3(const uint32_t* pixels, size_t pcount, char* b64){ static int write_kitty_data(FILE* fp, int linesize, int leny, int lenx, const uint32_t* data, int sprixelid){ -#define KITTY_MAXLEN 4096 // 4096B maximum payload if(linesize % sizeof(*data)){ return -1; } int total = leny * lenx; // total number of pixels (4 * total == bytecount) -#define RGBA_MAXLEN 768 // 768 base64-encoded pixels in 4096 bytes // number of 4KiB chunks we'll need int chunks = (total + (RGBA_MAXLEN - 1)) / RGBA_MAXLEN; int totalout = 0; // total pixels of payload out @@ -114,7 +147,6 @@ write_kitty_data(FILE* fp, int linesize, int leny, int lenx, } return 0; #undef RGBA_MAXLEN -#undef KITTY_MAXLEN } // Kitty graphics blitter. Kitty can take in up to 4KiB at a time of (optionally @@ -146,7 +178,6 @@ int kitty_blit(ncplane* nc, int linesize, const void* data, int begy, int begx, int leny, int lenx, const blitterargs* bargs){ (void)begy; (void)begx; -//fprintf(stderr, "s=%d,v=%d\n", lenx, leny); int r = kitty_blit_inner(nc, linesize, leny, lenx, data, bargs); if(r < 0){ return -1; diff --git a/src/lib/render.c b/src/lib/render.c index 9694d7556..ed614bc94 100644 --- a/src/lib/render.c +++ b/src/lib/render.c @@ -922,11 +922,6 @@ emit_bg_palindex(notcurses* nc, FILE* out, const nccell* srccell){ return 0; } -int sprite_kitty_cell_wipe(sprixel* s, int y, int x){ - // FIXME - return 0; -} - int sprite_kitty_annihilate(notcurses* nc, const ncpile* p, FILE* out, sprixel* s){ (void)p; (void)nc; @@ -936,7 +931,7 @@ int sprite_kitty_annihilate(notcurses* nc, const ncpile* p, FILE* out, sprixel* return 0; } -int sprite_sixel_cell_wipe(sprixel* s, int y, int x){ +int sprite_sixel_cell_wipe(notcurses* nc, sprixel* s, int y, int x){ return 0; // FIXME } diff --git a/src/lib/sprite.c b/src/lib/sprite.c index 8160cbc8b..2dfdf5690 100644 --- a/src/lib/sprite.c +++ b/src/lib/sprite.c @@ -15,7 +15,9 @@ void sprixel_hide(sprixel* s){ s->n = NULL; } -sprixel* sprixel_create(ncplane* n, const char* s, int bytes, int sprixelid){ +// y and x are the cell geometry, not the pixel geometry +sprixel* sprixel_create(ncplane* n, const char* s, int bytes, int sprixelid, + int dimy, int dimx){ sprixel* ret = malloc(sizeof(sprixel)); if(ret){ if((ret->glyph = memdup(s, bytes + 1)) == NULL){ @@ -24,6 +26,8 @@ sprixel* sprixel_create(ncplane* n, const char* s, int bytes, int sprixelid){ } ret->invalidated = SPRIXEL_INVALIDATED; ret->n = n; + ret->dimy = dimy; + ret->dimx = dimx; if(ncplane_pile(n)){ notcurses* nc = ncplane_notcurses(n); ret->next = nc->sprixelcache; diff --git a/src/lib/visual.c b/src/lib/visual.c index a9b5c3d7f..8ea2eeb83 100644 --- a/src/lib/visual.c +++ b/src/lib/visual.c @@ -484,12 +484,12 @@ ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitse ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blitset* bset, int placey, int placex, int begy, int begx, ncplane* n, ncscale_e scaling, ncplane* stdn){ - int disprows, dispcols; + int disprows = 0, dispcols = 0; if(scaling == NCSCALE_NONE || scaling == NCSCALE_NONE_HIRES){ dispcols = ncv->cols; disprows = ncv->rows; } -//fprintf(stderr, "INPUT N: %p\n", vopts ? vopts->n : NULL); +//fprintf(stderr, "INPUT N: %p rows: %d cols: %d\n", n ? n : NULL, disprows, dispcols); if(n == NULL){ // create plane if(scaling != NCSCALE_NONE && scaling != NCSCALE_NONE_HIRES){ ncplane_dim_yx(stdn, &disprows, &dispcols); @@ -524,7 +524,7 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits if(scaling == NCSCALE_SCALE || scaling == NCSCALE_SCALE_HIRES){ scale_visual(ncv, &disprows, &dispcols); } -//fprintf(stderr, "pblit: %dx%d <- %dx%d of %d/%d stride %u @%dx%d %p %u\n", disprows, dispcols, begy, begx, ncv->rows, ncv->cols, ncv->rowstride, placey, placex, ncv->data, ncplane_notcurses(stdn)->nc->tcache.cellpixx); +//fprintf(stderr, "pblit: %dx%d <- %dx%d of %d/%d stride %u @%dx%d %p %u\n", disprows, dispcols, begy, begx, ncv->rows, ncv->cols, ncv->rowstride, placey, placex, ncv->data, nc->tcache.cellpixx); blitterargs bargs; bargs.pixel.celldimx = nc->tcache.cellpixx; bargs.pixel.celldimy = nc->tcache.cellpixy; diff --git a/src/tests/pixel.cpp b/src/tests/pixel.cpp index f51c7b50d..692d535a1 100644 --- a/src/tests/pixel.cpp +++ b/src/tests/pixel.cpp @@ -39,8 +39,8 @@ TEST_CASE("Pixel") { SUBCASE("PixelCellWipe") { // first, assemble a visual equivalent to 4 cells - auto y = nc_->tcache.cellpixy; - auto x = nc_->tcache.cellpixx; + auto y = 2 * nc_->tcache.cellpixy; + auto x = 2 * nc_->tcache.cellpixx; std::vector v(x * y, 0xffffffff); auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x); REQUIRE(nullptr != ncv); @@ -58,13 +58,13 @@ TEST_CASE("Pixel") { auto s = n->sprite; REQUIRE(nullptr != s); CHECK(0 == notcurses_render(nc_)); - CHECK(0 == nc_->tcache.pixel_cell_wipe(s, 0, 0)); + CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 0, 0)); CHECK(0 == notcurses_render(nc_)); - CHECK(0 == nc_->tcache.pixel_cell_wipe(s, 1, 1)); + CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 1, 1)); CHECK(0 == notcurses_render(nc_)); - CHECK(0 == nc_->tcache.pixel_cell_wipe(s, 1, 0)); + CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 1, 0)); CHECK(0 == notcurses_render(nc_)); - CHECK(0 == nc_->tcache.pixel_cell_wipe(s, 0, 1)); + CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 0, 1)); CHECK(0 == notcurses_render(nc_)); ncplane_destroy(n); ncvisual_destroy(ncv);