[gimp] Faster paintcore



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]