diff --git a/src/lib/internal.h b/src/lib/internal.h index 8a6a6e36b..46421f309 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -32,6 +32,7 @@ extern "C" { #define ALLOC __attribute__((malloc)) __attribute__((warn_unused_result)) struct esctrie; +struct sixelmap; struct ncvisual_details; // Does this glyph completely obscure the background? If so, there's no need @@ -163,7 +164,7 @@ typedef struct tament { typedef struct sprixel { char* glyph; // glyph; can be quite large int glyphlen; // length of the glyph in bytes - uint32_t id; // embedded into glusters field of nccell, 24 bits + uint32_t id; // embedded into gcluster field of nccell, 24 bits // both the plane and visual can die before the sprixel does. they are // responsible in such a case for NULLing out this link themselves. struct ncplane* n; // associated ncplane @@ -176,10 +177,13 @@ typedef struct sprixel { int cellpxy, cellpxx; // cell-pixel geometry at time of creation // each tacache entry is one of 0 (standard opaque cell), 1 (cell with // some transparency), 2 (annihilated, excised) - int parse_start; // where to start parsing for cell wipes int movedfromy; // for SPRIXEL_MOVED, the starting absolute position, int movedfromx; // so that we can damage old cells when redrawn - bool wipes_outstanding; // do we need execute wipes on move? + // only used for kitty-based sprixels + int parse_start; // where to start parsing for cell wipes + // only used for sixel-based sprixels + struct sixelmap* smap; // copy of palette indices + transparency bits + bool wipes_outstanding; // do we need rebuild the sixel next render? } sprixel; // A plane is memory for some rectilinear virtual window, plus current cursor @@ -966,6 +970,7 @@ sprixel* sprixel_by_id(const ncpile* n, uint32_t id); void sprixel_invalidate(sprixel* s, int y, int x); void sprixel_movefrom(sprixel* s, int y, int x); void sprixel_debug(FILE* out, const sprixel* s); +void free_sixelmap(struct sixelmap *s); // create an auxiliary vector suitable for a sprixcell, and zero it out uint8_t* sprixel_auxiliary_vector(const sprixel* s); diff --git a/src/lib/sixel.c b/src/lib/sixel.c index 68ae6448f..6b03a2c0e 100644 --- a/src/lib/sixel.c +++ b/src/lib/sixel.c @@ -10,6 +10,51 @@ typedef enum { SIXEL_P2_TRANS = 1, } sixel_p2_e; +// we keep a copy of the visual data, reduced to a color index and a +// transparency bit per pixel. we keep the two arrays separate so the +// transparency bits don't absolutely destroy cache efficiency for the +// data array. this allows us to rebuild wiped sprixcells by simply +// rerunning the sprixel generation process following palette quantization, +// which is much, much easier than rebuilding inline, and can be done at +// the same time as wiping, and batches them both, and is probably just as +// fast (slow) as the complex in-place rebuild would be. there is, of course, +// a memory cost of about 1.125MB for a 1024x1024 sixel, but at least we +// needn't muck with auxvectors. +typedef struct sixelmap { + uint8_t* pixels; // 1 byte per pixel, index into color table + uint8_t* transmap; // 1 bit per pixel, 1 == transparent, 0 == opaque +} sixelmap; + +// whip up an all-zero sixelmap for the specified number of pixels +static sixelmap* +create_sixelmap(int pixels){ + sixelmap* ret = malloc(sizeof(*ret)); + if(ret){ + size_t pixsize = sizeof(*ret->pixels) * pixels; + ret->pixels = malloc(pixsize); + if(ret->pixels){ + size_t transsize = (pixels + 7) / 8; + ret->transmap = malloc(transsize); + if(ret->transmap){ + memset(ret->transmap, 0, transsize); + memset(ret->pixels, 0, pixsize); + return ret; + } + free(ret->pixels); + } + free(ret); + } + return NULL; +} + +void free_sixelmap(sixelmap *s){ + if(s){ + free(s->transmap); + free(s->pixels); + free(s); + } +} + // the P2 parameter on a sixel specifies how unspecified pixels are drawn. // if P2 is 1, unspecified pixels are transparent. otherwise, they're drawn // as something else. some terminals (e.g. foot) can draw more quickly if @@ -49,6 +94,7 @@ typedef struct cdetails { // second pass: construct data for extracted colors over the sixels typedef struct sixeltable { + sixelmap* map; // copy of palette indices / transparency bits // FIXME keep these internal to palette extraction; finalize there int colors; cdetails* deets; // |colorregs| cdetails structures @@ -469,6 +515,7 @@ int sixel_blit(ncplane* n, int linesize, const void* data, colorregs = 256; } sixeltable stable = { + .map = create_sixelmap(sixelcount * 6), .data = malloc(colorregs * sixelcount), .deets = malloc(colorregs * sizeof(cdetails)), .table = malloc(colorregs * CENTSIZE), @@ -477,7 +524,9 @@ int sixel_blit(ncplane* n, int linesize, const void* data, .colors = 0, .p2 = SIXEL_P2_ALLOPAQUE, }; - if(stable.data == NULL || stable.deets == NULL || stable.table == NULL){ + if(stable.data == NULL || stable.deets == NULL || stable.table == NULL + || stable.map == NULL){ + free_sixelmap(stable.map); free(stable.table); free(stable.deets); free(stable.data); diff --git a/src/lib/sprite.c b/src/lib/sprite.c index fca13b214..64be695ed 100644 --- a/src/lib/sprite.c +++ b/src/lib/sprite.c @@ -40,6 +40,7 @@ void sprixel_free(sprixel* s){ if(s->n){ s->n->sprite = NULL; } + free_sixelmap(s->smap); free(s->glyph); free(s); } @@ -131,7 +132,6 @@ sprixel* sprixel_alloc(ncplane* n, int dimy, int dimx, int placey, int placex){ ret->y = placey; ret->x = placex; ret->id = ++sprixelid_nonce; - ret->wipes_outstanding = false; //fprintf(stderr, "LOOKING AT %p (p->n = %p)\n", ret, ret->n); if(ncplane_pile(ret->n)){ ncpile* np = ncplane_pile(ret->n);