52triplet_alpha1(
const char* triplet){
53 uint8_t c1 = b64idx(triplet[0x4]);
54 uint8_t c2 = b64idx(triplet[0x5]);
55 return (c1 << 2u) | ((c2 & 0x30) >> 4);
59triplet_alpha2(
const char* triplet){
60 uint8_t c1 = b64idx(triplet[0x9]);
61 uint8_t c2 = b64idx(triplet[0xA]);
62 return ((c1 & 0xf) << 4u) | ((c2 & 0x3c) >> 2);
66triplet_alpha3(
const char* triplet){
67 uint8_t c1 = b64idx(triplet[0xE]);
68 uint8_t c2 = b64idx(triplet[0xF]);
69 return ((c1 & 0x3) << 6u) | c2;
96kitty_null(
char* triplet,
int skip,
int max,
int pleft, uint8_t* auxvec){
101 if(max + skip > pleft){
106 auxvec[0] = triplet_alpha1(triplet);
107 triplet[0x4] = b64subs[0];
108 triplet[0x5] = b64subs[b64idx(triplet[0x5]) & 0xf];
110 auxvec[1] = triplet_alpha2(triplet);
111 triplet[0x9] = b64subs[b64idx(triplet[0x9]) & 0x30];
112 triplet[0xA] = b64subs[b64idx(triplet[0xA]) & 0x3];
115 auxvec[2] = triplet_alpha3(triplet);
116 triplet[0xE] = b64subs[b64idx(triplet[0xE]) & 0x3c];
117 triplet[0xF] = b64subs[0];
120 auxvec[0] = triplet_alpha2(triplet);
121 triplet[0x9] = b64subs[b64idx(triplet[0x9]) & 0x30];
122 triplet[0xA] = b64subs[b64idx(triplet[0xA]) & 0x3];
124 auxvec[1] = triplet_alpha3(triplet);
125 triplet[0xE] = b64subs[b64idx(triplet[0xE]) & 0x3c];
126 triplet[0xF] = b64subs[0];
129 auxvec[0] = triplet_alpha3(triplet);
130 triplet[0xE] = b64subs[b64idx(triplet[0xE]) & 0x3c];
131 triplet[0xF] = b64subs[0];
143kitty_restore(
char* triplet,
int skip,
int max,
int pleft,
149 if(max + skip > pleft){
157 triplet[0x4] = b64subs[(a & 0xfc) >> 2];
158 triplet[0x5] = b64subs[((a & 0x3) << 4) | (b64idx(triplet[0x5]) & 0xf)];
164 triplet[0x9] = b64subs[(b64idx(triplet[0x9]) & 0x30) | ((a & 0xf0) >> 4)];
165 triplet[0xA] = b64subs[((a & 0xf) << 2) | (b64idx(triplet[0xA]) & 0x3)];
172 triplet[0xE] = b64subs[((a & 0xc0) >> 6) | (b64idx(triplet[0xE]) & 0x3c)];
173 triplet[0xF] = b64subs[(a & 0x3f)];
180 triplet[0x9] = b64subs[(b64idx(triplet[0x9]) & 0x30) | ((a & 0xf0) >> 4)];
181 triplet[0xA] = b64subs[((a & 0xf) << 2) | (b64idx(triplet[0xA]) & 0x3)];
187 triplet[0xE] = b64subs[((a & 0xc0) >> 6) | (b64idx(triplet[0xE]) & 0x3c)];
188 triplet[0xF] = b64subs[(a & 0x3f)];
195 triplet[0xE] = b64subs[((a & 0xc0) >> 6) | (b64idx(triplet[0xE]) & 0x3c)];
196 triplet[0xF] = b64subs[(a & 0x3f)];
204init_sprixel_animation(
sprixel* s){
208 fbuf_free(&s->
glyph);
209 if(fbuf_init(&s->
glyph)){
216#define RGBA_MAXLEN 768
220 const int totalpixels = s->
pixy * s->
pixx;
221 const int xpixels = ncplane_pile(s->
n)->cellpxx;
222 const int ypixels = ncplane_pile(s->
n)->cellpxy;
224 if((xcell + 1) * xpixels > s->
pixx){
225 targx = s->
pixx - xcell * xpixels;
228 if((ycell + 1) * ypixels > s->
pixy){
229 targy = s->
pixy - ycell * ypixels;
232 int nextpixel = (s->
pixx * ycell * ypixels) + (xpixels * xcell);
234 int chunkedhandled = 0;
238 while(targy && chunkedhandled < chunks){
239 int inchunk = totalpixels - chunkedhandled *
RGBA_MAXLEN;
245 while(nextpixel - curpixel <
RGBA_MAXLEN && thisrow){
248 int pixoffset = nextpixel - curpixel;
249 int triples = pixoffset / 3;
250 int tripbytes = triples * 16;
251 int tripskip = pixoffset - triples * 3;
258 int chomped = kitty_restore(
c + tripbytes, tripskip, thisrow,
259 inchunk - triples * 3, auxvec + auxvecidx,
262 auxvecidx += chomped;
274 nextpixel += s->
pixx - targx + chomped;
276 nextpixel += chomped;
294static inline unsigned
295kitty_anim_auxvec_blitsource_p(
const sprixel* s,
const uint8_t* auxvec){
296 size_t off = ncplane_pile(s->
n)->cellpxy * ncplane_pile(s->
n)->cellpxx * 4;
312kitty_anim_auxvec(
int dimy,
int dimx,
int posy,
int posx,
313 int cellpxy,
int cellpxx,
const uint32_t* data,
314 int rowstride, uint8_t* existing, uint32_t transcolor){
315 const size_t slen = 4 * cellpxy * cellpxx + 1;
316 uint32_t* a = existing ? existing : malloc(slen);
318 for(
int y = posy ;
y < posy + cellpxy &&
y < dimy ; ++
y){
319 int pixels = cellpxx;
320 if(pixels + posx > dimx){
321 pixels = dimx - posx;
328 memcpy(a + (
y - posy) * pixels, data +
y * (rowstride / 4) + posx, pixels * 4);
329 for(
int x = posx ;
x < posx + cellpxx &&
x < dimx ; ++
x){
330 uint32_t pixel = data[
y * (rowstride / 4) +
x];
331 if(rgba_trans_p(pixel, transcolor)){
332 uint32_t* ap = a + (
y - posy) * pixels + (
x - posx);
333 ncpixel_set_a(ap, 0);
337 ((uint8_t*)a)[slen - 1] = 0;
344 uint8_t* a = malloc(slen);
354kitty_blit_wipe_selfref(
sprixel* s,
fbuf* f,
int ycell,
int xcell){
355 const int cellpxx = ncplane_pile(s->
n)->cellpxx;
356 const int cellpxy = ncplane_pile(s->
n)->cellpxy;
357 if(fbuf_printf(f,
"\x1b_Ga=f,x=%d,y=%d,s=%d,v=%d,i=%d,X=1,r=2,c=1,q=2;",
358 xcell * cellpxx, ycell * cellpxy, cellpxx, cellpxy, s->
id) < 0){
362 int totalp = cellpxy * cellpxx;
364 #define TRINULLALPHA "AAAAAAAAAAAAAAAA"
365 for(
int p = 0 ; p + 3 <= totalp ; p += 3){
372 #define UNUMNULLALPHA "AAAAAA=="
377 }
else if(totalp % 3 == 2){
378 #define DUONULLALPHA "AAAAAAAAAAA="
385 if(fbuf_printf(f,
"\x1b\\\x1b_Ga=a,i=%d,c=2,q=2\x1b\\", s->
id) < 0){
395 logdebug(
"wiping sprixel %u at %d/%d", s->
id, ycell, xcell);
396 if(init_sprixel_animation(s)){
400 if(kitty_blit_wipe_selfref(s, f, ycell, xcell) < 0){
403 int tamidx = ycell * s->
dimx + xcell;
405 auxvec[ncplane_pile(s->
n)->cellpxx * ncplane_pile(s->
n)->cellpxy * 4] = 0;
411 if(init_sprixel_animation(s)){
414 const int tyx = xcell + ycell * s->
dimx;
417 logdebug(
"wiping sprixel %u at %d/%d auxvec: %p state: %d", s->
id, ycell, xcell, auxvec, state);
419 if(kitty_blit_wipe_selfref(s, f, ycell, xcell)){
423 memcpy(auxvec, &state,
sizeof(state));
430 int dimy = hides->
dimy;
431 int dimx = hides->
dimx;
438static inline uint8_t*
439kitty_auxiliary_vector(
const sprixel* s){
440 int pixels = ncplane_pile(s->
n)->cellpxy * ncplane_pile(s->
n)->cellpxx;
441 uint8_t* ret = malloc(
sizeof(*ret) * pixels);
443 memset(ret, 0,
sizeof(*ret) * pixels);
450 uint8_t* auxvec = kitty_auxiliary_vector(s);
454 const int totalpixels = s->
pixy * s->
pixx;
455 const int xpixels = ncplane_pile(s->
n)->cellpxx;
456 const int ypixels = ncplane_pile(s->
n)->cellpxy;
460 if((xcell + 1) * xpixels > s->
pixx){
461 targx = s->
pixx - xcell * xpixels;
464 if((ycell + 1) * ypixels > s->
pixy){
465 targy = s->
pixy - ycell * ypixels;
472 int nextpixel = (s->
pixx * ycell * ypixels) + (xpixels * xcell);
474 int chunkedhandled = 0;
477 while(targy && chunkedhandled < chunks){
479 int inchunk = totalpixels - chunkedhandled *
RGBA_MAXLEN;
485 while(nextpixel - curpixel <
RGBA_MAXLEN && thisrow){
488 int pixoffset = nextpixel - curpixel;
489 int triples = pixoffset / 3;
490 int tripbytes = triples * 16;
493 int tripskip = pixoffset - triples * 3;
499 int chomped = kitty_null(
c + tripbytes, tripskip, thisrow,
500 inchunk - triples * 3, auxvec + auxvecidx);
503 auxvecidx += chomped;
504 assert(auxvecidx <= ypixels * xpixels);
516 nextpixel += s->
pixx - targx + chomped;
518 nextpixel += chomped;
535 loginfo(
"committing Kitty graphic id %u", s->
id);
538 i = fbuf_printf(f,
"\e_Ga=p,i=%u,p=1,X=%u,Y=%u%s,q=2\e\\", s->
id,
541 i = fbuf_printf(f,
"\e_Ga=p,i=%u,p=1,q=2%s\e\\", s->
id, noscroll ?
",C=1" :
"");
553encode_and_chunkify(
fbuf* f,
const unsigned char* buf,
size_t blen,
unsigned compressed){
556 if(fbuf_putn(f,
",o=z", 4) < 0){
560 if(blen > 4096 * 3 / 4){
561 if(fbuf_putn(f,
",m=1", 4) < 0){
565 if(fbuf_putc(f,
';') < 0){
571 while(blen - i > 4096 * 3 / 4){
573 if(fbuf_putn(f,
"\x1b_Gm=1;", 7) < 0){
577 unsigned long max = i + 4096 * 3 / 4;
579 base64x3(buf + i, b64d);
580 if(fbuf_putn(f, b64d, 4) < 0){
586 if(fbuf_putn(f,
"\x1b\\", 2) < 0){
591 if(fbuf_putn(f,
"\x1b_Gm=0;", 7) < 0){
597 base64final(buf + i, b64d, blen - i);
598 if(fbuf_putn(f, b64d, 4) < 0){
603 base64x3(buf + i, b64d);
604 if(fbuf_putn(f, b64d, 4) < 0){
610 if(fbuf_putn(f,
"\x1b\\", 2) < 0){
617deflate_buf(
void* buf,
fbuf* f,
int dimy,
int dimx){
618 const size_t blen = dimx * dimy * 4;
624 struct libdeflate_compressor* cmp = libdeflate_alloc_compressor(2);
626 logerror(
"couldn't get libdeflate context");
632 clen = libdeflate_zlib_compress(cmp, buf, blen, cbuf, blen);
634 libdeflate_free_compressor(cmp);
637 int z = deflateInit(&zctx, 2);
639 logerror(
"couldn't get zlib context");
642 clen = deflateBound(&zctx, blen);
645 logerror(
"couldn't allocate %" PRIuPTR
"B", clen);
649 zctx.avail_out = clen;
650 zctx.next_out = cbuf;
652 zctx.avail_in = blen;
653 z = deflate(&zctx, Z_FINISH);
654 if(z != Z_STREAM_END){
655 logerror(
"error %d deflating %" PRIuPTR
"B -> %" PRIuPTR
"B", z, blen, clen);
660 clen -= zctx.avail_out;
664 loginfo(
"deflated in vain; using original %" PRIuPTR
"B", blen);
665 ret = encode_and_chunkify(f, buf, blen, 0);
667 loginfo(
"deflated %" PRIuPTR
"B to %" PRIuPTR
"B", blen, clen);
668 ret = encode_and_chunkify(f, cbuf, clen, 1);
677add_to_buf(uint32_t *dst,
const uint32_t* src,
int encodeable,
bool wipe[
static 3]){
679 if(wipe[0] || rgba_trans_p(dst[0], 0)){
680 ncpixel_set_a(&dst[0], 0);
684 if(wipe[1] || rgba_trans_p(dst[1], 0)){
685 ncpixel_set_a(&dst[1], 0);
689 if(wipe[2] || rgba_trans_p(dst[2], 0)){
690 ncpixel_set_a(&dst[2], 0);
700prep_animation(
ncpixelimpl_e level, uint32_t** buf,
int leny,
int lenx,
unsigned* animated){
707 if((*buf = malloc(lenx * leny *
sizeof(uint32_t))) ==
NULL){
722 for(
unsigned y = 0 ;
y < s->
dimy ; ++
y){
723 for(
unsigned x = 0 ;
x < s->
dimx ; ++
x){
724 unsigned tyxidx =
y * s->
dimx +
x;
725 unsigned state = s->
n->
tam[tyxidx].
state;
727 if(kitty_blit_wipe_selfref(s, f,
y,
x)){
743write_kitty_data(
fbuf* f,
int linesize,
int leny,
int lenx,
int cols,
746 if(linesize %
sizeof(*data)){
747 logerror(
"stride (%d) badly aligned", linesize);
755 if(prep_animation(level, &buf, leny, lenx, &animated)){
765 const uint32_t transcolor = bargs->
transcolor;
766 int total = leny * lenx;
777 bool selfref_annihilated =
false;
786 *parse_start = fbuf_printf(f,
"\e_Gf=32,s=%d,v=%d,i=%d,p=1,a=t,%s",
788 animated ?
"q=2" : chunks ?
"m=1;" :
"q=2;");
789 if(*parse_start < 0){
799 if(fbuf_printf(f,
"\e_G%sm=%d;", chunks ?
"" :
"q=2,", chunks ? 1 : 0) < 0){
807 while(totalout < targetout){
808 int encodeable = targetout - totalout;
814 for(
int e = 0 ;
e < encodeable ; ++
e){
819 const uint32_t* line = data + (linesize /
sizeof(*data)) *
y;
822 ncpixel_set_a(&source[
e], ncpixel_a(source[
e]) / 2);
824 int xcell =
x / cdimx;
825 int ycell =
y / cdimy;
826 int tyx = xcell + ycell * cols;
831 if(
x % cdimx == 0 &&
y % cdimy == 0){
834 tmp = kitty_anim_auxvec(leny, lenx,
y,
x, cdimy, cdimx,
835 data, linesize, tam[tyx].auxvector,
843 if(tam[tyx].auxvector ==
NULL){
844 tam[tyx].
auxvector = malloc(
sizeof(tam[tyx].state));
845 if(tam[tyx].auxvector ==
NULL){
846 logerror(
"got a NULL auxvec at %d", tyx);
850 memcpy(tam[tyx].auxvector, &tam[tyx].state,
sizeof(tam[tyx].state));
858 const int vyx = (
y % cdimy) * cdimx + (
x % cdimx);
859 ((uint8_t*)tam[tyx].auxvector)[vyx] = ncpixel_a(source[
e]);
862 selfref_annihilated =
true;
864 ((uint8_t*)tam[tyx].auxvector)[cdimx * cdimy * 4] = 1;
867 if(rgba_trans_p(source[
e], transcolor)){
868 ncpixel_set_a(&source[
e], 0);
869 if(
x % cdimx == 0 &&
y % cdimy == 0){
887 if(rgba_trans_p(source[
e], transcolor)){
888 ncpixel_set_a(&source[
e], 0);
889 if(
x % cdimx == 0 &&
y % cdimy == 0){
895 if(
x % cdimx == 0 &&
y % cdimy == 0){
904 totalout += encodeable;
906 if(add_to_buf(buf + bufidx, source, encodeable, wipe)){
909 bufidx += encodeable;
913 base64_rgba3(source, encodeable, out, wipe, 0);
914 if(fbuf_puts(f, out) < 0){
920 if(fbuf_putn(f,
"\x1b\\", 2) < 0){
928 if(deflate_buf(buf, f, leny, lenx)){
931 if(selfref_annihilated){
932 if(finalize_multiframe_selfref(s, f)){
937 scrub_tam_boundaries(tam, leny, lenx, cdimy, cdimx);
942 logerror(
"failed blitting kitty graphics");
943 cleanup_tam(tam, (leny + cdimy - 1) / cdimy, (lenx + cdimx - 1) / cdimx);
951 if(init_sprixel_animation(s)){
955 const int cellpxy = ncplane_pile(s->
n)->cellpxy;
956 const int cellpxx = ncplane_pile(s->
n)->cellpxx;
957 const int ystart = ycell * cellpxy;
958 const int xstart = xcell * cellpxx;
959 const int xlen = xstart + cellpxx > s->
pixx ? s->
pixx - xstart : cellpxx;
960 const int ylen = ystart + cellpxy > s->
pixy ? s->
pixy - ystart : cellpxy;
962 fbuf_printf(f,
"\e_Ga=c,x=%d,y=%d,X=%d,Y=%d,w=%d,h=%d,i=%d,r=1,c=2,q=2;\x1b\\",
963 xcell * cellpxx, ycell * cellpxy,
964 xcell * cellpxx, ycell * cellpxy,
966 const int tyx = xcell + ycell * s->
dimx;
974 if(init_sprixel_animation(s)){
978 const int cellpxy = ncplane_pile(s->
n)->cellpxy;
979 const int cellpxx = ncplane_pile(s->
n)->cellpxx;
980 const int ystart = ycell * cellpxy;
981 const int xstart = xcell * cellpxx;
982 const int xlen = xstart + cellpxx > s->
pixx ? s->
pixx - xstart : cellpxx;
983 const int ylen = ystart + cellpxy > s->
pixy ? s->
pixy - ystart : cellpxy;
984 const int linesize =
xlen * 4;
986 const int tyx = xcell + ycell * s->
dimx;
994 logdebug(
"placing %d/%d at %d/%d",
ylen,
xlen, ycell * cellpxy, xcell * cellpxx);
997 const int c = kitty_anim_auxvec_blitsource_p(s, auxvec) ? 2 : 1;
998 const int r = kitty_anim_auxvec_blitsource_p(s, auxvec) ? 1 : 2;
999 if(fbuf_printf(f,
"\e_Ga=f,x=%d,y=%d,s=%d,v=%d,i=%d,X=1,c=%d,r=%d,%s;",
1000 xcell * cellpxx, ycell * cellpxy,
xlen,
ylen,
1001 s->
id,
c,
r, chunks ?
"m=1" :
"q=2") < 0){
1005 if(fbuf_putn(f,
"\x1b_G", 3) < 0){
1009 if(fbuf_putn(f,
"q=2,", 4) < 0){
1013 if(fbuf_putn(f,
"m=", 2) < 0){
1016 if(fbuf_putint(f, chunks ? 1 : 0) < 0){
1019 if(fbuf_putc(f,
';') != 1){
1026 while(totalout < targetout){
1027 int encodeable = targetout - totalout;
1033 for(
int e = 0 ;
e < encodeable ; ++
e){
1038 const uint32_t* line = (
const uint32_t*)(auxvec + linesize *
y);
1039 source[
e] = line[
x];
1043 if(rgba_trans_p(source[
e], 0)){
1044 if(
x % cellpxx == 0 &&
y % cellpxy == 0){
1050 if(
x % cellpxx == 0 &&
y % cellpxy == 0){
1058 totalout += encodeable;
1060 base64_rgba3(source, encodeable, out, wipe, 0);
1061 if(fbuf_puts(f, out) < 0){
1065 if(fbuf_putn(f,
"\x1b\\", 2) < 0){
1078kitty_blit_core(
ncplane*
n,
int linesize,
const void* data,
int leny,
int lenx,
1082 if(init_sprixel_animation(s)){
1085 int parse_start = 0;
1089 if(write_kitty_data(f, linesize, leny, lenx, cols, data,
1090 bargs,
n->tam, &parse_start, level)){
1098 if(plane_blit_sixel(s, &s->
glyph, leny + pxoffy, lenx + pxoffx, parse_start,
1108 fbuf_free(&s->
glyph);
1114 return kitty_blit_core(
n, linesize, data, leny, lenx, bargs,
1120 return kitty_blit_core(
n, linesize, data, leny, lenx, bargs,
1126 return kitty_blit_core(
n, linesize, data, leny, lenx, bargs,
1131 loginfo(
"removing graphic %u",
id);
1132 if(fbuf_printf(f,
"\e_Ga=d,d=I,i=%d\e\\",
id) < 0){
1143 const int ridx = yy * p->
dimx + xx;
1149 sprixcell_e state = sprixel_state(
s, yy -
s->movedfromy +
s->n->absy,
1150 xx -
s->movedfromx +
s->n->absx);
1171 int yoff,
int xoff){
1174 bool animated =
false;
1176 s->animating =
false;
1179 int ret =
s->glyph.used;
1180 logdebug(
"dumping %" PRIu64
"b for %u at %d %d",
s->glyph.used,
s->id, yoff, xoff);
1182 if(fbuf_putn(f,
s->glyph.
buf,
s->glyph.used) < 0){
1187 fbuf_free(&
s->glyph);
1195 const int targy =
s->n->absy;
1196 const int targx =
s->n->absx;
1197 logdebug(
"moving %u to %d %d",
s->id, targy, targx);
1201 }
else if(fbuf_printf(f,
"\e_Ga=p,i=%d,p=1,q=2%s\e\\",
s->id,
1202 noscroll ?
",C=1" :
"") < 0){
1212 if(fbuf_putn(f,
"\x1b_Ga=d,q=2\x1b\\", 12) < 0){
API int API int API int uint64_t uint64_t uint64_t uint64_t unsigned unsigned xlen
API int API int API int uint64_t uint64_t uint64_t uint64_t unsigned ylen
void sprixel_hide(sprixel *s)
sprixel * sprixel_alloc(ncplane *n, int dimy, int dimx)
int kitty_remove(int id, fbuf *f)
int kitty_move(sprixel *s, fbuf *f, unsigned noscroll, int yoff, int xoff)
int kitty_wipe(sprixel *s, int ycell, int xcell)
int kitty_scrub(const ncpile *p, sprixel *s)
int kitty_blit_selfref(ncplane *n, int linesize, const void *data, int leny, int lenx, const blitterargs *bargs)
int kitty_rebuild_selfref(sprixel *s, int ycell, int xcell, uint8_t *auxvec)
int kitty_clear_all(fbuf *f)
int kitty_rebuild(sprixel *s, int ycell, int xcell, uint8_t *auxvec)
int kitty_rebuild_animation(sprixel *s, int ycell, int xcell, uint8_t *auxvec)
int kitty_blit(ncplane *n, int linesize, const void *data, int leny, int lenx, const blitterargs *bargs)
int kitty_draw(const tinfo *ti, const ncpile *p, sprixel *s, fbuf *f, int yoff, int xoff)
uint8_t * kitty_trans_auxvec(const ncpile *p)
int kitty_wipe_animation(sprixel *s, int ycell, int xcell)
sprixel * kitty_recycle(ncplane *n)
int kitty_commit(fbuf *f, sprixel *s, unsigned noscroll)
int kitty_wipe_selfref(sprixel *s, int ycell, int xcell)
int kitty_blit_animated(ncplane *n, int linesize, const void *data, int leny, int lenx, const blitterargs *bargs)
#define logerror(fmt,...)
#define logdebug(fmt,...)
notcurses * ncplane_notcurses(const ncplane *n)
#define NCVISUAL_OPTION_BLEND
@ SPRIXCELL_ANNIHILATED_TRANS
struct blitterargs::@3::@5 pixel