From 5e4c07816d0ae3550f38368a99dc1153a3faab50 Mon Sep 17 00:00:00 2001 From: nick black Date: Sun, 28 Mar 2021 16:31:21 -0400 Subject: [PATCH] [stream] restore erase(), preserve tacache across sixels #1482 --- src/lib/internal.h | 12 +++++++----- src/lib/kitty.c | 14 +++++++------- src/lib/notcurses.c | 1 + src/lib/render.c | 2 +- src/lib/sixel.c | 29 ++++++++++++----------------- src/lib/sprite.c | 19 ++++--------------- src/media/ffmpeg.cpp | 3 +++ 7 files changed, 35 insertions(+), 45 deletions(-) diff --git a/src/lib/internal.h b/src/lib/internal.h index 431e3b33d..7d082e33a 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -74,7 +74,6 @@ typedef struct sprixel { int y, x; int dimy, dimx; // cell geometry int pixy, pixx; // pixel geometry (might be smaller than cell geo) - sprixcell_e* tacache; // transparency-annihilation cache (dimy * dimx) // each tacache entry is one of 0 (standard opaque cell), 1 (cell with // some transparency), 2 (annihilated, excised) int parse_start; // where to start parsing for cell wipes @@ -124,6 +123,8 @@ typedef struct ncplane { struct ncplane* boundto;// plane to which we are bound (ourself for roots) sprixel* sprite; // pointer into the sprixel cache + sprixcell_e* tacache; // transparency-annihilation sprite matrix + int tacachey, tacachex;// tacache geometry FIXME get rid of this void* userptr; // slot for the user to stick some opaque pointer int (*resizecb)(struct ncplane*); // callback after parent is resized @@ -767,12 +768,10 @@ int sprite_destroy(const struct notcurses* nc, const struct ncpile* p, FILE* out void sprixel_free(sprixel* s); void sprixel_invalidate(sprixel* s); void sprixel_hide(sprixel* s); -// 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); + int parse_start); API int sprite_wipe_cell(const notcurses* nc, sprixel* s, int y, int x); int sprite_kitty_annihilate(const notcurses* nc, const ncpile* p, FILE* out, sprixel* s); int sprite_kitty_init(int fd); @@ -1178,7 +1177,7 @@ plane_blit_sixel(ncplane* n, char* s, int bytes, int placey, int placex, int leny, int lenx, int sprixelid, int dimy, int dimx, int parse_start, sprixcell_e * tacache){ sprixel* spx = sprixel_create(n, s, bytes, placey, placex, sprixelid, - leny, lenx, dimy, dimx, parse_start, tacache); + leny, lenx, dimy, dimx, parse_start); if(spx == NULL){ return -1; } @@ -1193,6 +1192,9 @@ plane_blit_sixel(ncplane* n, char* s, int bytes, int placey, int placex, if(n->sprite){ sprixel_hide(n->sprite); } + n->tacache = tacache; + n->tacachey = leny; + n->tacachex = lenx; n->sprite = spx; return 0; } diff --git a/src/lib/kitty.c b/src/lib/kitty.c index 655b6532b..952072313 100644 --- a/src/lib/kitty.c +++ b/src/lib/kitty.c @@ -300,11 +300,9 @@ int kitty_blit(ncplane* n, int linesize, const void* data, // 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. int sprixelid; - if(n->sprite){ - sprixel* s = n->sprite; - if(s->dimy == rows && s->dimx == cols){ - tacache = s->tacache; - s->tacache = NULL; + if(n->tacache){ + if(n->tacachey == rows && n->tacachex == cols){ + tacache = n->tacache; reuse = true; } } @@ -329,11 +327,13 @@ int kitty_blit(ncplane* n, int linesize, const void* data, free(buf); return -1; } - // take ownership of |buf| on success + // take ownership of |buf| and |tacache| on success if(plane_blit_sixel(n, buf, size, bargs->placey, bargs->placex, rows, cols, bargs->u.pixel.sprixelid, leny, lenx, parse_start, tacache) < 0){ - free(tacache); + if(!reuse){ + free(tacache); + } free(buf); return -1; } diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index ed95cd9bc..70b3329f6 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -355,6 +355,7 @@ ncplane* ncplane_new_internal(notcurses* nc, ncplane* n, p->name = strdup(nopts->name ? nopts->name : ""); p->halign = NCALIGN_UNALIGNED; p->valign = NCALIGN_UNALIGNED; + p->tacache = NULL; if(!n){ // new root/standard plane p->absy = nopts->y; p->absx = nopts->x; diff --git a/src/lib/render.c b/src/lib/render.c index 47cf04c27..f96c8a726 100644 --- a/src/lib/render.c +++ b/src/lib/render.c @@ -938,7 +938,7 @@ rasterize_sprixels(notcurses* nc, const ncpile* p, FILE* out){ ncplane_yx(s->n, &y, &x); y += s->y; x += s->x; -//fprintf(stderr, "DRAWING BITMAP %d AT %d/%d\n", s->id, y + nc->stdplane->absy, x + nc->stdplane->absx); +//fprintf(stderr, "DRAWING BITMAP %d AT %d/%d for %p\n", s->id, y + nc->stdplane->absy, x + nc->stdplane->absx, s->n); if(goto_location(nc, out, y + nc->stdplane->absy, x + nc->stdplane->absx)){ return -1; } diff --git a/src/lib/sixel.c b/src/lib/sixel.c index 4a454592e..4ae0004b4 100644 --- a/src/lib/sixel.c +++ b/src/lib/sixel.c @@ -384,8 +384,7 @@ write_sixel_data(FILE* fp, int lenx, sixeltable* stab, int* parse_start){ // A pixel block is indicated by setting cell_pixels_p(). static inline int sixel_blit_inner(ncplane* n, int leny, int lenx, sixeltable* stab, - const blitterargs* bargs, unsigned reuse, - sprixcell_e* tacache){ + const blitterargs* bargs, sprixcell_e* tacache){ char* buf = NULL; size_t size = 0; FILE* fp = open_memstream(&buf, &size); @@ -400,16 +399,12 @@ sixel_blit_inner(ncplane* n, int leny, int lenx, sixeltable* stab, 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){ - free(buf); - return -1; - } + // take ownership of buf on success + if(plane_blit_sixel(n, buf, size, bargs->placey, bargs->placex, + rows, cols, bargs->u.pixel.sprixelid, leny, lenx, + parse_start, tacache) < 0){ + free(buf); + return -1; } return 1; } @@ -447,10 +442,10 @@ int sixel_blit(ncplane* n, int linesize, const void* data, 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; + if(n->tacache){ +//fprintf(stderr, "OUGHT BE A REUSE %d %d %d %d\n", n->tacachey, rows, n->tacachex, cols); + if(n->tacachey == rows && n->tacachex == cols){ + tacache = n->tacache; reuse = true; } } @@ -473,7 +468,7 @@ int sixel_blit(ncplane* n, int linesize, const void* data, return -1; } refine_color_table(data, linesize, bargs->begy, bargs->begx, leny, lenx, &stable); - int r = sixel_blit_inner(n, leny, lenx, &stable, bargs, reuse, tacache); + int r = sixel_blit_inner(n, leny, lenx, &stable, bargs, tacache); free(stable.data); free(stable.deets); free(stable.table); diff --git a/src/lib/sprite.c b/src/lib/sprite.c index 744b34d3f..6b333a002 100644 --- a/src/lib/sprite.c +++ b/src/lib/sprite.c @@ -2,15 +2,14 @@ void sprixel_free(sprixel* s){ if(s){ - free(s->tacache); free(s->glyph); free(s); } } void sprixel_hide(sprixel* s){ - s->n->sprite = NULL; s->invalidated = SPRIXEL_HIDE; + s->n->sprite = NULL; s->n = NULL; } @@ -29,25 +28,15 @@ sprixel* sprixel_by_id(notcurses* nc, uint32_t id){ return NULL; } -// s ought already have been scrubbed according to the T-A matrix -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. 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){ + int parse_start){ sprixel* ret = malloc(sizeof(sprixel)); if(ret){ ret->glyph = s; ret->glyphlen = bytes; - ret->tacache = tacache; ret->invalidated = SPRIXEL_INVALIDATED; ret->n = n; ret->dimy = dimy; @@ -79,13 +68,13 @@ int sprite_wipe_cell(const notcurses* nc, sprixel* s, int ycell, int xcell){ logerror(nc, "Bad x coordinate %d (%d)\n", xcell, s->dimx); return -1; } - if(s->tacache[s->dimx * ycell + xcell] == SPRIXCELL_ANNIHILATED){ + if(s->n->tacache[s->dimx * ycell + xcell] == SPRIXCELL_ANNIHILATED){ //fprintf(stderr, "CACHED WIPE %d %d/%d\n", s->id, ycell, xcell); return 0; // already annihilated } // mark the cell as annihilated whether we actually scrubbed it or not, // so that we use this fact should we move to another frame - s->tacache[s->dimx * ycell + xcell] = SPRIXCELL_ANNIHILATED; + s->n->tacache[s->dimx * ycell + xcell] = SPRIXCELL_ANNIHILATED; if(!nc->tcache.pixel_cell_wipe){ // sixel has no cell wiping return -1; } diff --git a/src/media/ffmpeg.cpp b/src/media/ffmpeg.cpp index 3b74a896f..4d200dfaf 100644 --- a/src/media/ffmpeg.cpp +++ b/src/media/ffmpeg.cpp @@ -394,6 +394,9 @@ int ffmpeg_stream(notcurses* nc, ncvisual* ncv, float timescale, // all media when we loop =[. we seem to be accurate enough now with the // tbase/ppd. see https://github.com/dankamongmen/notcurses/issues/1352. double tbase = av_q2d(ncv->details->fmtctx->streams[ncv->details->stream_index]->time_base); + if(activevopts.n){ + ncplane_erase(activevopts.n); // new frame could be partially transparent + } // decay the blitter explicitly, so that the callback knows the blitter it // was actually rendered with auto bset = rgba_blitter(nc, &activevopts);