diff --git a/src/lib/egcpool.h b/src/lib/egcpool.h index a0f43b857..633009587 100644 --- a/src/lib/egcpool.h +++ b/src/lib/egcpool.h @@ -262,6 +262,12 @@ cell_sprixel_p(const nccell* c){ return (htole(c->gcluster) & htole(0xff000000ul)) == htole(0x02000000ul); } +// Is the cell part of a sprixel? +static inline uint32_t +cell_sprixel_id(const nccell* c){ + return htole(c->gcluster) & htole(0xfffffful); +} + // Is the cell simple (a UTF8-encoded EGC of four bytes or fewer)? static inline bool cell_simple_p(const nccell* c){ diff --git a/src/lib/internal.h b/src/lib/internal.h index 28a34e042..f4907e19b 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -58,7 +58,7 @@ typedef enum { // protocol, we just have to rewrite them. typedef struct sprixel { char* glyph; // glyph; can be quite large - int id; // embedded into glusters field of nccell + uint32_t id; // embedded into glusters field of nccell, 24 bits struct ncplane* n; // associated ncplane sprixel_e invalidated; struct sprixel* next; @@ -736,6 +736,8 @@ int sprite_kitty_init(int fd); int sprite_sixel_init(int fd); int sprite_sixel_annihilate(const notcurses* nc, const ncpile* p, FILE* out, sprixel* s); int sprite_init(const notcurses* nc); +void sprixel_invalidate(sprixel* s); +sprixel* sprixel_by_id(notcurses* nc, uint32_t id); static inline void pool_release(egcpool* pool, nccell* c){ diff --git a/src/lib/render.c b/src/lib/render.c index 39a6e1b83..564635997 100644 --- a/src/lib/render.c +++ b/src/lib/render.c @@ -190,6 +190,7 @@ struct crender { const ncplane *p; // source of glyph for this cell nccell c; uint32_t hcfg; // fg channel prior to HIGHCONTRAST (need full channel) + uint32_t sprixelid; // id of sprixel we're potentially invalidating struct { // If the glyph we render is from an ncvisual, and has a transparent or // blended background, blitter stacking is in effect. This is a complicated @@ -213,6 +214,7 @@ struct crender { // and then reapply any foreground shading from above the highcontrast // declaration. save the foreground state when we go highcontrast. unsigned hcfgblends: 8; // number of foreground blends prior to HIGHCONTRAST + unsigned sprixeled: 1; // have we passed through a sprixel? } s; }; @@ -242,6 +244,7 @@ highcontrast(uint32_t bchannel){ // // only those cells where 'p' intersects with the target rendering area are // rendered. +// static void paint(const ncplane* p, struct crender* rvec, int dstleny, int dstlenx, int dstabsy, int dstabsx){ @@ -285,9 +288,15 @@ paint(const ncplane* p, struct crender* rvec, int dstleny, int dstlenx, // scribbled upon. if(cell_sprixel_p(vis)){ // if we already have a glyph solved, and we run into a bitmap - // cell, we need to null that cell out. + // cell, we need to null that cell out of the bitmap. if(crender->p || crender->s.bgblends){ sprite_wipe_cell(ncplane_notcurses_const(p), p->sprite, y, x); + }else if(!crender->p){ + // if we are a bitmap, and above a cell that has changed (and + // will thus be printed), we'll need redraw the sprixel. + if(rvec->sprixelid == 0){ + rvec->sprixelid = cell_sprixel_id(vis); + } } continue; } @@ -922,11 +931,12 @@ int sprite_kitty_annihilate(const notcurses* nc, const ncpile* p, FILE* out, spr } int sprite_sixel_annihilate(const notcurses* nc, const ncpile* p, FILE* out, sprixel* s){ + /* (void)out; struct crender* rvec = p->crender; // FIXME need to cap by ends minus bottom, right margins also - const int ycap = nc->stdplane->leny /*s->dimy*/ + nc->margin_t; - const int xcap = nc->stdplane->lenx /*s->dimx*/ + nc->margin_l; + const int ycap = nc->stdplane->leny + nc->margin_t; + const int xcap = nc->stdplane->lenx + nc->margin_l; //fprintf(stderr, "yCAP: %d xCAP: %d\n", ycap, xcap); for(int y = s->y + nc->stdplane->absy ; y < s->y + nc->stdplane->absy + s->dimy && y < ycap ; ++y){ const int innery = y - nc->stdplane->absy; @@ -937,6 +947,7 @@ int sprite_sixel_annihilate(const notcurses* nc, const ncpile* p, FILE* out, spr rvec[damageidx].s.damaged = 1; } } + */ return 1; } @@ -1082,6 +1093,9 @@ rasterize_core(notcurses* nc, const ncpile* p, FILE* out){ nc->rstate.bgpalelidable = false; } //fprintf(stderr, "RAST %08x [%s] to %d/%d cols: %u %016lx\n", srccell->gcluster, pool_extended_gcluster(&nc->pool, srccell), y, x, srccell->width, srccell->channels); + if(rvec[damageidx].sprixelid){ + sprixel_invalidate(sprixel_by_id(nc, rvec[damageidx].sprixelid)); + } if(term_putc(out, &nc->pool, srccell)){ return -1; } diff --git a/src/lib/sixel.c b/src/lib/sixel.c index 9ae2ae39e..f0c9d7571 100644 --- a/src/lib/sixel.c +++ b/src/lib/sixel.c @@ -420,7 +420,7 @@ write_sixel_data(FILE* fp, int lenx, sixeltable* stab, int* parse_start, int* ta // Set Raster Attributes - pan/pad=1 (pixel aspect ratio), Ph=lenx, Pv=leny // using Ph/Pv causes a background to be drawn using color register 0 for all // unspecified pixels, which we do not want. - //fprintf(fp, "\"1;1;%d;%d", lenx, leny); +// fprintf(fp, "\"1;1;%d;%d", lenx, leny); for(int i = 0 ; i < stab->colors ; ++i){ const unsigned char* rgb = stab->table + i * CENTSIZE; diff --git a/src/lib/sprite.c b/src/lib/sprite.c index 67fdbf744..b16b6a636 100644 --- a/src/lib/sprite.c +++ b/src/lib/sprite.c @@ -14,6 +14,21 @@ void sprixel_hide(sprixel* s){ s->n = NULL; } +void sprixel_invalidate(sprixel* s){ + if(s->invalidated != SPRIXEL_HIDE){ + s->invalidated = SPRIXEL_INVALIDATED; + } +} + +sprixel* sprixel_by_id(notcurses* nc, uint32_t id){ + for(sprixel* cur = nc->sprixelcache ; cur ; cur = cur->next){ + if(cur->id == id){ + return cur; + } + } + return NULL; +} + // y and x are the cell geometry, not the pixel geometry sprixel* sprixel_create(ncplane* n, const char* s, int bytes, int placey, int placex, int sprixelid, int dimy, int dimx, int pixy, int pixx,