[gimp] app: improve gimp_brush_core_color_area_with_pixmap()



commit 5b09af4390403152bde3a971ca49b8231cbf7914
Author: Ell <ell_se yahoo com>
Date:   Sun Feb 24 12:54:58 2019 -0500

    app: improve gimp_brush_core_color_area_with_pixmap()
    
    Reimplement gimp_brush_core_color_area_with_pixmap(), which copies
    the brush's dab to the paint buffer when using a pixmap brush, in
    terms of gimp-gegl-loops.  This simplifies the functions,
    parallelizes processing, and transparently handles float brushes.
    
    Replace the "mode" parameter of the function with an "apply_mask"
    parameter, which specifies whether to apply the brush's mask to
    the dab as part of copying.  Avoid applying the mask in
    GimpPaintbrush; previously, we would erroneously apply the mask
    twice when using the paintbrush tool: once when copying the
    dab to the paint buffer, and again when pasting the paint buffer
    to the canvas.
    
    We still apply the mask in GimpSmudge, which results in the same
    double-application behavior, however, this might be less practical
    to fix.

 app/paint/gimpbrushcore.c  | 229 +++++++++++----------------------------------
 app/paint/gimpbrushcore.h  |   2 +-
 app/paint/gimppaintbrush.c |   2 +-
 app/paint/gimpsmudge.c     |   2 +-
 4 files changed, 57 insertions(+), 178 deletions(-)
---
diff --git a/app/paint/gimpbrushcore.c b/app/paint/gimpbrushcore.c
index a5756f8707..d2f499fdb1 100644
--- a/app/paint/gimpbrushcore.c
+++ b/app/paint/gimpbrushcore.c
@@ -29,6 +29,7 @@
 #include "operations/layer-modes/gimp-layer-modes.h"
 
 #include "gegl/gimp-babl.h"
+#include "gegl/gimp-gegl-loops.h"
 
 #include "core/gimpbrush-header.h"
 #include "core/gimpbrushgenerated.h"
@@ -110,15 +111,6 @@ static const GimpTempBuf *
 static void      gimp_brush_core_invalidate_cache   (GimpBrush         *brush,
                                                      GimpBrushCore     *core);
 
-/*  brush pipe utility functions  */
-static void  gimp_brush_core_paint_line_pixmap_mask (const Babl        *fish,
-                                                     const GimpTempBuf *pixmap_mask,
-                                                     const GimpTempBuf *brush_mask,
-                                                     gfloat            *d,
-                                                     gint               x,
-                                                     gint               y,
-                                                     gint               width);
-
 
 G_DEFINE_TYPE (GimpBrushCore, gimp_brush_core, GIMP_TYPE_PAINT_CORE)
 
@@ -1221,198 +1213,85 @@ gimp_brush_core_eval_transform_dynamics (GimpBrushCore     *core,
     }
 }
 
-
-/**************************************************/
-/*  Brush pipe utility functions                  */
-/**************************************************/
-
 void
