mirror of
https://github.com/dankamongmen/notcurses.git
synced 2024-11-04 06:00:30 +00:00
eliminate sixel flicker #1493
This commit is contained in:
parent
d4883d30f2
commit
aa80af8f87
@ -550,7 +550,13 @@ ncdirectv* ncdirect_render_frame(ncdirect* n, const char* file,
|
||||
bargs.u.pixel.celldimx = n->tcache.cellpixx;
|
||||
bargs.u.pixel.celldimy = n->tcache.cellpixy;
|
||||
bargs.u.pixel.colorregs = n->tcache.color_registers;
|
||||
bargs.u.pixel.sprixelid = n->tcache.sprixelnonce++;
|
||||
int cols = lenx / bargs.u.pixel.celldimx + !!(lenx % bargs.u.pixel.celldimx);
|
||||
int rows = leny / bargs.u.pixel.celldimy + !!(leny % bargs.u.pixel.celldimy);
|
||||
if((bargs.u.pixel.spx = sprixel_alloc(ncdv, rows, cols)) == NULL){
|
||||
ncvisual_destroy(ncv);
|
||||
free_plane(ncdv);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if(ncvisual_blit(ncv, disprows, dispcols, ncdv, bset, leny, lenx, &bargs)){
|
||||
ncvisual_destroy(ncv);
|
||||
|
@ -502,7 +502,7 @@ typedef struct {
|
||||
int celldimx; // horizontal pixels per cell
|
||||
int celldimy; // vertical pixels per cell
|
||||
int colorregs; // number of color registers
|
||||
int sprixelid; // unqie 24-bit id into sprixel cache
|
||||
sprixel* spx; // sprixel object
|
||||
} pixel; // for pixels
|
||||
} u;
|
||||
} blitterargs;
|
||||
@ -811,9 +811,9 @@ int sprite_draw(const notcurses* n, const ncpile *p, sprixel* s, FILE* out);
|
||||
int kitty_draw(const notcurses* n, const ncpile *p, sprixel* s, FILE* out);
|
||||
int sixel_draw(const notcurses* n, const ncpile *p, sprixel* s, FILE* out);
|
||||
// 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);
|
||||
sprixel* sprixel_alloc(ncplane* n, int dimy, int dimx);
|
||||
int sprixel_load(sprixel* spx, char* s, int bytes, int placey, int placex,
|
||||
int pixy, int pixx, int parse_start);
|
||||
int sprite_wipe_cell(const notcurses* nc, sprixel* s, int y, int x);
|
||||
int sixel_delete(const notcurses* nc, const ncpile* p, FILE* out, sprixel* s);
|
||||
int sprite_kitty_annihilate(const notcurses* nc, const ncpile* p, FILE* out, sprixel* s);
|
||||
@ -1216,14 +1216,13 @@ egc_rtl(const char* egc, int* bytes){
|
||||
// a reference to the context-wide sprixel cache. this ought be an entirely
|
||||
// new, purpose-specific plane.
|
||||
static inline int
|
||||
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);
|
||||
if(spx == NULL){
|
||||
plane_blit_sixel(sprixel* spx, char* s, int bytes,
|
||||
int placey, int placex, int leny, int lenx,
|
||||
int parse_start, sprixcell_e* tacache){
|
||||
if(sprixel_load(spx, s, bytes, placey, placex, leny, lenx, parse_start)){
|
||||
return -1;
|
||||
}
|
||||
ncplane* n = spx->n;
|
||||
uint32_t gcluster = htole(0x02000000ul) + htole(spx->id);
|
||||
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){
|
||||
@ -1232,13 +1231,12 @@ plane_blit_sixel(ncplane* n, char* s, int bytes, int placey, int placex,
|
||||
c->width = lenx;
|
||||
}
|
||||
}
|
||||
if(n->sprite){
|
||||
sprixel_hide(n->sprite);
|
||||
if(n){
|
||||
n->tacache = tacache;
|
||||
n->tacachey = leny;
|
||||
n->tacachex = lenx;
|
||||
n->sprite = spx;
|
||||
}
|
||||
n->tacache = tacache;
|
||||
n->tacachey = leny;
|
||||
n->tacachex = lenx;
|
||||
n->sprite = spx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -295,8 +295,8 @@ write_kitty_data(FILE* fp, int linesize, int leny, int lenx,
|
||||
// deflate-compressed) 24bit RGB. Returns -1 on error, 1 on success.
|
||||
int kitty_blit(ncplane* n, int linesize, const void* data,
|
||||
int leny, int lenx, const blitterargs* bargs){
|
||||
int rows = leny / bargs->u.pixel.celldimy + !!(leny % bargs->u.pixel.celldimy);
|
||||
int cols = lenx / bargs->u.pixel.celldimx + !!(lenx % bargs->u.pixel.celldimx);
|
||||
int cols = bargs->u.pixel.spx->dimx;
|
||||
int rows = bargs->u.pixel.spx->dimy;
|
||||
char* buf = NULL;
|
||||
size_t size = 0;
|
||||
FILE* fp = open_memstream(&buf, &size);
|
||||
@ -307,7 +307,6 @@ int kitty_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.
|
||||
int sprixelid;
|
||||
if(n->tacache){
|
||||
if(n->tacachey == rows && n->tacachex == cols){
|
||||
tacache = n->tacache;
|
||||
@ -324,11 +323,10 @@ int kitty_blit(ncplane* n, int linesize, const void* data,
|
||||
}
|
||||
memset(tacache, 0, sizeof(*tacache) * rows * cols);
|
||||
}
|
||||
sprixelid = bargs->u.pixel.sprixelid;
|
||||
// closes fp on all paths
|
||||
if(write_kitty_data(fp, linesize, leny, lenx, cols, data,
|
||||
bargs->u.pixel.celldimy, bargs->u.pixel.celldimx,
|
||||
sprixelid, tacache, &parse_start)){
|
||||
bargs->u.pixel.spx->id, tacache, &parse_start)){
|
||||
if(!reuse){
|
||||
free(tacache);
|
||||
}
|
||||
@ -336,9 +334,9 @@ int kitty_blit(ncplane* n, int linesize, const void* data,
|
||||
return -1;
|
||||
}
|
||||
// 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){
|
||||
if(plane_blit_sixel(bargs->u.pixel.spx, buf, size,
|
||||
bargs->placey, bargs->placex,
|
||||
leny, lenx, parse_start, tacache) < 0){
|
||||
if(!reuse){
|
||||
free(tacache);
|
||||
}
|
||||
|
@ -1984,9 +1984,9 @@ void ncplane_yx(const ncplane* n, int* y, int* x){
|
||||
}
|
||||
|
||||
void ncplane_erase(ncplane* n){
|
||||
if(n->sprite){
|
||||
/*if(n->sprite){
|
||||
sprixel_hide(n->sprite);
|
||||
}
|
||||
}*/
|
||||
// we must preserve the background, but a pure cell_duplicate() would be
|
||||
// wiped out by the egcpool_dump(). do a duplication (to get the stylemask
|
||||
// and channels), and then reload.
|
||||
|
@ -1085,16 +1085,19 @@ notcurses_rasterize_inner(notcurses* nc, const ncpile* p, FILE* out){
|
||||
// we explicitly move the cursor at the beginning of each output line, so no
|
||||
// need to home it expliticly.
|
||||
update_palette(nc, out);
|
||||
//fprintf(stderr, "pile %p ymax: %d xmax: %d\n", p, p->dimy + nc->stdplane->absy, p->dimx + nc->stdplane->absx);
|
||||
fprintf(stderr, "pile %p ymax: %d xmax: %d\n", p, p->dimy + nc->stdplane->absy, p->dimx + nc->stdplane->absx);
|
||||
if(clean_sprixels(nc, p, out) < 0){
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "RASTERIZE CORE\n");
|
||||
if(rasterize_core(nc, p, out)){
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "RASTERIZE SPRIXELS\n");
|
||||
if(rasterize_sprixels(nc, p, out) < 0){
|
||||
return -1;
|
||||
}
|
||||
fprintf(stderr, "RASTERIZE CORE\n");
|
||||
if(rasterize_core(nc, p, out)){
|
||||
return -1;
|
||||
}
|
||||
|
@ -386,7 +386,7 @@ write_sixel_data(FILE* fp, int lenx, sixeltable* stab, int* parse_start){
|
||||
// stacks. There is also a RLE component, handled in rasterization.
|
||||
// A pixel block is indicated by setting cell_pixels_p().
|
||||
static inline int
|
||||
sixel_blit_inner(ncplane* n, int leny, int lenx, sixeltable* stab,
|
||||
sixel_blit_inner(int leny, int lenx, sixeltable* stab,
|
||||
const blitterargs* bargs, sprixcell_e* tacache){
|
||||
char* buf = NULL;
|
||||
size_t size = 0;
|
||||
@ -395,17 +395,15 @@ sixel_blit_inner(ncplane* n, int leny, int lenx, sixeltable* stab,
|
||||
return -1;
|
||||
}
|
||||
int parse_start = 0;
|
||||
int cols = lenx / bargs->u.pixel.celldimx + !!(lenx % bargs->u.pixel.celldimx);
|
||||
int rows = leny / bargs->u.pixel.celldimy + !!(leny % bargs->u.pixel.celldimy);
|
||||
// calls fclose() on success
|
||||
if(write_sixel_data(fp, lenx, stab, &parse_start)){
|
||||
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){
|
||||
if(plane_blit_sixel(bargs->u.pixel.spx, buf, size,
|
||||
bargs->placey, bargs->placex,
|
||||
leny, lenx, parse_start, tacache) < 0){
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
@ -439,8 +437,8 @@ int sixel_blit(ncplane* n, int linesize, const void* data,
|
||||
// stable.table doesn't need initializing; we start from the bottom
|
||||
memset(stable.data, 0, sixelcount * colorregs);
|
||||
memset(stable.deets, 0, sizeof(*stable.deets) * colorregs);
|
||||
int cols = lenx / bargs->u.pixel.celldimx + !!(lenx % bargs->u.pixel.celldimx);
|
||||
int rows = leny / bargs->u.pixel.celldimy + !!(leny % bargs->u.pixel.celldimy);
|
||||
int cols = bargs->u.pixel.spx->dimx;
|
||||
int rows = bargs->u.pixel.spx->dimy;
|
||||
sprixcell_e* tacache = NULL;
|
||||
bool reuse = false;
|
||||
// if we have a sprixel attached to this plane, see if we can reuse it
|
||||
@ -471,7 +469,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, tacache);
|
||||
int r = sixel_blit_inner(leny, lenx, &stable, bargs, tacache);
|
||||
free(stable.data);
|
||||
free(stable.deets);
|
||||
free(stable.table);
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include "internal.h"
|
||||
|
||||
// FIXME needs be atomic
|
||||
static uint32_t sprixelid_nonce;
|
||||
|
||||
void sprixel_free(sprixel* s){
|
||||
if(s){
|
||||
free(s->glyph);
|
||||
@ -46,34 +49,42 @@ sprixel* sprixel_by_id(const notcurses* nc, uint32_t id){
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// '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){
|
||||
sprixel* sprixel_alloc(ncplane* n, int dimy, int dimx){
|
||||
sprixel* ret = malloc(sizeof(sprixel));
|
||||
if(ret){
|
||||
ret->glyph = s;
|
||||
ret->glyphlen = bytes;
|
||||
ret->invalidated = SPRIXEL_INVALIDATED;
|
||||
fprintf(stderr, "LOADING UP %p with %p\n", ret, n);
|
||||
memset(ret, 0, sizeof(*ret));
|
||||
ret->n = n;
|
||||
ret->dimy = dimy;
|
||||
ret->dimx = dimx;
|
||||
ret->pixx = pixx;
|
||||
ret->pixy = pixy;
|
||||
ret->y = placey;
|
||||
ret->x = placex;
|
||||
ret->parse_start = parse_start;
|
||||
if(ncplane_pile(n)){
|
||||
notcurses* nc = ncplane_notcurses(n);
|
||||
ret->id = ++sprixelid_nonce;
|
||||
//fprintf(stderr, "LOOKING AT %p (p->n = %p)\n", ret, ret->n);
|
||||
if(ncplane_pile(ret->n)){
|
||||
notcurses* nc = ncplane_notcurses(ret->n);
|
||||
ret->next = nc->sprixelcache;
|
||||
nc->sprixelcache = ret;
|
||||
ret->id = sprixelid;
|
||||
//fprintf(stderr, "%p %p %p\n", nc->sprixelcache, ret, nc->sprixelcache->next);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 'y' and 'x' are the cell geometry, not the pixel geometry. takes
|
||||
// ownership of 's' on success.
|
||||
int sprixel_load(sprixel* spx, char* s, int bytes, int placey, int placex,
|
||||
int pixy, int pixx, int parse_start){
|
||||
assert(spx->n);
|
||||
spx->glyph = s;
|
||||
spx->glyphlen = bytes;
|
||||
spx->invalidated = SPRIXEL_INVALIDATED;
|
||||
spx->pixx = pixx;
|
||||
spx->pixy = pixy;
|
||||
spx->y = placey;
|
||||
spx->x = placex;
|
||||
spx->parse_start = parse_start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sprite_wipe_cell(const notcurses* nc, sprixel* s, int ycell, int xcell){
|
||||
if(s->invalidated == SPRIXEL_HIDE){ // no need to do work if we're killing it
|
||||
return 0;
|
||||
|
@ -12,6 +12,7 @@ extern "C" {
|
||||
|
||||
struct blitset;
|
||||
struct ncplane;
|
||||
struct sprixel;
|
||||
struct ncvisual_details;
|
||||
|
||||
typedef struct ncvisual {
|
||||
@ -21,6 +22,7 @@ typedef struct ncvisual {
|
||||
// lines are sometimes padded. this many true bytes per row in data.
|
||||
int rowstride;
|
||||
bool owndata; // we own data iff owndata == true
|
||||
struct sprixel* spx; // non-NULL if this is NCBLIT_PIXEL
|
||||
} ncvisual;
|
||||
|
||||
static inline void
|
||||
|
@ -429,6 +429,7 @@ ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitse
|
||||
int leny, int lenx, ncplane* n, ncscale_e scaling,
|
||||
uint64_t flags){
|
||||
int disprows, dispcols;
|
||||
ncplane* createdn = NULL;
|
||||
//fprintf(stderr, "INPUT N: %p\n", n);
|
||||
if(n == NULL){ // create plane
|
||||
if(scaling == NCSCALE_NONE || scaling == NCSCALE_NONE_HIRES){
|
||||
@ -462,6 +463,7 @@ ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitse
|
||||
if((n = ncplane_create(notcurses_stdplane(nc), &nopts)) == NULL){
|
||||
return NULL;
|
||||
}
|
||||
createdn = n;
|
||||
placey = 0;
|
||||
placex = 0;
|
||||
}else{
|
||||
@ -499,7 +501,7 @@ ncplane* ncvisual_render_cells(notcurses* nc, ncvisual* ncv, const struct blitse
|
||||
bargs.placex = placex;
|
||||
bargs.u.cell.blendcolors = flags & NCVISUAL_OPTION_BLEND;
|
||||
if(ncvisual_blit(ncv, disprows, dispcols, n, bset, leny, lenx, &bargs)){
|
||||
ncplane_destroy(n);
|
||||
ncplane_destroy(createdn);
|
||||
return NULL;
|
||||
}
|
||||
return n;
|
||||
@ -524,6 +526,7 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
|
||||
dispcols = ncv->cols;
|
||||
disprows = ncv->rows;
|
||||
}
|
||||
ncplane* createdn = NULL;
|
||||
//fprintf(stderr, "INPUT N: %p rows: %d cols: %d 0x%016lx\n", n ? n : NULL, disprows, dispcols, flags);
|
||||
if(n == NULL){ // create plane
|
||||
if(scaling == NCSCALE_NONE || scaling == NCSCALE_NONE_HIRES){
|
||||
@ -559,6 +562,7 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
|
||||
}
|
||||
placey = 0;
|
||||
placex = 0;
|
||||
createdn = n;
|
||||
}else{
|
||||
if(scaling != NCSCALE_NONE && scaling != NCSCALE_NONE_HIRES){
|
||||
ncplane_dim_yx(n, &disprows, &dispcols);
|
||||
@ -598,12 +602,25 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
|
||||
bargs.u.pixel.celldimx = nc->tcache.cellpixx;
|
||||
bargs.u.pixel.celldimy = nc->tcache.cellpixy;
|
||||
bargs.u.pixel.colorregs = nc->tcache.color_registers;
|
||||
bargs.u.pixel.sprixelid = nc->tcache.sprixelnonce++;
|
||||
if(ncv->spx == NULL){
|
||||
int cols = dispcols / bargs.u.pixel.celldimx + !!(dispcols % bargs.u.pixel.celldimx);
|
||||
int rows = disprows / bargs.u.pixel.celldimy + !!(disprows % bargs.u.pixel.celldimy);
|
||||
if((ncv->spx = sprixel_alloc(n, rows, cols)) == NULL){
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
bargs.u.pixel.spx = ncv->spx;
|
||||
if(ncvisual_blit(ncv, disprows, dispcols, n, bset, disprows, dispcols, &bargs)){
|
||||
ncplane_destroy(n);
|
||||
return NULL;
|
||||
goto err;
|
||||
}
|
||||
return n;
|
||||
|
||||
err:
|
||||
if(ncv->spx){
|
||||
sprixel_free(ncv->spx);
|
||||
}
|
||||
ncplane_destroy(createdn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ncplane* ncvisual_render(notcurses* nc, ncvisual* ncv, const struct ncvisual_options* vopts){
|
||||
|
Loading…
Reference in New Issue
Block a user