[channels_blend] blend palette-indexed colors #2442

pull/2468/head
nick black 3 years ago
parent ca848a9987
commit b075de5da9
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -1337,25 +1337,33 @@ cell_set_fchannel(nccell* cl, uint32_t channel){
// 'c2'. If 'c1' is otherwise the default color, 'c1' will not be touched,
// since we can't blend default colors. Likewise, if 'c2' is a default color,
// it will not be used (unless 'blends' is 0).
//
// Palette-indexed colors do not blend. Do not pass me palette-indexed channels!
static inline unsigned
channels_blend(unsigned c1, unsigned c2, unsigned* blends){
channels_blend(notcurses* nc, unsigned c1, unsigned c2, unsigned* blends){
if(ncchannel_alpha(c2) == NCALPHA_TRANSPARENT){
return c1; // do *not* increment *blends
}
bool c2default = ncchannel_default_p(c2);
bool c2palette = ncchannel_palindex_p(c2);
if(*blends == 0){
// don't just return c2, or you set wide status and all kinds of crap
if(ncchannel_default_p(c2)){
if(c2default){
ncchannel_set_default(&c1);
}else if(c2palette){
ncchannel_set_palindex(&c1, ncchannel_palindex(c2));
}else{
ncchannel_set(&c1, c2 & NC_BG_RGB_MASK);
}
ncchannel_set_alpha(&c1, ncchannel_alpha(c2));
}else if(!c2default && !ncchannel_default_p(c1)){
unsigned rsum, gsum, bsum;
ncchannel_rgb8(c2, &rsum, &gsum, &bsum);
if(c2palette){
uint32_t rgb = nc->palette.chans[ncchannel_palindex(c2)];
bsum = rgb & 0xff;
gsum = (rgb >> 8u) & 0xff;
rsum = (rgb >> 16u) & 0xff;
}else{
ncchannel_rgb8(c2, &rsum, &gsum, &bsum);
}
rsum = (ncchannel_r(c1) * *blends + rsum) / (*blends + 1);
gsum = (ncchannel_g(c1) * *blends + gsum) / (*blends + 1);
bsum = (ncchannel_b(c1) * *blends + bsum) / (*blends + 1);
@ -1368,13 +1376,13 @@ channels_blend(unsigned c1, unsigned c2, unsigned* blends){
// do not pass palette-indexed channels!
static inline uint64_t
cell_blend_fchannel(nccell* cl, unsigned channel, unsigned* blends){
return cell_set_fchannel(cl, channels_blend(cell_fchannel(cl), channel, blends));
cell_blend_fchannel(notcurses* nc, nccell* cl, unsigned channel, unsigned* blends){
return cell_set_fchannel(cl, channels_blend(nc, cell_fchannel(cl), channel, blends));
}
static inline uint64_t
cell_blend_bchannel(nccell* cl, unsigned channel, unsigned* blends){
return cell_set_bchannel(cl, channels_blend(cell_bchannel(cl), channel, blends));
cell_blend_bchannel(notcurses* nc, nccell* cl, unsigned channel, unsigned* blends){
return cell_set_bchannel(cl, channels_blend(nc, cell_bchannel(cl), channel, blends));
}
// a sprixel occupies the entirety of its associated plane, usually an entirely

@ -305,25 +305,19 @@ paint(ncplane* p, struct crender* rvec, int dstleny, int dstlenx,
if(nccell_fg_default_p(vis)){
vis = &p->basecell;
}
if(nccell_fg_palindex_p(vis)){
if(nccell_fg_alpha(targc) == NCALPHA_TRANSPARENT){
nccell_set_fg_palindex(targc, nccell_fg_palindex(vis));
}
}else{
if(nccell_fg_alpha(vis) == NCALPHA_HIGHCONTRAST){
crender->s.highcontrast = true;
crender->s.hcfgblends = crender->s.fgblends;
crender->hcfg = cell_fchannel(targc);
}
unsigned fgblends = crender->s.fgblends;
cell_blend_fchannel(targc, cell_fchannel(vis), &fgblends);
crender->s.fgblends = fgblends;
// crender->highcontrast can only be true if we just set it, since we're
// about to set targc opaque based on crender->highcontrast (and this
// entire stanza is conditional on targc not being NCALPHA_OPAQUE).
if(crender->s.highcontrast){
nccell_set_fg_alpha(targc, NCALPHA_OPAQUE);
}
if(nccell_fg_alpha(vis) == NCALPHA_HIGHCONTRAST){
crender->s.highcontrast = true;
crender->s.hcfgblends = crender->s.fgblends;
crender->hcfg = cell_fchannel(targc);
}
unsigned fgblends = crender->s.fgblends;
cell_blend_fchannel(ncplane_notcurses(p), targc, cell_fchannel(vis), &fgblends);
crender->s.fgblends = fgblends;
// crender->highcontrast can only be true if we just set it, since we're
// about to set targc opaque based on crender->highcontrast (and this
// entire stanza is conditional on targc not being NCALPHA_OPAQUE).
if(crender->s.highcontrast){
nccell_set_fg_alpha(targc, NCALPHA_OPAQUE);
}
}
@ -342,28 +336,16 @@ paint(ncplane* p, struct crender* rvec, int dstleny, int dstlenx,
if(nccell_bg_default_p(vis)){
vis = &p->basecell;
}
if(nccell_bg_palindex_p(vis)){
if(nccell_bg_alpha(targc) == NCALPHA_TRANSPARENT){
nccell_set_bg_palindex(targc, nccell_bg_palindex(vis));
}
}else{
unsigned bgblends = crender->s.bgblends;
cell_blend_bchannel(targc, cell_bchannel(vis), &bgblends);
crender->s.bgblends = bgblends;
}
unsigned bgblends = crender->s.bgblends;
cell_blend_bchannel(ncplane_notcurses(p), targc, cell_bchannel(vis), &bgblends);
crender->s.bgblends = bgblends;
}else{ // use the local foreground; we're stacking blittings
if(nccell_fg_default_p(vis)){
vis = &p->basecell;
}
if(nccell_fg_palindex_p(vis)){
if(nccell_bg_alpha(targc) == NCALPHA_TRANSPARENT){
nccell_set_bg_palindex(targc, nccell_fg_palindex(vis));
}
}else{
unsigned bgblends = crender->s.bgblends;
cell_blend_bchannel(targc, cell_fchannel(vis), &bgblends);
crender->s.bgblends = bgblends;
}
unsigned bgblends = crender->s.bgblends;
cell_blend_bchannel(ncplane_notcurses(p), targc, cell_fchannel(vis), &bgblends);
crender->s.bgblends = bgblends;
crender->s.blittedquads = 0;
}
}
@ -434,7 +416,7 @@ init_rvec(struct crender* rvec, int totalcells){
// should be done at the end of rendering the cell, so that contrast is solved
// against the real background.
static inline void
lock_in_highcontrast(const tinfo* ti, nccell* targc, struct crender* crender){
lock_in_highcontrast(notcurses* nc, const tinfo* ti, nccell* targc, struct crender* crender){
if(nccell_fg_alpha(targc) == NCALPHA_TRANSPARENT){
nccell_set_fg_default(targc);
}
@ -447,10 +429,10 @@ lock_in_highcontrast(const tinfo* ti, nccell* targc, struct crender* crender){
unsigned fgblends = 3;
uint32_t fchan = cell_fchannel(targc);
uint32_t bchan = cell_bchannel(targc);
uint32_t hchan = channels_blend(highcontrast(ti, bchan), fchan, &fgblends);
uint32_t hchan = channels_blend(nc, highcontrast(ti, bchan), fchan, &fgblends);
cell_set_fchannel(targc, hchan);
fgblends = crender->s.hcfgblends;
hchan = channels_blend(hchan, crender->hcfg, &fgblends);
hchan = channels_blend(nc, hchan, crender->hcfg, &fgblends);
cell_set_fchannel(targc, hchan);
}else{
nccell_set_fg_rgb(targc, highcontrast(ti, cell_bchannel(targc)));
@ -462,10 +444,10 @@ lock_in_highcontrast(const tinfo* ti, nccell* targc, struct crender* crender){
// checking for and locking in high-contrast, checking for damage, and updating
// 'lastframe' for any cells which are damaged.
static inline void
postpaint_cell(const tinfo* ti, nccell* lastframe, int dimx,
postpaint_cell(notcurses* nc, const tinfo* ti, nccell* lastframe, int dimx,
struct crender* crender, egcpool* pool, int y, int* x){
nccell* targc = &crender->c;
lock_in_highcontrast(ti, targc, crender);
lock_in_highcontrast(nc, ti, targc, crender);
nccell* prevcell = &lastframe[fbcellidx(y, dimx, *x)];
if(cellcmp_and_dupfar(pool, prevcell, crender->p, targc) > 0){
//fprintf(stderr, "damaging due to cmp [%s] %d %d\n", nccell_extended_gcluster(crender->p, &crender->c), y, *x);
@ -515,12 +497,12 @@ postpaint_cell(const tinfo* ti, nccell* lastframe, int dimx,
// FIXME can we not do the blend a single time here, if we track sums in
// paint()? tried this before and didn't get a win...
static void
postpaint(const tinfo* ti, nccell* lastframe, int dimy, int dimx,
postpaint(notcurses* nc, const tinfo* ti, nccell* lastframe, int dimy, int dimx,
struct crender* rvec, egcpool* pool){
for(int y = 0 ; y < dimy ; ++y){
for(int x = 0 ; x < dimx ; ++x){
struct crender* crender = &rvec[fbcellidx(y, dimx, x)];
postpaint_cell(ti, lastframe, dimx, crender, pool, y, &x);
postpaint_cell(nc, ti, lastframe, dimx, crender, pool, y, &x);
}
}
}
@ -613,7 +595,7 @@ int ncplane_mergedown(ncplane* restrict src, ncplane* restrict dst,
assert(NULL == s);
//fprintf(stderr, "Postpaint start (%dx%d)\n", dst->leny, dst->lenx);
const struct tinfo* ti = &ncplane_notcurses_const(dst)->tcache;
postpaint(ti, rendfb, dst->leny, dst->lenx, rvec, &dst->pool);
postpaint(ncplane_notcurses(dst), ti, rendfb, dst->leny, dst->lenx, rvec, &dst->pool);
//fprintf(stderr, "Postpaint done (%dx%d)\n", dst->leny, dst->lenx);
free(dst->fb);
dst->fb = rendfb;
@ -1540,7 +1522,7 @@ int ncpile_rasterize(ncplane* n){
const int miny = pile->dimy < nc->lfdimy ? pile->dimy : nc->lfdimy;
const int minx = pile->dimx < nc->lfdimx ? pile->dimx : nc->lfdimx;
const struct tinfo* ti = &ncplane_notcurses_const(n)->tcache;
postpaint(ti, nc->lastframe, miny, minx, pile->crender, &nc->pool);
postpaint(nc, ti, nc->lastframe, miny, minx, pile->crender, &nc->pool);
clock_gettime(CLOCK_MONOTONIC, &rasterdone);
int bytes = notcurses_rasterize(nc, pile, &nc->rstate.f);
// accepts -1 as an indication of failure

@ -76,7 +76,7 @@ TEST_CASE("ChannelBlend0") {
ncchannel_set_rgb8(&c1, 0x80, 0x40, 0x20);
ncchannel_set_rgb8(&c2, 0x88, 0x44, 0x22);
unsigned blends = 0;
uint32_t c = channels_blend(c1, c2, &blends);
uint32_t c = channels_blend(nullptr, c1, c2, &blends);
CHECK(!ncchannel_default_p(c));
unsigned r, g, b;
ncchannel_rgb8(c, &r, &g, &b);
@ -93,7 +93,7 @@ TEST_CASE("ChannelBlend1") {
ncchannel_set_rgb8(&c1, 0x80, 0x40, 0x20);
ncchannel_set_rgb8(&c2, 0x0, 0x0, 0x0);
unsigned blends = 1;
uint32_t c = channels_blend(c1, c2, &blends);
uint32_t c = channels_blend(nullptr, c1, c2, &blends);
CHECK(!ncchannel_default_p(c));
unsigned r, g, b;
ncchannel_rgb8(c, &r, &g, &b);
@ -110,7 +110,7 @@ TEST_CASE("ChannelBlend2") {
ncchannel_set_rgb8(&c1, 0x60, 0x30, 0x0f);
ncchannel_set_rgb8(&c2, 0x0, 0x0, 0x0);
unsigned blends = 2;
uint32_t c = channels_blend(c1, c2, &blends);
uint32_t c = channels_blend(nullptr, c1, c2, &blends);
CHECK(!ncchannel_default_p(c));
unsigned r, g, b;
ncchannel_rgb8(c, &r, &g, &b);
@ -126,7 +126,7 @@ TEST_CASE("ChannelBlendDefaultLeft") {
uint32_t c2 = 0;
ncchannel_set_rgb8(&c2, 0x80, 0x40, 0x20);
unsigned blends = 0;
uint32_t c = channels_blend(c1, c2, &blends); // will replace
uint32_t c = channels_blend(nullptr, c1, c2, &blends); // will replace
CHECK(!ncchannel_default_p(c));
unsigned r, g, b;
ncchannel_rgb8(c, &r, &g, &b);
@ -134,14 +134,14 @@ TEST_CASE("ChannelBlendDefaultLeft") {
CHECK(0x40 == g);
CHECK(0x20 == b);
CHECK(1 == blends);
c = channels_blend(c1, c2, &blends); // will not replace
c = channels_blend(nullptr, c1, c2, &blends); // will not replace
CHECK(ncchannel_default_p(c));
ncchannel_rgb8(c, &r, &g, &b);
CHECK(0 == r);
CHECK(0 == g);
CHECK(0 == b);
CHECK(2 == blends);
c = channels_blend(c1, c2, &blends); // will not replace
c = channels_blend(nullptr, c1, c2, &blends); // will not replace
CHECK(ncchannel_default_p(c));
ncchannel_rgb8(c, &r, &g, &b);
CHECK(0 == r);
@ -158,10 +158,10 @@ TEST_CASE("ChannelBlendDefaultRight") {
CHECK(!ncchannel_default_p(c1));
CHECK(ncchannel_default_p(c2));
unsigned blends = 0;
uint32_t c = channels_blend(c1, c2, &blends);
uint32_t c = channels_blend(nullptr, c1, c2, &blends);
CHECK(ncchannel_default_p(c));
CHECK(1 == blends);
c = channels_blend(c1, c2, &blends);
c = channels_blend(nullptr, c1, c2, &blends);
CHECK(!ncchannel_default_p(c));
unsigned r, g, b;
ncchannel_rgb8(c, &r, &g, &b);

Loading…
Cancel
Save