[gimp] app: add gimp_gegl_replace() as replacement for combine_regions_replace()



commit b2c4bd5d3f098be3758ef72df71d611f2eeb6c39
Author: Michael Natterer <mitch gimp org>
Date:   Sun May 6 19:50:46 2012 +0200

    app: add gimp_gegl_replace() as replacement for combine_regions_replace()
    
    and use it in gimp_drawable_real_replace_buffer(). The new GEGL loop
    is a stupid 1:1 copy of legacy and needs improvement.

 app/core/gimpdrawable-combine.c |   86 +++++++++-----------------------
 app/gegl/gimp-gegl-loops.c      |  105 +++++++++++++++++++++++++++++++++++++++
 app/gegl/gimp-gegl-loops.h      |   11 ++++
 3 files changed, 139 insertions(+), 63 deletions(-)
---
diff --git a/app/core/gimpdrawable-combine.c b/app/core/gimpdrawable-combine.c
index ca759e5..f8a2011 100644
--- a/app/core/gimpdrawable-combine.c
+++ b/app/core/gimpdrawable-combine.c
@@ -268,50 +268,10 @@ gimp_drawable_real_replace_buffer (GimpDrawable        *drawable,
   GimpImage       *image = gimp_item_get_image (item);
   GimpChannel     *mask  = gimp_image_get_mask (image);
   GeglBuffer      *drawable_buffer;
-  GimpTempBuf     *temp_buf;
-  PixelRegion      src2PR;
-  PixelRegion      maskPR;
   gint             x, y, width, height;
   gint             offset_x, offset_y;
-  PixelRegion      src1PR, destPR;
   gboolean         active_components[MAX_CHANNELS];
 
-  temp_buf = gimp_gegl_buffer_get_temp_buf (buffer);
-
-  if (temp_buf)
-    {
-      pixel_region_init_temp_buf (&src2PR, temp_buf,
-                                  buffer_region->x, buffer_region->y,
-                                  buffer_region->width, buffer_region->height);
-    }
-  else
-    {
-      pixel_region_init (&src2PR, gimp_gegl_buffer_get_tiles (buffer),
-                         buffer_region->x, buffer_region->y,
-                         buffer_region->width, buffer_region->height,
-                         FALSE);
-    }
-
-  temp_buf = gimp_gegl_buffer_get_temp_buf (mask_buffer);
-
-  if (temp_buf)
-    {
-      pixel_region_init_temp_buf (&maskPR, temp_buf,
-                                  mask_buffer_region->x,
-                                  mask_buffer_region->y,
-                                  mask_buffer_region->width,
-                                  mask_buffer_region->height);
-    }
-  else
-    {
-      pixel_region_init (&maskPR, gimp_gegl_buffer_get_tiles (mask_buffer),
-                         mask_buffer_region->x,
-                         mask_buffer_region->y,
-                         mask_buffer_region->width,
-                         mask_buffer_region->height,
-                         FALSE);
-    }
-
   /*  don't apply the mask to itself and don't apply an empty mask  */
   if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
     mask = NULL;
@@ -323,7 +283,8 @@ gimp_drawable_real_replace_buffer (GimpDrawable        *drawable,
   gimp_item_get_offset (item, &offset_x, &offset_y);
 
   /*  make sure the image application coordinates are within drawable bounds  */
-  gimp_rectangle_intersect (dest_x, dest_y, src2PR.w, src2PR.h,
+  gimp_rectangle_intersect (dest_x, dest_y,
+                            buffer_region->width, buffer_region->height,
                             0, 0,
                             gimp_item_get_width  (item),
                             gimp_item_get_height (item),
@@ -351,20 +312,8 @@ gimp_drawable_real_replace_buffer (GimpDrawable        *drawable,
 
   drawable_buffer = gimp_drawable_get_buffer (drawable);
 
-  /* configure the pixel regions */
-  pixel_region_init (&src1PR, gimp_gegl_buffer_get_tiles (drawable_buffer),
-                     x, y, width, height,
-                     FALSE);
-  pixel_region_init (&destPR, gimp_gegl_buffer_get_tiles (drawable_buffer),
-                     x, y, width, height,
-                     TRUE);
-  pixel_region_resize (&src2PR,
-                       src2PR.x + (x - dest_x), src2PR.y + (y - dest_y),
-                       width, height);
-
   if (mask)
     {
-      PixelRegion  tempPR;
       GimpTempBuf *temp_buf;
       GeglBuffer  *src_buffer;
       GeglBuffer  *dest_buffer;
@@ -386,20 +335,31 @@ gimp_drawable_real_replace_buffer (GimpDrawable        *drawable,
                             dest_buffer, GEGL_RECTANGLE (0, 0, width, height),
                             1.0);
 
-      g_object_unref (dest_buffer);
-
-      pixel_region_init_temp_buf (&tempPR, temp_buf, 0, 0, width, height);
-
-      combine_regions_replace (&src1PR, &src2PR, &destPR, &tempPR,
-                               opacity * 255.999,
-                               active_components);
+      gimp_gegl_replace (buffer,
+                         buffer_region,
+                         drawable_buffer,
+                         GEGL_RECTANGLE (x, y, width, height),
+                         dest_buffer,
+                         GEGL_RECTANGLE (0, 0, width, height),
+                         drawable_buffer,
+                         GEGL_RECTANGLE (x, y, width, height),
+                         opacity * 255.999,
+                         active_components);
 
+      g_object_unref (dest_buffer);
       gimp_temp_buf_unref (temp_buf);
     }
   else
     {
-      combine_regions_replace (&src1PR, &src2PR, &destPR, &maskPR,
-                               opacity * 255.999,
-                               active_components);
+      gimp_gegl_replace (buffer,
+                         buffer_region,
+                         drawable_buffer,
+                         GEGL_RECTANGLE (x, y, width, height),
+                         mask_buffer,
+                         mask_buffer_region,
+                         drawable_buffer,
+                         GEGL_RECTANGLE (x, y, width, height),
+                         opacity * 255.999,
+                         active_components);
     }
 }
diff --git a/app/gegl/gimp-gegl-loops.c b/app/gegl/gimp-gegl-loops.c
index badf5f8..785bfa8 100644
--- a/app/gegl/gimp-gegl-loops.c
+++ b/app/gegl/gimp-gegl-loops.c
@@ -470,3 +470,108 @@ gimp_gegl_combine_mask (GeglBuffer          *mask_buffer,
         }
     }
 }
+
+void
+gimp_gegl_replace (GeglBuffer          *top_buffer,
+                   const GeglRectangle *top_rect,
+                   GeglBuffer          *bottom_buffer,
+                   const GeglRectangle *bottom_rect,
+                   GeglBuffer          *mask_buffer,
+                   const GeglRectangle *mask_rect,
+                   GeglBuffer          *dest_buffer,
+                   const GeglRectangle *dest_rect,
+                   guchar               opacity,
+                   const gboolean      *affect)
+{
+  GeglBufferIterator *iter;
+  const gint          alpha        = 4 - 1;
+  const gdouble       norm_opacity = opacity * (1.0 / 65536.0);
+
+  iter = gegl_buffer_iterator_new (top_buffer, top_rect, 0,
+                                   babl_format ("R'G'B'A u8"),
+                                   GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
+
+  gegl_buffer_iterator_add (iter, bottom_buffer, bottom_rect, 0,
+                            babl_format ("R'G'B'A u8"),
+                            GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
+
+  gegl_buffer_iterator_add (iter, mask_buffer, mask_rect, 0,
+                            babl_format ("Y u8"),
+                            GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
+
+  gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0,
+                            babl_format ("R'G'B'A u8"),
+                            GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
+
+  while (gegl_buffer_iterator_next (iter))
+    {
+      const guchar *top    = iter->data[0];
+      const guchar *bottom = iter->data[1];
+      const guchar *mask   = iter->data[2];
+      guchar       *dest   = iter->data[3];
+
+      while (iter->length--)
+        {
+          guint    b;
+          gdouble  mask_val = mask[0] * norm_opacity;
+
+          /* calculate new alpha first. */
+          gint     s1_a  = bottom[alpha];
+          gint     s2_a  = top[alpha];
+          gdouble  a_val = s1_a + mask_val * (s2_a - s1_a);
+
+          if (a_val == 0)
+            {
+              /* In any case, write out versions of the blending
+               * function that result when combinations of s1_a, s2_a,
+               * and mask_val --> 0 (or mask_val -->1)
+               */
+
+              /* 1: s1_a, s2_a, AND mask_val all approach 0+: */
+              /* 2: s1_a AND s2_a both approach 0+, regardless of mask_val: */
+              if (s1_a + s2_a == 0.0)
+                {
+                  for (b = 0; b < alpha; b++)
+                    {
+                      gint new_val = 0.5 + (gdouble) bottom[b] +
+                        mask_val * ((gdouble) top[b] - (gdouble) bottom[b]);
+
+                      dest[b] = affect[b] ? MIN (new_val, 255) : bottom[b];
+                    }
+                }
+
+              /* 3: mask_val AND s1_a both approach 0+, regardless of s2_a  */
+              else if (s1_a + mask_val == 0.0)
+                {
+                  for (b = 0; b < alpha; b++)
+                    dest[b] = bottom[b];
+                }
+
+              /* 4: mask_val -->1 AND s2_a -->0, regardless of s1_a */
+              else if (1.0 - mask_val + s2_a == 0.0)
+                {
+                  for (b = 0; b < alpha; b++)
+                    dest[b] = affect[b] ? top[b] : bottom[b];
+                }
+            }
+          else
+            {
+              gdouble a_recip = 1.0 / a_val;
+              /* possible optimization: fold a_recip into s1_a and s2_a */
+              for (b = 0; b < alpha; b++)
+                {
+                  gint new_val = 0.5 + a_recip * (bottom[b] * s1_a + mask_val *
+                                                  (top[b] * s2_a - bottom[b] * s1_a));
+                  dest[b] = affect[b] ? MIN (new_val, 255) : bottom[b];
+                }
+            }
+
+          dest[alpha] = affect[alpha] ? a_val + 0.5 : s1_a;
+
+          top    += 4;
+          bottom += 4;
+          mask   += 1;
+          dest   += 4;
+        }
+    }
+}
diff --git a/app/gegl/gimp-gegl-loops.h b/app/gegl/gimp-gegl-loops.h
index 76e6fe7..264a5a9 100644
--- a/app/gegl/gimp-gegl-loops.h
+++ b/app/gegl/gimp-gegl-loops.h
@@ -64,5 +64,16 @@ void   gimp_gegl_combine_mask (GeglBuffer          *mask_buffer,
                                gdouble              opacity,
                                gboolean             stipple);
 
+void   gimp_gegl_replace      (GeglBuffer          *top_buffer,
+                               const GeglRectangle *top_rect,
+                               GeglBuffer          *bottom_buffer,
+                               const GeglRectangle *bottom_rect,
+                               GeglBuffer          *mask_buffer,
+                               const GeglRectangle *mask_rect,
+                               GeglBuffer          *dest_buffer,
+                               const GeglRectangle *dest_rect,
+                               guchar               opacity,
+                               const gboolean      *affect);
+
 
 #endif /* __GIMP_GEGL_LOOPS_H__ */



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