-gimp_brush_core_color_area_with_pixmap (GimpBrushCore            *core,
-                                        GimpDrawable             *drawable,
-                                        const GimpCoords         *coords,
-                                        GeglNode                 *op,
-                                        GeglBuffer               *area,
-                                        gint                      area_x,
-                                        gint                      area_y,
-                                        GimpBrushApplicationMode  mode)
+gimp_brush_core_color_area_with_pixmap (GimpBrushCore    *core,
+                                        GimpDrawable     *drawable,
+                                        const GimpCoords *coords,
+                                        GeglNode         *op,
+                                        GeglBuffer       *area,
+                                        gint              area_x,
+                                        gint              area_y,
+                                        gboolean          apply_mask)
 {
-  GeglBufferIterator *iter;
-  GeglRectangle      *roi;
-  gint                ulx;
-  gint                uly;
-  gint                offsetx;
-  gint                offsety;
-  const GimpTempBuf  *pixmap_mask;
-  const GimpTempBuf  *brush_mask;
-  const Babl         *area_format;
-  const Babl         *pixmap_format;
-  const Babl         *fish = NULL;
+  const GimpTempBuf *pixmap;
+  GeglBuffer        *pixmap_buffer;
+  const GimpTempBuf *mask;
+  GeglBuffer        *mask_buffer;
+  gint               area_width;
+  gint               area_height;
+  gint               ul_x;
+  gint               ul_y;
+  gint               offset_x;
+  gint               offset_y;
 
   g_return_if_fail (GIMP_IS_BRUSH (core->brush));
   g_return_if_fail (gimp_brush_get_pixmap (core->brush) != NULL);
 
-  /*  scale the brushes  */
-  pixmap_mask = gimp_brush_core_transform_pixmap (core, core->brush, op);
+  /*  scale the brush  */
+  pixmap = gimp_brush_core_transform_pixmap (core, core->brush, op);
 
-  if (! pixmap_mask)
+  if (! pixmap)
     return;
 
-  if (mode != GIMP_BRUSH_HARD)
-    brush_mask = gimp_brush_core_transform_mask (core, core->brush, op);
+  if (apply_mask)
+    mask = gimp_brush_core_transform_mask (core, core->brush, op);
   else
-    brush_mask = NULL;
+    mask = NULL;
 
   /*  Calculate upper left corner of brush as in
    *  gimp_paint_core_get_paint_area.  Ugly to have to do this here, too.
    */
-  ulx = (gint) floor (coords->x) - (gimp_temp_buf_get_width  (pixmap_mask) >> 1);
-  uly = (gint) floor (coords->y) - (gimp_temp_buf_get_height (pixmap_mask) >> 1);
+  ul_x = (gint) floor (coords->x) - (gimp_temp_buf_get_width  (pixmap) >> 1);
+  ul_y = (gint) floor (coords->y) - (gimp_temp_buf_get_height (pixmap) >> 1);
 
   /*  Not sure why this is necessary, but empirically the code does
    *  not work without it for even-sided brushes.  See bug #166622.
    */
-  if (gimp_temp_buf_get_width (pixmap_mask) % 2 == 0)
-    ulx += ROUND (coords->x) - floor (coords->x);
-  if (gimp_temp_buf_get_height (pixmap_mask) % 2 == 0)
-    uly += ROUND (coords->y) - floor (coords->y);
-
-  offsetx = area_x - ulx;
-  offsety = area_y - uly;
-
-  area_format   = gegl_buffer_get_format (area);
-  pixmap_format = gimp_temp_buf_get_format (pixmap_mask);
-
-  iter = gegl_buffer_iterator_new (area, NULL, 0, area_format,
-                                   GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1);
-
-  if (mode == GIMP_BRUSH_SOFT && brush_mask)
-    {
-      GimpImageBaseType  pixmap_base_type;
-      GimpPrecision      pixmap_precision;
-      const Babl        *pixmap_space;
-
-      pixmap_base_type = gimp_babl_format_get_base_type (pixmap_format);
-      pixmap_precision = gimp_babl_format_get_precision (pixmap_format);
-      pixmap_space     = babl_format_get_space (pixmap_format);
-
-      fish = babl_fish (gimp_babl_format (pixmap_base_type, pixmap_precision,
-                                          TRUE, pixmap_space),
-                        area_format);
-    }
-  else
-    {
-      fish = babl_fish (pixmap_format, area_format);
-
-      brush_mask = NULL;
-    }
-
-  roi = &iter->items[0].roi;
-
-  while (gegl_buffer_iterator_next (iter))
-    {
-      gfloat *d = iter->items[0].data;
-      gint    y;
-
-      for (y = 0; y < roi->height; y++)
-        {
-          gimp_brush_core_paint_line_pixmap_mask (fish,
-                                                  pixmap_mask, brush_mask,
-                                                  d, offsetx, y + offsety,
-                                                  roi->width);
-          d += roi->width * 4;
-        }
-    }
-}
-
-static void
-gimp_brush_core_paint_line_pixmap_mask (const Babl        *fish,
-                                        const GimpTempBuf *pixmap_mask,
-                                        const GimpTempBuf *brush_mask,
-                                        gfloat            *d,
-                                        gint               x,
-                                        gint               y,
-                                        gint               width)
-{
-  const Babl *pixmap_format;
-  gint        pixmap_bytes;
-  gint        pixmap_width;
-  gint        pixmap_height;
-  guchar     *b;
+  if (gimp_temp_buf_get_width (pixmap) % 2 == 0)
+    ul_x += ROUND (coords->x) - floor (coords->x);
+  if (gimp_temp_buf_get_height (pixmap) % 2 == 0)
+    ul_y += ROUND (coords->y) - floor (coords->y);
 
-  pixmap_width  = gimp_temp_buf_get_width  (pixmap_mask);
-  pixmap_height = gimp_temp_buf_get_height (pixmap_mask);
+  offset_x = area_x - ul_x;
+  offset_y = area_y - ul_y;
 
-  /*  Make sure x, y are positive  */
-  x %= pixmap_width;
-  if (x < 0)
-    x += pixmap_width;
+  area_width  = gegl_buffer_get_width  (area);
+  area_height = gegl_buffer_get_height (area);
 
-  y %= pixmap_height;
-  if (y < 0)
-    y += pixmap_height;
+  pixmap_buffer = gimp_temp_buf_create_buffer (pixmap);
 
-  pixmap_format = gimp_temp_buf_get_format (pixmap_mask);
-  pixmap_bytes  = babl_format_get_bytes_per_pixel (pixmap_format);
+  gimp_gegl_buffer_copy (pixmap_buffer,
+                         GEGL_RECTANGLE (offset_x,   offset_y,
+                                         area_width, area_height),
+                         GEGL_ABYSS_NONE,
+                         area,
+                         GEGL_RECTANGLE (0,          0,
+                                         area_width, area_height));
 
-  /* Point to the appropriate scanline */
-  b = (gimp_temp_buf_get_data (pixmap_mask) +
-       y * pixmap_width * pixmap_bytes);
+  g_object_unref (pixmap_buffer);
 
-  if (brush_mask)
+  if (mask)
     {
-      const guchar *mask     = (gimp_temp_buf_get_data (brush_mask) +
-                                y * pixmap_width);
-      guchar       *line_buf = g_alloca (width * (pixmap_bytes + 1));
-      guchar       *l        = line_buf;
-      gint          i;
-
-      g_return_if_fail (gimp_temp_buf_get_width  (brush_mask) == pixmap_width);
-      g_return_if_fail (gimp_temp_buf_get_height (brush_mask) == pixmap_height);
-
-      /* put the source pixmap's pixels, plus the mask's alpha, into
-       * one line, so we can use one single call to babl_process() to
-       * convert the entire line
-       */
-
-      for (i = 0; i < width; i++)
-        {
-          gint    p_bytes = pixmap_bytes;
-          guchar *p       = b + x * p_bytes;
+      mask_buffer = gimp_temp_buf_create_buffer (mask);
 
-          while (p_bytes--)
-            *l++ = *p++;
-
-          *l++ = mask[x++];
-
-          if (x == pixmap_width)
-            x = 0;
-        }
-
-      babl_process (fish, line_buf, d, width);
-    }
-  else
-    {
-      guchar *line_buf = g_alloca (width * (pixmap_bytes));
-      guchar *l        = line_buf;
-      gint    i;
-
-      /* put the source pixmap's pixels into one line, so we can use
-       * one single call to babl_process() to convert the entire line
-       */
-      for (i = 0; i < width; i++)
-        {
-          gint    p_bytes = pixmap_bytes;
-          guchar *p       = b + x * p_bytes;
-
-          while (p_bytes--)
-            *l++ = *p++;
-
-          x++;
-
-          if (x == pixmap_width)
-            x = 0;
-        }
+      gimp_gegl_apply_mask (mask_buffer,
+                            GEGL_RECTANGLE (offset_x,   offset_y,
+                                            area_width, area_height),
+                            area,
+                            GEGL_RECTANGLE (0,          0,
+                                            area_width, area_height),
+                            1.0);
 
-      babl_process (fish, line_buf, d, width);
+      g_object_unref (mask_buffer);
     }
 }
