diff --git a/src/lib/internal.h b/src/lib/internal.h index 639fb4b1a..2689af52a 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -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 diff --git a/src/lib/render.c b/src/lib/render.c index 9bdf4a461..3251b6a5c 100644 --- a/src/lib/render.c +++ b/src/lib/render.c @@ -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). diff --git a/tests/channel.cpp b/tests/channel.cpp index ca3cca504..96c87ff82 100644 --- a/tests/channel.cpp +++ b/tests/channel.cpp @@ -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