diff --git a/include/notcurses.h b/include/notcurses.h index 78e169ec1..f1a3d844d 100644 --- a/include/notcurses.h +++ b/include/notcurses.h @@ -1000,24 +1000,23 @@ channels_set_bg_default(uint64_t* channels){ return *channels; } -// Returns the result of blending two channels. +// Returns the result of blending two channels. 'blends' indicates how heavily +// 'c1' ought be weighed. If 'blends' is 0, 'c1' will be entirely replaced by +// '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). static inline unsigned channels_blend(unsigned c1, unsigned c2, unsigned blends){ - if(channel_default_p(c1)){ - return c1; + if(blends == 0){ + return c2; } - if(channel_default_p(c2)){ - if(blends == 0){ - channel_set_default(&c1); - } - return c1; + if(!channel_default_p(c2) && !channel_default_p(c1)){ + int rsum = (channel_get_r(c1) * blends + channel_get_r(c2)) / (blends + 1); + int gsum = (channel_get_g(c1) * blends + channel_get_g(c2)) / (blends + 1); + int bsum = (channel_get_b(c1) * blends + channel_get_b(c2)) / (blends + 1); + channel_set_rgb(&c1, rsum, gsum, bsum); } - int rsum = (channel_get_r(c1) * blends + channel_get_r(c2)) / (blends + 1); - int gsum = (channel_get_g(c1) * blends + channel_get_g(c2)) / (blends + 1); - int bsum = (channel_get_b(c1) * blends + channel_get_b(c2)) / (blends + 1); - unsigned blend = 0; - channel_set_rgb(&blend, rsum, gsum, bsum); - return blend; + return c1; } // Extract the 32-bit background channel from a cell. diff --git a/src/lib/render.c b/src/lib/render.c index a2bd71e13..33d5dffeb 100644 --- a/src/lib/render.c +++ b/src/lib/render.c @@ -146,9 +146,9 @@ reshape_shadow_fb(notcurses* nc){ // tail recursion, though, we instead write first, and then recurse, blending // as we descend. α == 0 is opaque. α == 2 is fully transparent. static inline ncplane* -dig_visible_cell(cell* c, int y, int x, ncplane* p, int falpha, int balpha){ - unsigned fgblends = 1; - unsigned bgblends = 1; +dig_visible_cell(cell* c, int y, int x, ncplane* p){ + unsigned fgblends = 0; + unsigned bgblends = 0; // once we decide on our glyph, it cannot be changed by anything below, so // lock in this plane for the actual cell return. ncplane* glyphplane = NULL; @@ -178,30 +178,21 @@ dig_visible_cell(cell* c, int y, int x, ncplane* p, int falpha, int balpha){ c->attrword = vis->attrword; } } - if(falpha > CELL_ALPHA_OPAQUE && cell_get_fg_alpha(vis) < CELL_ALPHA_TRANSPARENT){ - if(falpha == CELL_ALPHA_BLEND){ - cell_blend_fchannel(c, cell_get_fchannel(vis), fgblends); - ++fgblends; - }else{ - cell_set_fchannel(c, cell_get_fchannel(vis)); - } - falpha = cell_get_fg_alpha(vis); + if(cell_get_fg_alpha(c) > CELL_ALPHA_OPAQUE && cell_get_fg_alpha(vis) < CELL_ALPHA_TRANSPARENT){ + cell_blend_fchannel(c, cell_get_fchannel(vis), fgblends); + ++fgblends; } // Background color takes effect independently of whether we have a // glyph. If we've already locked in the background, it has no effect. // If it's transparent, it has no effect. Otherwise, update the // background channel and balpha. - if(balpha > CELL_ALPHA_OPAQUE && cell_get_bg_alpha(vis) < CELL_ALPHA_TRANSPARENT){ - if(balpha == CELL_ALPHA_BLEND){ - cell_blend_bchannel(c, cell_get_bchannel(vis), bgblends); - ++bgblends; - }else{ // balpha == CELL_ALPHA_TRANSPARENT - cell_set_bchannel(c, cell_get_bchannel(vis)); - } - balpha = cell_get_bg_alpha(vis); + if(cell_get_bg_alpha(c) > CELL_ALPHA_OPAQUE && cell_get_bg_alpha(vis) < CELL_ALPHA_TRANSPARENT){ + cell_blend_bchannel(c, cell_get_bchannel(vis), bgblends); + ++bgblends; } // if everything's locked in, we're done - if((glyphplane && falpha == CELL_ALPHA_OPAQUE && balpha == CELL_ALPHA_OPAQUE)){ + if((glyphplane && cell_get_fg_alpha(c) == CELL_ALPHA_OPAQUE && + cell_get_bg_alpha(c) == CELL_ALPHA_OPAQUE)){ return glyphplane; } } @@ -219,7 +210,9 @@ dig_visible_cell(cell* c, int y, int x, ncplane* p, int falpha, int balpha){ static inline ncplane* visible_cell(cell* c, int y, int x, ncplane* n){ cell_init(c); - return dig_visible_cell(c, y, x, n, CELL_ALPHA_TRANSPARENT, CELL_ALPHA_TRANSPARENT); + cell_set_fg_alpha(c, CELL_ALPHA_TRANSPARENT); + cell_set_bg_alpha(c, CELL_ALPHA_TRANSPARENT); + return dig_visible_cell(c, y, x, n); } // write the cell's UTF-8 grapheme cluster to the provided FILE*. returns the diff --git a/tests/channel.cpp b/tests/channel.cpp index 95fb8af25..784e3b436 100644 --- a/tests/channel.cpp +++ b/tests/channel.cpp @@ -112,19 +112,25 @@ TEST_CASE("ChannelBlend2") { CHECK(0x0a == b); } -// you can't blend into a default color, at any number of blends +// you can't blend into a default color at any positive number of blends TEST_CASE("ChannelBlendDefaultLeft") { uint32_t c1 = 0; uint32_t c2 = 0; channel_set_rgb(&c2, 0x80, 0x40, 0x20); - uint32_t c = channels_blend(c1, c2, 0); - CHECK(channel_default_p(c)); + uint32_t c = channels_blend(c1, c2, 0); // will replace + CHECK(!channel_default_p(c)); unsigned r, g, b; channel_get_rgb(c, &r, &g, &b); + CHECK(0x80 == r); + CHECK(0x40 == g); + CHECK(0x20 == b); + c = channels_blend(c1, c2, 1); // will not replace + CHECK(channel_default_p(c)); + channel_get_rgb(c, &r, &g, &b); CHECK(0 == r); CHECK(0 == g); CHECK(0 == b); - c = channels_blend(c1, c2, 1); + c = channels_blend(c1, c2, 2); // will not replace CHECK(channel_default_p(c)); channel_get_rgb(c, &r, &g, &b); CHECK(0 == r); @@ -142,9 +148,9 @@ TEST_CASE("ChannelBlendDefaultRight") { CHECK(channel_default_p(c)); unsigned r, g, b; channel_get_rgb(c, &r, &g, &b); - CHECK(0x80 == r); - CHECK(0x40 == g); - CHECK(0x20 == b); + CHECK(0 == r); + CHECK(0 == g); + CHECK(0 == b); c = channels_blend(c1, c2, 1); CHECK(!channel_default_p(c)); channel_get_rgb(c, &r, &g, &b);