diff --git a/app/paint/Makefile.am b/app/paint/Makefile.am index 8343c01559..c2c72e2a7e 100644 --- a/app/paint/Makefile.am +++ b/app/paint/Makefile.am @@ -55,6 +55,8 @@ libapppaint_a_sources = \ gimpinkundo.h \ gimppaintcore.c \ gimppaintcore.h \ + gimppaintcore-loops.c \ + gimppaintcore-loops.h \ gimppaintcore-stroke.c \ gimppaintcore-stroke.h \ gimppaintcoreundo.c \ diff --git a/app/paint/gimpbrushcore.c b/app/paint/gimpbrushcore.c index 07ad88fd7f..02dbd6d873 100644 --- a/app/paint/gimpbrushcore.c +++ b/app/paint/gimpbrushcore.c @@ -822,10 +822,17 @@ gimp_brush_core_get_paint_buffer (GimpPaintCore *paint_core, if ((x2 - x1) && (y2 - y1)) { GimpTempBuf *temp_buf; + const Babl *format; + + if (gimp_drawable_get_linear (drawable)) + format = babl_format ("RGBA float"); + else + format = babl_format ("R'G'B'A float"); if (paint_core->paint_buffer && gegl_buffer_get_width (paint_core->paint_buffer) == (x2 - x1) && - gegl_buffer_get_height (paint_core->paint_buffer) == (y2 - y1)) + gegl_buffer_get_height (paint_core->paint_buffer) == (y2 - y1) && + gegl_buffer_get_format (paint_core->paint_buffer) == format ) { *paint_buffer_x = x1; *paint_buffer_y = y1; @@ -834,7 +841,7 @@ gimp_brush_core_get_paint_buffer (GimpPaintCore *paint_core, } temp_buf = gimp_temp_buf_new ((x2 - x1), (y2 - y1), - babl_format ("RGBA float")); + format); *paint_buffer_x = x1; *paint_buffer_y = y1; @@ -939,7 +946,6 @@ gimp_brush_core_paste_canvas (GimpBrushCore *core, if (brush_mask) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (core); - GeglBuffer *paint_mask; gint x; gint y; gint off_x; @@ -951,18 +957,12 @@ gimp_brush_core_paste_canvas (GimpBrushCore *core, off_x = (x < 0) ? -x : 0; off_y = (y < 0) ? -y : 0; - paint_mask = gimp_temp_buf_create_buffer ((GimpTempBuf *) brush_mask); - - gimp_paint_core_paste (paint_core, paint_mask, - GEGL_RECTANGLE (off_x, off_y, - gegl_buffer_get_width (paint_core->paint_buffer), - gegl_buffer_get_height (paint_core->paint_buffer)), + gimp_paint_core_paste (paint_core, brush_mask, + off_x, off_y, drawable, brush_opacity, image_opacity, paint_mode, mode); - - g_object_unref (paint_mask); } } @@ -989,7 +989,6 @@ gimp_brush_core_replace_canvas (GimpBrushCore *core, if (brush_mask) { GimpPaintCore *paint_core = GIMP_PAINT_CORE (core); - GeglBuffer *paint_mask; gint x; gint y; gint off_x; @@ -1001,18 +1000,12 @@ gimp_brush_core_replace_canvas (GimpBrushCore *core, off_x = (x < 0) ? -x : 0; off_y = (y < 0) ? -y : 0; - paint_mask = gimp_temp_buf_create_buffer ((GimpTempBuf *) brush_mask); - - gimp_paint_core_replace (paint_core, paint_mask, - GEGL_RECTANGLE (off_x, off_y, - gegl_buffer_get_width (paint_core->paint_buffer), - gegl_buffer_get_height (paint_core->paint_buffer)), + gimp_paint_core_replace (paint_core, brush_mask, + off_x, off_y, drawable, brush_opacity, image_opacity, mode); - - g_object_unref (paint_mask); } } diff --git a/app/paint/gimpink.c b/app/paint/gimpink.c index b84fdd0983..b2366459ec 100644 --- a/app/paint/gimpink.c +++ b/app/paint/gimpink.c @@ -220,9 +220,15 @@ gimp_ink_get_paint_buffer (GimpPaintCore *paint_core, if ((x2 - x1) && (y2 - y1)) { GimpTempBuf *temp_buf; + const Babl *format; + + if (gimp_drawable_get_linear (drawable)) + format = babl_format ("RGBA float"); + else + format = babl_format ("R'G'B'A float"); temp_buf = gimp_temp_buf_new ((x2 - x1), (y2 - y1), - babl_format ("RGBA float")); + format); *paint_buffer_x = x1; *paint_buffer_y = y1; @@ -332,11 +338,9 @@ gimp_ink_motion (GimpPaintCore *paint_core, /* draw the paint_area using the just rendered canvas_buffer as mask */ gimp_paint_core_paste (paint_core, - paint_core->canvas_buffer, - GEGL_RECTANGLE (paint_core->paint_buffer_x, - paint_core->paint_buffer_y, - gegl_buffer_get_width (paint_core->paint_buffer), - gegl_buffer_get_height (paint_core->paint_buffer)), + NULL, + paint_core->paint_buffer_x, + paint_core->paint_buffer_y, drawable, GIMP_OPACITY_OPAQUE, gimp_context_get_opacity (context), diff --git a/app/paint/gimppaintcore-loops.c b/app/paint/gimppaintcore-loops.c new file mode 100644 index 0000000000..a7b74b31e6 --- /dev/null +++ b/app/paint/gimppaintcore-loops.c @@ -0,0 +1,415 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 2013 Daniel Sabo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include + +#include "paint-types.h" + +#include "core/gimptempbuf.h" +#include "gimppaintcore-loops.h" +#include "operations/gimplayermodefunctions.h" + +void +combine_paint_mask_to_canvas_mask (const GimpTempBuf *paint_mask, + gint mask_x_offset, + gint mask_y_offset, + GeglBuffer *canvas_buffer, + gint x_offset, + gint y_offset, + gfloat opacity, + gboolean stipple) +{ + GeglRectangle roi; + GeglBufferIterator *iter; + + const gint mask_stride = gimp_temp_buf_get_width (paint_mask); + const gint mask_start_offset = mask_y_offset * mask_stride + mask_x_offset; + const Babl *mask_format = gimp_temp_buf_get_format (paint_mask); + + roi.x = x_offset; + roi.y = y_offset; + roi.width = gimp_temp_buf_get_width (paint_mask) - mask_x_offset; + roi.height = gimp_temp_buf_get_height (paint_mask) - mask_y_offset; + + iter = gegl_buffer_iterator_new (canvas_buffer, &roi, 0, + babl_format ("Y float"), + GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE); + + if (stipple) + { + if (mask_format == babl_format ("Y u8")) + { + const guint8 *mask_data = (const guint8 *) gimp_temp_buf_get_data (paint_mask); + mask_data += mask_start_offset; + + while (gegl_buffer_iterator_next (iter)) + { + gfloat *out_pixel = (gfloat *)iter->data[0]; + int iy, ix; + + for (iy = 0; iy < iter->roi[0].height; iy++) + { + int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x; + const guint8 *mask_pixel = &mask_data[mask_offset]; + + for (ix = 0; ix < iter->roi[0].width; ix++) + { + out_pixel[0] += (1.0 - out_pixel[0]) * (*mask_pixel / 255.0f) * opacity; + + mask_pixel += 1; + out_pixel += 1; + } + } + } + } + else if (mask_format == babl_format ("Y float")) + { + const gfloat *mask_data = (const gfloat *) gimp_temp_buf_get_data (paint_mask); + mask_data += mask_start_offset; + + while (gegl_buffer_iterator_next (iter)) + { + gfloat *out_pixel = (gfloat *)iter->data[0]; + int iy, ix; + + for (iy = 0; iy < iter->roi[0].height; iy++) + { + int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x; + const gfloat *mask_pixel = &mask_data[mask_offset]; + + for (ix = 0; ix < iter->roi[0].width; ix++) + { + out_pixel[0] += (1.0 - out_pixel[0]) * (*mask_pixel) * opacity; + + mask_pixel += 1; + out_pixel += 1; + } + } + } + } + else + { + g_warning("Mask format not supported: %s", babl_get_name (mask_format)); + } + } + else + { + if (mask_format == babl_format ("Y u8")) + { + const guint8 *mask_data = (const guint8 *) gimp_temp_buf_get_data (paint_mask); + mask_data += mask_start_offset; + + while (gegl_buffer_iterator_next (iter)) + { + gfloat *out_pixel = (gfloat *)iter->data[0]; + int iy, ix; + + for (iy = 0; iy < iter->roi[0].height; iy++) + { + int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x; + const guint8 *mask_pixel = &mask_data[mask_offset]; + + for (ix = 0; ix < iter->roi[0].width; ix++) + { + if (opacity > out_pixel[0]) + out_pixel[0] += (opacity - out_pixel[0]) * (*mask_pixel / 255.0f) * opacity; + + mask_pixel += 1; + out_pixel += 1; + } + } + } + } + else if (mask_format == babl_format ("Y float")) + { + const gfloat *mask_data = (const gfloat *) gimp_temp_buf_get_data (paint_mask); + mask_data += mask_start_offset; + + while (gegl_buffer_iterator_next (iter)) + { + gfloat *out_pixel = (gfloat *)iter->data[0]; + int iy, ix; + + for (iy = 0; iy < iter->roi[0].height; iy++) + { + int mask_offset = (iy + iter->roi[0].y - roi.y) * mask_stride + iter->roi[0].x - roi.x; + const gfloat *mask_pixel = &mask_data[mask_offset]; + + for (ix = 0; ix < iter->roi[0].width; ix++) + { + if (opacity > out_pixel[0]) + out_pixel[0] += (opacity - out_pixel[0]) * (*mask_pixel) * opacity; + + mask_pixel += 1; + out_pixel += 1; + } + } + } + } + else + { + g_warning("Mask format not supported: %s", babl_get_name (mask_format)); + } + } +} + +void +canvas_buffer_to_paint_buf_alpha (GimpTempBuf *paint_buf, + GeglBuffer *canvas_buffer, + gint x_offset, + gint y_offset) +{ + /* Copy the canvas buffer in rect to the paint buffer's alpha channel */ + GeglRectangle roi; + GeglBufferIterator *iter; + + const guint paint_stride = gimp_temp_buf_get_width (paint_buf); + gfloat *paint_data = (gfloat *) gimp_temp_buf_get_data (paint_buf); + + roi.x = x_offset; + roi.y = y_offset; + roi.width = gimp_temp_buf_get_width (paint_buf); + roi.height = gimp_temp_buf_get_height (paint_buf); + + iter = gegl_buffer_iterator_new (canvas_buffer, &roi, 0, + babl_format ("Y float"), + GEGL_BUFFER_READ, GEGL_ABYSS_NONE); + while (gegl_buffer_iterator_next (iter)) + { + gfloat *canvas_pixel = (gfloat *)iter->data[0]; + int iy, ix; + + for (iy = 0; iy < iter->roi[0].height; iy++) + { + int paint_offset = (iy + iter->roi[0].y - roi.y) * paint_stride + iter->roi[0].x - roi.x; + float *paint_pixel = &paint_data[paint_offset * 4]; + + for (ix = 0; ix < iter->roi[0].width; ix++) + { + paint_pixel[3] *= *canvas_pixel; + + canvas_pixel += 1; + paint_pixel += 4; + } + } + } +} + +void +paint_mask_to_paint_buffer (const GimpTempBuf *paint_mask, + gint mask_x_offset, + gint mask_y_offset, + GimpTempBuf *paint_buf, + gfloat paint_opacity) +{ + gint width = gimp_temp_buf_get_width (paint_buf); + gint height = gimp_temp_buf_get_height (paint_buf); + + const gint mask_stride = gimp_temp_buf_get_width (paint_mask); + const gint mask_start_offset = mask_y_offset * mask_stride + mask_x_offset; + const Babl *mask_format = gimp_temp_buf_get_format (paint_mask); + + int iy, ix; + gfloat *paint_pixel = (gfloat *)gimp_temp_buf_get_data (paint_buf); + + /* Validate that the paint buffer is withing the bounds of the paint mask */ + g_return_if_fail (width <= gimp_temp_buf_get_width (paint_mask) - mask_x_offset); + g_return_if_fail (height <= gimp_temp_buf_get_height (paint_mask) - mask_y_offset); + + if (mask_format == babl_format ("Y u8")) + { + const guint8 *mask_data = (const guint8 *) gimp_temp_buf_get_data (paint_mask); + mask_data += mask_start_offset; + + for (iy = 0; iy < height; iy++) + { + int mask_offset = iy * mask_stride; + const guint8 *mask_pixel = &mask_data[mask_offset]; + + for (ix = 0; ix < width; ix++) + { + paint_pixel[3] *= (((gfloat)*mask_pixel) / 255.0f) * paint_opacity; + + mask_pixel += 1; + paint_pixel += 4; + } + } + } + else if (mask_format == babl_format ("Y float")) + { + const gfloat *mask_data = (const gfloat *) gimp_temp_buf_get_data (paint_mask); + mask_data += mask_start_offset; + + for (iy = 0; iy < height; iy++) + { + int mask_offset = iy * mask_stride; + const gfloat *mask_pixel = &mask_data[mask_offset]; + + for (ix = 0; ix < width; ix++) + { + paint_pixel[3] *= (*mask_pixel) * paint_opacity; + + mask_pixel += 1; + paint_pixel += 4; + } + } + } +} + +void +do_layer_blend (GeglBuffer *src_buffer, + GeglBuffer *dst_buffer, + GimpTempBuf *paint_buf, + GeglBuffer *mask_buffer, + gfloat opacity, + gint x_offset, + gint y_offset, + gint mask_x_offset, + gint mask_y_offset, + gboolean linear_mode, + GimpLayerModeEffects paint_mode) +{ + GeglRectangle roi; + GeglRectangle mask_roi; + GeglRectangle process_roi; + const Babl *iterator_format; + GeglBufferIterator *iter; + + const guint paint_stride = gimp_temp_buf_get_width (paint_buf); + gfloat *paint_data = (gfloat *) gimp_temp_buf_get_data (paint_buf); + + GimpLayerModeFunction apply_func = get_layer_mode_function (paint_mode); + + if (linear_mode) + iterator_format = babl_format ("RGBA float"); + else + iterator_format = babl_format ("R'G'B'A float"); + + roi.x = x_offset; + roi.y = y_offset; + roi.width = gimp_temp_buf_get_width (paint_buf); + roi.height = gimp_temp_buf_get_height (paint_buf); + + mask_roi.x = roi.x + mask_x_offset; + mask_roi.y = roi.y + mask_y_offset; + mask_roi.width = roi.width; + mask_roi.height = roi.height; + + g_return_if_fail (gimp_temp_buf_get_format (paint_buf) == iterator_format); + + iter = gegl_buffer_iterator_new (dst_buffer, &roi, 0, + iterator_format, + GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE); + + gegl_buffer_iterator_add (iter, src_buffer, &roi, 0, + iterator_format, + GEGL_BUFFER_READ, GEGL_ABYSS_NONE); + + if (mask_buffer) + { + gegl_buffer_iterator_add (iter, mask_buffer, &mask_roi, 0, + babl_format ("Y float"), + GEGL_BUFFER_READ, GEGL_ABYSS_NONE); + } + + while (gegl_buffer_iterator_next(iter)) + { + gfloat *out_pixel = (gfloat *)iter->data[0]; + gfloat *in_pixel = (gfloat *)iter->data[1]; + gfloat *mask_pixel = NULL; + gfloat *paint_pixel = paint_data + ((iter->roi[0].y - roi.y) * paint_stride + iter->roi[0].x - roi.x) * 4; + int iy; + + if (mask_buffer) + mask_pixel = (gfloat *)iter->data[2]; + + process_roi.x = iter->roi[0].x; + process_roi.width = iter->roi[0].width; + process_roi.height = 1; + + for (iy = 0; iy < iter->roi[0].height; iy++) + { + process_roi.x = iter->roi[0].y + iy; + + (*apply_func) (in_pixel, + paint_pixel, + mask_pixel, + out_pixel, + opacity, + iter->roi[0].width, + &process_roi, + 0); + + in_pixel += iter->roi[0].width * 4; + out_pixel += iter->roi[0].width * 4; + if (mask_buffer) + mask_pixel += iter->roi[0].width; + paint_pixel += paint_stride * 4; + } + } +} + +void +mask_components_onto (GeglBuffer *src_buffer, + GeglBuffer *aux_buffer, + GeglBuffer *dst_buffer, + GeglRectangle *roi, + GimpComponentMask mask, + gboolean linear_mode) +{ + GeglBufferIterator *iter; + const Babl *iterator_format; + + if (linear_mode) + iterator_format = babl_format ("RGBA float"); + else + iterator_format = babl_format ("R'G'B'A float"); + + iter = gegl_buffer_iterator_new (dst_buffer, roi, 0, + iterator_format, + GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE); + + gegl_buffer_iterator_add (iter, src_buffer, roi, 0, + iterator_format, + GEGL_BUFFER_READ, GEGL_ABYSS_NONE); + + gegl_buffer_iterator_add (iter, aux_buffer, roi, 0, + iterator_format, + GEGL_BUFFER_READ, GEGL_ABYSS_NONE); + + while (gegl_buffer_iterator_next(iter)) + { + gfloat *dest = (gfloat *)iter->data[0]; + gfloat *src = (gfloat *)iter->data[1]; + gfloat *aux = (gfloat *)iter->data[2]; + glong samples = iter->length; + + while (samples--) + { + dest[RED] = (mask & GIMP_COMPONENT_RED) ? aux[RED] : src[RED]; + dest[GREEN] = (mask & GIMP_COMPONENT_GREEN) ? aux[GREEN] : src[GREEN]; + dest[BLUE] = (mask & GIMP_COMPONENT_BLUE) ? aux[BLUE] : src[BLUE]; + dest[ALPHA] = (mask & GIMP_COMPONENT_ALPHA) ? aux[ALPHA] : src[ALPHA]; + + src += 4; + aux += 4; + dest += 4; + } + } +} diff --git a/app/paint/gimppaintcore-loops.h b/app/paint/gimppaintcore-loops.h new file mode 100644 index 0000000000..e8ceafad38 --- /dev/null +++ b/app/paint/gimppaintcore-loops.h @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 2013 Daniel Sabo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +void combine_paint_mask_to_canvas_mask (const GimpTempBuf *paint_mask, + gint mask_x_offset, + gint mask_y_offset, + GeglBuffer *canvas_buffer, + gint x_offset, + gint y_offset, + gfloat opacity, + gboolean stipple); + +void canvas_buffer_to_paint_buf_alpha (GimpTempBuf *paint_buf, + GeglBuffer *canvas_buffer, + gint x_offset, + gint y_offset); + +void paint_mask_to_paint_buffer (const GimpTempBuf *paint_mask, + gint mask_x_offset, + gint mask_y_offset, + GimpTempBuf *paint_buf, + gfloat paint_opacity); + +void do_layer_blend (GeglBuffer *src_buffer, + GeglBuffer *dst_buffer, + GimpTempBuf *paint_buf, + GeglBuffer *mask_buffer, + gfloat opacity, + gint x_offset, + gint y_offset, + gint mask_x_offset, + gint mask_y_offset, + gboolean linear_mode, + GimpLayerModeEffects paint_mode); + +void mask_components_onto (GeglBuffer *src_buffer, + GeglBuffer *aux_buffer, + GeglBuffer *dst_buffer, + GeglRectangle *roi, + GimpComponentMask mask, + gboolean linear_mode); diff --git a/app/paint/gimppaintcore.c b/app/paint/gimppaintcore.c index 1453ab43ff..1f99847fae 100644 --- a/app/paint/gimppaintcore.c +++ b/app/paint/gimppaintcore.c @@ -1,5 +1,6 @@ /* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * Copyright (C) 2013 Daniel Sabo * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,10 +27,8 @@ #include "paint-types.h" -#include "gegl/gimp-gegl-loops.h" #include "gegl/gimp-gegl-nodes.h" #include "gegl/gimp-gegl-utils.h" -#include "gegl/gimpapplicator.h" #include "core/gimp.h" #include "core/gimp-utils.h" @@ -42,6 +41,7 @@ #include "gimppaintcore.h" #include "gimppaintcoreundo.h" +#include "gimppaintcore-loops.h" #include "gimppaintoptions.h" #include "gimpairbrush.h" @@ -405,9 +405,6 @@ gimp_paint_core_start (GimpPaintCore *core, if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask)) mask = NULL; - core->applicator = gimp_applicator_new (NULL, - gimp_drawable_get_linear (drawable)); - if (mask) { GeglBuffer *mask_buffer; @@ -417,15 +414,42 @@ gimp_paint_core_start (GimpPaintCore *core, mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); gimp_item_get_offset (item, &offset_x, &offset_y); - gimp_applicator_set_mask_buffer (core->applicator, mask_buffer); - gimp_applicator_set_mask_offset (core->applicator, - -offset_x, -offset_y); + g_object_ref (mask_buffer); + core->mask_buffer = mask_buffer; + core->mask_x_offset = -offset_x; + core->mask_y_offset = -offset_y; + } + else + { + core->mask_buffer = NULL; } - gimp_applicator_set_affect (core->applicator, - gimp_drawable_get_active_mask (drawable)); - gimp_applicator_set_dest_buffer (core->applicator, - gimp_drawable_get_buffer (drawable)); + core->linear_mode = gimp_drawable_get_linear (drawable); + + /* Allocate the scratch buffer if there's a component mask */ + if (gimp_drawable_get_active_mask (drawable) != GIMP_COMPONENT_ALL) + { + if (core->linear_mode) + { + core->comp_buffer = + gegl_buffer_new (GEGL_RECTANGLE (0, 0, + gimp_item_get_width (item), + gimp_item_get_height (item)), + babl_format ("RGBA float")); + } + else + { + core->comp_buffer = + gegl_buffer_new (GEGL_RECTANGLE (0, 0, + gimp_item_get_width (item), + gimp_item_get_height (item)), + babl_format ("R'G'B'A float")); + } + } + else + { + core->comp_buffer = NULL; + } /* Freeze the drawable preview so that it isn't constantly updated. */ gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable)); @@ -444,18 +468,24 @@ gimp_paint_core_finish (GimpPaintCore *core, g_return_if_fail (GIMP_IS_DRAWABLE (drawable)); g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable))); - if (core->applicator) - { - g_object_unref (core->applicator); - core->applicator = NULL; - } - if (core->stroke_buffer) { g_array_free (core->stroke_buffer, TRUE); core->stroke_buffer = NULL; } + if (core->mask_buffer) + { + g_object_unref (core->mask_buffer); + core->mask_buffer = NULL; + } + + if (core->comp_buffer) + { + g_object_unref (core->comp_buffer); + core->comp_buffer = NULL; + } + image = gimp_item_get_image (GIMP_ITEM (drawable)); /* Determine if any part of the image has been altered-- @@ -737,75 +767,94 @@ gimp_paint_core_get_orig_proj (GimpPaintCore *core) void gimp_paint_core_paste (GimpPaintCore *core, - GeglBuffer *paint_mask, - const GeglRectangle *paint_mask_rect, + const GimpTempBuf *paint_mask, + gint paint_mask_offset_x, + gint paint_mask_offset_y, GimpDrawable *drawable, gdouble paint_opacity, gdouble image_opacity, GimpLayerModeEffects paint_mode, GimpPaintApplicationMode mode) { - gint width = gegl_buffer_get_width (core->paint_buffer); - gint height = gegl_buffer_get_height (core->paint_buffer); + GimpTempBuf *paint_buf = gimp_gegl_buffer_get_temp_buf (core->paint_buffer); + GeglBuffer *dest_buffer; + GeglBuffer *src_buffer; + + gint width = gimp_temp_buf_get_width (paint_buf); + gint height = gimp_temp_buf_get_height (paint_buf); + + if (!paint_buf) + return; + + if (core->comp_buffer) + dest_buffer = core->comp_buffer; + else + dest_buffer = gimp_drawable_get_buffer (drawable); - /* If the mode is CONSTANT: - * combine the canvas buf, the paint mask to the canvas buffer - */ if (mode == GIMP_PAINT_CONSTANT) { - /* Some tools (ink) paint the mask to paint_core->canvas_buffer - * directly. Don't need to copy it in this case. - */ - if (paint_mask != core->canvas_buffer) + /* This step is skipped by the ink tool, which writes directly to canvas_buffer */ + if (paint_mask != NULL) { - gimp_gegl_combine_mask_weird (paint_mask, paint_mask_rect, - core->canvas_buffer, - GEGL_RECTANGLE (core->paint_buffer_x, - core->paint_buffer_y, - width, height), - paint_opacity, - GIMP_IS_AIRBRUSH (core)); + /* Mix paint mask and canvas_buffer */ + combine_paint_mask_to_canvas_mask (paint_mask, + paint_mask_offset_x, + paint_mask_offset_y, + core->canvas_buffer, + core->paint_buffer_x, + core->paint_buffer_y, + paint_opacity, + GIMP_IS_AIRBRUSH (core)); } - gimp_gegl_apply_mask (core->canvas_buffer, - GEGL_RECTANGLE (core->paint_buffer_x, - core->paint_buffer_y, - width, height), - core->paint_buffer, - GEGL_RECTANGLE (0, 0, width, height), - 1.0); + /* Write canvas_buffer to paint_buf */ + canvas_buffer_to_paint_buf_alpha (paint_buf, + core->canvas_buffer, + core->paint_buffer_x, + core->paint_buffer_y); - gimp_applicator_set_src_buffer (core->applicator, - core->undo_buffer); + /* undo buf -> paint_buf -> dest_buffer */ + src_buffer = core->undo_buffer; } - /* Otherwise: - * combine the canvas buf and the paint mask to the canvas buf - */ else { - gimp_gegl_apply_mask (paint_mask, paint_mask_rect, - core->paint_buffer, - GEGL_RECTANGLE (0, 0, width, height), - paint_opacity); + g_return_if_fail (paint_mask); - gimp_applicator_set_src_buffer (core->applicator, - gimp_drawable_get_buffer (drawable)); + /* Write paint_mask to paint_buf, does not modify canvas_buffer */ + paint_mask_to_paint_buffer (paint_mask, + paint_mask_offset_x, + paint_mask_offset_y, + paint_buf, + paint_opacity); + + /* dest_buffer -> paint_buf -> dest_buffer */ + src_buffer = dest_buffer; } - gimp_applicator_set_apply_buffer (core->applicator, - core->paint_buffer); - gimp_applicator_set_apply_offset (core->applicator, - core->paint_buffer_x, - core->paint_buffer_y); + do_layer_blend (src_buffer, + dest_buffer, + paint_buf, + core->mask_buffer, + image_opacity, + core->paint_buffer_x, + core->paint_buffer_y, + core->mask_x_offset, + core->mask_y_offset, + core->linear_mode, + paint_mode); - gimp_applicator_set_mode (core->applicator, - image_opacity, paint_mode); - - /* apply the paint area to the image */ - gimp_applicator_blit (core->applicator, - GEGL_RECTANGLE (core->paint_buffer_x, - core->paint_buffer_y, - width, height)); + if (core->comp_buffer) + { + mask_components_onto (src_buffer, + core->comp_buffer, + gimp_drawable_get_buffer (drawable), + GEGL_RECTANGLE(core->paint_buffer_x, + core->paint_buffer_y, + width, + height), + gimp_drawable_get_active_mask (drawable), + core->linear_mode); + } /* Update the undo extents */ core->x1 = MIN (core->x1, core->paint_buffer_x); @@ -830,19 +879,23 @@ gimp_paint_core_paste (GimpPaintCore *core, */ void gimp_paint_core_replace (GimpPaintCore *core, - GeglBuffer *paint_mask, - const GeglRectangle *paint_mask_rect, + const GimpTempBuf *paint_mask, + gint paint_mask_offset_x, + gint paint_mask_offset_y, GimpDrawable *drawable, gdouble paint_opacity, gdouble image_opacity, GimpPaintApplicationMode mode) { - GeglRectangle mask_rect; - gint width, height; + GeglRectangle mask_rect; + gint width, height; + GeglBuffer *paint_mask_buffer; if (! gimp_drawable_has_alpha (drawable)) { - gimp_paint_core_paste (core, paint_mask, paint_mask_rect, + gimp_paint_core_paste (core, paint_mask, + paint_mask_offset_x, + paint_mask_offset_y, drawable, paint_opacity, image_opacity, GIMP_NORMAL_MODE, @@ -858,19 +911,22 @@ gimp_paint_core_replace (GimpPaintCore *core, /* Some tools (ink) paint the mask to paint_core->canvas_buffer * directly. Don't need to copy it in this case. */ - paint_mask != core->canvas_buffer) + (paint_mask != NULL)) { - /* combine the paint mask and the canvas buffer */ - gimp_gegl_combine_mask_weird (paint_mask, paint_mask_rect, - core->canvas_buffer, - GEGL_RECTANGLE (core->paint_buffer_x, - core->paint_buffer_y, - width, height), - paint_opacity, - GIMP_IS_AIRBRUSH (core)); + /* Mix paint mask and canvas_buffer */ + combine_paint_mask_to_canvas_mask (paint_mask, + paint_mask_offset_x, + paint_mask_offset_y, + core->canvas_buffer, + core->paint_buffer_x, + core->paint_buffer_y, + paint_opacity, + GIMP_IS_AIRBRUSH (core)); /* initialize the maskPR from the canvas buffer */ - paint_mask = core->canvas_buffer; + paint_mask_buffer = core->canvas_buffer; + + g_object_ref (paint_mask_buffer); mask_rect = *GEGL_RECTANGLE (core->paint_buffer_x, core->paint_buffer_y, @@ -878,7 +934,11 @@ gimp_paint_core_replace (GimpPaintCore *core, } else { - mask_rect = *paint_mask_rect; + paint_mask_buffer = gimp_temp_buf_create_buffer ((GimpTempBuf *) paint_mask); + + mask_rect = *GEGL_RECTANGLE (paint_mask_offset_x, + paint_mask_offset_y, + width, height); } /* apply the paint area to the image */ @@ -886,10 +946,12 @@ gimp_paint_core_replace (GimpPaintCore *core, GEGL_RECTANGLE (0, 0, width, height), FALSE, NULL, image_opacity, - paint_mask, &mask_rect, + paint_mask_buffer, &mask_rect, core->paint_buffer_x, core->paint_buffer_y); + g_object_unref (paint_mask_buffer); + /* Update the undo extents */ core->x1 = MIN (core->x1, core->paint_buffer_x); core->y1 = MIN (core->y1, core->paint_buffer_y); diff --git a/app/paint/gimppaintcore.h b/app/paint/gimppaintcore.h index 1fd4fea971..0ea1b91837 100644 --- a/app/paint/gimppaintcore.h +++ b/app/paint/gimppaintcore.h @@ -58,14 +58,18 @@ struct _GimpPaintCore GeglBuffer *undo_buffer; /* pixels which have been modified */ GeglBuffer *saved_proj_buffer; /* proj tiles which have been modified */ GeglBuffer *canvas_buffer; /* the buffer to paint the mask to */ + GeglBuffer *comp_buffer; /* scratch buffer used when masking components */ + gboolean linear_mode; /* if painting to a linear surface */ GeglBuffer *paint_buffer; /* the buffer to paint pixels to */ gint paint_buffer_x; gint paint_buffer_y; - GArray *stroke_buffer; + GeglBuffer *mask_buffer; /* the target drawable's mask */ + gint mask_x_offset; + gint mask_y_offset; - GimpApplicator *applicator; + GArray *stroke_buffer; }; struct _GimpPaintCoreClass @@ -168,16 +172,20 @@ GeglBuffer * gimp_paint_core_get_orig_image (GimpPaintCore *core); GeglBuffer * gimp_paint_core_get_orig_proj (GimpPaintCore *core); void gimp_paint_core_paste (GimpPaintCore *core, - GeglBuffer *paint_mask, - const GeglRectangle *paint_mask_rect, + const GimpTempBuf *paint_mask, + gint paint_mask_offset_x, + gint paint_mask_offset_y, GimpDrawable *drawable, gdouble paint_opacity, gdouble image_opacity, GimpLayerModeEffects paint_mode, GimpPaintApplicationMode mode); + + void gimp_paint_core_replace (GimpPaintCore *core, - GeglBuffer *paint_mask, - const GeglRectangle *paint_mask_rect, + const GimpTempBuf *paint_mask, + gint paint_mask_offset_x, + gint paint_mask_offset_y, GimpDrawable *drawable, gdouble paint_opacity, gdouble image_opacity,