[kitty] get most of animation working #1895

dankamongmen/linuxfbdumb
nick black 3 years ago committed by Nick Black
parent d2e0c64a7c
commit ebc405b165

@ -646,8 +646,8 @@ uint8_t* sprixel_auxiliary_vector(const sprixel* s);
// asking whether it was sixel and there were no errors).
static inline int
sprite_scrub(const notcurses* n, const ncpile* p, sprixel* s){
//fprintf(stderr, "Destroying sprite %u\n", s->id);
//sprixel_debug(s, stderr);
logdebug("Sprixel %u state %d\n", s->id, s->invalidated);
return n->tcache.pixel_scrub(p, s);
}
@ -656,6 +656,7 @@ sprite_scrub(const notcurses* n, const ncpile* p, sprixel* s){
static inline int
sprite_draw(const notcurses* n, const ncpile* p, sprixel* s, FILE* out){
//sprixel_debug(s, stderr);
logdebug("Sprixel %u state %d\n", s->id, s->invalidated);
return n->tcache.pixel_draw(p, s, out);
}
@ -664,6 +665,7 @@ sprite_draw(const notcurses* n, const ncpile* p, sprixel* s, FILE* out){
static inline int
sprite_redraw(const notcurses* n, const ncpile* p, sprixel* s, FILE* out){
//sprixel_debug(s, stderr);
logdebug("Sprixel %u state %d\n", s->id, s->invalidated);
if(s->invalidated == SPRIXEL_MOVED && n->tcache.pixel_move){
// if we are kitty prior to 0.20.0, C=1 isn't available to us, and we must
// not emit it. we use sixel_maxy_pristine as a side channel to encode

@ -354,15 +354,18 @@ int kitty_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
}
// an animation auxvec requires storing all the pixel data for the cell,
// instead of just the alpha channel.
// instead of just the alpha channel. pass the start of the RGBA to be
// copied, and the rowstride.
static inline uint8_t*
kitty_transanim_auxvec(const sprixel* s){
const size_t slen = 4 * s->cellpxy * s->cellpxx;
kitty_transanim_auxvec(int cellpxy, int cellpxx, const uint32_t* data, int rowstride){
const size_t slen = 4 * cellpxy * cellpxx;
uint8_t* a = malloc(slen);
if(a){
memset(a, 0, slen);
for(int y = 0 ; y < cellpxy ; ++y){
fprintf(stderr, "COPYING %d from %p to %p\n", cellpxx * 4, data + y * (rowstride / 4), a + y * (cellpxx * 4));
memcpy(a + y * (cellpxx * 4), data + y * (rowstride / 4), cellpxx * 4);
}
}
// FIXME decode glyph into auxvec -- need to keep original glyph!
return a;
}
@ -374,10 +377,6 @@ int kitty_wipe_animation(sprixel* s, int ycell, int xcell){
return -1;
}
logdebug("Wiping sprixel %u at %d/%d\n", s->id, ycell, xcell);
uint8_t* auxvec = kitty_transanim_auxvec(s);
if(auxvec == NULL){
return -1;
}
FILE* fp = s->mstreamfp;
fprintf(fp, "\e_Ga=f,x=%d,y=%d,s=%d,v=%d,i=%d,X=1,r=1,q=2;",
xcell * s->cellpxx,
@ -397,7 +396,6 @@ int kitty_wipe_animation(sprixel* s, int ycell, int xcell){
}
// FIXME need chunking for cells of 768+ pixels
fprintf(fp, "\e\\");
s->n->tam[s->dimx * ycell + xcell].auxvector = auxvec;
s->invalidated = SPRIXEL_INVALIDATED;
return 1;
}
@ -511,6 +509,7 @@ write_kitty_data(FILE* fp, int linesize, int leny, int lenx, int cols,
tament* tam, int* parse_start){
//fprintf(stderr, "drawing kitty %p\n", tam);
if(linesize % sizeof(*data)){
logerror("Stride (%d) badly aligned\n", linesize);
fclose(fp);
return -1;
}
@ -558,6 +557,11 @@ write_kitty_data(FILE* fp, int linesize, int leny, int lenx, int cols,
int xcell = x / cdimx;
int ycell = y / cdimy;
int tyx = xcell + ycell * cols;
if(tam[tyx].auxvector == NULL){
if((tam[tyx].auxvector = kitty_transanim_auxvec(cdimy, cdimx, line + x, linesize)) == NULL){
return -1; // FIXME need clean up auxvecs, fp
}
}
//fprintf(stderr, "Tyx: %d y: %d (%d) * %d x: %d (%d) state %d %p\n", tyx, y, y / cdimy, cols, x, x / cdimx, tam[tyx].state, tam[tyx].auxvector);
if(tam[tyx].state == SPRIXCELL_ANNIHILATED || tam[tyx].state == SPRIXCELL_ANNIHILATED_TRANS){
// this pixel is part of a cell which is currently wiped (alpha-nulled
@ -592,7 +596,7 @@ write_kitty_data(FILE* fp, int linesize, int leny, int lenx, int cols,
fprintf(fp, "\e\\");
}
if(fclose(fp) == EOF){
return -1;
return -1; // FIXME clean up auxvecs!
}
scrub_tam_boundaries(tam, leny, lenx, cdimy, cdimx);
return 0;
@ -601,8 +605,8 @@ write_kitty_data(FILE* fp, int linesize, int leny, int lenx, int cols,
// Kitty graphics blitter. Kitty can take in up to 4KiB at a time of (optionally
// 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 bpp __attribute__ ((unused))){
int kitty_blit_core(ncplane* n, int linesize, const void* data, int leny, int lenx,
const blitterargs* bargs, int bpp __attribute__ ((unused))){
int cols = bargs->u.pixel.spx->dimx;
int rows = bargs->u.pixel.spx->dimy;
char* buf = NULL;
@ -651,6 +655,17 @@ int kitty_blit(ncplane* n, int linesize, const void* data, int leny, int lenx,
return 1;
}
int kitty_blit(ncplane* n, int linesize, const void* data, int leny, int lenx,
const blitterargs* bargs, int bpp __attribute__ ((unused))){
return kitty_blit_core(n, linesize, data, leny, lenx, bargs, false);
}
int kitty_blit_animated(ncplane* n, int linesize, const void* data,
int leny, int lenx, const blitterargs* bargs,
int bpp __attribute__ ((unused))){
return kitty_blit_core(n, linesize, data, leny, lenx, bargs, true);
}
int kitty_remove(int id, FILE* out){
loginfo("Removing graphic %u\n", id);
if(fprintf(out, "\e_Ga=d,d=i,i=%d\e\\", id) < 0){
@ -693,11 +708,29 @@ int kitty_scrub(const ncpile* p, sprixel* s){
// returns the number of bytes written
int kitty_draw(const ncpile* p, sprixel* s, FILE* out){
(void)p;
bool animated = false;
if(s->mstreamfp){ // active animation
int fret = fclose(s->mstreamfp);
s->mstreamfp = NULL;
if(fret == EOF){
return -1;
}
animated = true;
}
int ret = s->glyphlen;
if(fwrite(s->glyph, s->glyphlen, 1, out) != 1){
ret = -1;
if(ret){
if(fwrite(s->glyph, s->glyphlen, 1, out) != 1){
ret = -1;
}
}
if(animated){
free(s->glyph);
s->glyph = NULL;
s->glyphlen = 0;
s->invalidated = SPRIXEL_QUIESCENT;
}else{
s->invalidated = SPRIXEL_LOADED;
}
s->invalidated = SPRIXEL_LOADED;
return ret;
}

@ -881,14 +881,16 @@ clean_sprixels(notcurses* nc, ncpile* p, FILE* out){
}
// otherwise it's a new pile, so we couldn't have been on-screen
}
if(goto_location(nc, out, y + nc->margin_t, x + nc->margin_l) == 0){
int r = sprite_redraw(nc, p, s, out);
if(r < 0){
return -1;
}
bytesemitted += r;
nc->rstate.hardcursorpos = true;
if(goto_location(nc, out, y + nc->margin_t, x + nc->margin_l)){
return -1;
}
int r = sprite_redraw(nc, p, s, out);
if(r < 0){
return -1;
}
bytesemitted += r;
// FIXME might not need this if it was only an upload
nc->rstate.hardcursorpos = true;
parent = &s->next;
++nc->stats.sprixelemissions;
}else{
@ -1111,7 +1113,7 @@ notcurses_rasterize_inner(notcurses* nc, ncpile* p, FILE* out, unsigned* asu){
// don't write a clearscreen. we only update things that have been changed.
// we explicitly move the cursor at the beginning of each output line, so no
// need to home it expliticly.
//fprintf(stderr, "RASTERIZE SPRIXELS\n");
logdebug("Starting sprixel phase 1\n");
int64_t sprixelbytes = clean_sprixels(nc, p, out);
if(sprixelbytes < 0){
return -1;
@ -1120,11 +1122,11 @@ notcurses_rasterize_inner(notcurses* nc, ncpile* p, FILE* out, unsigned* asu){
if(rasterize_scrolls(p, out)){
return -1;
}
//fprintf(stderr, "RASTERIZE CORE PASS 1\n");
logdebug("Starting glyph phase 1\n");
if(rasterize_core(nc, p, out, 0)){
return -1;
}
//fprintf(stderr, "FINALIZE SPRIXELS\n");
logdebug("Starting sprixel phase 2\n");
int64_t rasprixelbytes = rasterize_sprixels(nc, p, out);
if(rasprixelbytes < 0){
return -1;
@ -1133,7 +1135,7 @@ notcurses_rasterize_inner(notcurses* nc, ncpile* p, FILE* out, unsigned* asu){
pthread_mutex_lock(&nc->statlock);
nc->stats.sprixelbytes += sprixelbytes;
pthread_mutex_unlock(&nc->statlock);
//fprintf(stderr, "RASTERIZE CORE PASS 2\n");
logdebug("Starting glyph phase 2\n");
if(rasterize_core(nc, p, out, 1)){
return -1;
}

@ -161,6 +161,9 @@ int sixel_wipe(sprixel* s, int ycell, int xcell);
// throughout to 0. the same trick doesn't work on sixel, but there we
// can just print directly over the bitmap.
int kitty_wipe(sprixel* s, int ycell, int xcell);
// wipes out a cell by animating an all-transparent cell, and integrating
// it with the original image using the animation protocol of 0.20.0+.
int kitty_wipe_animation(sprixel* s, int ycell, int xcell);
int sixel_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec);
int kitty_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec);
int kitty_draw(const struct ncpile *p, sprixel* s, FILE* out);
@ -181,6 +184,9 @@ int sixel_blit(struct ncplane* nc, int linesize, const void* data,
int leny, int lenx, const struct blitterargs* bargs, int bpp);
int kitty_blit(struct ncplane* nc, int linesize, const void* data,
int leny, int lenx, const struct blitterargs* bargs, int bpp);
int kitty_blit_animated(struct ncplane* n, int linesize, const void* data,
int leny, int lenx, const struct blitterargs* bargs,
int bpp);
#ifdef __cplusplus
}

@ -62,10 +62,10 @@ setup_sixel_bitmaps(tinfo* ti, int fd, bool invert80){
sprite_init(ti, fd);
}
// kitty 0.19.3 didn't have C=1, and thus needs sixel_maxy_pristine
// kitty 0.19.3 didn't have C=1, and thus needs sixel_maxy_pristine. it also
// lacked animation, and thus requires the older interface.
static inline void
setup_kitty_bitmaps(tinfo* ti, int fd, int sixel_maxy_pristine){
ti->pixel_wipe = kitty_wipe;
ti->pixel_scrub = kitty_scrub;
ti->pixel_remove = kitty_remove;
ti->pixel_draw = kitty_draw;
@ -75,9 +75,15 @@ setup_kitty_bitmaps(tinfo* ti, int fd, int sixel_maxy_pristine){
ti->sprixel_scale_height = 1;
ti->pixel_rebuild = kitty_rebuild;
ti->pixel_clear_all = kitty_clear_all;
ti->pixel_trans_auxvec = kitty_trans_auxvec;
ti->sixel_maxy_pristine = sixel_maxy_pristine;
set_pixel_blitter(kitty_blit);
if(sixel_maxy_pristine){
ti->pixel_wipe = kitty_wipe;
ti->pixel_trans_auxvec = kitty_trans_auxvec;
set_pixel_blitter(kitty_blit);
}else{
ti->pixel_wipe = kitty_wipe_animation;
set_pixel_blitter(kitty_blit_animated);
}
sprite_init(ti, fd);
}

Loading…
Cancel
Save