[sprixels] use cell-pixel geometry from ncpile #1687

This commit is contained in:
nick black 2021-11-28 03:19:39 -05:00 committed by nick black
parent b26bc27072
commit 0dbb469a27
18 changed files with 296 additions and 227 deletions

View File

@ -1778,6 +1778,7 @@ API int ncplane_scrollup(struct ncplane* n, int r)
// Scroll |n| up until |child| is no longer hidden beneath it. Returns an
// error if |child| is not a child of |n|, or |n| is not scrolling, or |child|
// is fixed. Returns the number of scrolling events otherwise (might be 0).
// If the child plane is not fixed, it will likely scroll as well.
API int ncplane_scrollup_child(struct ncplane* n, const struct ncplane* child)
__attribute__ ((nonnull (1, 2)));

View File

@ -38,13 +38,13 @@ int init_banner(const notcurses* nc, fbuf* f){
free(osver);
term_fg_palindex(nc, f, nc->tcache.caps.colors <= 256 ?
14 % nc->tcache.caps.colors : 0x2080e0);
if(nc->tcache.cellpixy && nc->tcache.cellpixx){
if(nc->tcache.cellpxy && nc->tcache.cellpxx){
fbuf_printf(f, "%s%d rows (%dpx) %d cols (%dpx) %dx%d ",
clreol,
nc->stdplane->leny, nc->tcache.cellpixy,
nc->stdplane->lenx, nc->tcache.cellpixx,
nc->stdplane->leny * nc->tcache.cellpixy,
nc->stdplane->lenx * nc->tcache.cellpixx);
nc->stdplane->leny, nc->tcache.cellpxy,
nc->stdplane->lenx, nc->tcache.cellpxx,
nc->stdplane->leny * nc->tcache.cellpxy,
nc->stdplane->lenx * nc->tcache.cellpxx);
}else{
fbuf_printf(f, "%d rows %d cols ",
nc->stdplane->leny, nc->stdplane->lenx);

View File

@ -9,7 +9,7 @@ extern "C" {
static inline int
encoding_y_scale(const tinfo* tcache, const struct blitset* bset) {
if(bset->geom == NCBLIT_PIXEL){
return tcache->cellpixy;
return tcache->cellpxy;
}
return bset->height;
}
@ -18,7 +18,7 @@ encoding_y_scale(const tinfo* tcache, const struct blitset* bset) {
static inline int
encoding_x_scale(const tinfo* tcache, const struct blitset* bset) {
if(bset->geom == NCBLIT_PIXEL){
return tcache->cellpixx;
return tcache->cellpxx;
}
return bset->width;
}

View File

@ -654,8 +654,8 @@ ncdirect_render_visual(ncdirect* n, ncvisual* ncv,
disprows = dimy * encoding_y_scale(&n->tcache, bset) - 1;
outy = disprows;
}else{
dispcols = dimx * n->tcache.cellpixx;
disprows = dimy * n->tcache.cellpixy;
dispcols = dimx * n->tcache.cellpxx;
disprows = dimy * n->tcache.cellpxy;
clamp_to_sixelmax(&n->tcache, &disprows, &dispcols, &outy, vopts->scaling);
}
if(vopts->scaling == NCSCALE_SCALE || vopts->scaling == NCSCALE_SCALE_HIRES){
@ -675,7 +675,7 @@ ncdirect_render_visual(ncdirect* n, ncvisual* ncv,
}
}
if(bset->geom == NCBLIT_PIXEL){
while((outy + n->tcache.cellpixy - 1) / n->tcache.cellpixy > dimy){
while((outy + n->tcache.cellpxy - 1) / n->tcache.cellpxy > dimy){
outy -= n->tcache.sprixel_scale_height;
disprows = outy;
}
@ -693,8 +693,8 @@ ncdirect_render_visual(ncdirect* n, ncvisual* ncv,
.flags = 0,
};
if(bset->geom == NCBLIT_PIXEL){
nopts.rows = outy / n->tcache.cellpixy + !!(outy % n->tcache.cellpixy);
nopts.cols = dispcols / n->tcache.cellpixx + !!(dispcols % n->tcache.cellpixx);
nopts.rows = outy / n->tcache.cellpxy + !!(outy % n->tcache.cellpxy);
nopts.cols = dispcols / n->tcache.cellpxx + !!(dispcols % n->tcache.cellpxx);
}
if(ymax && nopts.rows > ymax){
nopts.rows = ymax;
@ -717,7 +717,9 @@ ncdirect_render_visual(ncdirect* n, ncvisual* ncv,
}
if(bset->geom == NCBLIT_PIXEL){
bargs.u.pixel.colorregs = n->tcache.color_registers;
if((bargs.u.pixel.spx = sprixel_alloc(&n->tcache, ncdv, nopts.rows, nopts.cols)) == NULL){
bargs.u.pixel.cellpxy = n->tcache.cellpxy;
bargs.u.pixel.cellpxx = n->tcache.cellpxx;
if((bargs.u.pixel.spx = sprixel_alloc(ncdv, nopts.rows, nopts.cols)) == NULL){
free_plane(ncdv);
return NULL;
}

View File

@ -288,17 +288,37 @@ struct crender {
} s;
};
// a pile is a collection of planes which will be rendered together. piles are
// completely distinct with regards to thread-safety; one can always operate
// concurrently on distinct piles (save rasterizing, of course). material from
// other piles will be blown away whenever a pile is rasterized. no ordering
// is meaningful between planes. when a new one is added, or one is destroyed,
// the pilelock (in struct notcurses) is taken. a pile is destroyed whenever
// its last plane is destroyed or reparented away. a pile contains a totally-
// ordered list of piles (ordered on the z axis) and a directed acyclic forest
// of bound planes, with each root plane rooting a DAG.
//
// the geometries are updated each time the pile is rendered. until a pile is
// rendered, its geometries might be out-of-date with regards to the terminal
// description in tcache. when it is rendered again, the geometries will be
// updated, sprixels will have their TAMs rebuilt (if necessary), and each
// root plane will have its resize callback invoked (possibly invoking its
// bound planes' resize callbacks in turn).
//
// at context start, there is one pile (the standard pile), containing one
// plane (the standard plane). each ncplane holds a pointer to its pile.
typedef struct ncpile {
ncplane* top; // topmost plane, never NULL
ncplane* bottom; // bottommost plane, never NULL
ncplane* roots; // head of root plane list
struct crender* crender; // array (rows * cols crender objects)
struct notcurses* nc; // notcurses context
struct ncpile *prev, *next; // circular list
struct ncpile *prev, *next; // circular list pointers
size_t crenderlen; // size of crender vector
unsigned dimy, dimx; // rows and cols at time of last render
unsigned dimy, dimx; // rows and cols at last render/creation
unsigned cellpxx, cellpxy; // cell-pixel geometry at last render/creation
int scrolls; // how many real lines need be scrolled at raster
sprixel* sprixelcache; // list of sprixels
sprixel* sprixelcache; // sorted list of sprixels, assembled during paint
} ncpile;
// the standard pile can be reached through ->stdplane.
@ -359,6 +379,8 @@ typedef struct blitterargs {
sprixel* spx; // sprixel object
int pxoffy; // pixel y-offset within origin cell
int pxoffx; // pixel x-offset within origin cell
int cellpxy; // targeted cell-pixel geometry. this ought come from the
int cellpxx; // target ncpile, or tcache in Direct Mode
} pixel; // for pixels
} u;
} blitterargs;
@ -664,7 +686,7 @@ void sprixel_free(sprixel* s);
void sprixel_hide(sprixel* s);
// dimy and dimx are cell geometry, not pixel.
sprixel* sprixel_alloc(const tinfo* ti, ncplane* n, int dimy, int dimx);
sprixel* sprixel_alloc(ncplane* n, int dimy, int dimx);
sprixel* sprixel_recycle(ncplane* n);
int sprite_init(const tinfo* t, int fd);
int sprite_clear_all(const tinfo* t, fbuf* f);
@ -1748,7 +1770,7 @@ typedef struct ncvisual_implementation {
int (*visual_decode_loop)(struct ncvisual* nc);
int (*visual_stream)(notcurses* nc, struct ncvisual* ncv, float timescale,
ncstreamcb streamer, const struct ncvisual_options* vopts, void* curry);
struct ncplane* (*visual_subtitle)(struct ncplane* parent, const struct ncvisual* ncv);
ncplane* (*visual_subtitle)(ncplane* parent, const struct ncvisual* ncv);
int rowalign; // rowstride base, can be 0 for no padding
// do a persistent resize, changing the ncv itself
int (*visual_resize)(struct ncvisual* ncv, unsigned rows, unsigned cols);

View File

@ -233,8 +233,8 @@ init_sprixel_animation(sprixel* s){
// auxiliary vector back into the actual data. we then free the auxvector.
int kitty_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
const int totalpixels = s->pixy * s->pixx;
const int xpixels = s->cellpxx;
const int ypixels = s->cellpxy;
const int xpixels = ncplane_pile(s->n)->cellpxx;
const int ypixels = ncplane_pile(s->n)->cellpxy;
int targx = xpixels;
if((xcell + 1) * xpixels > s->pixx){
targx = s->pixx - xcell * xpixels;
@ -308,8 +308,8 @@ int kitty_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
// wiping)?
static inline unsigned
kitty_anim_auxvec_blitsource_p(const sprixel* s, const uint8_t* auxvec){
const size_t offset = s->cellpxy * s->cellpxx * 4;
if(auxvec[offset]){
size_t off = ncplane_pile(s->n)->cellpxy * ncplane_pile(s->n)->cellpxx * 4;
if(auxvec[off]){
return 1;
}
return 0;
@ -354,8 +354,8 @@ kitty_anim_auxvec(int dimy, int dimx, int posy, int posx,
return a;
}
uint8_t* kitty_trans_auxvec(const tinfo* ti){
const size_t slen = ti->cellpixy * ti->cellpixx;
uint8_t* kitty_trans_auxvec(const ncpile* p){
const size_t slen = p->cellpxy * p->cellpxx;
uint8_t* a = malloc(slen);
if(a){
memset(a, 0, slen);
@ -367,13 +367,14 @@ uint8_t* kitty_trans_auxvec(const tinfo* ti){
// by the wipe proper, and when blitting a new frame with annihilations.
static int
kitty_blit_wipe_selfref(sprixel* s, fbuf* f, int ycell, int xcell){
const int cellpxx = ncplane_pile(s->n)->cellpxx;
const int cellpxy = ncplane_pile(s->n)->cellpxy;
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;",
xcell * s->cellpxx, ycell * s->cellpxy,
s->cellpxx, s->cellpxy, s->id) < 0){
xcell * cellpxx, ycell * cellpxy, cellpxx, cellpxy, s->id) < 0){
return -1;
}
// FIXME ought be smaller around the fringes!
int totalp = s->cellpxy * s->cellpxx;
int totalp = cellpxy * cellpxx;
// FIXME preserve so long as cellpixel geom stays constant?
#define TRINULLALPHA "AAAAAAAAAAAAAAAA"
for(int p = 0 ; p + 3 <= totalp ; p += 3){
@ -416,7 +417,7 @@ int kitty_wipe_animation(sprixel* s, int ycell, int xcell){
}
int tamidx = ycell * s->dimx + xcell;
uint8_t* auxvec = s->n->tam[tamidx].auxvector;
auxvec[s->cellpxx * s->cellpxy * 4] = 0;
auxvec[ncplane_pile(s->n)->cellpxx * ncplane_pile(s->n)->cellpxy * 4] = 0;
s->invalidated = SPRIXEL_INVALIDATED;
return 1;
}
@ -444,14 +445,14 @@ sprixel* kitty_recycle(ncplane* n){
int dimy = hides->dimy;
int dimx = hides->dimx;
sprixel_hide(hides);
return sprixel_alloc(&ncplane_notcurses_const(n)->tcache, n, dimy, dimx);
return sprixel_alloc(n, dimy, dimx);
}
// for pre-animation kitty (NCPIXEL_KITTY_STATIC), we need a byte per pixel,
// in which we stash the alpha.
static inline uint8_t*
kitty_auxiliary_vector(const sprixel* s){
int pixels = s->cellpxy * s->cellpxx;
int pixels = ncplane_pile(s->n)->cellpxy * ncplane_pile(s->n)->cellpxx;
uint8_t* ret = malloc(sizeof(*ret) * pixels);
if(ret){
memset(ret, 0, sizeof(*ret) * pixels);
@ -466,8 +467,8 @@ int kitty_wipe(sprixel* s, int ycell, int xcell){
return -1;
}
const int totalpixels = s->pixy * s->pixx;
const int xpixels = s->cellpxx;
const int ypixels = s->cellpxy;
const int xpixels = ncplane_pile(s->n)->cellpxx;
const int ypixels = ncplane_pile(s->n)->cellpxy;
// 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;
@ -515,7 +516,7 @@ int kitty_wipe(sprixel* s, int ycell, int xcell){
//fprintf(stderr, "POSTCHOMP: [%.16s]\n", c + tripbytes);
assert(chomped >= 0);
auxvecidx += chomped;
assert(auxvecidx <= s->cellpxy * s->cellpxx);
assert(auxvecidx <= ypixels * xpixels);
thisrow -= chomped;
//fprintf(stderr, "POSTCHIMP CHOMP: %d pixoffset: %d next: %d tripbytes: %d tripskip: %d thisrow: %d\n", chomped, pixoffset, nextpixel, tripbytes, tripskip, thisrow);
if(thisrow == 0){
@ -746,8 +747,10 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols,
unsigned bufidx = 0; // an index; the actual offset is bufidx * 4
bool translucent = bargs->flags & NCVISUAL_OPTION_BLEND;
sprixel* s = bargs->u.pixel.spx;
const int cdimy = s->cellpxy;
const int cdimx = s->cellpxx;
const int cdimy = bargs->u.pixel.cellpxy;
const int cdimx = bargs->u.pixel.cellpxx;
assert(0 != cdimy);
assert(0 != cdimx);
const uint32_t transcolor = bargs->transcolor;
int total = leny * lenx; // total number of pixels (4 * total == bytecount)
// number of 4KiB chunks we'll need
@ -847,7 +850,7 @@ write_kitty_data(fbuf* f, int linesize, int leny, int lenx, int cols,
}else if(level == NCPIXEL_KITTY_SELFREF){
selfref_annihilated = true;
}else{
((uint8_t*)tam[tyx].auxvector)[s->cellpxx * s->cellpxy * 4] = 1;
((uint8_t*)tam[tyx].auxvector)[cdimx * cdimy * 4] = 1;
wipe[e] = 1;
}
if(rgba_trans_p(source[e], transcolor)){
@ -938,14 +941,16 @@ int kitty_rebuild_selfref(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
return -1;
}
fbuf* f = &s->glyph;
const int ystart = ycell * s->cellpxy;
const int xstart = xcell * s->cellpxx;
const int xlen = xstart + s->cellpxx > s->pixx ? s->pixx - xstart : s->cellpxx;
const int ylen = ystart + s->cellpxy > s->pixy ? s->pixy - ystart : s->cellpxy;
const int cellpxy = ncplane_pile(s->n)->cellpxy;
const int cellpxx = ncplane_pile(s->n)->cellpxx;
const int ystart = ycell * cellpxy;
const int xstart = xcell * cellpxx;
const int xlen = xstart + cellpxx > s->pixx ? s->pixx - xstart : cellpxx;
const int ylen = ystart + cellpxy > s->pixy ? s->pixy - ystart : cellpxy;
logdebug("rematerializing %u at %d/%d (%dx%d)\n", s->id, ycell, xcell, ylen, xlen);
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\\",
xcell * s->cellpxx, ycell * s->cellpxy,
xcell * s->cellpxx, ycell * s->cellpxy,
xcell * cellpxx, ycell * cellpxy,
xcell * cellpxx, ycell * cellpxy,
xlen, ylen, s->id);
const int tyx = xcell + ycell * s->dimx;
memcpy(&s->n->tam[tyx].state, auxvec, sizeof(s->n->tam[tyx].state));
@ -959,10 +964,12 @@ int kitty_rebuild_animation(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
return -1;
}
fbuf* f = &s->glyph;
const int ystart = ycell * s->cellpxy;
const int xstart = xcell * s->cellpxx;
const int xlen = xstart + s->cellpxx > s->pixx ? s->pixx - xstart : s->cellpxx;
const int ylen = ystart + s->cellpxy > s->pixy ? s->pixy - ystart : s->cellpxy;
const int cellpxy = ncplane_pile(s->n)->cellpxy;
const int cellpxx = ncplane_pile(s->n)->cellpxx;
const int ystart = ycell * cellpxy;
const int xstart = xcell * cellpxx;
const int xlen = xstart + cellpxx > s->pixx ? s->pixx - xstart : cellpxx;
const int ylen = ystart + cellpxy > s->pixy ? s->pixy - ystart : cellpxy;
const int linesize = xlen * 4;
const int total = xlen * ylen;
const int tyx = xcell + ycell * s->dimx;
@ -973,13 +980,13 @@ int kitty_rebuild_animation(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
int targetout = 0; // number of pixels expected out after this chunk
//fprintf(stderr, "total: %d chunks = %d, s=%d,v=%d\n", total, chunks, lenx, leny);
// FIXME this ought be factored out and shared with write_kitty_data()
logdebug("placing %d/%d at %d/%d\n", ylen, xlen, ycell * s->cellpxy, xcell * s->cellpxx);
logdebug("placing %d/%d at %d/%d\n", ylen, xlen, ycell * cellpxy, xcell * cellpxx);
while(chunks--){
if(totalout == 0){
const int c = kitty_anim_auxvec_blitsource_p(s, auxvec) ? 2 : 1;
const int r = kitty_anim_auxvec_blitsource_p(s, auxvec) ? 1 : 2;
if(fbuf_printf(f, "\e_Ga=f,x=%d,y=%d,s=%d,v=%d,i=%d,X=1,c=%d,r=%d,%s;",
xcell * s->cellpxx, ycell * s->cellpxy, xlen, ylen,
xcell * cellpxx, ycell * cellpxy, xlen, ylen,
s->id, c, r, chunks ? "m=1" : "q=2") < 0){
return -1;
}
@ -1023,13 +1030,13 @@ int kitty_rebuild_animation(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
//fprintf(stderr, "Tyx: %d y: %d (%d) * %d x: %d (%d) state %d %p\n", tyx, y, y / cdimy, cols, x, x / cdimx, tam[tyx].state, tam[tyx].auxvector);
wipe[e] = 0;
if(rgba_trans_p(source[e], 0)){
if(x % s->cellpxx == 0 && y % s->cellpxy == 0){
if(x % cellpxx == 0 && y % cellpxy == 0){
s->n->tam[tyx].state = SPRIXCELL_TRANSPARENT;
}else if(s->n->tam[tyx].state == SPRIXCELL_OPAQUE_KITTY){
s->n->tam[tyx].state = SPRIXCELL_MIXED_KITTY;
}
}else{
if(x % s->cellpxx == 0 && y % s->cellpxy == 0){
if(x % cellpxx == 0 && y % cellpxy == 0){
s->n->tam[tyx].state = SPRIXCELL_OPAQUE_KITTY;
}else if(s->n->tam[tyx].state == SPRIXCELL_TRANSPARENT){
s->n->tam[tyx].state = SPRIXCELL_MIXED_KITTY;

View File

@ -1,11 +1,11 @@
#include "linux.h"
#include "internal.h"
// auxvecs for framebuffer are 1B each for s->cellpxx * s->cellpxy elements,
// auxvecs for framebuffer are 1B each for cellpxx * cellpxy elements,
// and store the original alpha value.
static inline uint8_t*
fbcon_auxiliary_vector(const sprixel* s){
int pixels = s->cellpxy * s->cellpxx;
int pixels = ncplane_pile(s->n)->cellpxy * ncplane_pile(s->n)->cellpxx;
uint8_t* ret = malloc(sizeof(*ret) * pixels);
if(ret){
memset(ret, 0, sizeof(*ret) * pixels);
@ -18,19 +18,21 @@ int fbcon_wipe(sprixel* s, int ycell, int xcell){
if(auxvec == NULL){
return -1;
}
const int cellpxy = ncplane_pile(s->n)->cellpxy;
const int cellpxx = ncplane_pile(s->n)->cellpxx;
char* glyph = s->glyph.buf;
for(int y = 0 ; y < s->cellpxy ; ++y){
if(ycell * s->cellpxy + y >= s->pixy){
for(int y = 0 ; y < cellpxy ; ++y){
if(ycell * cellpxy + y >= s->pixy){
break;
}
// number of pixels total above our pixel row
const size_t yoff = s->pixx * (ycell * s->cellpxy + y);
for(int x = 0 ; x < s->cellpxx ; ++x){
if(xcell * s->cellpxx + x >= s->pixx){
const size_t yoff = s->pixx * (ycell * cellpxy + y);
for(int x = 0 ; x < cellpxx ; ++x){
if(xcell * cellpxx + x >= s->pixx){
break;
}
size_t offset = (yoff + xcell * s->cellpxx + x) * 4;
const int vyx = (y % s->cellpxy) * s->cellpxx + x;
size_t offset = (yoff + xcell * cellpxx + x) * 4;
const int vyx = (y % cellpxy) * cellpxx + x;
auxvec[vyx] = glyph[offset + 3];
glyph[offset + 3] = 0;
}
@ -43,8 +45,8 @@ int fbcon_blit(struct ncplane* n, int linesize, const void* data,
int leny, int lenx, const struct blitterargs* bargs){
uint32_t transcolor = bargs->transcolor;
sprixel* s = bargs->u.pixel.spx;
int cdimx = s->cellpxx;
int cdimy = s->cellpxy;
int cdimx = bargs->u.pixel.cellpxx;
int cdimy = bargs->u.pixel.cellpxy;
// FIXME this will need be a copy of the tinfo's fbuf map
size_t flen = leny * lenx * 4;
if(fbuf_reserve(&s->glyph, flen)){
@ -124,18 +126,20 @@ int fbcon_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
if(auxvec == NULL){
return -1;
}
const int cellpxy = ncplane_pile(s->n)->cellpxy;
const int cellpxx = ncplane_pile(s->n)->cellpxx;
sprixcell_e state = SPRIXCELL_TRANSPARENT;
for(int y = 0 ; y < s->cellpxy ; ++y){
if(ycell * s->cellpxy + y >= s->pixy){
for(int y = 0 ; y < cellpxy ; ++y){
if(ycell * cellpxy + y >= s->pixy){
break;
}
const size_t yoff = s->pixx * (ycell * s->cellpxy + y);
for(int x = 0 ; x < s->cellpxx ; ++x){
if(xcell * s->cellpxx + x >= s->pixx){
const size_t yoff = s->pixx * (ycell * cellpxy + y);
for(int x = 0 ; x < cellpxx ; ++x){
if(xcell * cellpxx + x >= s->pixx){
break;
}
size_t offset = (yoff + xcell * s->cellpxx + x) * 4;
const int vyx = (y % s->cellpxy) * s->cellpxx + x;
size_t offset = (yoff + xcell * cellpxx + x) * 4;
const int vyx = (y % cellpxy) * cellpxx + x;
if(x == 0 && y == 0){
if(auxvec[vyx] == 0){
state = SPRIXCELL_TRANSPARENT;
@ -160,9 +164,11 @@ int fbcon_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
int fbcon_draw(const tinfo* ti, sprixel* s, int y, int x){
logdebug("id %" PRIu32 " dest %d/%d\n", s->id, y, x);
int wrote = 0;
for(unsigned l = 0 ; l < (unsigned)s->pixy && l + y * ti->cellpixy < ti->pixy ; ++l){
const int cellpxy = ncplane_pile(s->n)->cellpxy;
const int cellpxx = ncplane_pile(s->n)->cellpxx;
for(unsigned l = 0 ; l < (unsigned)s->pixy && l + y * cellpxy < ti->pixy ; ++l){
// FIXME pixel size isn't necessarily 4B, line isn't necessarily psize*pixx
size_t offset = ((l + y * ti->cellpixy) * ti->pixx + x * ti->cellpixx) * 4;
size_t offset = ((l + y * cellpxy) * ti->pixx + x * cellpxx) * 4;
uint8_t* tl = ti->linux_fbuffer + offset;
const char* src = (char*)s->glyph.buf + (l * s->pixx * 4);
for(unsigned c = 0 ; c < (unsigned)s->pixx && c < ti->pixx ; ++c){
@ -186,13 +192,15 @@ int fbcon_draw(const tinfo* ti, sprixel* s, int y, int x){
// they're written in order. if we're scrolling all rows, we're clearing the
// entire space; we always clear something (we might not always move anything).
void fbcon_scroll(const struct ncpile* p, tinfo* ti, int rows){
if(ti->cellpixy < 1){
const int cellpxy = p->cellpxy;
const int cellpxx = p->cellpxx;
if(cellpxy < 1){
return;
}
logdebug("scrolling %d\n", rows);
const int rowbytes = ti->cellpixx * p->dimx * 4;
const int totalrows = ti->cellpixy * p->dimy;
int srows = rows * ti->cellpixy; // number of pixel rows being scrolled
const int rowbytes = cellpxx * p->dimx * 4;
const int totalrows = cellpxy * p->dimy;
int srows = rows * cellpxy; // number of pixel rows being scrolled
if(srows > totalrows){
srows = totalrows;
}

View File

@ -261,8 +261,8 @@ int update_term_dimensions(unsigned* rows, unsigned* cols, tinfo* tcache,
if(cols){
*cols = tcache->default_cols;
}
tcache->cellpixy = 0;
tcache->cellpixx = 0;
tcache->cellpxy = 0;
tcache->cellpxx = 0;
return 0;
}
unsigned rowsafe, colsafe;
@ -296,18 +296,18 @@ int update_term_dimensions(unsigned* rows, unsigned* cols, tinfo* tcache,
tcache->pixx = ws.ws_xpixel;
}
// update even if we didn't get values just now, because we need set
// cellpix{y,x} up from an initial CSI14n, which set only pix{y,x}.
// cellpx{y,x} up from an initial CSI14n, which set only pix{y,x}.
unsigned cpixy = ws.ws_row ? tcache->pixy / ws.ws_row : 0;
unsigned cpixx = ws.ws_col ? tcache->pixx / ws.ws_col : 0;
if(tcache->cellpixy != cpixy){
tcache->cellpixy = cpixy;
if(tcache->cellpxy != cpixy){
tcache->cellpxy = cpixy;
*pgeo_changed = 1;
}
if(tcache->cellpixx != cpixx){
tcache->cellpixx = cpixx;
if(tcache->cellpxx != cpixx){
tcache->cellpxx = cpixx;
*pgeo_changed = 1;
}
if(tcache->cellpixy == 0 || tcache->cellpixx == 0){
if(tcache->cellpxy == 0 || tcache->cellpxx == 0){
tcache->pixel_draw = NULL; // disable support
}
}
@ -363,7 +363,7 @@ int update_term_dimensions(unsigned* rows, unsigned* cols, tinfo* tcache,
if(margin_b){
++sixelrows;
}
tcache->sixel_maxy = sixelrows * tcache->cellpixy;
tcache->sixel_maxy = sixelrows * tcache->cellpxy;
if(tcache->sixel_maxy > tcache->sixel_maxy_pristine){
tcache->sixel_maxy = tcache->sixel_maxy_pristine;
}
@ -451,8 +451,10 @@ make_ncpile(notcurses* nc, ncplane* n){
}
n->above = NULL;
n->below = NULL;
ret->dimy = 0;
ret->dimx = 0;
ret->dimy = nc->tcache.dimy;
ret->dimx = nc->tcache.dimx;
ret->cellpxy = nc->tcache.cellpxy;
ret->cellpxx = nc->tcache.cellpxx;
ret->crender = NULL;
ret->crenderlen = 0;
ret->sprixelcache = NULL;
@ -3102,28 +3104,29 @@ void ncplane_pixel_geom(const ncplane* n,
unsigned* RESTRICT pxy, unsigned* RESTRICT pxx,
unsigned* RESTRICT celldimy, unsigned* RESTRICT celldimx,
unsigned* RESTRICT maxbmapy, unsigned* RESTRICT maxbmapx){
notcurses* nc = ncplane_notcurses(n);
const notcurses* nc = ncplane_notcurses_const(n);
const ncpile* p = ncplane_pile_const(n);
if(celldimy){
*celldimy = nc->tcache.cellpixy;
*celldimy = p->cellpxy;
}
if(celldimx){
*celldimx = nc->tcache.cellpixx;
*celldimx = p->cellpxx;
}
if(pxy){
*pxy = nc->tcache.cellpixy * ncplane_dim_y(n);
*pxy = p->cellpxy * ncplane_dim_y(n);
}
if(pxx){
*pxx = nc->tcache.cellpixx * ncplane_dim_x(n);
*pxx = p->cellpxx * ncplane_dim_x(n);
}
if(notcurses_check_pixel_support(nc) > 0){
if(maxbmapy){
*maxbmapy = nc->tcache.cellpixy * ncplane_dim_y(n);
*maxbmapy = p->cellpxy * ncplane_dim_y(n);
if(*maxbmapy > nc->tcache.sixel_maxy && nc->tcache.sixel_maxy){
*maxbmapy = nc->tcache.sixel_maxy;
}
}
if(maxbmapx){
*maxbmapx = nc->tcache.cellpixx * ncplane_dim_x(n);
*maxbmapx = p->cellpxx * ncplane_dim_x(n);
if(*maxbmapx > nc->tcache.sixel_maxx && nc->tcache.sixel_maxx){
*maxbmapx = nc->tcache.sixel_maxx;
}

View File

@ -59,11 +59,11 @@ create_pixelp(ncplot *p, ncplane* n){
// we have some color gradient across the life of the plot (almost; it gets
// recalculated if the cell-pixel geometry changes and we're using
// NCBLIT_PIXEL). if we're using cell blitting, we only get one channel pair
// per row, no matter what height we have. with pixels, we get cellpixy * rows.
// per row, no matter what height we have. with pixels, we get cellpxy * rows.
static int
calculate_gradient_vector(ncplot* p, unsigned pixelp){
const int dimy = ncplane_dim_y(p->ncp);
const unsigned states = dimy * (pixelp ? ncplane_notcurses(p->ncp)->tcache.cellpixy : 1);
const unsigned states = dimy * (pixelp ? ncplane_pile(p->ncp)->cellpxy : 1);
if(states == p->chancount){ // no need to recalculate
return 0;
}
@ -93,13 +93,13 @@ int redraw_pixelplot_##T(nc##X##plot* ncp){ \
if(calculate_gradient_vector(&ncp->plot, 1)){ \
return -1; \
} \
const int scale = ncplane_notcurses_const(ncp->plot.ncp)->tcache.cellpixx; \
const int scale = ncplane_pile_const(ncp->plot.ncp)->cellpxx; \
ncplane_erase(ncp->plot.ncp); \
unsigned dimy, dimx; \
ncplane_dim_yx(ncp->plot.ncp, &dimy, &dimx); \
const unsigned scaleddim = dimx * scale; \
/* each transition is worth this much change in value */ \
const size_t states = ncplane_notcurses_const(ncp->plot.ncp)->tcache.cellpixy; \
const size_t states = ncplane_pile_const(ncp->plot.ncp)->cellpxy; \
/* FIXME can we not rid ourselves of this meddlesome double? either way, the \
interval is one row's range (for linear plots), or the base \
(base^slots == maxy-miny) of the range (for exponential plots). */ \
@ -480,8 +480,8 @@ create_##T(nc##X##plot* ncpp, ncplane* n, const ncplot_options* opts, const T mi
ncpp->plot.rangex = opts->rangex; \
/* if we're sizing the plot based off the plane dimensions, scale it by the \
plot geometry's width for all calculations */ \
const unsigned scaleddim = dimx * (bset->geom == NCBLIT_PIXEL ? ncplane_notcurses(n)->tcache.cellpixx : bset->width); \
const unsigned scaledprefixlen = NCPREFIXCOLUMNS * (bset->geom == NCBLIT_PIXEL ? ncplane_notcurses(n)->tcache.cellpixx : bset->width); \
const unsigned scaleddim = dimx * (bset->geom == NCBLIT_PIXEL ? ncplane_pile_const(n)->cellpxx : bset->width); \
const unsigned scaledprefixlen = NCPREFIXCOLUMNS * (bset->geom == NCBLIT_PIXEL ? ncplane_pile_const(n)->cellpxx : bset->width); \
if((ncpp->plot.slotcount = ncpp->plot.rangex) == 0){ \
ncpp->plot.slotcount = scaleddim; \
} \

View File

@ -27,7 +27,7 @@ sixelcount(int dimy, int dimx){
// bytes, saving 7/8 of the space FIXME).
static inline uint8_t*
sixel_auxiliary_vector(const sprixel* s){
int pixels = s->cellpxy * s->cellpxx;
int pixels = ncplane_pile(s->n)->cellpxy * ncplane_pile(s->n)->cellpxx;
uint8_t* ret = malloc(sizeof(*ret) * pixels * 2);
if(ret){
memset(ret, 0, sizeof(*ret) * pixels);
@ -229,15 +229,17 @@ int sixel_wipe(sprixel* s, int ycell, int xcell){
if(auxvec == NULL){
return -1;
}
memset(auxvec + s->cellpxx * s->cellpxy, 0xff, s->cellpxx * s->cellpxy);
const int cellpxy = ncplane_pile(s->n)->cellpxy;
const int cellpxx = ncplane_pile(s->n)->cellpxx;
memset(auxvec + cellpxx * cellpxy, 0xff, cellpxx * cellpxy);
sixelmap* smap = s->smap;
const int startx = xcell * s->cellpxx;
const int starty = ycell * s->cellpxy;
int endx = ((xcell + 1) * s->cellpxx) - 1;
const int startx = xcell * cellpxx;
const int starty = ycell * cellpxy;
int endx = ((xcell + 1) * cellpxx) - 1;
if(endx >= s->pixx){
endx = s->pixx - 1;
}
int endy = ((ycell + 1) * s->cellpxy) - 1;
int endy = ((ycell + 1) * cellpxy) - 1;
if(endy >= s->pixy){
endy = s->pixy - 1;
}
@ -248,7 +250,7 @@ int sixel_wipe(sprixel* s, int ycell, int xcell){
int w = 0;
for(int c = 0 ; c < smap->colors ; ++c){
w |= wipe_color(smap, c, startband, endband, startx, endx, starty, endy,
s->pixx, s->cellpxy, s->cellpxx, auxvec);
s->pixx, cellpxy, cellpxx, auxvec);
}
if(w){
s->wipes_outstanding = true;
@ -429,8 +431,8 @@ extract_color_table(const uint32_t* data, int linesize, int cols,
const int begx = bargs->begx;
const int begy = bargs->begy;
sprixel* s = bargs->u.pixel.spx;
const int cdimy = s->cellpxy;
const int cdimx = s->cellpxx;
const int cdimy = ncplane_pile(s->n)->cellpxy;
const int cdimx = ncplane_pile(s->n)->cellpxx;
unsigned char mask = 0xc0;
int pos = 0; // pixel position
unsigned char* rmatrix = bargs->u.pixel.spx->needs_refresh;
@ -876,11 +878,14 @@ sixel_reblit(sprixel* s){
// scaled geometry in pixels. We calculate output geometry herein, and supply
// transparent filler input for any missing rows.
static inline int
sixel_blit_inner(int leny, int lenx, sixeltable* stab, sprixel* s, tament* tam){
sixel_blit_inner(int leny, int lenx, sixeltable* stab, const blitterargs* bargs, tament* tam){
fbuf f;
if(fbuf_init(&f)){
return -1;
}
sprixel* s = bargs->u.pixel.spx;
const int cellpxy = bargs->u.pixel.cellpxy;
const int cellpxx = bargs->u.pixel.cellpxx;
int parse_start = 0;
int outy = leny;
if(leny % 6){
@ -892,7 +897,7 @@ sixel_blit_inner(int leny, int lenx, sixeltable* stab, sprixel* s, tament* tam){
fbuf_free(&f);
return -1;
}
scrub_tam_boundaries(tam, outy, lenx, s->cellpxy, s->cellpxx);
scrub_tam_boundaries(tam, outy, lenx, cellpxy, cellpxx);
// take ownership of buf on success
if(plane_blit_sixel(s, &f, outy, lenx, parse_start, tam, SPRIXEL_INVALIDATED) < 0){
fbuf_free(&f);
@ -945,7 +950,7 @@ int sixel_blit(ncplane* n, int linesize, const void* data, int leny, int lenx,
}
refine_color_table(data, linesize, bargs->begy, bargs->begx, leny, lenx, &stable);
// takes ownership of sixelmap on success
int r = sixel_blit_inner(leny, lenx, &stable, bargs->u.pixel.spx, n->tam);
int r = sixel_blit_inner(leny, lenx, &stable, bargs, n->tam);
if(r < 0){
sixelmap_free(stable.map);
}
@ -1063,13 +1068,15 @@ int sixel_init_inverted(int fd){
int sixel_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
s->wipes_outstanding = true;
sixelmap* smap = s->smap;
const int startx = xcell * s->cellpxx;
const int starty = ycell * s->cellpxy;
int endx = ((xcell + 1) * s->cellpxx) - 1;
const int cellpxx = ncplane_pile(s->n)->cellpxx;
const int cellpxy = ncplane_pile(s->n)->cellpxy;
const int startx = xcell * cellpxx;
const int starty = ycell * cellpxy;
int endx = ((xcell + 1) * cellpxx) - 1;
if(endx > s->pixx){
endx = s->pixx;
}
int endy = ((ycell + 1) * s->cellpxy) - 1;
int endy = ((ycell + 1) * cellpxy) - 1;
if(endy > s->pixy){
endy = s->pixy;
}
@ -1077,8 +1084,8 @@ int sixel_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
//fprintf(stderr, "%d/%d start: %d/%d end: %d/%d bands: %d-%d\n", ycell, xcell, starty, startx, endy, endx, starty / 6, endy / 6);
for(int x = startx ; x <= endx ; ++x){
for(int y = starty ; y <= endy ; ++y){
int auxvecidx = (y - starty) * s->cellpxx + (x - startx);
int trans = auxvec[s->cellpxx * s->cellpxy + auxvecidx];
int auxvecidx = (y - starty) * cellpxx + (x - startx);
int trans = auxvec[cellpxx * cellpxy + auxvecidx];
if(!trans){
int color = auxvec[auxvecidx];
int didx = ctable_to_dtable(smap->table + color * CENTSIZE);
@ -1094,7 +1101,7 @@ int sixel_rebuild(sprixel* s, int ycell, int xcell, uint8_t* auxvec){
}
}
sprixcell_e newstate;
if(transparent == s->cellpxx * s->cellpxy){
if(transparent == cellpxx * cellpxy){
newstate = SPRIXCELL_TRANSPARENT;
}else if(transparent){
newstate = SPRIXCELL_MIXED_SIXEL;
@ -1111,8 +1118,8 @@ int sixel_shutdown(fbuf* f){
return 0;
}
uint8_t* sixel_trans_auxvec(const tinfo* ti){
const size_t slen = 2 * ti->cellpixy * ti->cellpixx;
uint8_t* sixel_trans_auxvec(const ncpile* p){
const size_t slen = 2 * p->cellpxy * p->cellpxx;
uint8_t* a = malloc(slen);
if(a){
memset(a, 0, slen);

View File

@ -56,7 +56,7 @@ sprixel* sprixel_recycle(ncplane* n){
int dimy = hides->dimy;
int dimx = hides->dimx;
sprixel_hide(hides);
return sprixel_alloc(&nc->tcache, n, dimy, dimx);
return sprixel_alloc(n, dimy, dimx);
}
sixelmap_free(n->sprite->smap);
n->sprite->smap = NULL;
@ -114,7 +114,7 @@ void sprixel_invalidate(sprixel* s, int y, int x){
}
}
sprixel* sprixel_alloc(const tinfo* ti, ncplane* n, int dimy, int dimx){
sprixel* sprixel_alloc(ncplane* n, int dimy, int dimx){
sprixel* ret = malloc(sizeof(sprixel));
if(ret == NULL){
return NULL;
@ -134,8 +134,6 @@ sprixel* sprixel_alloc(const tinfo* ti, ncplane* n, int dimy, int dimx){
sprixelid_nonce = 1;
}
//fprintf(stderr, "LOOKING AT %p (p->n = %p)\n", ret, ret->n);
ret->cellpxy = ti->cellpixy;
ret->cellpxx = ti->cellpixx;
if(ncplane_pile(ret->n)){ // rendered mode
ncpile* np = ncplane_pile(ret->n);
if( (ret->next = np->sprixelcache) ){
@ -156,6 +154,7 @@ sprixel* sprixel_alloc(const tinfo* ti, ncplane* n, int dimy, int dimx){
int sprixel_load(sprixel* spx, fbuf* f, unsigned pixy, unsigned pixx,
int parse_start, sprixel_e state){
assert(spx->n);
/*
if(spx->cellpxy > 0){ // don't explode on ncdirect case
if((pixy + spx->cellpxy - 1) / spx->cellpxy > spx->dimy){
logerror("bad pixy %d (cellpxy %d dimy %d)\n", pixy, spx->cellpxy, spx->dimy);
@ -166,6 +165,7 @@ int sprixel_load(sprixel* spx, fbuf* f, unsigned pixy, unsigned pixx,
return -1;
}
}
*/
if(&spx->glyph != f){
fbuf_free(&spx->glyph);
memcpy(&spx->glyph, f, sizeof(*f));
@ -187,7 +187,7 @@ int sprite_wipe(const notcurses* nc, sprixel* s, int ycell, int xcell){
// be entirely 0s coming from pixel_trans_auxvec().
if(s->n->tam[idx].auxvector == NULL){
if(nc->tcache.pixel_trans_auxvec){
s->n->tam[idx].auxvector = nc->tcache.pixel_trans_auxvec(&nc->tcache);
s->n->tam[idx].auxvector = nc->tcache.pixel_trans_auxvec(ncplane_pile(s->n));
if(s->n->tam[idx].auxvector == NULL){
return -1;
}

View File

@ -143,7 +143,6 @@ typedef struct sprixel {
struct sprixel* prev;
unsigned dimy, dimx; // cell geometry
int pixy, pixx; // pixel geometry (might be smaller than cell geo)
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 movedfromy; // for SPRIXEL_MOVED, the starting absolute position,
@ -196,8 +195,8 @@ int kitty_remove(int id, fbuf* f);
int kitty_clear_all(fbuf* f);
int sixel_init(int fd);
int sixel_init_inverted(int fd);
uint8_t* sixel_trans_auxvec(const struct tinfo* ti);
uint8_t* kitty_trans_auxvec(const struct tinfo* ti);
uint8_t* sixel_trans_auxvec(const struct ncpile* p);
uint8_t* kitty_trans_auxvec(const struct ncpile* p);
int kitty_commit(fbuf* f, sprixel* s, unsigned noscroll);
int sixel_blit(struct ncplane* nc, int linesize, const void* data,
int leny, int lenx, const struct blitterargs* bargs);

View File

@ -1078,8 +1078,8 @@ int interrogate_terminfo(tinfo* ti, FILE* out, unsigned utf8,
ti->pixx = iresp->pixx;
}
if(ti->default_rows && ti->default_cols){
ti->cellpixy = ti->pixy / ti->default_rows;
ti->cellpixx = ti->pixx / ti->default_cols;
ti->cellpxy = ti->pixy / ti->default_rows;
ti->cellpxx = ti->pixx / ti->default_cols;
}
if(iresp->got_bg){
// reset the 0xfe000000 we loaded during initialization. if we're

View File

@ -110,8 +110,8 @@ typedef struct tinfo {
unsigned pixx; // total pixel geometry, width
// we use the cell's size in pixels for pixel blitting. this information can
// be acquired on all terminals with pixel support.
unsigned cellpixy; // cell pixel height, might be 0
unsigned cellpixx; // cell pixel width, might be 0
unsigned cellpxy; // cell pixel height, might be 0
unsigned cellpxx; // cell pixel width, might be 0
unsigned dimy, dimx; // most recent cell geometry
unsigned supported_styles; // bitmask over NCSTYLE_* driven via sgr/ncv
@ -149,7 +149,7 @@ typedef struct tinfo {
int (*pixel_commit)(fbuf* f, struct sprixel* s, unsigned noscroll);
// scroll all graphics up. only used with fbcon.
void (*pixel_scroll)(const struct ncpile* p, struct tinfo*, int rows);
uint8_t* (*pixel_trans_auxvec)(const struct tinfo* ti); // create tranparent auxvec
uint8_t* (*pixel_trans_auxvec)(const struct ncpile* p); // create tranparent auxvec
// sprixel parameters. there are several different sprixel protocols, of
// which we support sixel and kitty. the kitty protocol is used based
// on TERM heuristics. otherwise, we attempt to detect sixel support, and

View File

@ -141,22 +141,27 @@ ncvisual_origin(const struct ncvisual_options* vopts, unsigned* restrict begy,
// included within |disppixx| nor |disppixy|, but count towards |outx| and
// |outy|. these last two are furthermore clamped to sixel maxima, and |outy|
// accounts for sixels being a multiple of six pixels tall.
//
// cellpxy/cellpxx and dimy/dimx ought describe the cell-pixel and cell
// geometry of the target pile or, in Direct Mode, the tcache.
static void
shape_sprixel_plane(const tinfo* ti, ncplane* parent, const ncvisual* ncv,
shape_sprixel_plane(const tinfo* ti, unsigned cellpxy, unsigned cellpxx,
unsigned dimy, unsigned dimx,
ncplane* parent, const ncvisual* ncv,
ncscale_e scaling, unsigned* disppixy, unsigned* disppixx,
uint64_t flags, unsigned* outy, unsigned* outx,
int* placey, int* placex, int pxoffy, int pxoffx){
if(scaling != NCSCALE_NONE && scaling != NCSCALE_NONE_HIRES){
// disppixy/disppix are treated initially as cells
if(parent == NULL){
*disppixy = ti->dimy;
*disppixx = ti->dimx;
*disppixy = dimy;
*disppixx = dimx;
}else{
ncplane_dim_yx(parent, disppixy, disppixx);
}
// FIXME why do we clamp only vertical, not horizontal, here?
if(*placey + *disppixy >= ti->dimy){
*disppixy = ti->dimy - *placey;
if(*placey + *disppixy >= dimy){
*disppixy = dimy - *placey;
}
if(!(flags & NCVISUAL_OPTION_VERALIGNED)){
*disppixy -= *placey;
@ -164,8 +169,8 @@ shape_sprixel_plane(const tinfo* ti, ncplane* parent, const ncvisual* ncv,
if(!(flags & NCVISUAL_OPTION_HORALIGNED)){
*disppixx -= *placex;
}
*disppixx *= ti->cellpixx;
*disppixy *= ti->cellpixy;
*disppixx *= cellpxx;
*disppixy *= cellpxy;
*disppixx += pxoffx;
*disppixy += pxoffy;
*outx = *disppixx;
@ -187,10 +192,16 @@ shape_sprixel_plane(const tinfo* ti, ncplane* parent, const ncvisual* ncv,
*disppixx -= pxoffx;
}
// in addition to the geom fields, we pass out:
// in addition to the fields in 'geom', we pass out:
// * 'disppixx'/'disppixy': scaled output size in pixels
// * 'outy'/'outx': true output size in pixels (ie post-sixel clamping)
// * 'placey'/'placex': offset at which to draw
// * 'bset': blitter that will be used
// we take in:
// * 'p': target pile (for cell-pixel and cell geometry)
// * 'ti': used if p is NULL (direct mode only!)
// * 'n': input ncvisual
// * 'vopts': requested ncvisual_options
int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
const struct ncvisual_options* vopts, ncvgeom* geom,
const struct blitset** bset,
@ -230,7 +241,7 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
geom->pixy = n->pixy;
geom->pixx = n->pixx;
}
// when nc is NULL, we only report properties intrinsic to the ncvisual,
// when ti is NULL, we only report properties intrinsic to the ncvisual,
// i.e. only its original pixel geometry.
if(ti == NULL){
return 0;
@ -241,8 +252,9 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
logerror("couldn't get a blitter for %d\n", vopts ? vopts->blitter : NCBLIT_DEFAULT);
return -1;
}
geom->cdimy = ti->cellpixy;
geom->cdimx = ti->cellpixx;
const ncpile* p = vopts->n ? ncplane_pile_const(vopts->n) : NULL;
geom->cdimy = p ? p->cellpxy : ti->cellpxy;
geom->cdimx = p ? p->cellpxx : ti->cellpxx;
if((geom->blitter = (*bset)->geom) == NCBLIT_PIXEL){
geom->maxpixely = ti->sixel_maxy;
geom->maxpixelx = ti->sixel_maxx;
@ -301,41 +313,44 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
logerror("non-origin x placement %d for sprixel\n", vopts->x);
return -1;
}
if(vopts->pxoffy >= ti->cellpixy){
logerror("pixel y-offset %d too tall for cell %d\n", vopts->pxoffy, ti->cellpixy);
if(vopts->pxoffy >= geom->cdimy){
logerror("pixel y-offset %d too tall for cell %d\n", vopts->pxoffy, geom->cdimy);
return -1;
}
if(vopts->pxoffx >= ti->cellpixx){
logerror("pixel x-offset %d too wide for cell %d\n", vopts->pxoffx, ti->cellpixx);
if(vopts->pxoffx >= geom->cdimx){
logerror("pixel x-offset %d too wide for cell %d\n", vopts->pxoffx, geom->cdimx);
return -1;
}
if(scaling == NCSCALE_NONE || scaling == NCSCALE_NONE_HIRES){
// FIXME clamp to sprixel limits
unsigned rows = ((geom->leny + ti->cellpixy - 1) / ti->cellpixy) + !!vopts->pxoffy;
unsigned rows = ((geom->leny + geom->cdimy - 1) / geom->cdimy) + !!vopts->pxoffy;
if(rows > ncplane_dim_y(vopts->n)){
logerror("sprixel too tall %d for plane %d\n", geom->leny + vopts->pxoffy,
ncplane_dim_y(vopts->n) * ti->cellpixy);
ncplane_dim_y(vopts->n) * geom->cdimy);
return -1;
}
unsigned cols = ((geom->lenx + ti->cellpixx - 1) / ti->cellpixx) + !!vopts->pxoffx;
unsigned cols = ((geom->lenx + geom->cdimx - 1) / geom->cdimx) + !!vopts->pxoffx;
if(cols > ncplane_dim_x(vopts->n)){
logerror("sprixel too wide %d for plane %d\n", geom->lenx + vopts->pxoffx,
ncplane_dim_x(vopts->n) * ti->cellpixx);
ncplane_dim_x(vopts->n) * geom->cdimx);
return -1;
}
}
}
if(vopts->n == NULL || (vopts->flags & NCVISUAL_OPTION_CHILDPLANE)){
// we'll need to create the plane
shape_sprixel_plane(ti, vopts->n, n, scaling, disppixy, disppixx,
const int dimy = p ? p->dimy : ti->dimy;
const int dimx = p ? p->dimx : ti->dimx;
shape_sprixel_plane(ti, geom->cdimy, geom->cdimx, dimy, dimx,
vopts->n, n, scaling, disppixy, disppixx,
vopts->flags, outy, outx, placey, placex,
vopts->pxoffy, vopts->pxoffx);
}else{
if(scaling != NCSCALE_NONE && scaling != NCSCALE_NONE_HIRES){
ncplane_dim_yx(vopts->n, disppixy, disppixx);
*disppixx *= ti->cellpixx;
*disppixx *= geom->cdimx;
*disppixx += vopts->pxoffx;
*disppixy *= ti->cellpixy;
*disppixy *= geom->cdimy;
*disppixy += vopts->pxoffy;
clamp_to_sixelmax(ti, disppixy, disppixx, outy, scaling);
int absplacex = 0, absplacey = 0;
@ -345,8 +360,8 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
if(!(vopts->flags & NCVISUAL_OPTION_VERALIGNED)){
absplacey = *placey;
}
*disppixx -= absplacex * ti->cellpixx;
*disppixy -= absplacey * ti->cellpixy;
*disppixx -= absplacex * geom->cdimx;
*disppixy -= absplacey * geom->cdimy;
}else{
*disppixx = geom->lenx + vopts->pxoffx;
*disppixy = geom->leny + vopts->pxoffy;
@ -358,7 +373,7 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
}
clamp_to_sixelmax(ti, disppixy, disppixx, outy, scaling);
// FIXME use a closed form
while((*outy + ti->cellpixy - 1) / ti->cellpixy > (unsigned)ncplane_dim_y(vopts->n)){
while((*outy + geom->cdimy - 1) / geom->cdimy > ncplane_dim_y(vopts->n)){
*outy -= ti->sprixel_scale_height;
*disppixy = *outy;
}
@ -366,11 +381,11 @@ int ncvisual_geom_inner(const tinfo* ti, const ncvisual* n,
*disppixx -= vopts->pxoffx;
*disppixy -= vopts->pxoffy;
}
logdebug("pblit: %dx%d ← %dx%d of %d/%d stride %u @%dx%d %p %u\n", *disppixy, *disppixx, geom->begy, geom->begx, n->pixy, n->pixx, n->rowstride, *placey, *placex, n->data, ti->cellpixx);
logdebug("pblit: %dx%d ← %dx%d of %d/%d stride %u @%dx%d %p %u\n", *disppixy, *disppixx, geom->begy, geom->begx, n->pixy, n->pixx, n->rowstride, *placey, *placex, n->data, geom->cdimx);
geom->rpixy = *disppixy;
geom->rpixx = *disppixx;
geom->rcellx = *outx / ti->cellpixx + !!(*outx % ti->cellpixx);
geom->rcelly = *outy / ti->cellpixy + !!(*outy % ti->cellpixy);
geom->rcellx = *outx / geom->cdimx + !!(*outx % geom->cdimx);
geom->rcelly = *outy / geom->cdimy + !!(*outy % geom->cdimy);
}else{ // cellblit
if(vopts->pxoffx || vopts->pxoffy){
logerror("pixel offsets cannot be used with cell blitting\n");
@ -1009,8 +1024,11 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
bargs.u.pixel.colorregs = ti->color_registers;
bargs.u.pixel.pxoffy = pxoffy;
bargs.u.pixel.pxoffx = pxoffx;
bargs.u.pixel.cellpxy = geom->cdimy;
bargs.u.pixel.cellpxx = geom->cdimx;
const ncpile* p = ncplane_pile_const(n);
if(n->sprite == NULL){
if((n->sprite = sprixel_alloc(&nc->tcache, n, geom->rcelly, geom->rcellx)) == NULL){
if((n->sprite = sprixel_alloc(n, geom->rcelly, geom->rcellx)) == NULL){
return NULL;
}
if((n->tam = create_tam(geom->rcelly, geom->rcellx)) == NULL){
@ -1036,9 +1054,9 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
// zeroed out, thus neither of these will have any effect.
if(flags & NCVISUAL_OPTION_HORALIGNED){
if(placex == NCALIGN_CENTER){
placex = (ncplane_dim_x(ncplane_parent_const(n)) * ti->cellpixx - geom->rpixx) / 2 / ti->cellpixx;
placex = (ncplane_dim_x(ncplane_parent_const(n)) * p->cellpxx - geom->rpixx) / 2 / p->cellpxx;
}else if(placex == NCALIGN_RIGHT){
placex = (ncplane_dim_x(ncplane_parent_const(n)) * ti->cellpixx - geom->rpixx) / ti->cellpixx;
placex = (ncplane_dim_x(ncplane_parent_const(n)) * p->cellpxx - geom->rpixx) / p->cellpxx;
}
if(placex < 0){
return NULL;
@ -1046,9 +1064,9 @@ ncplane* ncvisual_render_pixels(notcurses* nc, ncvisual* ncv, const struct blits
}
if(flags & NCVISUAL_OPTION_VERALIGNED){
if(placey == NCALIGN_CENTER){
placey = (ncplane_dim_y(ncplane_parent_const(n)) * ti->cellpixy - geom->rpixy) / 2 / ti->cellpixy;
placey = (ncplane_dim_y(ncplane_parent_const(n)) * p->cellpxy - geom->rpixy) / 2 / p->cellpxy;
}else if(placey == NCALIGN_BOTTOM){
placey = (ncplane_dim_y(ncplane_parent_const(n)) * ti->cellpixy - geom->rpixy) / ti->cellpixy;
placey = (ncplane_dim_y(ncplane_parent_const(n)) * p->cellpxy - geom->rpixy) / p->cellpxy;
}
if(placey < 0){
return NULL;

View File

@ -173,7 +173,9 @@ struct ncplane* ffmpeg_subtitle(ncplane* parent, const ncvisual* ncv){
continue;
}
struct notcurses* nc = ncplane_notcurses(parent);
if(nc->tcache.cellpixy <= 0 || nc->tcache.cellpixx <= 0){
const unsigned cellpxy = ncplane_pile_const(parent)->cellpxy;
const unsigned cellpxx = ncplane_pile_const(parent)->cellpxx;
if(cellpxy <= 0 || cellpxx <= 0){
continue;
}
struct ncvisual* v = ncvisual_from_palidx(rect->data[0], rect->h,
@ -182,10 +184,10 @@ struct ncplane* ffmpeg_subtitle(ncplane* parent, const ncvisual* ncv){
if(v == NULL){
return NULL;
}
int rows = (rect->h + nc->tcache.cellpixy - 1) / nc->tcache.cellpixy;
int rows = (rect->h + cellpxx - 1) / cellpxy;
struct ncplane_options nopts = {
.rows = rows,
.cols = (rect->w + nc->tcache.cellpixx - 1) / nc->tcache.cellpixx,
.cols = (rect->w + cellpxx - 1) / cellpxx,
.y = ncplane_dim_y(parent) - rows - 1,
.name = "t1st",
};

View File

@ -14,8 +14,8 @@ TEST_CASE("Bitmaps") {
}
SUBCASE("SprixelTermValues") {
CHECK(0 < nc_->tcache.cellpixy);
CHECK(0 < nc_->tcache.cellpixx);
CHECK(0 < nc_->tcache.cellpxy);
CHECK(0 < nc_->tcache.cellpxx);
if(!nc_->tcache.pixel_draw_late){
CHECK(nc_->tcache.pixel_draw);
}
@ -66,8 +66,8 @@ TEST_CASE("Bitmaps") {
// a sprixel requires a plane large enough to hold it
SUBCASE("SprixelTooTall") {
auto y = nc_->tcache.cellpixy + 6;
auto x = nc_->tcache.cellpixx;
auto y = nc_->tcache.cellpxy + 6;
auto x = nc_->tcache.cellpxx;
std::vector<uint32_t> v(x * y, htole(0xe61c28ff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -89,8 +89,8 @@ TEST_CASE("Bitmaps") {
}
SUBCASE("SprixelTooWide") {
auto y = nc_->tcache.cellpixy;
auto x = nc_->tcache.cellpixx + 1;
auto y = nc_->tcache.cellpxy;
auto x = nc_->tcache.cellpxx + 1;
std::vector<uint32_t> v(x * y, htole(0xe61c28ff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -114,8 +114,8 @@ TEST_CASE("Bitmaps") {
// should not be able to emit glyphs to a sprixelated plane
SUBCASE("SprixelNoGlyphs") {
auto y = nc_->tcache.cellpixy;
auto x = nc_->tcache.cellpixx;
auto y = nc_->tcache.cellpxy;
auto x = nc_->tcache.cellpxx;
std::vector<uint32_t> v(x * y, htole(0xe61c28ff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -139,8 +139,8 @@ TEST_CASE("Bitmaps") {
}
SUBCASE("BitmapStack") {
auto y = nc_->tcache.cellpixy * 10;
auto x = nc_->tcache.cellpixx * 10;
auto y = nc_->tcache.cellpxy * 10;
auto x = nc_->tcache.cellpxx * 10;
std::vector<uint32_t> v(x * y, htole(0xe61c28ff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -152,8 +152,8 @@ TEST_CASE("Bitmaps") {
REQUIRE(nullptr != botn);
// should just have a red plane
CHECK(0 == notcurses_render(nc_));
y = nc_->tcache.cellpixy * 5;
x = nc_->tcache.cellpixx * 5;
y = nc_->tcache.cellpxy * 5;
x = nc_->tcache.cellpxx * 5;
std::vector<uint32_t> v2(x * y, htole(0x8142f1ff));
auto ncv2 = ncvisual_from_rgba(v2.data(), y, sizeof(decltype(v2)::value_type) * x, x);
REQUIRE(nullptr != ncv2);
@ -198,8 +198,8 @@ TEST_CASE("Bitmaps") {
SUBCASE("BitmapStretch") {
// first, assemble a visual equivalent to 1 cell
auto y = nc_->tcache.cellpixy;
auto x = nc_->tcache.cellpixx;
auto y = nc_->tcache.cellpxy;
auto x = nc_->tcache.cellpxx;
std::vector<uint32_t> v(x * y, htole(0xffffffff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -211,8 +211,8 @@ TEST_CASE("Bitmaps") {
REQUIRE(nullptr != n);
auto s = n->sprite;
REQUIRE(nullptr != s);
CHECK(nc_->tcache.cellpixy == ncv->pixy);
CHECK(nc_->tcache.cellpixx == ncv->pixx);
CHECK(nc_->tcache.cellpxy == ncv->pixy);
CHECK(nc_->tcache.cellpxx == ncv->pixx);
CHECK(0 == notcurses_render(nc_));
struct ncplane_options nopts = {
.y = 1,
@ -232,8 +232,8 @@ TEST_CASE("Bitmaps") {
CHECK(vopts.n == ncvisual_blit(nc_, ncv, &vopts));
CHECK(0 == notcurses_render(nc_));
CHECK(0 == ncvisual_resize_noninterpolative(ncv, ncv->pixy * 4, ncv->pixx * 4));
CHECK(4 * nc_->tcache.cellpixy == ncv->pixy);
CHECK(4 * nc_->tcache.cellpixx == ncv->pixx);
CHECK(4 * nc_->tcache.cellpxy == ncv->pixy);
CHECK(4 * nc_->tcache.cellpxx == ncv->pixx);
vopts.y = 1;
vopts.x = 6;
vopts.n = n_;
@ -242,7 +242,7 @@ TEST_CASE("Bitmaps") {
auto infn = ncvisual_blit(nc_, ncv, &vopts);
REQUIRE(infn);
if(nc_->tcache.sprixel_scale_height == 6){
if(4 * nc_->tcache.cellpixy % 6){
if(4 * nc_->tcache.cellpxy % 6){
CHECK(5 == ncplane_dim_y(infn));
}else{
CHECK(4 == ncplane_dim_y(infn));
@ -259,8 +259,8 @@ TEST_CASE("Bitmaps") {
vopts.x = 11;
auto resizen = ncvisual_blit(nc_, ncv, &vopts);
REQUIRE(resizen);
CHECK((8 + nc_->tcache.cellpixy - 1) / nc_->tcache.cellpixy == ncplane_dim_y(resizen));
CHECK((8 + nc_->tcache.cellpixx - 1) / nc_->tcache.cellpixx == ncplane_dim_x(resizen));
CHECK((8 + nc_->tcache.cellpxy - 1) / nc_->tcache.cellpxy == ncplane_dim_y(resizen));
CHECK((8 + nc_->tcache.cellpxx - 1) / nc_->tcache.cellpxx == ncplane_dim_x(resizen));
CHECK(0 == notcurses_render(nc_));
CHECK(0 == ncplane_destroy(bigp));
CHECK(0 == ncplane_destroy(resizen));
@ -274,8 +274,8 @@ TEST_CASE("Bitmaps") {
// resulting geometries for (rough) equality
SUBCASE("InflateVsScale") {
// first, assemble a visual equivalent to 1 cell
auto y = nc_->tcache.cellpixy;
auto x = nc_->tcache.cellpixx;
auto y = nc_->tcache.cellpxy;
auto x = nc_->tcache.cellpxx;
std::vector<uint32_t> v(x * y, htole(0xff7799dd));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -355,8 +355,8 @@ TEST_CASE("Bitmaps") {
.transcolor = 0,
.pxoffy = 0, .pxoffx = 0,
};
auto y = nc_->tcache.cellpixy * 6;
auto x = nc_->tcache.cellpixx;
auto y = nc_->tcache.cellpxy * 6;
auto x = nc_->tcache.cellpxx;
std::vector<uint32_t> v(x * y, htole(0xffffffff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -399,8 +399,8 @@ TEST_CASE("Bitmaps") {
.transcolor = 0,
.pxoffy = 0, .pxoffx = 0,
};
auto y = nc_->tcache.cellpixy * 6;
auto x = nc_->tcache.cellpixx;
auto y = nc_->tcache.cellpxy * 6;
auto x = nc_->tcache.cellpxx;
std::vector<uint32_t> v(x * y, htole(0xffffffff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -417,8 +417,8 @@ TEST_CASE("Bitmaps") {
SUBCASE("PixelCellWipe") {
// first, assemble a visual equivalent to 4 cells
auto y = 2 * nc_->tcache.cellpixy;
auto x = 2 * nc_->tcache.cellpixx;
auto y = 2 * nc_->tcache.cellpxy;
auto x = 2 * nc_->tcache.cellpxx;
std::vector<uint32_t> v(x * y, htole(0xffffffff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -446,8 +446,8 @@ TEST_CASE("Bitmaps") {
SUBCASE("PixelCellWipePolychromatic") {
// first, assemble a visual equivalent to 4 cells
auto y = 2 * nc_->tcache.cellpixy;
auto x = 2 * nc_->tcache.cellpixx;
auto y = 2 * nc_->tcache.cellpxy;
auto x = 2 * nc_->tcache.cellpxx;
std::vector<uint32_t> v(x * y, htole(0xffffffff));
for(auto& e : v){
e -= htole(rand() % 0x1000000);
@ -478,8 +478,8 @@ TEST_CASE("Bitmaps") {
SUBCASE("PixelBigCellWipePolychromatic") {
// first, assemble a visual equivalent to 100 cells
auto y = 10 * nc_->tcache.cellpixy;
auto x = 10 * nc_->tcache.cellpixx;
auto y = 10 * nc_->tcache.cellpxy;
auto x = 10 * nc_->tcache.cellpxx;
std::vector<uint32_t> v(x * y, htole(0xffffffff));
for(auto& e : v){
e -= htole(rand() % 0x1000000);
@ -513,14 +513,14 @@ TEST_CASE("Bitmaps") {
// first, assemble a visual equivalent to 54 cells
auto dimy = 6;
auto dimx = 9;
auto y = dimy * nc_->tcache.cellpixy;
auto x = dimx * nc_->tcache.cellpixx;
auto y = dimy * nc_->tcache.cellpxy;
auto x = dimx * nc_->tcache.cellpxx;
std::vector<uint32_t> v(x * y, htole(0xffffffff));
// every other cell, set some pixels transparent
for(int i = 0 ; i < dimy * dimx ; ++i){
if(i % 2){
int py = (i / dimx) * nc_->tcache.cellpixy;
int px = (i % dimx) * nc_->tcache.cellpixx;
int py = (i / dimx) * nc_->tcache.cellpxy;
int px = (i % dimx) * nc_->tcache.cellpxx;
ncpixel_set_a(&v[py * x + px], 0);
}
}
@ -540,8 +540,8 @@ TEST_CASE("Bitmaps") {
CHECK(s->dimx == dimx);
const auto tam = n->tam;
for(unsigned i = 0 ; i < s->dimy * s->dimx ; ++i){
int py = (i / dimx) * nc_->tcache.cellpixy;
int px = (i % dimx) * nc_->tcache.cellpixx;
int py = (i / dimx) * nc_->tcache.cellpxy;
int px = (i % dimx) * nc_->tcache.cellpxx;
// cells with a transparent pixel ought be SPRIXCELL_MIXED;
// cells without one ought be SPRIXCELL_OPAQUE.
sprixcell_e state = tam[(i / dimx) + (i % dimx)].state;
@ -613,8 +613,8 @@ TEST_CASE("Bitmaps") {
SUBCASE("BitmapMoveOffscreenLeft") {
// first, assemble a visual equivalent to 2x2 cells
auto y = nc_->tcache.cellpixy * 2;
auto x = nc_->tcache.cellpixx * 2;
auto y = nc_->tcache.cellpxy * 2;
auto x = nc_->tcache.cellpxx * 2;
std::vector<uint32_t> v(x * y * 4, htole(0xffccccff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -634,8 +634,8 @@ TEST_CASE("Bitmaps") {
SUBCASE("BitmapMoveOffscreenRight") {
// first, assemble a visual equivalent to 2x2 cells
auto y = nc_->tcache.cellpixy * 2;
auto x = nc_->tcache.cellpixx * 2;
auto y = nc_->tcache.cellpxy * 2;
auto x = nc_->tcache.cellpxx * 2;
std::vector<uint32_t> v(x * y * 4, htole(0xffccccff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -656,8 +656,8 @@ TEST_CASE("Bitmaps") {
SUBCASE("BitmapMoveOffscreenDown") {
// first, assemble a visual equivalent to 2x2 cells
auto y = nc_->tcache.cellpixy * 2;
auto x = nc_->tcache.cellpixx * 2;
auto y = nc_->tcache.cellpxy * 2;
auto x = nc_->tcache.cellpxx * 2;
std::vector<uint32_t> v(x * y * 4, htole(0xffccccff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -677,8 +677,8 @@ TEST_CASE("Bitmaps") {
SUBCASE("BitmapMoveOffscreenUp") {
// first, assemble a visual equivalent to 2x2 cells
auto y = nc_->tcache.cellpixy * 2;
auto x = nc_->tcache.cellpixx * 2;
auto y = nc_->tcache.cellpxy * 2;
auto x = nc_->tcache.cellpxx * 2;
std::vector<uint32_t> v(x * y * 4, htole(0xffccccff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -700,8 +700,8 @@ TEST_CASE("Bitmaps") {
// smoothly move a bitmap diagonally across the screen
SUBCASE("BitmapSmoothMove") {
// first, assemble a visual equivalent to 2x2 cells
auto y = nc_->tcache.cellpixy * 2;
auto x = nc_->tcache.cellpixx * 2;
auto y = nc_->tcache.cellpxy * 2;
auto x = nc_->tcache.cellpxx * 2;
std::vector<uint32_t> v(x * y * 4, htole(0xffccccff));
auto ncv = ncvisual_from_rgba(v.data(), y, sizeof(decltype(v)::value_type) * x, x);
REQUIRE(nullptr != ncv);
@ -711,15 +711,15 @@ TEST_CASE("Bitmaps") {
vopts.flags = NCVISUAL_OPTION_NODEGRADE | NCVISUAL_OPTION_CHILDPLANE;
auto n = ncvisual_blit(nc_, ncv, &vopts);
REQUIRE(nullptr != n);
auto xpx = (ncplane_dim_x(n_) - 2) * nc_->tcache.cellpixx;
auto ypx = (ncplane_dim_y(n_) - 2) * nc_->tcache.cellpixy;
auto xpx = (ncplane_dim_x(n_) - 2) * nc_->tcache.cellpxx;
auto ypx = (ncplane_dim_y(n_) - 2) * nc_->tcache.cellpxy;
double xyrat = (double)ypx / xpx;
for(unsigned xat = 0 ; xat < xpx ; ++xat){
vopts.x = xat / nc_->tcache.cellpixx;
vopts.pxoffx = xat % nc_->tcache.cellpixx;
vopts.x = xat / nc_->tcache.cellpxx;
vopts.pxoffx = xat % nc_->tcache.cellpxx;
int yat = xat * xyrat;
vopts.y = yat / nc_->tcache.cellpixy;
vopts.pxoffy = yat % nc_->tcache.cellpixy;
vopts.y = yat / nc_->tcache.cellpxy;
vopts.pxoffy = yat % nc_->tcache.cellpxy;
CHECK(0 == ncplane_destroy(n));
n = ncvisual_blit(nc_, ncv, &vopts);
REQUIRE(nullptr != n);

View File

@ -7,8 +7,8 @@
void default_visual_extrinsics(const notcurses* nc, const ncvgeom& g) {
CHECK(0 == g.pixy);
CHECK(0 == g.pixx);
CHECK(nc->tcache.cellpixy == g.cdimy);
CHECK(nc->tcache.cellpixx == g.cdimx);
CHECK(nc->tcache.cellpxy == g.cdimy);
CHECK(nc->tcache.cellpxx == g.cdimx);
CHECK(1 <= g.scaley);
CHECK(1 <= g.scalex);
CHECK(0 == g.rpixy);
@ -91,8 +91,8 @@ TEST_CASE("Visual") {
CHECK(0 == ncvisual_geom(nc_, nullptr, &vopts, &g));
CHECK(0 == g.pixy);
CHECK(0 == g.pixx);
CHECK(nc_->tcache.cellpixy == g.cdimy);
CHECK(nc_->tcache.cellpixx == g.cdimx);
CHECK(nc_->tcache.cellpxy == g.cdimy);
CHECK(nc_->tcache.cellpxx == g.cdimx);
if(notcurses_canpixel(nc_)){
CHECK(g.cdimy == g.scaley);
CHECK(g.cdimx == g.scalex);