diff --git a/brushmodes.c b/brushmodes.c index bbcad09a..2e291931 100644 --- a/brushmodes.c +++ b/brushmodes.c @@ -446,42 +446,66 @@ void get_color_pixels_accumulate (uint16_t * mask, float * sum_r, float * sum_g, float * sum_b, - float * sum_a + float * sum_a, + float paint ) { - // The sum of a 64x64 tile fits into a 32 bit integer, but the sum - // of an arbitrary number of tiles may not fit. We assume that we - // are processing a single tile at a time, so we can use integers. - // But for the result we need floats. + // Sample the canvas as additive and subtractive + // According to paint parameter + // Average the results normally + // Only sample a random selection of pixels - uint32_t weight = 0; - uint32_t r = 0; - uint32_t g = 0; - uint32_t b = 0; - uint32_t a = 0; + float avg_spectral[10] = {0}; + float avg_rgb[3] = {*sum_r, *sum_g, *sum_b}; + if (paint > 0.0f) { + rgb_to_spectral(*sum_r, *sum_g, *sum_b, avg_spectral); + } while (1) { for (; mask[0]; mask++, rgba+=4) { - uint32_t opa = mask[0]; - weight += opa; - r += opa*rgba[0]/(1<<15); - g += opa*rgba[1]/(1<<15); - b += opa*rgba[2]/(1<<15); - a += opa*rgba[3]/(1<<15); - + // sample at least one pixel but then only 1% + if (rand() % 100 != 0 && *sum_a > 0.0) { + continue; + } + float a = (float)mask[0] * rgba[3] / (1<<30); + float alpha_sums = a + *sum_a; + *sum_weight += (float)mask[0] / (1<<15); + float fac_a, fac_b; + fac_a = fac_b = 1.0f; + if (alpha_sums > 0.0f) { + fac_a = a / alpha_sums; + fac_b = 1.0 - fac_a; + } + if (paint > 0.0f) { + float spectral[10] = {0}; + if (rgba[3] > 0) { + rgb_to_spectral((float)rgba[0] / rgba[3], (float)rgba[1] / rgba[3], (float)rgba[2] / rgba[3], spectral); + for (int i=0; i<10; i++) { + avg_spectral[i] = fastpow(spectral[i], fac_a) * fastpow(avg_spectral[i], fac_b); + } + } + } + if (paint < 1.0f) { + if (rgba[3] > 0) { + for (int i=0; i<3; i++) { + avg_rgb[i] = (float)rgba[i] * fac_a / rgba[3] + (float)avg_rgb[i] * fac_b; + } + } + } + *sum_a += a; } + float spec_rgb[3] = {0}; + spectral_to_rgb(avg_spectral, spec_rgb); + + *sum_r = spec_rgb[0] * paint + (1.0 - paint) * avg_rgb[0]; + *sum_g = spec_rgb[1] * paint + (1.0 - paint) * avg_rgb[1]; + *sum_b = spec_rgb[2] * paint + (1.0 - paint) * avg_rgb[2]; + if (!mask[1]) break; rgba += mask[1]; mask += 2; } - - // convert integer to float outside the performance critical loop - *sum_weight += weight; - *sum_r += r; - *sum_g += g; - *sum_b += b; - *sum_a += a; }; diff --git a/brushmodes.h b/brushmodes.h index c8e47e20..30485d83 100644 --- a/brushmodes.h +++ b/brushmodes.h @@ -63,7 +63,8 @@ void get_color_pixels_accumulate (uint16_t * mask, float * sum_r, float * sum_g, float * sum_b, - float * sum_a + float * sum_a, + float paint ); diff --git a/mypaint-brush.c b/mypaint-brush.c index e0f1a1d1..41c90eee 100755 --- a/mypaint-brush.c +++ b/mypaint-brush.c @@ -828,7 +828,7 @@ mypaint_brush_set_state(MyPaintBrush *self, MyPaintBrushState i, float value) float smudge_radius = radius * fasterexp(self->settings_value[MYPAINT_BRUSH_SETTING_SMUDGE_RADIUS_LOG]); smudge_radius = CLAMP(smudge_radius, ACTUAL_RADIUS_MIN, ACTUAL_RADIUS_MAX); - mypaint_surface_get_color(surface, px, py, smudge_radius, &r, &g, &b, &a); + mypaint_surface_get_color(surface, px, py, smudge_radius, &r, &g, &b, &a, self->settings_value[MYPAINT_BRUSH_SETTING_PAINT_MODE]); //don't draw unless the picked-up alpha is above a certain level diff --git a/mypaint-surface.c b/mypaint-surface.c index 8d89cc0c..ec6ee235 100644 --- a/mypaint-surface.c +++ b/mypaint-surface.c @@ -49,11 +49,12 @@ void mypaint_surface_get_color(MyPaintSurface *self, float x, float y, float radius, - float * color_r, float * color_g, float * color_b, float * color_a + float * color_r, float * color_g, float * color_b, float * color_a, + float paint ) { assert(self->get_color); - self->get_color(self, x, y, radius, color_r, color_g, color_b, color_a); + self->get_color(self, x, y, radius, color_r, color_g, color_b, color_a, paint); } @@ -98,7 +99,7 @@ mypaint_surface_unref(MyPaintSurface *self) float mypaint_surface_get_alpha (MyPaintSurface *self, float x, float y, float radius) { float color_r, color_g, color_b, color_a; - mypaint_surface_get_color (self, x, y, radius, &color_r, &color_g, &color_b, &color_a); + mypaint_surface_get_color (self, x, y, radius, &color_r, &color_g, &color_b, &color_a, 1.0); return color_a; } diff --git a/mypaint-surface.h b/mypaint-surface.h index 9fae02df..26aa5d8b 100644 --- a/mypaint-surface.h +++ b/mypaint-surface.h @@ -28,7 +28,8 @@ typedef struct MyPaintSurface MyPaintSurface; typedef void (*MyPaintSurfaceGetColorFunction) (MyPaintSurface *self, float x, float y, float radius, - float * color_r, float * color_g, float * color_b, float * color_a + float * color_r, float * color_g, float * color_b, float * color_a, + float paint ); typedef int (*MyPaintSurfaceDrawDabFunction) (MyPaintSurface *self, @@ -93,7 +94,8 @@ void mypaint_surface_get_color(MyPaintSurface *self, float x, float y, float radius, - float * color_r, float * color_g, float * color_b, float * color_a + float * color_r, float * color_g, float * color_b, float * color_a, + float paint ); diff --git a/mypaint-tiled-surface.c b/mypaint-tiled-surface.c index 1f9ae4a7..8ea257cc 100644 --- a/mypaint-tiled-surface.c +++ b/mypaint-tiled-surface.c @@ -776,7 +776,8 @@ int draw_dab (MyPaintSurface *surface, float x, float y, void get_color (MyPaintSurface *surface, float x, float y, float radius, - float * color_r, float * color_g, float * color_b, float * color_a + float * color_r, float * color_g, float * color_b, float * color_a, + float paint ) { MyPaintTiledSurface *self = (MyPaintTiledSurface *)surface; @@ -839,7 +840,7 @@ void get_color (MyPaintSurface *surface, float x, float y, #pragma omp critical { get_color_pixels_accumulate (mask, rgba_p, - &sum_weight, &sum_r, &sum_g, &sum_b, &sum_a); + &sum_weight, &sum_r, &sum_g, &sum_b, &sum_a, paint); } mypaint_tiled_surface_tile_request_end(self, &request_data); @@ -848,16 +849,12 @@ void get_color (MyPaintSurface *surface, float x, float y, assert(sum_weight > 0.0f); sum_a /= sum_weight; - sum_r /= sum_weight; - sum_g /= sum_weight; - sum_b /= sum_weight; - *color_a = sum_a; // now un-premultiply the alpha if (sum_a > 0.0f) { - *color_r = sum_r / sum_a; - *color_g = sum_g / sum_a; - *color_b = sum_b / sum_a; + *color_r = sum_r; + *color_g = sum_g; + *color_b = sum_b; } else { // it is all transparent, so don't care about the colors // (let's make them ugly so bugs will be visible)