mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-09 09:09:03 -04:00
first pass at fast blending
This commit is contained in:
parent
900dd20e1c
commit
e944319019
@ -678,26 +678,24 @@ void* bgra_to_rgba(const void* data, int rows, int rowstride, int cols);
|
||||
// them, we just don't fuck wit' 'em here. Do not pass me palette-indexed
|
||||
// channels! I will eat them.
|
||||
static inline unsigned
|
||||
channels_blend(unsigned c1, unsigned c2, unsigned* blends){
|
||||
channels_blend(uint32_t c1, uint32_t c2, unsigned* blends, unsigned* rsum,
|
||||
unsigned* gsum, unsigned* bsum){
|
||||
if(channel_alpha(c2) == CELL_ALPHA_TRANSPARENT){
|
||||
return c1; // do *not* increment *blends
|
||||
}
|
||||
unsigned rsum, gsum, bsum;
|
||||
channel_rgb(c2, &rsum, &gsum, &bsum);
|
||||
bool c2default = channel_default_p(c2);
|
||||
if(*blends == 0){
|
||||
// don't just return c2, or you set wide status and all kinds of crap
|
||||
if(channel_default_p(c2)){
|
||||
channel_set_default(&c1);
|
||||
}else{
|
||||
channel_set_rgb(&c1, rsum, gsum, bsum);
|
||||
channel_rgb(c2, rsum, gsum, bsum);
|
||||
}
|
||||
channel_set_alpha(&c1, channel_alpha(c2));
|
||||
}else if(!c2default && !channel_default_p(c1)){
|
||||
rsum = (channel_r(c1) * *blends + rsum) / (*blends + 1);
|
||||
gsum = (channel_g(c1) * *blends + gsum) / (*blends + 1);
|
||||
bsum = (channel_b(c1) * *blends + bsum) / (*blends + 1);
|
||||
channel_set_rgb(&c1, rsum, gsum, bsum);
|
||||
*rsum += channel_r(c2);
|
||||
*gsum += channel_g(c2);
|
||||
*bsum += channel_b(c2);
|
||||
channel_set_alpha(&c1, channel_alpha(c2));
|
||||
}
|
||||
++*blends;
|
||||
@ -706,13 +704,17 @@ channels_blend(unsigned c1, unsigned c2, unsigned* blends){
|
||||
|
||||
// do not pass palette-indexed channels!
|
||||
static inline uint64_t
|
||||
cell_blend_fchannel(cell* cl, unsigned channel, unsigned* blends){
|
||||
return cell_set_fchannel(cl, channels_blend(cell_fchannel(cl), channel, blends));
|
||||
cell_blend_fchannel(cell* cl, unsigned channel, struct crender* cr){
|
||||
return cell_set_fchannel(cl, channels_blend(cell_fchannel(cl), channel,
|
||||
&cr->fgblends, &cr->frsum,
|
||||
&cr->fgsum, &cr->fbsum));
|
||||
}
|
||||
|
||||
static inline uint64_t
|
||||
cell_blend_bchannel(cell* cl, unsigned channel, unsigned* blends){
|
||||
return cell_set_bchannel(cl, channels_blend(cell_bchannel(cl), channel, blends));
|
||||
cell_blend_bchannel(cell* cl, unsigned channel, struct crender* cr){
|
||||
return cell_set_bchannel(cl, channels_blend(cell_bchannel(cl), channel,
|
||||
&cr->bgblends, &cr->brsum,
|
||||
&cr->bgsum, &cr->bbsum));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -136,6 +136,7 @@ cellcmp_and_dupfar(const notcurses* nc, egcpool* dampool, cell* damcell,
|
||||
const ncplane* srcplane, const cell* srccell){
|
||||
bool srcsimple = cell_simple_p(srccell);
|
||||
if(!srcsimple && !enforce_utf8(nc)){
|
||||
// FIXME
|
||||
}
|
||||
if(damcell->attrword == srccell->attrword){
|
||||
if(damcell->channels == srccell->channels){
|
||||
@ -208,22 +209,38 @@ highcontrast(uint32_t bchannel){
|
||||
return conrgb;
|
||||
}
|
||||
|
||||
// adjust an otherwise locked-in cell if highcontrast has been requested. this
|
||||
// should be done at the end of rendering the cell, so that contrast is solved
|
||||
// against the real background.
|
||||
// Finalize color of a cell. adjust an otherwise locked-in cell if highcontrast
|
||||
// has been requested, and divide down the blended color sums. this 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(cell* targc, struct crender* crender){
|
||||
if(crender->highcontrast){
|
||||
// highcontrast weighs the original at 1/4 and the contrast at 3/4
|
||||
if(!cell_fg_default_p(targc)){
|
||||
crender->fgblends = 3;
|
||||
uint32_t fchan = cell_fchannel(targc);
|
||||
uint32_t bchan = cell_bchannel(targc);
|
||||
cell_set_fchannel(targc, channels_blend(highcontrast(bchan), fchan, &crender->fgblends));
|
||||
// give highcontrast-adjusted color the influence of 3 planes
|
||||
// FIXME this ought just be 2/3 or something, independent of plane #
|
||||
for(int i = 0 ; i < 3 ; ++i){
|
||||
cell_set_fchannel(targc, channels_blend(highcontrast(bchan), fchan,
|
||||
&crender->fgblends, &crender->frsum,
|
||||
&crender->fgsum, &crender->fbsum));
|
||||
}
|
||||
}else{
|
||||
cell_set_fg(targc, highcontrast(cell_bchannel(targc)));
|
||||
}
|
||||
}
|
||||
if(crender->fgblends){
|
||||
cell_set_fg_rgb(targc, crender->frsum / crender->fgblends,
|
||||
crender->fgsum / crender->fgblends,
|
||||
crender->fbsum / crender->fgblends);
|
||||
}
|
||||
if(crender->bgblends){
|
||||
cell_set_fg_rgb(targc, crender->frsum / crender->fgblends,
|
||||
crender->fgsum / crender->fgblends,
|
||||
crender->fbsum / crender->fgblends);
|
||||
}
|
||||
}
|
||||
|
||||
// Paints a single ncplane into the provided scratch framebuffer 'fb', and
|
||||
@ -314,7 +331,7 @@ paint(notcurses* nc, ncplane* p, cell* lastframe, struct crender* rvec,
|
||||
cell_set_bg_palindex(targc, cell_bg_palindex(vis));
|
||||
}
|
||||
}else if(cell_bg_alpha(targc) > CELL_ALPHA_OPAQUE){
|
||||
cell_blend_bchannel(targc, cell_bchannel(vis), &crender->bgblends);
|
||||
cell_blend_bchannel(targc, cell_bchannel(vis), crender);
|
||||
}
|
||||
// Evaluate the background first, in case this is HIGHCONTRAST fg text.
|
||||
if(cell_fg_palindex_p(vis)){
|
||||
@ -325,7 +342,7 @@ paint(notcurses* nc, ncplane* p, cell* lastframe, struct crender* rvec,
|
||||
if(cell_fg_alpha(vis) == CELL_ALPHA_HIGHCONTRAST){
|
||||
crender->highcontrast = true;
|
||||
}
|
||||
cell_blend_fchannel(targc, cell_fchannel(vis), &crender->fgblends);
|
||||
cell_blend_fchannel(targc, cell_fchannel(vis), crender);
|
||||
// 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 CELL_ALPHA_OPAQUE).
|
||||
|
@ -69,19 +69,18 @@ TEST_CASE("ChannelSetDefault") {
|
||||
|
||||
// blend of 0 ought set c1 to c2
|
||||
TEST_CASE("ChannelBlend0") {
|
||||
struct crender cr{};
|
||||
uint32_t c1 = 0;
|
||||
uint32_t c2 = 0;
|
||||
channel_set_rgb(&c1, 0x80, 0x40, 0x20);
|
||||
channel_set_rgb(&c2, 0x88, 0x44, 0x22);
|
||||
unsigned blends = 0;
|
||||
uint32_t c = channels_blend(c1, c2, &blends);
|
||||
uint32_t c = channels_blend(c1, c2, &cr.fgblends, &cr.frsum, &cr.fgsum, &cr.fbsum);
|
||||
CHECK(!channel_default_p(c));
|
||||
unsigned r, g, b;
|
||||
channel_rgb(c, &r, &g, &b);
|
||||
CHECK(0x88 == r);
|
||||
CHECK(0x44 == g);
|
||||
CHECK(0x22 == b);
|
||||
CHECK(1 == blends);
|
||||
CHECK(0x88 == cr.frsum);
|
||||
CHECK(0x44 == cr.fgsum);
|
||||
CHECK(0x22 == cr.fbsum);
|
||||
CHECK(1 == cr.fgblends);
|
||||
}
|
||||
|
||||
// blend of 1 ought perfectly average c1 and c2
|
||||
|
Loading…
x
Reference in New Issue
Block a user