Skip to content

Commit

Permalink
[sixel] correct writeout of the auxvec on wipe #2573
Browse files Browse the repository at this point in the history
  • Loading branch information
dankamongmen committed Feb 8, 2022
1 parent e3de2e8 commit 7e00205
Showing 1 changed file with 50 additions and 31 deletions.
81 changes: 50 additions & 31 deletions src/lib/sixel.c
Original file line number Diff line number Diff line change
Expand Up @@ -483,31 +483,50 @@ auxvec_idx(int y, int x, int cellpxy, int cellpxx){
return AUXVECELEMSIZE * off;
}

// the sixel |rep| is being wiped. the active pixels need be written to the
// |auxvec|, which is (|ey| - |sy| + 1) rows of (|ex| - |sx| + 1) columns.
// we are wiping the sixel |rep|, changing it to |mask|.
// write to this cell's auxvec, backing up the pixels cleared by a wipe. wipes
// are requested at cell granularity, broken down into sixelbands, broken down
// by color, and then finally effected at the sixel RLE level. we're thus in
// any given call handling a horizontal contiguous range of sixels for a single
// color. the x range is wholly within the cell to be wiped, but the y range
// might not be, since cells and bands don't necessarily line up. |y| ought be
// the row of the first pixel of the *band*.
//
// we thus need:
// - the starting and ending true x positions for the *portion of this sixel
// contained within the wiped cell*.
// - the true y position at which the sixel starts.
// - the previous sixel rep and the masked sixel rep--the difference between
// the two tells us which rows (offset from y) need be written. they ought
// be the binary forms, not the presentation forms (i.e. [0..63]).
// - the cell-pixel geometry, necessary for computing offset into the auxvec.
// - the color.
//
// precondition: mask is a bitwise proper subset of rep
//
// we find which [1..6] of six rows are affected by examining the difference
// between |rep| and |masked|, the sixel's row within the cell by taking |y|
// modulo |cellpxy|, and the position within the auxvec by multiplying that
// result by |cellpxx| and adding |x| modulo |cellpxx|. we set |len| pixels.
static inline void
write_auxvec(uint8_t* auxvec, int color, int y, int x, int len, int sx,
int sy, int ey, char rep, char masked, int cellpxy, int cellpxx){
rep -= 63;
fprintf(stderr, "AUXVEC WRITE[%d] y/x: %d/%d:%d s: %d/%d e: %d %d 0x%x\n", color, y, x, len, sy, sx, ey, rep, masked);
for(int i = x ; i < sx + len ; ++i){
char bitselector = 1;
for(int dy = 0 ; dy < 6 ; bitselector <<= 1u, ++dy){
if((rep & bitselector) == (masked & bitselector)){
continue; // no change
}
// we get the auxvec
const int idx = auxvec_idx(y + dy, i, cellpxy, cellpxx);
if(idx < 0 || idx > cellpxy * cellpxx * AUXVECELEMSIZE){
fprintf(stderr, "INVALID AUXIDX %d\n", idx);
continue;
}
uint16_t a;
memcpy(&a, &auxvec[idx], AUXVECELEMSIZE);
fprintf(stderr, "AUXVEC %p %d/%d for cidx %d: idx %d (was 0x%04x) BS: 0x%x\n", auxvec, y + dy, i, color, idx, a, bitselector);
(void)ey; // FIXME
write_auxvec(uint8_t* auxvec, uint16_t color, int y, int x, int len,
char rep, char masked, int cellpxy, int cellpxx){
const char diff = rep ^ masked;
//fprintf(stderr, "AUXVEC WRITE[%hu] y/x: %d/%d:%d r: 0x%x m: 0x%x d: 0x%x\n", color, y, x, len, rep, masked, diff);
const int xoff = x % cellpxx;
const int yoff = y % cellpxy;
int dy = 0;
for(char bitselector = 1 ; bitselector < 0x40 ; bitselector <<= 1u, ++dy){
if((diff & bitselector) == 0){
continue;
}
if(yoff + dy >= cellpxy){ // reached the next cell below
break;
}
//fprintf(stderr, " writing to row %d (%d)\n", y + dy, bitselector);
const int idx = ((yoff + dy) * cellpxx + xoff) * AUXVECELEMSIZE;
//fprintf(stderr, " xoff: %d yoff: %d dy: %d idx: %d\n", xoff, yoff, dy, idx);
for(int i = 0 ; i < len ; ++i){
memcpy(&auxvec[idx + i * AUXVECELEMSIZE], &color, AUXVECELEMSIZE);
}
}
}
Expand All @@ -518,7 +537,7 @@ fprintf(stderr, "AUXVEC %p %d/%d for cidx %d: idx %d (was 0x%04x) BS: 0x%x\n", a
// pixels were wiped.
static inline int
wipe_color(sixelband* b, int color, int y, int startx, int endx,
int starty, int endy, char mask, int dimx, uint8_t* auxvec,
char mask, int dimx, uint8_t* auxvec,
int cellpxy, int cellpxx){
const char* vec = b->vecs[color];
if(vec == NULL){
Expand Down Expand Up @@ -570,14 +589,14 @@ wipe_color(sixelband* b, int color, int y, int startx, int endx,
// FIXME this might equal the prev/next rep, and we ought combine
//fprintf(stderr, "************************* %d %d %d\n", endx - x, x, rle);
write_rle(newvec, &voff, endx - x, masked);
write_auxvec(auxvec, color, y, x, endx - x, startx, starty,
endy, rep, masked, cellpxy, cellpxx);
write_auxvec(auxvec, color, y, x, endx - x,
rep - 63, masked - 63, cellpxy, cellpxx);
rle -= endx - x;
x = endx;
}else{
write_rle(newvec, &voff, rle, masked);
write_auxvec(auxvec, color, y, x, rle, startx, starty, endy,
rep, masked, cellpxy, cellpxx);
write_auxvec(auxvec, color, y, x, rle,
rep - 63, masked - 63, cellpxy, cellpxx);
x += rle;
rle = 0;
}
Expand Down Expand Up @@ -611,7 +630,6 @@ static inline int
wipe_band(sixelmap* smap, int band, int startx, int endx,
int starty, int endy, int dimx, int cellpxy, int cellpxx,
uint8_t* auxvec){
//fprintf(stderr, "******************** BAND %d ********************8\n", band);
int wiped = 0;
// get 0-offset start and end row bounds for our band.
const int sy = band * 6 < starty ? starty - band * 6 : 0;
Expand All @@ -621,14 +639,15 @@ wipe_band(sixelmap* smap, int band, int startx, int endx,
unsigned char mask = 63;
// knock out a bit for each row we're wiping within the band
for(int i = 0 ; i < 6 ; ++i){
if(i >= sy && i <= ey){
if(i >= sy && i < ey){
mask &= ~(1u << i);
}
}
//fprintf(stderr, "******************** BAND %d MASK 0x%x ********************8\n", band, mask);
sixelband* b = &smap->bands[band];
// offset into map->data where our color starts
for(int i = 0 ; i < b->size ; ++i){
wiped += wipe_color(b, i, band * 6, startx, endx, starty, endy, mask,
wiped += wipe_color(b, i, band * 6, startx, endx, mask,
dimx, auxvec, cellpxy, cellpxx);
}
return wiped;
Expand Down

0 comments on commit 7e00205

Please sign in to comment.