diff --git a/src/lib/internal.h b/src/lib/internal.h index 841c36835..41235834a 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -56,6 +56,7 @@ typedef enum { SPRIXCELL_NORMAL, // no transparent pixels in this cell SPRIXCELL_CONTAINS_TRANS, // this cell has transparent pixels SPRIXCELL_ANNIHILATED, // this cell has been wiped + SPRIXCELL_UNHIDDEN, // this cell needs be unwiped } sprixcell_e; // there is a context-wide set of displayed pixel glyphs ("sprixels"); i.e. @@ -761,8 +762,9 @@ plane_debug(const ncplane* n, bool details){ void sprixel_free(sprixel* s); void sprixel_invalidate(sprixel* s); void sprixel_hide(sprixel* s); -// dimy and dimx are cell geometry, not pixel +// takes ownership of g on success sprixel* sprixel_update(sprixel* s, char* g, int bytes); +// dimy and dimx are cell geometry, not pixel. takes ownership of s on success. sprixel* sprixel_create(ncplane* n, char* s, int bytes, int placey, int placex, int sprixelid, int dimy, int dimx, int pixy, int pixx, int parse_start, sprixcell_e* tacache); @@ -1180,7 +1182,11 @@ plane_blit_sixel(ncplane* n, char* s, int bytes, int placey, int placex, for(int y = placey ; y < placey + leny && y < ncplane_dim_y(n) ; ++y){ for(int x = placex ; x < placex + lenx && x < ncplane_dim_x(n) ; ++x){ nccell* c = ncplane_cell_ref_yx(n, y, x); - memcpy(&c->gcluster, &gcluster, sizeof(gcluster)); + if(x == placex){ + memcpy(&c->gcluster, &gcluster, sizeof(gcluster)); + }else{ + c->gcluster = 0; + } c->width = lenx; } } diff --git a/src/lib/kitty.c b/src/lib/kitty.c index 7868866ab..2cd658ff3 100644 --- a/src/lib/kitty.c +++ b/src/lib/kitty.c @@ -296,6 +296,7 @@ int kitty_blit(ncplane* nc, int linesize, const void* data, return -1; } int parse_start = 0; + // closes fp on success sprixcell_e* tacache = write_kitty_data(fp, rows, cols, linesize, leny, lenx, data, bargs->u.pixel.sprixelid, &parse_start); if(tacache == NULL){ diff --git a/src/lib/sixel.c b/src/lib/sixel.c index 6e8ae2c07..b471dc7a9 100644 --- a/src/lib/sixel.c +++ b/src/lib/sixel.c @@ -485,7 +485,7 @@ write_sixel_data(FILE* fp, int lenx, sixeltable* stab, int* parse_start, sprixce // are programmed as a set of registers, which are then referenced by the // stacks. There is also a RLE component, handled in rasterization. // A pixel block is indicated by setting cell_pixels_p(). -int sixel_blit_inner(ncplane* nc, int leny, int lenx, sixeltable* stab, +int sixel_blit_inner(ncplane* n, int leny, int lenx, sixeltable* stab, const blitterargs* bargs){ char* buf = NULL; size_t size = 0; @@ -494,31 +494,55 @@ int sixel_blit_inner(ncplane* nc, int leny, int lenx, sixeltable* stab, return -1; } int parse_start = 0; - unsigned cols = lenx / bargs->u.pixel.celldimx + !!(lenx % bargs->u.pixel.celldimx); - unsigned rows = leny / bargs->u.pixel.celldimy + !!(leny % bargs->u.pixel.celldimy); - sprixcell_e* tacache = malloc(sizeof(*tacache) * rows * cols); - memset(tacache, 0, sizeof(*tacache) * rows * cols); - if(tacache == NULL){ - free(buf); - return -1; + int cols = lenx / bargs->u.pixel.celldimx + !!(lenx % bargs->u.pixel.celldimx); + int rows = leny / bargs->u.pixel.celldimy + !!(leny % bargs->u.pixel.celldimy); + sprixcell_e* tacache = NULL; + bool reuse = false; + // if we have a sprixel attached to this plane, see if we can reuse it + // (we need the same dimensions) and thus immediately apply its T-A table. + if(n->sprite){ + sprixel* s = n->sprite; + if(s->dimy == rows && s->dimx == cols){ + tacache = s->tacache; + reuse = true; + } } + if(!reuse){ + tacache = malloc(sizeof(*tacache) * rows * cols); + if(tacache == NULL){ + fclose(fp); + free(buf); + return -1; + } + memset(tacache, 0, sizeof(*tacache) * rows * cols); + } + // calls fclose() on success if(write_sixel_data(fp, lenx, stab, &parse_start, tacache)){ - free(tacache); + if(!reuse){ + free(tacache); + } + fclose(fp); free(buf); return -1; } - // takes ownership of |buf| on success - if(plane_blit_sixel(nc, buf, size, bargs->placey, bargs->placex, - rows, cols, bargs->u.pixel.sprixelid, leny, lenx, - parse_start, tacache) < 0){ - free(tacache); - free(buf); - return -1; + // both paths take ownership of buf on success + if(reuse){ + sprixel_update(n->sprite, buf, size); + }else{ + if(plane_blit_sixel(n, buf, size, bargs->placey, bargs->placex, + rows, cols, bargs->u.pixel.sprixelid, leny, lenx, + parse_start, tacache) < 0){ + if(!reuse){ + free(tacache); + } + free(buf); + return -1; + } } return 1; } -int sixel_blit(ncplane* nc, int linesize, const void* data, +int sixel_blit(ncplane* n, int linesize, const void* data, int leny, int lenx, const blitterargs* bargs){ int sixelcount = (lenx - bargs->begx) * ((leny - bargs->begy + 5) / 6); int colorregs = bargs->u.pixel.colorregs; @@ -552,7 +576,7 @@ int sixel_blit(ncplane* nc, int linesize, const void* data, return -1; } refine_color_table(data, linesize, bargs->begy, bargs->begx, leny, lenx, &stable); - int r = sixel_blit_inner(nc, leny, lenx, &stable, bargs); + int r = sixel_blit_inner(n, leny, lenx, &stable, bargs); free(stable.data); free(stable.deets); free(stable.table); diff --git a/src/lib/sprite.c b/src/lib/sprite.c index 03db8a832..091c832a5 100644 --- a/src/lib/sprite.c +++ b/src/lib/sprite.c @@ -30,14 +30,16 @@ sprixel* sprixel_by_id(notcurses* nc, uint32_t id){ } // s ought already have been scrubbed according to the T-A matrix -sprixel* sprixel_update(sprixel* s, const char* g, int bytes){ +sprixel* sprixel_update(sprixel* s, char* g, int bytes){ free(s->glyph); s->glyph = g; s->glyphlen = bytes; s->invalidated = SPRIXEL_INVALIDATED; + return s; } -// y and x are the cell geometry, not the pixel geometry +// 'y' and 'x' are the cell geometry, not the pixel geometry. takes +// ownership of 's' on success. sprixel* sprixel_create(ncplane* n, char* s, int bytes, int placey, int placex, int sprixelid, int dimy, int dimx, int pixy, int pixx, int parse_start, sprixcell_e* tacache){