[gimp] Faster paintcore
- From: Daniel Sabo <daniels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] Faster paintcore
- Date: Tue, 21 May 2013 12:26:01 +0000 (UTC)
commit cd91144f9e0a08f793bcc35501cdf4637ffe459c
Author: Daniel Sabo <DanielSabo gmail com>
Date: Tue May 21 04:03:28 2013 -0700
Faster paintcore
Directly access the brush and paint buffers rather than using
GEGL iterators.
Replicate the relevant parts of GimpApplicator using direct
access.
app/paint/Makefile.am | 2 +
app/paint/gimpbrushcore.c | 33 ++--
app/paint/gimpink.c | 16 +-
app/paint/gimppaintcore-loops.c | 415 +++++++++++++++++++++++++++++++++++++++
app/paint/gimppaintcore-loops.h | 55 +++++
app/paint/gimppaintcore.c | 232 ++++++++++++++--------
app/paint/gimppaintcore.h | 20 ++-
7 files changed, 656 insertions(+), 117 deletions(-)
---
diff --git a/app/paint/Makefile.am b/app/paint/Makefile.am
index 8343c01..c2c72e2 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 07ad88f..02dbd6d 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 b84fdd0..b236645 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 0000000..a7b74b3
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+
+#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 0000000..e8ceafa
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+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 1453ab4..1f99847 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);
-
- gimp_applicator_set_src_buffer (core->applicator,
- gimp_drawable_get_buffer (drawable));
- }
+ g_return_if_fail (paint_mask);
- 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);
+ /* 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);
- gimp_applicator_set_mode (core->applicator,
- image_opacity, paint_mode);
+ /* dest_buffer -> paint_buf -> dest_buffer */
+ src_buffer = dest_buffer;
+ }
- /* apply the paint area to the image */
- gimp_applicator_blit (core->applicator,
- GEGL_RECTANGLE (core->paint_buffer_x,
- core->paint_buffer_y,
- width, height));
+ 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);
+
+ 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 1fd4fea..0ea1b91 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,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]