Skip to content

Commit

Permalink
use pigment mode for smudge sampling
Browse files Browse the repository at this point in the history
blend additive and subtractive methods
limit sampling to small percentage of pixels
  • Loading branch information
briend committed Mar 31, 2019
1 parent d180edd commit 635975d
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 40 deletions.
72 changes: 48 additions & 24 deletions brushmodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};


Expand Down
3 changes: 2 additions & 1 deletion brushmodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
);


Expand Down
2 changes: 1 addition & 1 deletion mypaint-brush.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions mypaint-surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}


Expand Down Expand Up @@ -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;
}

Expand Down
6 changes: 4 additions & 2 deletions mypaint-surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
);


Expand Down
15 changes: 6 additions & 9 deletions mypaint-tiled-surface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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)
Expand Down

2 comments on commit 635975d

@jtojnar
Copy link
Contributor

@jtojnar jtojnar commented on 635975d Apr 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we release a new alpha? mypaint-2.0.0-alpha.11 does not build with libmypaint-2.0.0-alpha.1.

@briend
Copy link
Contributor Author

@briend briend commented on 635975d Apr 8, 2019 via email

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.