|
|
|
@ -833,16 +833,29 @@ emit_bg_palindex(notcurses* nc, FILE* out, const nccell* srccell){
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// remove any sprixels which are no longer desired. for kitty, this will be
|
|
|
|
|
// a pure erase; for sixel, we must overwrite. returns -1 on failure, and
|
|
|
|
|
// otherwise the number of bytes emitted redrawing sprixels.
|
|
|
|
|
// this first phase of sprixel rasterization is responsible for:
|
|
|
|
|
// 1) invalidating all QUIESCENT sprixels if the pile has changed (because
|
|
|
|
|
// it would have been destroyed when switching away from our pile).
|
|
|
|
|
// for the same reason, invalidated all MOVE sprixels in this case.
|
|
|
|
|
// 2) damaging all cells under a HIDE sixel, so text phase 1 consumes it
|
|
|
|
|
// (not necessary for kitty graphics)
|
|
|
|
|
// 3) damaging uncovered cells under a MOVE (not necessary for kitty)
|
|
|
|
|
// 4) drawing invalidated sixels and loading invalidated kitty graphics
|
|
|
|
|
// (new kitty graphics are *not* yet made visible)
|
|
|
|
|
// by the end of this pass, all sixels are *complete*. all kitty graphics
|
|
|
|
|
// are loaded, but old kitty graphics remain visible, and new/updated kitty
|
|
|
|
|
// graphics are not yet visible, and they have not moved.
|
|
|
|
|
static int64_t
|
|
|
|
|
clean_sprixels(notcurses* nc, ncpile* p, FILE* out){
|
|
|
|
|
sprixel* s;
|
|
|
|
|
sprixel** parent = &p->sprixelcache;
|
|
|
|
|
int64_t bytesemitted = 0;
|
|
|
|
|
while( (s = *parent) ){
|
|
|
|
|
if(s->invalidated == SPRIXEL_HIDE){
|
|
|
|
|
if(s->invalidated == SPRIXEL_QUIESCENT){
|
|
|
|
|
if(p != nc->last_pile){
|
|
|
|
|
s->invalidated = SPRIXEL_INVALIDATED;
|
|
|
|
|
}
|
|
|
|
|
}else if(s->invalidated == SPRIXEL_HIDE){
|
|
|
|
|
//fprintf(stderr, "OUGHT HIDE %d [%dx%d] %p\n", s->id, s->dimy, s->dimx, s);
|
|
|
|
|
if(sprite_scrub(nc, p, s)){
|
|
|
|
|
return -1;
|
|
|
|
@ -851,13 +864,18 @@ clean_sprixels(notcurses* nc, ncpile* p, FILE* out){
|
|
|
|
|
s->next->prev = s->prev;
|
|
|
|
|
}
|
|
|
|
|
sprixel_free(s);
|
|
|
|
|
}else if(s->invalidated == SPRIXEL_MOVED || s->invalidated == SPRIXEL_INVALIDATED){
|
|
|
|
|
continue; // don't account as an elision
|
|
|
|
|
}
|
|
|
|
|
if(s->invalidated == SPRIXEL_MOVED || s->invalidated == SPRIXEL_INVALIDATED){
|
|
|
|
|
int y, x;
|
|
|
|
|
ncplane_yx(s->n, &y, &x);
|
|
|
|
|
//fprintf(stderr, "1 MOVING BITMAP %d STATE %d AT %d/%d for %p\n", s->id, s->invalidated, y + nc->margin_t, x + nc->margin_l, s->n);
|
|
|
|
|
// without this, kitty flickers
|
|
|
|
|
if(s->invalidated == SPRIXEL_MOVED){
|
|
|
|
|
sprite_scrub(nc, p, s);
|
|
|
|
|
if(p != nc->last_pile){
|
|
|
|
|
s->invalidated = SPRIXEL_INVALIDATED;
|
|
|
|
|
}else{ // this is a new pile, so we couldn't have been on-screen
|
|
|
|
|
//sprite_scrub(nc, p, s);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(goto_location(nc, out, y + nc->margin_t, x + nc->margin_l) == 0){
|
|
|
|
|
int r = sprite_redraw(nc, p, s, out);
|
|
|
|
@ -873,6 +891,7 @@ clean_sprixels(notcurses* nc, ncpile* p, FILE* out){
|
|
|
|
|
++nc->stats.sprixelelisions;
|
|
|
|
|
parent = &s->next;
|
|
|
|
|
}
|
|
|
|
|
//fprintf(stderr, "SPRIXEL STATE: %d\n", s->invalidated);
|
|
|
|
|
}
|
|
|
|
|
return bytesemitted;
|
|
|
|
|
}
|
|
|
|
@ -889,8 +908,13 @@ rasterize_scrolls(ncpile* p, FILE* out){
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// draw any invalidated sprixels. returns -1 on error, number of bytes written
|
|
|
|
|
// on success. any material underneath them has already been updated.
|
|
|
|
|
// second sprixel pass in rasterization. by this time, all sixels are handled
|
|
|
|
|
// (and in the QUIESCENT state); only persistent kitty graphics still require
|
|
|
|
|
// operation. responsibilities of this second pass include:
|
|
|
|
|
//
|
|
|
|
|
// 1) if we're a different pile, issue the kitty universal clear
|
|
|
|
|
// 2) first, hide all sprixels in the HIDE state
|
|
|
|
|
// 3) then, make allo LOADED sprixels visible
|
|
|
|
|
static int64_t
|
|
|
|
|
rasterize_sprixels(notcurses* nc, ncpile* p, FILE* out){
|
|
|
|
|
int64_t bytesemitted = 0;
|
|
|
|
@ -898,7 +922,7 @@ rasterize_sprixels(notcurses* nc, ncpile* p, FILE* out){
|
|
|
|
|
if(s->invalidated == SPRIXEL_INVALIDATED){
|
|
|
|
|
int y, x;
|
|
|
|
|
ncplane_yx(s->n, &y, &x);
|
|
|
|
|
//fprintf(stderr, "3 DRAWING BITMAP %d STATE %d AT %d/%d for %p\n", s->id, s->invalidated, y + nc->margin_t, x + nc->margin_l, s->n);
|
|
|
|
|
fprintf(stderr, "3 DRAWING BITMAP %d STATE %d AT %d/%d for %p\n", s->id, s->invalidated, y + nc->margin_t, x + nc->margin_l, s->n);
|
|
|
|
|
if(goto_location(nc, out, y + nc->margin_t, x + nc->margin_l)){
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
@ -909,6 +933,18 @@ rasterize_sprixels(notcurses* nc, ncpile* p, FILE* out){
|
|
|
|
|
bytesemitted += r;
|
|
|
|
|
nc->rstate.hardcursorpos = true;
|
|
|
|
|
++nc->stats.sprixelemissions;
|
|
|
|
|
}else if(s->invalidated == SPRIXEL_LOADED){
|
|
|
|
|
if(nc->tcache.pixel_commit){
|
|
|
|
|
int y,x;
|
|
|
|
|
ncplane_yx(s->n, &y, &x);
|
|
|
|
|
//fprintf(stderr, "3 DRAWING BITMAP %d STATE %d AT %d/%d for %p\n", s->id, s->invalidated, y + nc->margin_t, x + nc->margin_l, s->n);
|
|
|
|
|
if(goto_location(nc, out, y + nc->margin_t, x + nc->margin_l)){
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
if(nc->tcache.pixel_commit(out, s) < 0){
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return bytesemitted;
|
|
|
|
@ -1050,25 +1086,26 @@ rasterize_core(notcurses* nc, const ncpile* p, FILE* out, unsigned phase){
|
|
|
|
|
// desired; in this case, an ASU footer is present at the end of the buffer.
|
|
|
|
|
static int
|
|
|
|
|
notcurses_rasterize_inner(notcurses* nc, ncpile* p, FILE* out, unsigned* asu){
|
|
|
|
|
//fprintf(stderr, "pile %p ymax: %d xmax: %d\n", p, p->dimy + nc->margin_t, p->dimx + nc->margin_l);
|
|
|
|
|
// we only need to emit a coordinate if it was damaged. the damagemap is a
|
|
|
|
|
// bit per coordinate, one per struct crender.
|
|
|
|
|
// 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, "pile %p ymax: %d xmax: %d\n", p, p->dimy + nc->margin_t, p->dimx + nc->margin_l);
|
|
|
|
|
//fprintf(stderr, "RASTERIZE SPRIXELS\n");
|
|
|
|
|
int64_t sprixelbytes = clean_sprixels(nc, p, out);
|
|
|
|
|
if(sprixelbytes < 0){
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
update_palette(nc, out);
|
|
|
|
|
//fprintf(stderr, "RASTERIZE CORE\n");
|
|
|
|
|
if(rasterize_scrolls(p, out)){
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
//fprintf(stderr, "RASTERIZE CORE PASS 1\n");
|
|
|
|
|
if(rasterize_core(nc, p, out, 0)){
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
//fprintf(stderr, "RASTERIZE SPRIXELS\n");
|
|
|
|
|
//fprintf(stderr, "FINALIZE SPRIXELS\n");
|
|
|
|
|
int64_t rasprixelbytes = rasterize_sprixels(nc, p, out);
|
|
|
|
|
if(rasprixelbytes < 0){
|
|
|
|
|
return -1;
|
|
|
|
@ -1077,7 +1114,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\n");
|
|
|
|
|
//fprintf(stderr, "RASTERIZE CORE PASS 2\n");
|
|
|
|
|
if(rasterize_core(nc, p, out, 1)){
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
@ -1119,13 +1156,6 @@ raster_and_write(notcurses* nc, ncpile* p, FILE* out){
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// if the last pile was different from this one, we need clear all old
|
|
|
|
|
// sprixels (and invalidate all those of the current pile -- FIXME).
|
|
|
|
|
if(nc->last_pile != p && nc->last_pile){
|
|
|
|
|
if(sprite_clear_all(&nc->tcache, out)){
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(notcurses_rasterize_inner(nc, p, out, &useasu) < 0){
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|