[gimp/wip/alxsa/mypaint-brush-v2: 59/66] Connecting new parameters to paint output
- From: Alx Sa <sawyeralex src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/alxsa/mypaint-brush-v2: 59/66] Connecting new parameters to paint output
- Date: Sun, 16 Oct 2022 17:45:30 +0000 (UTC)
commit 6d8ea71d9387576a566341b2abcc874c58995103
Author: Alx Sa <cmyk student gmail com>
Date: Tue Oct 4 10:43:27 2022 +0000
Connecting new parameters to paint output
app/paint/gimpmybrushcore.c | 37 +++---
app/paint/gimpmybrushsurface.c | 266 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 276 insertions(+), 27 deletions(-)
---
diff --git a/app/paint/gimpmybrushcore.c b/app/paint/gimpmybrushcore.c
index c8d6c618ef..9fb2f19da7 100644
--- a/app/paint/gimpmybrushcore.c
+++ b/app/paint/gimpmybrushcore.c
@@ -80,7 +80,10 @@ static void gimp_mybrush_core_motion (GimpPaintCore *paint_core
GimpDrawable *drawable,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
- guint32 time);
+ guint32 time,
+ gfloat view_zoom,
+ gfloat view_rotation,
+ gfloat barrel_rotation);
static void gimp_mybrush_core_create_brushes (GimpMybrushCore *mybrush,
GimpDrawable *drawable,
GimpPaintOptions *paint_options,
@@ -231,12 +234,11 @@ gimp_mybrush_core_paint (GimpPaintCore *paint_core,
case GIMP_PAINT_STATE_MOTION:
gimp_mybrush_core_motion (paint_core, drawables->data, paint_options,
- sym, time);
+ sym, time, 1.0f, 0.0f, 0.0f);
break;
case GIMP_PAINT_STATE_FINISH:
gimp_symmetry_set_stateful (sym, FALSE);
- /*mypaint_surface_unref ((MyPaintSurface *) mybrush->private->surface);*/
mybrush->private->surface = NULL;
g_list_free_full (mybrush->private->brushes,
@@ -251,10 +253,14 @@ gimp_mybrush_core_motion (GimpPaintCore *paint_core,
GimpDrawable *drawable,
GimpPaintOptions *paint_options,
GimpSymmetry *sym,
- guint32 time)
+ guint32 time,
+ gfloat view_zoom,
+ gfloat view_rotation,
+ gfloat barrel_rotation)
{
GimpMybrushCore *mybrush = GIMP_MYBRUSH_CORE (paint_core);
MyPaintRectangle rect;
+ MyPaintRectangles rects = {1, &rect};
GList *iter;
gdouble dt = 0.0;
gint off_x, off_y;
@@ -272,7 +278,8 @@ gimp_mybrush_core_motion (GimpPaintCore *paint_core,
gimp_mybrush_core_create_brushes (mybrush, drawable, paint_options, sym);
}
- /*mypaint_surface_begin_atomic ((MyPaintSurface2 *) mybrush->private->surface);*/
+ mypaint_surface_begin_atomic (mypaint_surface2_to_surface (
+ (MyPaintSurface2 *) mybrush->private->surface));
if (mybrush->private->last_time < 0)
{
@@ -292,7 +299,7 @@ gimp_mybrush_core_motion (GimpPaintCore *paint_core,
coords.xtilt,
coords.ytilt,
1.0f, /* Pretend the cursor hasn't moved in a while */
- 1.0f, 1.0f, 1.0f);
+ view_zoom, view_rotation, barrel_rotation);
}
dt = 0.015;
@@ -325,22 +332,22 @@ gimp_mybrush_core_motion (GimpPaintCore *paint_core,
coords.xtilt,
coords.ytilt,
dt,
- 1.0f, 1.0f, 1.0f);
+ view_zoom, view_rotation, barrel_rotation);
}
mybrush->private->last_time = time;
- /*mypaint_surface_end_atomic ((MyPaintSurface2 *) mybrush->private->surface,
- &rect);*/
+ mypaint_surface2_end_atomic ((MyPaintSurface2 *) mybrush->private->surface,
+ &rects);
- if (rect.width > 0 && rect.height > 0)
+ if (rects.rectangles[0].width > 0 && rects.rectangles[0].height > 0)
{
- paint_core->x1 = MIN (paint_core->x1, rect.x);
- paint_core->y1 = MIN (paint_core->y1, rect.y);
- paint_core->x2 = MAX (paint_core->x2, rect.x + rect.width);
- paint_core->y2 = MAX (paint_core->y2, rect.y + rect.height);
+ paint_core->x1 = MIN (paint_core->x1, rects.rectangles[0].x);
+ paint_core->y1 = MIN (paint_core->y1, rects.rectangles[0].y);
+ paint_core->x2 = MAX (paint_core->x2, rects.rectangles[0].x + rects.rectangles[0].width);
+ paint_core->y2 = MAX (paint_core->y2, rects.rectangles[0].y + rects.rectangles[0].height);
- gimp_drawable_update (drawable, rect.x, rect.y, rect.width, rect.height);
+ gimp_drawable_update (drawable, rects.rectangles[0].x, rects.rectangles[0].y,
rects.rectangles[0].width, rects.rectangles[0].height);
}
}
diff --git a/app/paint/gimpmybrushsurface.c b/app/paint/gimpmybrushsurface.c
index 5e4ae76195..7f0b78ac8e 100644
--- a/app/paint/gimpmybrushsurface.c
+++ b/app/paint/gimpmybrushsurface.c
@@ -593,6 +593,153 @@ gimp_mypaint_surface_draw_dab_2 (MyPaintSurface2 *base_surface,
float paint)
{
/* Placeholder - eventually implement here */
+ GimpMybrushSurface2 *surface = (GimpMybrushSurface2 *) base_surface;
+ GeglBufferIterator *iter;
+ GeglRectangle dabRect;
+ GimpComponentMask component_mask = surface->component_mask;
+
+ const float one_over_radius2 = 1.0f / (radius * radius);
+ const double angle_rad = angle / 360 * 2 * M_PI;
+ const float cs = cos(angle_rad);
+ const float sn = sin(angle_rad);
+ float normal_mode;
+ float segment1_slope;
+ float segment2_slope;
+ float r_aa_start;
+
+ hardness = CLAMP (hardness, 0.0f, 1.0f);
+ segment1_slope = -(1.0f / hardness - 1.0f);
+ segment2_slope = -hardness / (1.0f - hardness);
+ aspect_ratio = MAX (1.0f, aspect_ratio);
+
+ r_aa_start = radius - 1.0f;
+ r_aa_start = MAX (r_aa_start, 0);
+ r_aa_start = (r_aa_start * r_aa_start) / aspect_ratio;
+
+ normal_mode = opaque * (1.0f - colorize);
+ colorize = opaque * colorize;
+
+ /* FIXME: This should use the real matrix values to trim aspect_ratio dabs */
+ dabRect = calculate_dab_roi (x, y, radius);
+ gegl_rectangle_intersect (&dabRect, &dabRect, gegl_buffer_get_extent (surface->buffer));
+
+ if (dabRect.width <= 0 || dabRect.height <= 0)
+ return 0;
+
+ gegl_rectangle_bounding_box (&surface->dirty, &surface->dirty, &dabRect);
+
+ iter = gegl_buffer_iterator_new (surface->buffer, &dabRect, 0,
+ babl_format ("R'G'B'A float"),
+ GEGL_BUFFER_READWRITE,
+ GEGL_ABYSS_NONE, 2);
+ if (surface->paint_mask)
+ {
+ GeglRectangle mask_roi = dabRect;
+ mask_roi.x -= surface->paint_mask_x;
+ mask_roi.y -= surface->paint_mask_y;
+ gegl_buffer_iterator_add (iter, surface->paint_mask, &mask_roi, 0,
+ babl_format ("Y float"),
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+ }
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ float *pixel = (float *)iter->items[0].data;
+ float *mask;
+ int iy, ix;
+
+ if (surface->paint_mask)
+ mask = iter->items[1].data;
+ else
+ mask = NULL;
+
+ for (iy = iter->items[0].roi.y; iy < iter->items[0].roi.y + iter->items[0].roi.height; iy++)
+ {
+ for (ix = iter->items[0].roi.x; ix < iter->items[0].roi.x + iter->items[0].roi.width; ix++)
+ {
+ float rr, base_alpha, alpha, dst_alpha, r, g, b, a;
+ if (radius < 3.0f)
+ rr = calculate_rr_antialiased (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2,
r_aa_start);
+ else
+ rr = calculate_rr (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2);
+ base_alpha = calculate_alpha_for_rr (rr, hardness, segment1_slope, segment2_slope);
+ alpha = base_alpha * normal_mode;
+ if (mask)
+ alpha *= *mask;
+ dst_alpha = pixel[ALPHA];
+ /* a = alpha * color_a + dst_alpha * (1.0f - alpha);
+ * which converts to: */
+ a = alpha * (color_a - dst_alpha) + dst_alpha;
+ r = pixel[RED];
+ g = pixel[GREEN];
+ b = pixel[BLUE];
+
+ if (a > 0.0f)
+ {
+ /* By definition the ratio between each color[] and pixel[] component in a
non-pre-multipled blend always sums to 1.0f.
+ * Originally this would have been "(color[n] * alpha * color_a + pixel[n] * dst_alpha *
(1.0f - alpha)) / a",
+ * instead we only calculate the cheaper term. */
+ float src_term = (alpha * color_a) / a;
+ float dst_term = 1.0f - src_term;
+ r = color_r * src_term + r * dst_term;
+ g = color_g * src_term + g * dst_term;
+ b = color_b * src_term + b * dst_term;
+ }
+
+ if (colorize > 0.0f && base_alpha > 0.0f)
+ {
+ alpha = base_alpha * colorize;
+ a = alpha + dst_alpha - alpha * dst_alpha;
+ if (a > 0.0f)
+ {
+ GimpHSL pixel_hsl, out_hsl;
+ GimpRGB pixel_rgb = {color_r, color_g, color_b};
+ GimpRGB out_rgb = {r, g, b};
+ float src_term = alpha / a;
+ float dst_term = 1.0f - src_term;
+
+ gimp_rgb_to_hsl (&pixel_rgb, &pixel_hsl);
+ gimp_rgb_to_hsl (&out_rgb, &out_hsl);
+
+ out_hsl.h = pixel_hsl.h;
+ out_hsl.s = pixel_hsl.s;
+ gimp_hsl_to_rgb (&out_hsl, &out_rgb);
+
+ r = (float)out_rgb.r * src_term + r * dst_term;
+ g = (float)out_rgb.g * src_term + g * dst_term;
+ b = (float)out_rgb.b * src_term + b * dst_term;
+ }
+ }
+
+ if (surface->options->no_erasing)
+ a = MAX (a, pixel[ALPHA]);
+
+ if (component_mask != GIMP_COMPONENT_MASK_ALL)
+ {
+ if (component_mask & GIMP_COMPONENT_MASK_RED)
+ pixel[RED] = r;
+ if (component_mask & GIMP_COMPONENT_MASK_GREEN)
+ pixel[GREEN] = g;
+ if (component_mask & GIMP_COMPONENT_MASK_BLUE)
+ pixel[BLUE] = b;
+ if (component_mask & GIMP_COMPONENT_MASK_ALPHA)
+ pixel[ALPHA] = a;
+ }
+ else
+ {
+ pixel[RED] = r;
+ pixel[GREEN] = g;
+ pixel[BLUE] = b;
+ pixel[ALPHA] = a;
+ }
+
+ pixel += 4;
+ if (mask)
+ mask += 1;
+ }
+ }
+ }
+
return 1;
}
@@ -636,6 +783,99 @@ gimp_mypaint_surface_get_color_2 (MyPaintSurface2 *base_surface,
float paint)
{
/* Placeholder - eventually implement here */
+ GimpMybrushSurface2 *surface = (GimpMybrushSurface2 *) base_surface;
+ GeglRectangle dabRect;
+
+ if (radius < 1.0f)
+ radius = 1.0f;
+
+ dabRect = calculate_dab_roi (x, y, radius);
+
+ *color_r = 0.0f;
+ *color_g = 0.0f;
+ *color_b = 0.0f;
+ *color_a = 0.0f;
+
+ if (dabRect.width > 0 || dabRect.height > 0)
+ {
+ const float one_over_radius2 = 1.0f / (radius * radius);
+ float sum_weight = 0.0f;
+ float sum_r = 0.0f;
+ float sum_g = 0.0f;
+ float sum_b = 0.0f;
+ float sum_a = 0.0f;
+
+ /* Read in clamp mode to avoid transparency bleeding in at the edges */
+ GeglBufferIterator *iter = gegl_buffer_iterator_new (surface->buffer, &dabRect, 0,
+ babl_format ("R'aG'aB'aA float"),
+ GEGL_BUFFER_READ,
+ GEGL_ABYSS_CLAMP, 2);
+ if (surface->paint_mask)
+ {
+ GeglRectangle mask_roi = dabRect;
+ mask_roi.x -= surface->paint_mask_x;
+ mask_roi.y -= surface->paint_mask_y;
+ gegl_buffer_iterator_add (iter, surface->paint_mask, &mask_roi, 0,
+ babl_format ("Y float"),
+ GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+ }
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ float *pixel = (float *)iter->items[0].data;
+ float *mask;
+ int iy, ix;
+
+ if (surface->paint_mask)
+ mask = iter->items[1].data;
+ else
+ mask = NULL;
+
+ for (iy = iter->items[0].roi.y; iy < iter->items[0].roi.y + iter->items[0].roi.height; iy++)
+ {
+ float yy = (iy + 0.5f - y);
+ for (ix = iter->items[0].roi.x; ix < iter->items[0].roi.x + iter->items[0].roi.width; ix++)
+ {
+ /* pixel_weight == a standard dab with hardness = 0.5, aspect_ratio = 1.0, and angle = 0.0 */
+ float xx = (ix + 0.5f - x);
+ float rr = (yy * yy + xx * xx) * one_over_radius2;
+ float pixel_weight = 0.0f;
+ if (rr <= 1.0f)
+ pixel_weight = 1.0f - rr;
+ if (mask)
+ pixel_weight *= *mask;
+
+ sum_r += pixel_weight * pixel[RED];
+ sum_g += pixel_weight * pixel[GREEN];
+ sum_b += pixel_weight * pixel[BLUE];
+ sum_a += pixel_weight * pixel[ALPHA];
+ sum_weight += pixel_weight;
+
+ pixel += 4;
+ if (mask)
+ mask += 1;
+ }
+ }
+ }
+
+ if (sum_a > 0.0f && sum_weight > 0.0f)
+ {
+ sum_r /= sum_weight;
+ sum_g /= sum_weight;
+ sum_b /= sum_weight;
+ sum_a /= sum_weight;
+
+ sum_r /= sum_a;
+ sum_g /= sum_a;
+ sum_b /= sum_a;
+
+ /* FIXME: Clamping is wrong because GEGL allows alpha > 1, this should probably re-multipy things */
+ *color_r = CLAMP(sum_r, 0.0f, 1.0f);
+ *color_g = CLAMP(sum_g, 0.0f, 1.0f);
+ *color_b = CLAMP(sum_b, 0.0f, 1.0f);
+ *color_a = CLAMP(sum_a, 0.0f, 1.0f);
+ }
+ }
}
@@ -667,10 +907,10 @@ gimp_mypaint_surface_end_atomic_2 (MyPaintSurface2 *base_surface,
for (gint i = 0; i < roi_rects; i++)
{
- roi->rectangles[i].x = 0;
- roi->rectangles[i].y = 0;
- roi->rectangles[i].width = 0;
- roi->rectangles[i].height = 0;
+ roi->rectangles[i].x = surface->dirty.x;
+ roi->rectangles[i].y = surface->dirty.y;
+ roi->rectangles[i].width = surface->dirty.width;
+ roi->rectangles[i].height = surface->dirty.height;
surface->dirty = *GEGL_RECTANGLE (0, 0, 0, 0);
}
}
@@ -693,17 +933,19 @@ gimp_mypaint_surface2_new (GeglBuffer *buffer,
GimpMybrushOptions *options)
{
GimpMybrushSurface2 *surface = g_malloc0 (sizeof (GimpMybrushSurface2));
+ MyPaintSurface2 *s;
mypaint_surface_init (&surface->surface.parent);
+ s = &surface->surface;
- surface->surface.get_color_pigment = gimp_mypaint_surface_get_color_2;
- surface->surface.draw_dab_pigment = gimp_mypaint_surface_draw_dab_2;
- surface->surface.parent.begin_atomic = gimp_mypaint_surface_begin_atomic;
- surface->surface.end_atomic_multi = gimp_mypaint_surface_end_atomic_2;
+ s->get_color_pigment = gimp_mypaint_surface_get_color_2;
+ s->draw_dab_pigment = gimp_mypaint_surface_draw_dab_2;
+ s->parent.begin_atomic = gimp_mypaint_surface_begin_atomic;
+ s->end_atomic_multi = gimp_mypaint_surface_end_atomic_2;
- surface->surface.parent.draw_dab = gimp_mypaint_surface_draw_dab_wrapper;
- surface->surface.parent.get_color = gimp_mypaint_surface_get_color_wrapper;
- surface->surface.parent.end_atomic = gimp_mypaint_surface_end_atomic_wrapper;
+ s->parent.draw_dab = gimp_mypaint_surface_draw_dab_wrapper;
+ s->parent.get_color = gimp_mypaint_surface_get_color_wrapper;
+ s->parent.end_atomic = gimp_mypaint_surface_end_atomic_wrapper;
surface->component_mask = component_mask;
surface->options = options;
@@ -716,4 +958,4 @@ gimp_mypaint_surface2_new (GeglBuffer *buffer,
surface->dirty = *GEGL_RECTANGLE (0, 0, 0, 0);
return surface;
-}
\ No newline at end of file
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]