diff --git a/app/paint/gimpbrushcore.h b/app/paint/gimpbrushcore.h
index b733f0f50f..b46a1080ae 100644
--- a/app/paint/gimpbrushcore.h
+++ b/app/paint/gimpbrushcore.h
@@ -128,7 +128,7 @@ void   gimp_brush_core_color_area_with_pixmap
                                        GeglBuffer               *area,
                                        gint                      area_x,
                                        gint                      area_y,
-                                       GimpBrushApplicationMode  mode);
+                                       gboolean                  apply_mask);
 
 const GimpTempBuf * gimp_brush_core_get_brush_mask
                                       (GimpBrushCore            *core,
diff --git a/app/paint/gimppaintbrush.c b/app/paint/gimppaintbrush.c
index 367d1c0f94..944bbfe1fb 100644
--- a/app/paint/gimppaintbrush.c
+++ b/app/paint/gimppaintbrush.c
@@ -235,7 +235,7 @@ _gimp_paintbrush_motion (GimpPaintCore    *paint_core,
                                                   paint_buffer,
                                                   paint_buffer_x,
                                                   paint_buffer_y,
-                                                  gimp_paint_options_get_brush_mode (paint_options));
+                                                  FALSE);
 
           paint_appl_mode = GIMP_PAINT_INCREMENTAL;
         }
diff --git a/app/paint/gimpsmudge.c b/app/paint/gimpsmudge.c
index 5d11a78b6d..c991e03f24 100644
--- a/app/paint/gimpsmudge.c
+++ b/app/paint/gimpsmudge.c
@@ -501,7 +501,7 @@ gimp_smudge_motion (GimpPaintCore    *paint_core,
                                                   paint_buffer,
                                                   paint_buffer_x,
                                                   paint_buffer_y,
-                                                  gimp_paint_options_get_brush_mode (paint_options));
+                                                  TRUE);
         }
 
       gimp_gegl_smudge_with_paint (accum_buffer,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]