[gimp] app: resurrect the Iscissors tool to a zombie state



commit d11f83a640eb4810826a729f51a213c8b43806b7
Author: Michael Natterer <mitch gimp org>
Date:   Tue Mar 17 22:19:29 2015 +0100

    app: resurrect the Iscissors tool to a zombie state
    
    The interaction is fully restored, it's also ported to the new halt()
    and commit() API of tools and semi-properly GEGLized: the gradient map
    is now constructed on the fly using a GimpTileHandlerValidate
    subclass.
    
    The only problem is that it doesn't find any edges in the image and is
    totally useless. Pushing anyway to put an end to the bitrot, any help
    with debugging is greatly appreciated...

 app/tools/Makefile.am                |    2 +
 app/tools/gimp-tools.c               |    2 -
 app/tools/gimpiscissorstool.c        |  458 +++++++++++-----------------------
 app/tools/gimpiscissorstool.h        |    6 +-
 app/tools/gimptilehandleriscissors.c |  330 ++++++++++++++++++++++++
 app/tools/gimptilehandleriscissors.h |   59 +++++
 menus/image-menu.xml.in              |    2 -
 7 files changed, 537 insertions(+), 322 deletions(-)
---
diff --git a/app/tools/Makefile.am b/app/tools/Makefile.am
index 08186ac..6203bb9 100644
--- a/app/tools/Makefile.am
+++ b/app/tools/Makefile.am
@@ -192,6 +192,8 @@ libapptools_a_sources = \
        gimptexttool-editor.h           \
        gimpthresholdtool.c             \
        gimpthresholdtool.h             \
+       gimptilehandleriscissors.c      \
+       gimptilehandleriscissors.h      \
        gimptool.c                      \
        gimptool.h                      \
        gimptool-progress.c             \
diff --git a/app/tools/gimp-tools.c b/app/tools/gimp-tools.c
index 54b44fc..2fe40fa 100644
--- a/app/tools/gimp-tools.c
+++ b/app/tools/gimp-tools.c
@@ -183,9 +183,7 @@ gimp_tools_init (Gimp *gimp)
     /*  selection tools */
 
     gimp_foreground_select_tool_register,
-#if 0
     gimp_iscissors_tool_register,
-#endif
     gimp_by_color_select_tool_register,
     gimp_fuzzy_select_tool_register,
     gimp_free_select_tool_register,
diff --git a/app/tools/gimpiscissorstool.c b/app/tools/gimpiscissorstool.c
index 9135dc2..e805f3f 100644
--- a/app/tools/gimpiscissorstool.c
+++ b/app/tools/gimpiscissorstool.c
@@ -42,8 +42,6 @@
 
 /* Livewire boundary implementation done by Laramie Leavitt */
 
-#if 0
-
 #include "config.h"
 
 #include <stdlib.h>
@@ -57,12 +55,6 @@
 
 #include "tools-types.h"
 
-#include "base/pixel-region.h"
-#include "base/tile-manager.h"
-#include "base/tile.h"
-
-#include "paint-funcs/paint-funcs.h"
-
 #include "gegl/gimp-gegl-utils.h"
 
 #include "core/gimpchannel.h"
@@ -80,17 +72,16 @@
 
 #include "gimpiscissorsoptions.h"
 #include "gimpiscissorstool.h"
+#include "gimptilehandleriscissors.h"
 #include "gimptoolcontrol.h"
 
 #include "gimp-intl.h"
 
 
 /*  defines  */
-#define  MAX_GRADIENT      179.606  /* == sqrt (127^2 + 127^2) */
 #define  GRADIENT_SEARCH   32  /* how far to look when snapping to an edge */
 #define  EXTEND_BY         0.2 /* proportion to expand cost map by */
 #define  FIXED             5   /* additional fixed size to expand cost map */
-#define  MIN_GRADIENT      63  /* gradients < this are directionless */
 
 #define  COST_WIDTH        2   /* number of bytes for each pixel in cost map  */
 
@@ -151,16 +142,18 @@ static gboolean gimp_iscissors_tool_key_press    (GimpTool              *tool,
                                                   GdkEventKey           *kevent,
                                                   GimpDisplay           *display);
 
-static void   gimp_iscissors_tool_apply          (GimpIscissorsTool     *iscissors,
-                                                  GimpDisplay           *display);
 static void   gimp_iscissors_tool_draw           (GimpDrawTool          *draw_tool);
 
+static void   gimp_iscissors_tool_halt           (GimpIscissorsTool     *iscissors,
+                                                  GimpDisplay           *display);
+static void   gimp_iscissors_tool_commit         (GimpIscissorsTool     *iscissors,
+                                                  GimpDisplay           *display);
 
 static void          iscissors_convert         (GimpIscissorsTool *iscissors,
                                                 GimpDisplay       *display);
-static TileManager * gradient_map_new          (GimpImage         *image);
+static GeglBuffer  * gradient_map_new          (GimpImage         *image);
 
