diff --git a/src/lib/kitty.c b/src/lib/kitty.c index bb213d92e..6b7847e75 100644 --- a/src/lib/kitty.c +++ b/src/lib/kitty.c @@ -413,16 +413,10 @@ int kitty_wipe_animation(sprixel* s, int ycell, int xcell){ return 1; } -// FIXME merge back with kitty_wipe_animation -int kitty_wipe_selfref(sprixel* s, int ycell, int xcell){ - if(init_sprixel_animation(s)){ - return -1; - } - const int tyx = xcell + ycell * s->dimx; - int state = s->n->tam[tyx].state; - void* auxvec = s->n->tam[tyx].auxvector; - logdebug("Wiping sprixel %u at %d/%d auxvec: %p state: %d\n", s->id, ycell, xcell, auxvec, state); - fbuf* f = &s->glyph; +// just dump the wipe into the fbuf -- don't manipulate any state. used both +// by the wipe proper, and when blitting a new frame with annihilations. +static int +kitty_blit_wipe_selfref(sprixel* s, fbuf* f, int ycell, int xcell){ if(fbuf_printf(f, "\e_Ga=f,x=%d,y=%d,s=%d,v=%d,i=%d,X=1,r=2,c=1,q=2;", xcell * s->cellpxx, ycell * s->cellpxy, s->cellpxx, s->cellpxy, s->id) < 0){ @@ -455,6 +449,22 @@ int kitty_wipe_selfref(sprixel* s, int ycell, int xcell){ if(fbuf_printf(f, "\e\\\e_Ga=a,i=%d,c=2,q=2;\e\\", s->id) < 0){ return -1; } + return 0; +} + +// FIXME merge back with kitty_wipe_animation +int kitty_wipe_selfref(sprixel* s, int ycell, int xcell){ + if(init_sprixel_animation(s)){ + return -1; + } + const int tyx = xcell + ycell * s->dimx; + int state = s->n->tam[tyx].state; + void* auxvec = s->n->tam[tyx].auxvector; + logdebug("Wiping sprixel %u at %d/%d auxvec: %p state: %d\n", s->id, ycell, xcell, auxvec, state); + fbuf* f = &s->glyph; + if(kitty_blit_wipe_selfref(s, f, ycell, xcell)){ + return -1; + } s->invalidated = SPRIXEL_INVALIDATED; memcpy(auxvec, &state, sizeof(state)); return 1; @@ -721,6 +731,31 @@ destroy_deflator(unsigned animated, z_stream* zctx, int pixy, int pixx){ } } +// if we're KITTY_SELFREF, and we're blitting a secondary frame, we need +// carry through the TAM's annihilation entires...but we also need load the +// frame *without* annihilations, lest we be unable to build it. we thus go +// back through the TAM following a selfref blit, and any sprixcells which +// are annihilated will have their annhilation appended to the main blit. +// ought only be called for KITTY_SELFREF. +static int +finalize_multiframe_selfref(sprixel* s, fbuf* f){ + int prewiped = 0; + for(int y = 0 ; y < s->dimy ; ++y){ + for(int x = 0 ; x < s->dimx ; ++x){ + int tyxidx = y * s->dimx + x; + int state = s->n->tam[tyxidx].state; + if(state >= SPRIXCELL_ANNIHILATED){ + if(kitty_blit_wipe_selfref(s, f, y, x)){ + return -1; + } + ++prewiped; + } + } + } + loginfo("transitively wiped %d/%d\n", prewiped, s->dimy * s->dimx); + return 0; +} + // we can only write 4KiB at a time. we're writing base64-encoded RGBA. each // pixel is 4B raw (32 bits). each chunk of three pixels is then 12 bytes, or // 16 base64-encoded bytes. 4096 / 16 == 256 3-pixel groups, or 768 pixels. @@ -756,6 +791,9 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols, int targetout = 0; // number of pixels expected out after this chunk //fprintf(stderr, "total: %d chunks = %d, s=%d,v=%d\n", total, chunks, lenx, leny); char out[17]; // three pixels base64 to no more than 17 bytes + // set high if we are (1) reloading a frame with (2) annihilated cells copied over + // from the TAM and (3) we are KITTY_SELFREF. calls finalize_multiframe_selfref(). + bool selfref_annihilated = false; while(chunks--){ // q=2 has been able to go on chunks other than the last chunk since // 2021-03, but there's no harm in this small bit of backwards compat. @@ -836,16 +874,30 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols, // transparent, but we need to update the auxiliary vector. const int vyx = (y % cdimy) * cdimx + (x % cdimx); tam[tyx].auxvector[vyx] = ncpixel_a(source[e]); + wipe[e] = 1; + }else if(level == KITTY_SELFREF){ + selfref_annihilated = true; + }else{ + wipe[e] = 1; } if(rgba_trans_p(source[e], transcolor)){ ncpixel_set_a(&source[e], 0); // in case it was transcolor if(x % cdimx == 0 && y % cdimy == 0){ tam[tyx].state = SPRIXCELL_ANNIHILATED_TRANS; + if(level == KITTY_SELFREF){ + *tam[tyx].auxvector = SPRIXCELL_TRANSPARENT; + } + }else if(level == KITTY_SELFREF && tam[tyx].state == SPRIXCELL_ANNIHILATED_TRANS){ + *tam[tyx].auxvector = SPRIXCELL_MIXED_KITTY; } }else{ + if(x % cdimx == 0 && y % cdimy == 0 && level == KITTY_SELFREF){ + *tam[tyx].auxvector = SPRIXCELL_OPAQUE_KITTY; + }else if(level == KITTY_SELFREF && *tam[tyx].auxvector == SPRIXCELL_TRANSPARENT){ + *tam[tyx].auxvector = SPRIXCELL_MIXED_KITTY; + } tam[tyx].state = SPRIXCELL_ANNIHILATED; } - wipe[e] = 1; }else{ wipe[e] = 0; if(rgba_trans_p(source[e], transcolor)){ @@ -889,6 +941,11 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols, if(finalize_deflator(&zctx, f, leny, lenx)){ goto err; } + if(selfref_annihilated){ + if(finalize_multiframe_selfref(s, f)){ + goto err; + } + } } scrub_tam_boundaries(tam, leny, lenx, cdimy, cdimx); destroy_deflator(animated, &zctx, leny, lenx);