don't blend default colors #235

pull/238/head
nick black 5 years ago
parent f48cdd2a0e
commit 924d80f0d5
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -11,14 +11,11 @@ notcurses_cell(3) -- operations on notcurses cells
uint64_t channels;
} cell;</pre>
`#define CELL_TRIVIAL_INITIALIZER \
{ .gcluster = '\0', .attrword = 0, .channels = 0, }`
`#define CELL_TRIVIAL_INITIALIZER { .gcluster = '\0', .attrword = 0, .channels = 0, }`
`#define CELL_SIMPLE_INITIALIZER(c) \
{ .gcluster = (c), .attrword = 0, .channels = 0, }`
`#define CELL_SIMPLE_INITIALIZER(c) { .gcluster = (c), .attrword = 0, .channels = 0, }`
`#define CELL_INITIALIZER(c, a, chan) \
{ .gcluster = (c), .attrword = (a), .channels = (chan), }`
`#define CELL_INITIALIZER(c, a, chan) { .gcluster = (c), .attrword = (a), .channels = (chan), }`
`void cell_init(cell* c);`

@ -1002,13 +1002,19 @@ channels_set_bg_default(uint64_t* channels){
// Returns the result of blending two channels.
static inline unsigned
channels_blend(unsigned c1, unsigned c2){
channels_blend(unsigned c1, unsigned c2, unsigned blends){
if(channel_default_p(c1)){
return c1;
}
int rsum = (channel_get_r(c1) + channel_get_r(c2)) / 2;
int gsum = (channel_get_g(c1) + channel_get_g(c2)) / 2;
int bsum = (channel_get_b(c1) + channel_get_b(c2)) / 2;
if(channel_default_p(c2)){
if(blends == 0){
channel_set_default(&c1);
}
return 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);
unsigned blend = 0;
channel_set_rgb(&blend, rsum, gsum, bsum);
return blend;
@ -1039,13 +1045,13 @@ cell_set_fchannel(cell* cl, uint32_t channel){
}
static inline uint64_t
cell_blend_fchannel(cell* cl, unsigned channel){
return cell_set_fchannel(cl, channels_blend(cell_get_fchannel(cl), channel));
cell_blend_fchannel(cell* cl, unsigned channel, unsigned blends){
return cell_set_fchannel(cl, channels_blend(cell_get_fchannel(cl), channel, blends));
}
static inline uint64_t
cell_blend_bchannel(cell* cl, unsigned channel){
return cell_set_bchannel(cl, channels_blend(cell_get_bchannel(cl), channel));
cell_blend_bchannel(cell* cl, unsigned channel, unsigned blends){
return cell_set_bchannel(cl, channels_blend(cell_get_bchannel(cl), channel, blends));
}
// Extract 24 bits of foreground RGB from 'cell', shifted to LSBs.

@ -147,6 +147,8 @@ reshape_shadow_fb(notcurses* nc){
// 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;
// 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,7 +180,8 @@ dig_visible_cell(cell* c, int y, int x, ncplane* p, int falpha, int balpha){
}
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));
cell_blend_fchannel(c, cell_get_fchannel(vis), fgblends);
++fgblends;
}else{
cell_set_fchannel(c, cell_get_fchannel(vis));
}
@ -190,7 +193,8 @@ dig_visible_cell(cell* c, int y, int x, ncplane* p, int falpha, int balpha){
// 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));
cell_blend_bchannel(c, cell_get_bchannel(vis), bgblends);
++bgblends;
}else{ // balpha == CELL_ALPHA_TRANSPARENT
cell_set_bchannel(c, cell_get_bchannel(vis));
}

@ -66,3 +66,72 @@ TEST_CASE("ChannelSetDefault") {
CHECK(channel_default_p(channel));
}
}
// blend of 0 ought perfectly set
TEST_CASE("ChannelBlend0") {
uint32_t c1 = 0;
uint32_t c2 = 0;
channel_set_rgb(&c1, 0x80, 0x40, 0x20);
channel_set_rgb(&c2, 0x88, 0x44, 0x22);
uint32_t c = channels_blend(c1, c2, 0);
unsigned r, g, b;
channel_get_rgb(c, &r, &g, &b);
CHECK(0x88 == r);
CHECK(0x44 == g);
CHECK(0x22 == b);
}
// blend of 1 ought perfectly average
TEST_CASE("ChannelBlend1") {
uint32_t c1 = 0;
uint32_t c2 = 0;
channel_set_rgb(&c1, 0x80, 0x40, 0x20);
channel_set_rgb(&c2, 0x0, 0x0, 0x0);
uint32_t c = channels_blend(c1, c2, 1);
unsigned r, g, b;
channel_get_rgb(c, &r, &g, &b);
CHECK(0x40 == r);
CHECK(0x20 == g);
CHECK(0x10 == b);
}
// you can't blend into a default color, at any 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));
unsigned r, g, b;
channel_get_rgb(c, &r, &g, &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);
CHECK(0 == r);
CHECK(0 == g);
CHECK(0 == b);
}
// you can't blend from a default color, but blend 0 sets it
TEST_CASE("ChannelBlendDefaultRight") {
uint32_t c1 = 0;
uint32_t c2 = 0;
channel_set_rgb(&c1, 0x80, 0x40, 0x20);
CHECK(channel_default_p(c2));
uint32_t c = channels_blend(c1, c2, 0);
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);
CHECK(!channel_default_p(c));
channel_get_rgb(c, &r, &g, &b);
CHECK(0x80 == r);
CHECK(0x40 == g);
CHECK(0x20 == b);
}

Loading…
Cancel
Save