-static void          find_optimal_path         (TileManager       *gradient_map,
+static void          find_optimal_path         (GeglBuffer        *gradient_map,
                                                 GimpTempBuf       *dp_buf,
                                                 gint               x1,
                                                 gint               y1,
@@ -200,12 +193,6 @@ static GPtrArray   * plot_pixels               (GimpIscissorsTool *iscissors,
                                                 gint               ye);
 
 
-G_DEFINE_TYPE (GimpIscissorsTool, gimp_iscissors_tool,
-               GIMP_TYPE_SELECTION_TOOL)
-
-#define parent_class gimp_iscissors_tool_parent_class
-
-
 /*  static variables  */
 
 /*  where to move on a given link direction  */
@@ -231,39 +218,16 @@ static const gint move[8][2] =
  * `---+---+---'
  */
 
-
-/*  temporary convolution buffers --  */
-static guchar  maxgrad_conv0[TILE_WIDTH * TILE_HEIGHT * 4] = "";
-static guchar  maxgrad_conv1[TILE_WIDTH * TILE_HEIGHT * 4] = "";
-static guchar  maxgrad_conv2[TILE_WIDTH * TILE_HEIGHT * 4] = "";
-
-
-static const gfloat horz_deriv[9] =
-{
-   1,  0, -1,
-   2,  0, -2,
-   1,  0, -1,
-};
-
-static const gfloat vert_deriv[9] =
-{
-   1,  2,  1,
-   0,  0,  0,
-  -1, -2, -1,
-};
-
-static const gfloat blur_32[9] =
-{
-   1,  1,  1,
-   1, 24,  1,
-   1,  1,  1,
-};
-
 static gfloat  distance_weights[GRADIENT_SEARCH * GRADIENT_SEARCH];
 
 static gint    diagonal_weight[256];
 static gint    direction_value[256][4];
-static Tile   *cur_tile    = NULL;
+
+
+G_DEFINE_TYPE (GimpIscissorsTool, gimp_iscissors_tool,
+               GIMP_TYPE_SELECTION_TOOL)
+
+#define parent_class gimp_iscissors_tool_parent_class
 
 
 void
@@ -374,50 +338,11 @@ gimp_iscissors_tool_control (GimpTool       *tool,
       break;
 
     case GIMP_TOOL_ACTION_HALT:
-      /*  Free and reset the curve list  */
-      while (! g_queue_is_empty (iscissors->curves))
-        {
-          ICurve *curve = g_queue_pop_head (iscissors->curves);
-
-          if (curve->points)
-            g_ptr_array_free (curve->points, TRUE);
-
-          g_slice_free (ICurve, curve);
-        }
-
-      /*  free mask  */
-      if (iscissors->mask)
-        {
-          g_object_unref (iscissors->mask);
-          iscissors->mask = NULL;
-        }
-
-      /* free the gradient map */
-      if (iscissors->gradient_map)
-        {
-          /* release any tile we were using */
-          if (cur_tile)
-            {
-              tile_release (cur_tile, FALSE);
-              cur_tile = NULL;
-            }
-
-          tile_manager_unref (iscissors->gradient_map);
-          iscissors->gradient_map = NULL;
-        }
-
-      iscissors->curve1      = NULL;
-      iscissors->curve2      = NULL;
-      iscissors->first_point = TRUE;
-      iscissors->connected   = FALSE;
-      iscissors->state       = NO_ACTION;
+      gimp_iscissors_tool_halt (iscissors, display);
+      break;
 
-      /*  Reset the dp buffers  */
-      if (iscissors->dp_buf)
-        {
-          gimp_temp_buf_unref (iscissors->dp_buf);
-          iscissors->dp_buf = NULL;
-        }
+    case GIMP_TOOL_ACTION_COMMIT:
+      gimp_iscissors_tool_commit (iscissors, display);
       break;
     }
 
@@ -481,7 +406,8 @@ gimp_iscissors_tool_button_press (GimpTool            *tool,
                                              iscissors->x,
                                              iscissors->y))
         {
-          gimp_iscissors_tool_apply (iscissors, display);
+          gimp_tool_control (tool, GIMP_TOOL_ACTION_COMMIT, display);
+          gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
         }
       else if (! iscissors->connected)
         {
@@ -1070,7 +996,8 @@ gimp_iscissors_tool_key_press (GimpTool    *tool,
     case GDK_KEY_ISO_Enter:
       if (iscissors->connected && iscissors->mask)
         {
-          gimp_iscissors_tool_apply (iscissors, display);
+          gimp_tool_control (tool, GIMP_TOOL_ACTION_COMMIT, display);
+          gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
           return TRUE;
         }
       return FALSE;
@@ -1085,27 +1012,69 @@ gimp_iscissors_tool_key_press (GimpTool    *tool,
 }
 
 static void
-gimp_iscissors_tool_apply (GimpIscissorsTool *iscissors,
-                           GimpDisplay       *display)
+gimp_iscissors_tool_halt (GimpIscissorsTool *iscissors,
+                          GimpDisplay       *display)
 {
-  GimpTool             *tool    = GIMP_TOOL (iscissors);
-  GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
-  GimpImage            *image   = gimp_display_get_image (display);
+  /*  Free and reset the curve list  */
+  while (! g_queue_is_empty (iscissors->curves))
+    {
+      ICurve *curve = g_queue_pop_head (iscissors->curves);
 
-  gimp_draw_tool_stop (GIMP_DRAW_TOOL (tool));
+      if (curve->points)
+        g_ptr_array_free (curve->points, TRUE);
 
-  gimp_channel_select_channel (gimp_image_get_mask (image),
-                               tool->tool_info->blurb,
-                               iscissors->mask,
-                               0, 0,
-                               options->operation,
-                               options->feather,
-                               options->feather_radius,
-                               options->feather_radius);
+      g_slice_free (ICurve, curve);
+    }
 
-  gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
+  /*  free mask  */
+  if (iscissors->mask)
+    {
+      g_object_unref (iscissors->mask);
+      iscissors->mask = NULL;
+    }
+
+  /* free the gradient map */
+  if (iscissors->gradient_map)
+    {
+      g_object_unref (iscissors->gradient_map);
+      iscissors->gradient_map = NULL;
+    }
 
-  gimp_image_flush (image);
+  iscissors->curve1      = NULL;
+  iscissors->curve2      = NULL;
+  iscissors->first_point = TRUE;
+  iscissors->connected   = FALSE;
+  iscissors->state       = NO_ACTION;
+
+  /*  Reset the dp buffers  */
+  if (iscissors->dp_buf)
+    {
+      gimp_temp_buf_unref (iscissors->dp_buf);
+      iscissors->dp_buf = NULL;
+    }
+}
+
+static void
+gimp_iscissors_tool_commit (GimpIscissorsTool *iscissors,
+                            GimpDisplay       *display)
+{
+  GimpTool             *tool    = GIMP_TOOL (iscissors);
+  GimpSelectionOptions *options = GIMP_SELECTION_TOOL_GET_OPTIONS (tool);
+  GimpImage            *image   = gimp_display_get_image (display);
+
+  if (iscissors->connected && iscissors->mask)
+    {
+      gimp_channel_select_channel (gimp_image_get_mask (image),
+                                   tool->tool_info->blurb,
+                                   iscissors->mask,
+                                   0, 0,
+                                   options->operation,
+                                   options->feather,
+                                   options->feather_radius,
+                                   options->feather_radius);
+
+      gimp_image_flush (image);
+    }
 }
 
 
@@ -1345,8 +1314,8 @@ calculate_curve (GimpIscissorsTool *iscissors,
 
       /* Initialise the gradient map tile manager for this image if we
        * don't already have one. */
-      if (!iscissors->gradient_map)
-          iscissors->gradient_map = gradient_map_new (image);
+      if (! iscissors->gradient_map)
+        iscissors->gradient_map = gradient_map_new (image);
 
       /*  allocate the dynamic programming array  */
       if (iscissors->dp_buf)
@@ -1394,51 +1363,46 @@ calculate_curve (GimpIscissorsTool *iscissors,
 
 /* badly need to get a replacement - this is _way_ too expensive */
 static gboolean
-gradient_map_value (TileManager *map,
-                    gint         x,
-                    gint         y,
-                    guint8      *grad,
-                    guint8      *dir)
+gradient_map_value (GeglBuffer *map,
+                    gint        x,
+                    gint        y,
+                    guint8     *grad,
+                    guint8     *dir)
 {
-  static gint   cur_tilex;
-  static gint   cur_tiley;
-  const guint8 *p;
+  const GeglRectangle *extents;
+
+  extents = gegl_buffer_get_extent (map);
 
-  if (! cur_tile ||
-      x / TILE_WIDTH != cur_tilex ||
-      y / TILE_HEIGHT != cur_tiley)
+  if (x >= extents->x     &&
+      y >= extents->y     &&
+      x <  extents->width &&
+      y <  extents->height)
     {
-      if (cur_tile)
-        tile_release (cur_tile, FALSE);
+      guint8 sample[2];
 
-      cur_tile = tile_manager_get_tile (map, x, y, TRUE, FALSE);
+      gegl_buffer_sample (map, x, y, NULL, sample, NULL,
+                          GEGL_SAMPLER_NEAREST, GEGL_ABYSS_NONE);
 
-      if (!cur_tile)
-        return FALSE;
+      *grad = sample[0];
+      *dir  = sample[1];
 
-      cur_tilex = x / TILE_WIDTH;
-      cur_tiley = y / TILE_HEIGHT;
+      return TRUE;
     }
 
-  p = tile_data_pointer (cur_tile, x, y);
-
-  *grad = p[0];
-  *dir  = p[1];
-
-  return TRUE;
+  return FALSE;
 }
 
 static gint
-calculate_link (TileManager *gradient_map,
-                gint         x,
-                gint         y,
-                guint32      pixel,
-                gint         link)
+calculate_link (GeglBuffer *gradient_map,
+                gint        x,
+                gint        y,
+                guint32     pixel,
+                gint        link)
 {
   gint   value = 0;
   guint8 grad1, dir1, grad2, dir2;
 
-  if (!gradient_map_value (gradient_map, x, y, &grad1, &dir1))
+  if (! gradient_map_value (gradient_map, x, y, &grad1, &dir1))
     {
       grad1 = 0;
       dir1 = 255;
@@ -1458,7 +1422,7 @@ calculate_link (TileManager *gradient_map,
   x += (gint8)(pixel & 0xff);
   y += (gint8)((pixel & 0xff00) >> 8);
 
-  if (!gradient_map_value (gradient_map, x, y, &grad2, &dir2))
+  if (! gradient_map_value (gradient_map, x, y, &grad2, &dir2))
     {
       grad2 = 0;
       dir2 = 255;
@@ -1521,7 +1485,7 @@ plot_pixels (GimpIscissorsTool *iscissors,
 
 
 static void
-find_optimal_path (TileManager *gradient_map,
+find_optimal_path (GeglBuffer  *gradient_map,
                    GimpTempBuf *dp_buf,
                    gint         x1,
                    gint         y1,
@@ -1654,159 +1618,30 @@ find_optimal_path (TileManager *gradient_map,
     }
 }
 
-
-/* Called to fill in a newly referenced tile in the gradient map */
-static void
-gradmap_tile_validate (TileManager *tm,
-                       Tile        *tile,
-                       GimpImage   *image)
+static GeglBuffer *
+gradient_map_new (GimpImage *image)
 {
-  GimpPickable *pickable;
-  const Babl   *pickable_format;
-  GeglBuffer   *src_buffer;
-  Tile         *srctile;
-  PixelRegion   srcPR;
-  PixelRegion   destPR;
-  gint          x, y;
-  gint          dw, dh;
-  gint          sw, sh;
-  gint          i, j;
-  gint          b;
-  gfloat        gradient;
-  guint8       *tiledata;
-  guint8       *gradmap;
-
-  tile_manager_get_tile_coordinates (tm, tile, &x, &y);
-
-  dw = tile_ewidth (tile);
-  dh = tile_eheight (tile);
-
-  pickable = GIMP_PICKABLE (image);
-
-  gimp_pickable_flush (pickable);
-
-  /* get corresponding tile in the image */
-  src_buffer = gimp_pickable_get_buffer (pickable);
-  srctile = tile_manager_get_tile (gimp_gegl_buffer_get_tiles (src_buffer),
-                                   x, y, TRUE, FALSE);
-  if (! srctile)
-    return;
-
-  sw = tile_ewidth (srctile);
-  sh = tile_eheight (srctile);
-
-  pickable_format = gimp_pickable_get_format (pickable);
-
-  pixel_region_init_data (&srcPR,
-                          tile_data_pointer (srctile, 0, 0),
-                          babl_format_get_bytes_per_pixel (pickable_format),
-                          babl_format_get_bytes_per_pixel (pickable_format) *
-                          MIN (dw, sw),
-                          0, 0, MIN (dw, sw), MIN (dh, sh));
-
-
-  /* XXX tile edges? */
-
-  /*  Blur the source to get rid of noise  */
-  pixel_region_init_data (&destPR, maxgrad_conv0, 4, TILE_WIDTH * 4,
-                          0, 0, srcPR.w, srcPR.h);
-  convolve_region (&srcPR, &destPR, blur_32, 3, 32, GIMP_NORMAL_CONVOL, FALSE);
-
-  /*  Use the blurred region as the new source pixel region  */
-  pixel_region_init_data (&srcPR, maxgrad_conv0, 4, TILE_WIDTH * 4,
-                          0, 0, srcPR.w, srcPR.h);
+  GeglBuffer      *buffer;
+  GeglTileHandler *handler;
 
-  /*  Get the horizontal derivative  */
-  pixel_region_init_data (&destPR, maxgrad_conv1, 4, TILE_WIDTH * 4,
-                          0, 0, srcPR.w, srcPR.h);
-  convolve_region (&srcPR, &destPR, horz_deriv, 3, 1, GIMP_NEGATIVE_CONVOL,
-                   FALSE);
+  buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+                                            gimp_image_get_width  (image),
+                                            gimp_image_get_height (image)),
+                            babl_format_n (babl_type ("u8"), 2));
 
-  /*  Get the vertical derivative  */
-  pixel_region_init_data (&destPR, maxgrad_conv2, 4, TILE_WIDTH * 4,
-                          0, 0, srcPR.w, srcPR.h);
-  convolve_region (&srcPR, &destPR, vert_deriv, 3, 1, GIMP_NEGATIVE_CONVOL,
-                   FALSE);
+  handler = gimp_tile_handler_iscissors_new (image);
 
-  /* calculate overall gradient */
-  tiledata = tile_data_pointer (tile, 0, 0);
+  gimp_tile_handler_validate_assign (GIMP_TILE_HANDLER_VALIDATE (handler),
+                                     buffer);
 
-  for (i = 0; i < srcPR.h; i++)
-    {
-      const guint8 *datah = maxgrad_conv1 + srcPR.rowstride * i;
-      const guint8 *datav = maxgrad_conv2 + srcPR.rowstride * i;
-
-      gradmap = tiledata + tile_ewidth (tile) * COST_WIDTH * i;
-
-      for (j = 0; j < srcPR.w; j++)
-        {
-          gint8 hmax = datah[0] - 128;
-          gint8 vmax = datav[0] - 128;
+  gimp_tile_handler_validate_invalidate (GIMP_TILE_HANDLER_VALIDATE (handler),
+                                         0, 0,
+                                         gimp_image_get_width  (image),
+                                         gimp_image_get_height (image));
 
-          for (b = 1; b < srcPR.bytes; b++)
-            {
-              if (abs (datah[b] - 128) > abs (hmax))
-                hmax = datah[b] - 128;
-
-              if (abs (datav[b] - 128) > abs (vmax))
-                vmax = datav[b] - 128;
-            }
+  g_object_unref (handler);
 
-          if (i == 0 || j == 0 || i == srcPR.h-1 || j == srcPR.w-1)
-            {
-              gradmap[j * COST_WIDTH + 0] = 0;
-              gradmap[j * COST_WIDTH + 1] = 255;
-              goto contin;
-            }
-
-          /* 1 byte absolute magnitude first */
-          gradient = sqrt (SQR (hmax) + SQR (vmax));
-          gradmap[j * COST_WIDTH] = gradient * 255 / MAX_GRADIENT;
-
-          /* then 1 byte direction */
-          if (gradient > MIN_GRADIENT)
-            {
-              gfloat direction;
-
-              if (!hmax)
-                direction = (vmax > 0) ? G_PI_2 : -G_PI_2;
-              else
-                direction = atan ((gdouble) vmax / (gdouble) hmax);
-
-              /* Scale the direction from between 0 and 254,
-               *  corresponding to -PI/2, PI/2 255 is reserved for
-               *  d9irectionless pixels */
-              gradmap[j * COST_WIDTH + 1] =
-                (guint8) (254 * (direction + G_PI_2) / G_PI);
-            }
-          else
-            {
-              gradmap[j * COST_WIDTH + 1] = 255; /* reserved for weak gradient */
-            }
-
-        contin:
-          datah += srcPR.bytes;
-          datav += srcPR.bytes;
-        }
-    }
-
-  tile_release (srctile, FALSE);
-}
-
-static TileManager *
-gradient_map_new (GimpImage *image)
-{
-  TileManager *tm;
-
-  tm = tile_manager_new (gimp_image_get_width  (image),
-                         gimp_image_get_height (image),
-                         sizeof (guint8) * COST_WIDTH);
-
-  tile_manager_set_validate_proc (tm,
-                                  (TileValidateProc) gradmap_tile_validate,
-                                  image);
-
-  return tm;
+  return buffer;
 }
 
 static void
@@ -1815,14 +1650,12 @@ find_max_gradient (GimpIscissorsTool *iscissors,
                    gint              *x,
                    gint              *y)
 {
-  PixelRegion  srcPR;
-  gint         radius;
-  gint         i, j;
-  gint         endx, endy;
-  gint         cx, cy;
-  gint         x1, y1, x2, y2;
-  gpointer     pr;
-  gfloat       max_gradient;
+  GeglBufferIterator *iter;
+  GeglRectangle      *roi;
+  gint                radius;
+  gint                cx, cy;
+  gint                x1, y1, x2, y2;
+  gfloat              max_gradient;
 
   /* Initialise the gradient map tile manager for this image if we
    * don't already have one. */
@@ -1844,29 +1677,30 @@ find_max_gradient (GimpIscissorsTool *iscissors,
   *x = cx;
   *y = cy;
 
-  /*  Find the point of max gradient  */
-  pixel_region_init (&srcPR, iscissors->gradient_map,
-                     x1, y1, x2 - x1, y2 - y1, FALSE);
+  iter = gegl_buffer_iterator_new (iscissors->gradient_map,
+                                   GEGL_RECTANGLE (x1, y1, x2 - x1, y2 - y1),
+                                   0, NULL,
+                                   GEGL_ACCESS_READ, GEGL_ABYSS_NONE);
+  roi = &iter->roi[0];
 
-  /* this iterates over 1, 2 or 4 tiles only */
-  for (pr = pixel_regions_register (1, &srcPR);
-       pr != NULL;
-       pr = pixel_regions_process (pr))
+  while (gegl_buffer_iterator_next (iter))
     {
-      endx = srcPR.x + srcPR.w;
-      endy = srcPR.y + srcPR.h;
+      guint8 *data = iter->data[0];
+      gint    endx = roi->x + roi->width;
+      gint    endy = roi->y + roi->height;
+      gint    i, j;
 
-      for (i = srcPR.y; i < endy; i++)
+      for (i = roi->y; i < endy; i++)
         {
-          const guint8 *gradient = srcPR.data + srcPR.rowstride * (i - srcPR.y);
+          const guint8 *gradient = data + 2 * roi->width * (i - roi->y);
 
-          for (j = srcPR.x; j < endx; j++)
+          for (j = roi->x; j < endx; j++)
             {
               gfloat g = *gradient;
 
               gradient += COST_WIDTH;
 
-              g *= distance_weights [(i-y1) * GRADIENT_SEARCH + (j-x1)];
+              g *= distance_weights [(i - y1) * GRADIENT_SEARCH + (j - x1)];
 
               if (g > max_gradient)
                 {
@@ -1879,5 +1713,3 @@ find_max_gradient (GimpIscissorsTool *iscissors,
         }
     }
 }
-
-#endif
diff --git a/app/tools/gimpiscissorstool.h b/app/tools/gimpiscissorstool.h
index 74e2325..e0941d9 100644
--- a/app/tools/gimpiscissorstool.h
+++ b/app/tools/gimpiscissorstool.h
@@ -15,8 +15,6 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#if 0
-
 #ifndef __GIMP_ISCISSORS_TOOL_H__
 #define __GIMP_ISCISSORS_TOOL_H__
 
@@ -86,7 +84,7 @@ struct _GimpIscissorsTool
 
   /* XXX might be useful */
   GimpChannel    *mask;         /*  selection mask                        */
-  TileManager    *gradient_map; /*  lazily filled gradient map            */
+  GeglBuffer     *gradient_map; /*  lazily filled gradient map            */
 };
 
 struct _GimpIscissorsToolClass
@@ -102,5 +100,3 @@ GType   gimp_iscissors_tool_get_type (void) G_GNUC_CONST;
 
 
 #endif  /*  __GIMP_ISCISSORS_TOOL_H__  */
-
-#endif
diff --git a/app/tools/gimptilehandleriscissors.c b/app/tools/gimptilehandleriscissors.c
new file mode 100644
index 0000000..dd4150d
--- /dev/null
+++ b/app/tools/gimptilehandleriscissors.c
@@ -0,0 +1,330 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 <stdlib.h>
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include "libgimpmath/gimpmath.h"
+
+#include "tools-types.h"
+
+#include "gegl/gimp-gegl-loops.h"
+
+#include "core/gimpimage.h"
+#include "core/gimppickable.h"
+
+#include "gimptilehandleriscissors.h"
+
+
+enum
+{
+  PROP_0,
+  PROP_IMAGE
+};
+
+
+static void   gimp_tile_handler_iscissors_finalize     (GObject         *object);
+static void   gimp_tile_handler_iscissors_set_property (GObject         *object,
+                                                        guint            property_id,
+                                                        const GValue    *value,
+                                                        GParamSpec      *pspec);
+static void   gimp_tile_handler_iscissors_get_property (GObject         *object,
+                                                        guint            property_id,
+                                                        GValue          *value,
+                                                        GParamSpec      *pspec);
+
+static void   gimp_tile_handler_iscissors_validate     (GimpTileHandlerValidate *validate,
+                                                        const GeglRectangle     *rect,
+                                                        const Babl              *format,
+                                                        gpointer                 dest_buf,
+                                                        gint                     dest_stride);
+
+
+G_DEFINE_TYPE (GimpTileHandlerIscissors, gimp_tile_handler_iscissors,
+               GIMP_TYPE_TILE_HANDLER_VALIDATE)
+
+#define parent_class gimp_tile_handler_iscissors_parent_class
+
+
+static void
+gimp_tile_handler_iscissors_class_init (GimpTileHandlerIscissorsClass *klass)
+{
+  GObjectClass                 *object_class = G_OBJECT_CLASS (klass);
+  GimpTileHandlerValidateClass *validate_class;
+
+  validate_class = GIMP_TILE_HANDLER_VALIDATE_CLASS (klass);
+
+  object_class->finalize     = gimp_tile_handler_iscissors_finalize;
+  object_class->set_property = gimp_tile_handler_iscissors_set_property;
+  object_class->get_property = gimp_tile_handler_iscissors_get_property;
+
+  validate_class->validate   = gimp_tile_handler_iscissors_validate;
+
+  g_object_class_install_property (object_class, PROP_IMAGE,
+                                   g_param_spec_object ("image", NULL, NULL,
+                                                        GIMP_TYPE_IMAGE,
+                                                        GIMP_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gimp_tile_handler_iscissors_init (GimpTileHandlerIscissors *iscissors)
+{
+}
+
+static void
+gimp_tile_handler_iscissors_finalize (GObject *object)
+{
+  GimpTileHandlerIscissors *iscissors = GIMP_TILE_HANDLER_ISCISSORS (object);
+
+  if (iscissors->image)
+    {
+      g_object_unref (iscissors->image);
+      iscissors->image = NULL;
+    }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gimp_tile_handler_iscissors_set_property (GObject      *object,
+                                          guint         property_id,
+                                          const GValue *value,
+                                          GParamSpec   *pspec)
+{
+  GimpTileHandlerIscissors *iscissors = GIMP_TILE_HANDLER_ISCISSORS (object);
+
+  switch (property_id)
+    {
+    case PROP_IMAGE:
+      iscissors->image = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_tile_handler_iscissors_get_property (GObject    *object,
+                                          guint       property_id,
+                                          GValue     *value,
+                                          GParamSpec *pspec)
+{
+  GimpTileHandlerIscissors *iscissors = GIMP_TILE_HANDLER_ISCISSORS (object);
+
+  switch (property_id)
+    {
+    case PROP_IMAGE:
+      g_value_set_object (value, iscissors->image);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static const gfloat horz_deriv[9] =
+{
+  1,  0, -1,
+  2,  0, -2,
+  1,  0, -1,
+};
+
+static const gfloat vert_deriv[9] =
+{
+  1,  2,  1,
+  0,  0,  0,
+  -1, -2, -1,
+};
+
+static const gfloat blur_32[9] =
+{
+  1,  1,  1,
+  1, 24,  1,
+  1,  1,  1,
+};
+
+#define  MAX_GRADIENT 179.606  /* == sqrt (127^2 + 127^2) */
+#define  MIN_GRADIENT  63      /* gradients < this are directionless */
+#define  COST_WIDTH     2      /* number of bytes for each pixel in cost map */
+
+static void
+gimp_tile_handler_iscissors_validate (GimpTileHandlerValidate *validate,
+                                      const GeglRectangle     *rect,
+                                      const Babl              *format,
+                                      gpointer                 dest_buf,
+                                      gint                     dest_stride)
+{
+  GimpTileHandlerIscissors *iscissors = GIMP_TILE_HANDLER_ISCISSORS (validate);
+  GeglBuffer               *src;
+  GeglBuffer               *temp0;
+  GeglBuffer               *temp1;
+  GeglBuffer               *temp2;
+  gint                      stride1;
+  gint                      stride2;
+  gint                      i, j;
+
+  /*  temporary convolution buffers --  */
+  guchar *maxgrad_conv1;
+  guchar *maxgrad_conv2;
+
+#if 0
+  g_printerr ("validating at %d %d %d %d\n",
+              rect->x,
+              rect->y,
+              rect->width,
+              rect->height);
+#endif
+
+  gimp_pickable_flush (GIMP_PICKABLE (iscissors->image));
+
+  src = gimp_pickable_get_buffer (GIMP_PICKABLE (iscissors->image));
+
+  temp0 = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+                                           rect->width,
+                                           rect->height),
+                           babl_format ("R'G'B'A u8"));
+
+  temp1 = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+                                           rect->width,
+                                           rect->height),
+                           babl_format ("R'G'B'A u8"));
+
+  temp2 = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+                                           rect->width,
+                                           rect->height),
+                           babl_format ("R'G'B'A u8"));
+
+  /* XXX tile edges? */
+
+  /*  Blur the source to get rid of noise  */
+  gimp_gegl_convolve (src,   rect,
+                      temp0, GEGL_RECTANGLE (0, 0, rect->width, rect->height),
+                      blur_32, 3, 32, GIMP_NORMAL_CONVOL, FALSE);
+
+  /*  Use this blurred region as the new source  */
+
+  /*  Get the horizontal derivative  */
+  gimp_gegl_convolve (temp0, GEGL_RECTANGLE (0, 0, rect->width, rect->height),
+                      temp1, GEGL_RECTANGLE (0, 0, rect->width, rect->height),
+                      horz_deriv, 3, 1, GIMP_NEGATIVE_CONVOL, FALSE);
+
+  /*  Get the vertical derivative  */
+  gimp_gegl_convolve (temp0, GEGL_RECTANGLE (0, 0, rect->width, rect->height),
+                      temp2, GEGL_RECTANGLE (0, 0, rect->width, rect->height),
+                      vert_deriv, 3, 1, GIMP_NEGATIVE_CONVOL, FALSE);
+
+  maxgrad_conv1 = gegl_buffer_linear_open (temp1,
+                                           GEGL_RECTANGLE (0, 0,
+                                                           rect->width,
+                                                           rect->height),
+                                           &stride1, NULL);
+
+  maxgrad_conv2 = gegl_buffer_linear_open (temp2,
+                                           GEGL_RECTANGLE (0, 0,
+                                                           rect->width,
+                                                           rect->height),
+                                           &stride2, NULL);
+
+  /* calculate overall gradient */
+
+  for (i = 0; i < rect->height; i++)
+    {
+      const guint8 *datah   = maxgrad_conv1 + stride1 * i;
+      const guint8 *datav   = maxgrad_conv2 + stride2 * i;
+      guint8       *gradmap = (guint8 *) dest_buf + dest_stride * i;
+
+      for (j = 0; j < rect->width; j++)
+        {
+          gint8  hmax = datah[0] - 128;
+          gint8  vmax = datav[0] - 128;
+          gfloat gradient;
+          gint   b;
+
+          for (b = 1; b < 4; b++)
+            {
+              if (abs (datah[b] - 128) > abs (hmax))
+                hmax = datah[b] - 128;
+
+              if (abs (datav[b] - 128) > abs (vmax))
+                vmax = datav[b] - 128;
+            }
+
+          if (i == 0 || j == 0 || i == rect->height - 1 || j == rect->width - 1)
+            {
+              gradmap[j * COST_WIDTH + 0] = 0;
+              gradmap[j * COST_WIDTH + 1] = 255;
+              goto contin;
+            }
+
+          /* 1 byte absolute magnitude first */
+          gradient = sqrt (SQR (hmax) + SQR (vmax));
+          gradmap[j * COST_WIDTH] = gradient * 255 / MAX_GRADIENT;
+
+          /* then 1 byte direction */
+          if (gradient > MIN_GRADIENT)
+            {
+              gfloat direction;
+
+              if (! hmax)
+                direction = (vmax > 0) ? G_PI_2 : -G_PI_2;
+              else
+                direction = atan ((gdouble) vmax / (gdouble) hmax);
+
+              /* Scale the direction from between 0 and 254,
+               *  corresponding to -PI/2, PI/2 255 is reserved for
+               *  directionless pixels
+               */
+              gradmap[j * COST_WIDTH + 1] =
+                (guint8) (254 * (direction + G_PI_2) / G_PI);
+            }
+          else
+            {
+              gradmap[j * COST_WIDTH + 1] = 255; /* reserved for weak gradient */
+            }
+
+        contin:
+          datah += 4;
+          datav += 4;
+        }
+    }
+
+  gegl_buffer_linear_close (temp1, maxgrad_conv1);
+  gegl_buffer_linear_close (temp2, maxgrad_conv2);
+
+  g_object_unref (temp0);
+  g_object_unref (temp1);
+  g_object_unref (temp2);
+}
+
+GeglTileHandler *
+gimp_tile_handler_iscissors_new (GimpImage *image)
+{
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
+
+  return g_object_new (GIMP_TYPE_TILE_HANDLER_ISCISSORS,
+                       "whole-tile", TRUE,
+                       "image",      image,
+                       NULL);
+}
diff --git a/app/tools/gimptilehandleriscissors.h b/app/tools/gimptilehandleriscissors.h
new file mode 100644
index 0000000..756f5ce
--- /dev/null
+++ b/app/tools/gimptilehandleriscissors.h
@@ -0,0 +1,59 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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/>.
+ */
+
+#ifndef __GIMP_TILE_HANDLER_ISCISSORS_H__
+#define __GIMP_TILE_HANDLER_ISCISSORS_H__
+
+
+#include "gegl/gimptilehandlervalidate.h"
+
+
+/***
+ * GimpTileHandlerIscissors is a GeglTileHandler that renders the
+ * Iscissors tool's gradmap.
+ */
+
+#define GIMP_TYPE_TILE_HANDLER_ISCISSORS            (gimp_tile_handler_iscissors_get_type ())
+#define GIMP_TILE_HANDLER_ISCISSORS(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
GIMP_TYPE_TILE_HANDLER_ISCISSORS, GimpTileHandlerIscissors))
+#define GIMP_TILE_HANDLER_ISCISSORS_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  
GIMP_TYPE_TILE_HANDLER_ISCISSORS, GimpTileHandlerIscissorsClass))
+#define GIMP_IS_TILE_HANDLER_ISCISSORS(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
GIMP_TYPE_TILE_HANDLER_ISCISSORS))
+#define GIMP_IS_TILE_HANDLER_ISCISSORS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  
GIMP_TYPE_TILE_HANDLER_ISCISSORS))
+#define GIMP_TILE_HANDLER_ISCISSORS_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  
GIMP_TYPE_TILE_HANDLER_ISCISSORS, GimpTileHandlerIscissorsClass))
+
+
+typedef struct _GimpTileHandlerIscissors      GimpTileHandlerIscissors;
+typedef struct _GimpTileHandlerIscissorsClass GimpTileHandlerIscissorsClass;
+
+struct _GimpTileHandlerIscissors
+{
+  GimpTileHandlerValidate  parent_instance;
+
+  GimpImage               *image;
+};
+
+struct _GimpTileHandlerIscissorsClass
+{
+  GimpTileHandlerValidateClass  parent_class;
+};
+
+
+GType             gimp_tile_handler_iscissors_get_type (void) G_GNUC_CONST;
+
+GeglTileHandler * gimp_tile_handler_iscissors_new      (GimpImage *image);
+
+
+#endif /* __GIMP_TILE_HANDLER_ISCISSORS_H__ */
diff --git a/menus/image-menu.xml.in b/menus/image-menu.xml.in
index 313c575..319d1e2 100644
--- a/menus/image-menu.xml.in
+++ b/menus/image-menu.xml.in
@@ -574,9 +574,7 @@
         <menuitem action="tools-foreground-select" />
         <menuitem action="tools-fuzzy-select" />
         <menuitem action="tools-by-color-select" />
-       <!--
         <menuitem action="tools-iscissors" />
-       -->
       </menu>
       <menu action="tools-paint-menu" name="Paint Tools">
         <menuitem action="tools-bucket-fill" />



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