[kitty] further work on kitty_cell_wipe()

pull/1428/head
nick black 3 years ago committed by Nick Black
parent fc4c0a2d9c
commit c067c2bfd9

@ -61,7 +61,8 @@ typedef struct sprixel {
} invalidated;
struct sprixel* next;
int y, x;
int dimy, dimx;
int dimy, dimx; // cell geometry
int pixy, pixx; // pixel geometry (might be smaller than cell geo)
} sprixel;
// A plane is memory for some rectilinear virtual window, plus current cursor
@ -700,7 +701,8 @@ plane_debug(const ncplane* n, bool details){
void sprixel_free(sprixel* s);
void sprixel_hide(sprixel* s);
// dimy and dimx are cell geometry, not pixel
sprixel* sprixel_create(ncplane* n, const char* s, int bytes, int sprixelid, int dimy, int dimx);
sprixel* sprixel_create(ncplane* n, const char* s, int bytes, int sprixelid,
int dimy, int dimx, int pixy, int pixx);
int sprite_kitty_annihilate(notcurses* nc, const ncpile* p, FILE* out, sprixel* s);
int sprite_sixel_annihilate(notcurses* nc, const ncpile* p, FILE* out, sprixel* s);
@ -1097,8 +1099,8 @@ egc_rtl(const char* egc, int* bytes){
// new, purpose-specific plane.
static inline int
plane_blit_sixel(ncplane* n, const char* s, int bytes, int leny, int lenx,
int sprixelid){
sprixel* spx = sprixel_create(n, s, bytes, sprixelid, leny, lenx);
int sprixelid, int dimy, int dimx){
sprixel* spx = sprixel_create(n, s, bytes, sprixelid, leny, lenx, dimy, dimx);
if(spx == NULL){
return -1;
}

@ -1,40 +1,5 @@
#include "internal.h"
#define RGBA_MAXLEN 768 // 768 base64-encoded pixels in 4096 bytes
int sprite_kitty_cell_wipe(notcurses* nc, sprixel* s, int ycell, int xcell){
if(ycell >= s->dimy){
return -1;
}
if(xcell >= s->dimx){
return -1;
}
int xpixels = nc->tcache.cellpixx;
int ypixels = nc->tcache.cellpixy;
int xpx = xpixels * xcell; // pixel coordinates where we start erasing
int ypx = ypixels * ycell;
char* c = s->glyph;
// every pixel was 4 source bytes, 32 bits, 6.33 base64 bytes. every 3 input pixels is
// 12 bytes (96 bits), an even 16 base64 bytes. there is chunking to worry about. there
// are up to 768 pixels in a chunk.
int chunks = (xcell + s->dimx * ycell) / RGBA_MAXLEN;
do{
while(*c != ';'){
++c;
}
++c;
if(chunks == 0){
// we're in the proper chunk. find the pixel offset of the first
// pixel (within the chunk).
int offset = (xpx + s->dimx * ypx) % RGBA_MAXLEN;
// skip the 16-byte pixel triples
int bytes = (offset / 3) * 16;
// FIXME
return 0;
}
}while(--chunks);
return -1;
}
static unsigned const char b64subs[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@ -93,6 +58,80 @@ base64_rgba3(const uint32_t* pixels, size_t pcount, char* b64){
b64[16] = '\0';
}
// null out part of a triplet (a triplet is 3 pixels, which map to 12 bytes, which map to
// 16 bytes when base64 encoded). skip the initial |skip| pixels, and null out a maximum
// of |max| pixels after that. returns the number of pixels nulled out. |max| must be
// positive. |skip| must be non-negative, and less than 3.
static inline int
kitty_null(char* triplet, int skip, int max){
(void)triplet;
(void)max;
(void)skip;
char pixels[12];
return max;
}
#define RGBA_MAXLEN 768 // 768 base64-encoded pixels in 4096 bytes
int sprite_kitty_cell_wipe(notcurses* nc, sprixel* s, int ycell, int xcell){
if(ycell >= s->dimy){
return -1;
}
if(xcell >= s->dimx){
return -1;
}
const int xpixels = nc->tcache.cellpixx;
const int ypixels = nc->tcache.cellpixy;
// if the cell is on the right or bottom borders, it might only be partially
// filled by actual graphic data, and we need to cap our target area.
int targx = xpixels;
if(xcell * xpixels > s->pixx){
targx -= ((xcell * xpixels) - s->pixx);
}
int targy = ypixels;
if(ycell * ypixels > s->pixy){
targy -= ((ycell * ypixels) - s->pixy);
}
fprintf(stderr, "TARGET AREA: %d x %d\n", targy, targx);
char* c = s->glyph;
// every pixel was 4 source bytes, 32 bits, 6.33 base64 bytes. every 3 input pixels is
// 12 bytes (96 bits), an even 16 base64 bytes. there is chunking to worry about. there
// are up to 768 pixels in a chunk.
int nextpixel = s->dimx * xpixels * ycell + xpixels * xcell;
int nextend = nextpixel + targx - 1;
fprintf(stderr, "NEXTPIXEL: %d\n", nextpixel);
int curpixel = 0;
int thisrow = targx;
while(targy){ // need to null out |targy| rows of |targx| pixels, track with |thisrow|
while(*c != ';'){
++c;
}
++c;
while(nextpixel - curpixel < RGBA_MAXLEN && thisrow){
// our next pixel is within this chunk. find the pixel offset of the
// first pixel (within the chunk).
int pixoffset = nextpixel - curpixel;
int triples = pixoffset / 3;
int tripbytes = triples * 16;
// we start within a 16-byte chunk |tripbytes| into the chunk. determine
// the number of bits.
int tripskip = pixoffset - triples * 3;
int chomped = kitty_null(c + tripbytes, tripskip, thisrow);
thisrow -= chomped;
nextpixel += chomped;
fprintf(stderr, "pixoffset: %d next: %d tripbytes: %d tripskip: %d\n", pixoffset, nextpixel, tripbytes, tripskip);
if(thisrow == 0){
if(--targy == 0){
return 0;
}
thisrow = targx;
nextpixel += s->dimx - xpixels;
}
}
c += RGBA_MAXLEN * 4 * 4 / 3; // 4bpp * 4/3 for base64, 4096b per chunk
}
return -1;
}
// 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.
@ -146,8 +185,8 @@ write_kitty_data(FILE* fp, int linesize, int leny, int lenx,
return -1;
}
return 0;
#undef RGBA_MAXLEN
}
#undef RGBA_MAXLEN
// Kitty graphics blitter. Kitty can take in up to 4KiB at a time of (optionally
// deflate-compressed) 24bit RGB.
@ -166,7 +205,7 @@ int kitty_blit_inner(ncplane* nc, int linesize, int leny, int lenx,
free(buf);
return -1;
}
if(plane_blit_sixel(nc, buf, size, rows, cols, bargs->pixel.sprixelid) < 0){
if(plane_blit_sixel(nc, buf, size, rows, cols, bargs->pixel.sprixelid, leny, lenx) < 0){
free(buf);
return -1;
}

@ -395,7 +395,7 @@ int sixel_blit_inner(ncplane* nc, int leny, int lenx, sixeltable* stab,
}
unsigned cols = lenx / bargs->pixel.celldimx + !!(lenx % bargs->pixel.celldimx);
unsigned rows = leny / bargs->pixel.celldimy + !!(leny % bargs->pixel.celldimy);
if(plane_blit_sixel(nc, buf, size, rows, cols, bargs->pixel.sprixelid) < 0){
if(plane_blit_sixel(nc, buf, size, rows, cols, bargs->pixel.sprixelid, leny, lenx) < 0){
free(buf);
return -1;
}

@ -17,7 +17,7 @@ void sprixel_hide(sprixel* s){
// y and x are the cell geometry, not the pixel geometry
sprixel* sprixel_create(ncplane* n, const char* s, int bytes, int sprixelid,
int dimy, int dimx){
int dimy, int dimx, int pixy, int pixx){
sprixel* ret = malloc(sizeof(sprixel));
if(ret){
if((ret->glyph = memdup(s, bytes + 1)) == NULL){
@ -28,6 +28,8 @@ sprixel* sprixel_create(ncplane* n, const char* s, int bytes, int sprixelid,
ret->n = n;
ret->dimy = dimy;
ret->dimx = dimx;
ret->pixx = pixx;
ret->pixy = pixy;
if(ncplane_pile(n)){
notcurses* nc = ncplane_notcurses(n);
ret->next = nc->sprixelcache;

@ -58,14 +58,19 @@ TEST_CASE("Pixel") {
auto s = n->sprite;
REQUIRE(nullptr != s);
CHECK(0 == notcurses_render(nc_));
sleep(3);
CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 0, 0));
CHECK(0 == notcurses_render(nc_));
sleep(3);
CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 1, 1));
CHECK(0 == notcurses_render(nc_));
sleep(3);
CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 1, 0));
CHECK(0 == notcurses_render(nc_));
sleep(3);
CHECK(0 == nc_->tcache.pixel_cell_wipe(nc_, s, 0, 1));
CHECK(0 == notcurses_render(nc_));
sleep(3);
ncplane_destroy(n);
ncvisual_destroy(ncv);
CHECK(0 == notcurses_render(nc_));

Loading…
Cancel
Save