add auxiliary vector to TAM #1440

pull/1604/head
nick black 3 years ago committed by Nick Black
parent 3e0783593d
commit dd85c7042b

@ -143,6 +143,13 @@ typedef enum {
SPRIXCELL_ANNIHILATED, // this cell has been wiped (all trans)
} sprixcell_e;
// a TAM entry is a sprixcell_e state plus a possible auxiliary vector for
// reconstruction of annihilated cells, valid only for SPRIXCELL_ANNIHILATED.
typedef struct tament {
sprixcell_e state;
uint8_t auxvector; // palette entries for sixel, alphas for kitty
} tament;
// a sprixel represents a bitmap, using whatever local protocol is available.
// there is a list of sprixels per ncpile. there ought never be very many
// associated with a context (a dozen or so at max). with the kitty protocol,
@ -215,7 +222,7 @@ 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
tament* tam; // transparency-annihilation sprite matrix
void* userptr; // slot for the user to stick some opaque pointer
int (*resizecb)(struct ncplane*); // callback after parent is resized
@ -931,7 +938,6 @@ int kitty_rebuild(const notcurses* nc, sprixel* s, int ycell, int xcell);
void sprixel_free(sprixel* s);
void sprixel_hide(sprixel* s);
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.
@ -964,6 +970,13 @@ sprite_destroy(const notcurses* nc, const ncpile* p, FILE* out, sprixel* s){
return nc->tcache.pixel_destroy(nc, p, out, s);
}
// precondition: s->invalidated is SPRIXEL_INVALIDATED or SPRIXEL_MOVED.
static inline int
sprite_draw(const notcurses* n, const ncpile* p, sprixel* s, FILE* out){
//sprixel_debug(stderr, s);
return n->tcache.pixel_draw(n, p, s, out);
}
static inline int
sprite_rebuild(const notcurses* nc, sprixel* s, int ycell, int xcell){
return nc->tcache.pixel_rebuild(nc, s, ycell, xcell);
@ -986,26 +999,26 @@ clamp_to_sixelmax(const tinfo* t, int* y, int* x){
// cannot be SPRIXCELL_OPAQUE. this postprocesses the TAM, flipping any
// such sprixcells to SPRIXCELL_MIXED.
static inline void
scrub_tam_boundaries(sprixcell_e* tam, int leny, int lenx, int cdimy, int cdimx){
scrub_tam_boundaries(tament* tam, int leny, int lenx, int cdimy, int cdimx){
// any sprixcells which don't cover the full cell underneath them cannot
// be SPRIXCELL_OPAQUE
const int cols = (lenx + cdimx - 1) / cdimx;
if(lenx % cdimx){
for(int y = 0 ; y < (leny + cdimy - 1) / cdimy ; ++y){
if(tam[y * cols + cols - 1] == SPRIXCELL_OPAQUE_KITTY){
tam[y * cols + cols - 1] = SPRIXCELL_MIXED_KITTY;
}else if(tam[y * cols + cols - 1] == SPRIXCELL_OPAQUE_SIXEL){
tam[y * cols + cols - 1] = SPRIXCELL_MIXED_SIXEL;
if(tam[y * cols + cols - 1].state == SPRIXCELL_OPAQUE_KITTY){
tam[y * cols + cols - 1].state = SPRIXCELL_MIXED_KITTY;
}else if(tam[y * cols + cols - 1].state == SPRIXCELL_OPAQUE_SIXEL){
tam[y * cols + cols - 1].state = SPRIXCELL_MIXED_SIXEL;
}
}
}
if(leny % cdimy){
const int y = (leny + cdimy - 1) / cdimy - 1;
for(int x = 0 ; x < cols ; ++x){
if(tam[y * cols + x] == SPRIXCELL_OPAQUE_KITTY){
tam[y * cols + x] = SPRIXCELL_MIXED_KITTY;
}else if(tam[y * cols + x] == SPRIXCELL_OPAQUE_SIXEL){
tam[y * cols + x] = SPRIXCELL_MIXED_SIXEL;
if(tam[y * cols + x].state == SPRIXCELL_OPAQUE_KITTY){
tam[y * cols + x].state = SPRIXCELL_MIXED_KITTY;
}else if(tam[y * cols + x].state == SPRIXCELL_OPAQUE_SIXEL){
tam[y * cols + x].state = SPRIXCELL_MIXED_SIXEL;
}
}
}
@ -1022,7 +1035,7 @@ sprixel_state(const sprixel* s, int y, int x){
assert(localy < s->dimy);
assert(localx >= 0);
assert(localx < s->dimx);
return s->n->tacache[localy * s->dimx + localx];
return s->n->tam[localy * s->dimx + localx].state;
}
// is sprixel backend kitty (only valid after calling setup_kitty_bitmaps())?
@ -1426,7 +1439,7 @@ egc_rtl(const char* egc, int* bytes){
static inline int
plane_blit_sixel(sprixel* spx, char* s, int bytes, int rows, int cols,
int placey, int placex, int leny, int lenx,
int parse_start, sprixcell_e* tacache){
int parse_start, tament* tam){
if(sprixel_load(spx, s, bytes, placey, placex, leny, lenx, parse_start)){
return -1;
}
@ -1442,11 +1455,11 @@ plane_blit_sixel(sprixel* spx, char* s, int bytes, int rows, int cols,
}
}
if(n){
//fprintf(stderr, "TACACHE WAS: %p NOW: %p size: %d/%d\n", n->tacache, tacache, rows, cols);
if(n->tacache != tacache){
free(n->tacache);
//fprintf(stderr, "TAM WAS: %p NOW: %p size: %d/%d\n", n->tam, tam, rows, cols);
if(n->tam != tam){
free(n->tam);
}
n->tacache = tacache;
n->tam = tam;
n->sprite = spx;
}
return 0;

@ -162,7 +162,7 @@ int kitty_rebuild(const notcurses* nc, sprixel* s, int ycell, int xcell){
}
int kitty_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell){
if(s->n->tacache[s->dimx * ycell + xcell] == SPRIXCELL_ANNIHILATED){
if(s->n->tam[s->dimx * ycell + xcell].state == SPRIXCELL_ANNIHILATED){
//fprintf(stderr, "CACHED WIPE %d %d/%d\n", s->id, ycell, xcell);
return 0; // already annihilated, needn't draw glyph in kitty
}
@ -246,7 +246,7 @@ int kitty_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell){
static int
write_kitty_data(FILE* fp, int linesize, int leny, int lenx,
int cols, const uint32_t* data, int cdimy, int cdimx,
int sprixelid, sprixcell_e* tacache, int* parse_start,
int sprixelid, tament* tam, int* parse_start,
uint32_t transcolor){
if(linesize % sizeof(*data)){
fclose(fp);
@ -289,21 +289,21 @@ write_kitty_data(FILE* fp, int linesize, int leny, int lenx,
int ycell = y / cdimy;
int tyx = xcell + ycell * cols;
//fprintf(stderr, "Tyx: %d y: %d (%d) * %d x: %d (%d)\n", tyx, y, y / cdimy, cols, x, x / cdimx);
if(tacache[tyx] == SPRIXCELL_ANNIHILATED){
if(tam[tyx].state == SPRIXCELL_ANNIHILATED){
wipe[e] = 1;
}else{
wipe[e] = 0;
if(rgba_trans_p(source[e], transcolor)){
if(x % cdimx == 0 && y % cdimy == 0){
tacache[tyx] = SPRIXCELL_TRANSPARENT;
}else if(tacache[tyx] == SPRIXCELL_OPAQUE_KITTY){
tacache[tyx] = SPRIXCELL_MIXED_KITTY;
tam[tyx].state = SPRIXCELL_TRANSPARENT;
}else if(tam[tyx].state == SPRIXCELL_OPAQUE_KITTY){
tam[tyx].state = SPRIXCELL_MIXED_KITTY;
}
}else{
if(x % cdimx == 0 && y % cdimy == 0){
tacache[tyx] = SPRIXCELL_OPAQUE_KITTY;
}else if(tacache[tyx] == SPRIXCELL_TRANSPARENT){
tacache[tyx] = SPRIXCELL_MIXED_KITTY;
tam[tyx].state = SPRIXCELL_OPAQUE_KITTY;
}else if(tam[tyx].state == SPRIXCELL_TRANSPARENT){
tam[tyx].state = SPRIXCELL_MIXED_KITTY;
}
}
}
@ -319,7 +319,7 @@ write_kitty_data(FILE* fp, int linesize, int leny, int lenx,
if(fclose(fp) == EOF){
return -1;
}
scrub_tam_boundaries(tacache, leny, lenx, cdimy, cdimx);
scrub_tam_boundaries(tam, leny, lenx, cdimy, cdimx);
return 0;
}
#undef RGBA_MAXLEN
@ -336,43 +336,43 @@ int kitty_blit(ncplane* n, int linesize, const void* data,
if(fp == NULL){
return -1;
}
sprixcell_e* tacache = NULL;
tament* tam = NULL;
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->tacache){
if(n->tam){
if(n->leny == rows && n->lenx == cols){
tacache = n->tacache;
tam = n->tam;
reuse = true;
}
}
int parse_start = 0;
if(!reuse){
tacache = malloc(sizeof(*tacache) * rows * cols);
if(tacache == NULL){
tam = malloc(sizeof(*tam) * rows * cols);
if(tam == NULL){
fclose(fp);
free(buf);
return -1;
}
memset(tacache, 0, sizeof(*tacache) * rows * cols);
memset(tam, 0, sizeof(*tam) * rows * cols);
}
// closes fp on all paths
if(write_kitty_data(fp, linesize, leny, lenx, cols, data,
bargs->u.pixel.celldimy, bargs->u.pixel.celldimx,
bargs->u.pixel.spx->id, tacache, &parse_start,
bargs->u.pixel.spx->id, tam, &parse_start,
bargs->transcolor)){
if(!reuse){
free(tacache);
free(tam);
}
free(buf);
return -1;
}
// take ownership of |buf| and |tacache| on success
// take ownership of |buf| and |tam| on success
if(plane_blit_sixel(bargs->u.pixel.spx, buf, size, rows, cols,
bargs->placey, bargs->placex,
leny, lenx, parse_start, tacache) < 0){
leny, lenx, parse_start, tam) < 0){
if(!reuse){
free(tacache);
free(tam);
}
free(buf);
return -1;

@ -269,7 +269,7 @@ void free_plane(ncplane* p){
if(p->sprite){
sprixel_hide(p->sprite);
}
free(p->tacache);
free(p->tam);
egcpool_dump(&p->pool);
free(p->name);
free(p->fb);
@ -381,7 +381,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;
p->tam = NULL;
if(!n){ // new root/standard plane
p->absy = nopts->y;
p->absx = nopts->x;

@ -158,7 +158,7 @@ update_deets(uint32_t rgb, cdetails* deets){
static inline int
extract_color_table(const uint32_t* data, int linesize, int cols,
int leny, int lenx, sixeltable* stab,
sprixcell_e* tacache, const blitterargs* bargs){
tament* tam, const blitterargs* bargs){
const int begx = bargs->begx;
const int begy = bargs->begy;
const int cdimy = bargs->u.pixel.celldimy;
@ -170,23 +170,23 @@ extract_color_table(const uint32_t* data, int linesize, int cols,
for(int sy = visy ; sy < (begy + leny) && sy < visy + 6 ; ++sy){ // offset within sprixel
const uint32_t* rgb = (data + (linesize / 4 * sy) + visx);
int txyidx = (sy / cdimy) * cols + (visx / cdimx);
if(tacache[txyidx] == SPRIXCELL_ANNIHILATED){
if(tam[txyidx].state == SPRIXCELL_ANNIHILATED){
//fprintf(stderr, "TRANS SKIP %d %d %d %d (cell: %d %d)\n", visy, visx, sy, txyidx, sy / cdimy, visx / cdimx);
continue;
}
if(rgba_trans_p(*rgb, bargs->transcolor)){
if(sy % cdimy == 0 && visx % cdimx == 0){
tacache[txyidx] = SPRIXCELL_TRANSPARENT;
}else if(tacache[txyidx] == SPRIXCELL_OPAQUE_SIXEL){
tacache[txyidx] = SPRIXCELL_MIXED_SIXEL;
tam[txyidx].state = SPRIXCELL_TRANSPARENT;
}else if(tam[txyidx].state == SPRIXCELL_OPAQUE_SIXEL){
tam[txyidx].state = SPRIXCELL_MIXED_SIXEL;
}
stab->p2 = SIXEL_P2_TRANS; // even one forces P2=1
continue;
}else{
if(sy % cdimy == 0 && visx % cdimx == 0){
tacache[txyidx] = SPRIXCELL_OPAQUE_SIXEL;
}else if(tacache[txyidx] == SPRIXCELL_TRANSPARENT){
tacache[txyidx] = SPRIXCELL_MIXED_SIXEL;
tam[txyidx].state = SPRIXCELL_OPAQUE_SIXEL;
}else if(tam[txyidx].state == SPRIXCELL_TRANSPARENT){
tam[txyidx].state = SPRIXCELL_MIXED_SIXEL;
}
}
unsigned char comps[RGBSIZE];
@ -417,7 +417,7 @@ write_sixel_data(FILE* fp, int leny, int lenx, const sixeltable* stab, int* pars
// A pixel block is indicated by setting cell_pixels_p().
static inline int
sixel_blit_inner(int leny, int lenx, const sixeltable* stab, int rows, int cols,
const blitterargs* bargs, sprixcell_e* tacache){
const blitterargs* bargs, tament* tam){
char* buf = NULL;
size_t size = 0;
FILE* fp = open_memstream(&buf, &size);
@ -431,12 +431,12 @@ sixel_blit_inner(int leny, int lenx, const sixeltable* stab, int rows, int cols,
free(buf);
return -1;
}
scrub_tam_boundaries(tacache, leny, lenx, bargs->u.pixel.celldimy,
scrub_tam_boundaries(tam, leny, lenx, bargs->u.pixel.celldimy,
bargs->u.pixel.celldimx);
// take ownership of buf on success
if(plane_blit_sixel(bargs->u.pixel.spx, buf, size, rows, cols,
bargs->placey, bargs->placex,
leny, lenx, parse_start, tacache) < 0){
leny, lenx, parse_start, tam) < 0){
free(buf);
return -1;
}
@ -476,28 +476,28 @@ int sixel_blit(ncplane* n, int linesize, const void* data,
memset(stable.deets, 0, sizeof(*stable.deets) * colorregs);
int cols = bargs->u.pixel.spx->dimx;
int rows = bargs->u.pixel.spx->dimy;
sprixcell_e* tacache = NULL;
tament* tam = NULL;
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->tacache){
//fprintf(stderr, "IT'S A REUSE %d %d %d %d\n", n->tacachey, rows, n->tacachex, cols);
if(n->tam){
//fprintf(stderr, "IT'S A REUSE %d %d\n", rows, cols);
if(n->leny == rows && n->lenx == cols){
tacache = n->tacache;
tam = n->tam;
reuse = true;
}
}
if(!reuse){
tacache = malloc(sizeof(*tacache) * rows * cols);
if(tacache == NULL){
tam = malloc(sizeof(*tam) * rows * cols);
if(tam == NULL){
return -1;
}
memset(tacache, 0, sizeof(*tacache) * rows * cols);
memset(tam, 0, sizeof(*tam) * rows * cols);
}
if(extract_color_table(data, linesize, cols, leny, lenx,
&stable, tacache, bargs)){
&stable, tam, bargs)){
if(!reuse){
free(tacache);
free(tam);
}
free(stable.table);
free(stable.data);
@ -505,7 +505,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(leny, lenx, &stable, rows, cols, bargs, tacache);
int r = sixel_blit_inner(leny, lenx, &stable, rows, cols, bargs, tam);
free(stable.data);
free(stable.deets);
free(stable.table);
@ -546,7 +546,7 @@ deepclean_output(FILE* fp, const sprixel* s, int y, int *x, int rle,
unsigned char mask = 0;
for(int yi = y ; yi < y + 6 ; ++yi){
const int tidx = (yi / s->cellpxy) * s->dimx + (xi / s->cellpxx);
const bool nihil = (s->n->tacache[tidx] == SPRIXCELL_ANNIHILATED);
const bool nihil = (s->n->tam[tidx].state == SPRIXCELL_ANNIHILATED);
if(!nihil){
mask |= (1u << (yi - y));
}
@ -759,7 +759,7 @@ int sixel_rebuild(const notcurses* nc, sprixel* s, int ycell, int xcell){
// redrawn, it's redrawn using P2=1.
int sixel_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell){
(void)nc;
if(s->n->tacache[s->dimx * ycell + xcell] == SPRIXCELL_ANNIHILATED){
if(s->n->tam[s->dimx * ycell + xcell].state == SPRIXCELL_ANNIHILATED){
//fprintf(stderr, "CACHED WIPE %d %d/%d\n", s->id, ycell, xcell);
return 1; // already annihilated FIXME but 0 breaks things
}

@ -14,7 +14,7 @@ sprixel_debug(FILE* out, const sprixel* s){
int idx = 0;
for(int y = 0 ; y < s->dimy ; ++y){
for(int x = 0 ; x < s->dimx ; ++x){
fprintf(out, "%d", s->n->tacache[idx]);
fprintf(out, "%d", s->n->tam[idx].state);
++idx;
}
fprintf(out, "\n");
@ -85,9 +85,9 @@ void sprixel_invalidate(sprixel* s, int y, int x){
if(s->invalidated != SPRIXEL_HIDE && s->n){
int localy = y - s->n->absy;
int localx = x - s->n->absx;
//fprintf(stderr, "INVALIDATING AT %d/%d (%d/%d) TAM: %d\n", y, x, localy, localx, s->n->tacache[localy * s->dimx + localx]);
if(s->n->tacache[localy * s->dimx + localx] != SPRIXCELL_TRANSPARENT &&
s->n->tacache[localy * s->dimx + localx] != SPRIXCELL_ANNIHILATED){
//fprintf(stderr, "INVALIDATING AT %d/%d (%d/%d) TAM: %d\n", y, x, localy, localx, s->n->tam[localy * s->dimx + localx].state);
if(s->n->tam[localy * s->dimx + localx].state != SPRIXCELL_TRANSPARENT &&
s->n->tam[localy * s->dimx + localx].state != SPRIXCELL_ANNIHILATED){
s->invalidated = SPRIXEL_INVALIDATED;
}
}
@ -156,19 +156,12 @@ int sprite_wipe(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;
}
//fprintf(stderr, "ANNIHILATED %p %d\n", s->n->tacache, s->dimx * ycell + xcell);
//fprintf(stderr, "ANNIHILATED %p %d\n", s->n->tam, s->dimx * ycell + xcell);
int r = nc->tcache.pixel_cell_wipe(nc, s, ycell, xcell);
//fprintf(stderr, "WIPED %d %d/%d ret=%d\n", s->id, ycell, xcell, r);
// 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->n->tacache[s->dimx * ycell + xcell] = SPRIXCELL_ANNIHILATED;
return r;
}
// precondition: s->invalidated is SPRIXEL_INVALIDATED or SPRIXEL_MOVED.
int sprite_draw(const notcurses* n, const ncpile* p, sprixel* s, FILE* out){
//sprixel_debug(stderr, s);
int r = n->tcache.pixel_draw(n, p, s, out);
s->n->tam[s->dimx * ycell + xcell].state = SPRIXCELL_ANNIHILATED;
return r;
}

@ -419,13 +419,13 @@ TEST_CASE("Bitmaps") {
REQUIRE(s);
CHECK(s->dimy == dimy);
CHECK(s->dimx == dimx);
const auto tam = n->tacache;
const auto tam = n->tam;
for(int i = 0 ; i < s->dimy * s->dimx ; ++i){
int py = (i / dimx) * nc_->tcache.cellpixy;
int px = (i % dimx) * nc_->tcache.cellpixx;
// cells with a transparent pixel ought be SPRIXCELL_MIXED;
// cells without one ought be SPRIXCELL_OPAQUE.
sprixcell_e state = tam[(i / dimx) + (i % dimx)];
sprixcell_e state = tam[(i / dimx) + (i % dimx)].state;
if(i % 2){
if(state == SPRIXCELL_MIXED_SIXEL){
state = SPRIXCELL_MIXED_KITTY;

Loading…
Cancel
Save