[gimp/soc-2011-seamless-clone] Add outline finding code for the tool, including outline preview



commit e3908956d5d4759ea445191f97d658915a8ed281
Author: Barak Itkin <lightningismyname gmail com>
Date:   Mon Jul 18 18:15:41 2011 +0300

    Add outline finding code for the tool, including outline preview

 app/gegl/Makefile.am                |    2 +
 app/gegl/gimp-gegl-types.h          |    1 +
 app/gegl/gimp-gegl.c                |    2 +
 app/gegl/gimpoperationfindoutline.c |  430 +++++++++++++++++++++++++++++++++++
 app/gegl/gimpoperationfindoutline.h |   68 ++++++
 app/tools/gimpseamlessclonetool.c   |   80 ++++++-
 app/tools/gimpseamlessclonetool.h   |    2 +
 7 files changed, 580 insertions(+), 5 deletions(-)
---
diff --git a/app/gegl/Makefile.am b/app/gegl/Makefile.am
index addc33f..bcd5143 100644
--- a/app/gegl/Makefile.am
+++ b/app/gegl/Makefile.am
@@ -65,6 +65,8 @@ libappgegl_a_sources = \
 	gimpoperationcurves.h		\
 	gimpoperationdesaturate.c	\
 	gimpoperationdesaturate.h	\
+	gimpoperationfindoutline.c	\
+	gimpoperationfindoutline.h	\
 	gimpoperationhuesaturation.c	\
 	gimpoperationhuesaturation.h	\
 	gimpoperationlevels.c		\
diff --git a/app/gegl/gimp-gegl-types.h b/app/gegl/gimp-gegl-types.h
index af17404..413d341 100644
--- a/app/gegl/gimp-gegl-types.h
+++ b/app/gegl/gimp-gegl-types.h
@@ -37,6 +37,7 @@ typedef struct _GimpOperationCageCoefCalc     GimpOperationCageCoefCalc;
 typedef struct _GimpOperationCageTransform    GimpOperationCageTransform;
 typedef struct _GimpOperationCurves           GimpOperationCurves;
 typedef struct _GimpOperationDesaturate       GimpOperationDesaturate;
+typedef struct _GimpOperationFindOutline      GimpOperationFindOutline;
 typedef struct _GimpOperationHueSaturation    GimpOperationHueSaturation;
 typedef struct _GimpOperationLevels           GimpOperationLevels;
 typedef struct _GimpOperationPosterize        GimpOperationPosterize;
diff --git a/app/gegl/gimp-gegl.c b/app/gegl/gimp-gegl.c
index e5f8a51..c07f380 100644
--- a/app/gegl/gimp-gegl.c
+++ b/app/gegl/gimp-gegl.c
@@ -37,6 +37,7 @@
 #include "gimpoperationcolorize.h"
 #include "gimpoperationcurves.h"
 #include "gimpoperationdesaturate.h"
+#include "gimpoperationfindoutline.h"
 #include "gimpoperationhuesaturation.h"
 #include "gimpoperationlevels.h"
 #include "gimpoperationposterize.h"
@@ -103,6 +104,7 @@ gimp_gegl_init (Gimp *gimp)
   g_type_class_ref (GIMP_TYPE_OPERATION_COLORIZE);
   g_type_class_ref (GIMP_TYPE_OPERATION_CURVES);
   g_type_class_ref (GIMP_TYPE_OPERATION_DESATURATE);
+  g_type_class_ref (GIMP_TYPE_OPERATION_FIND_OUTLINE);
   g_type_class_ref (GIMP_TYPE_OPERATION_HUE_SATURATION);
   g_type_class_ref (GIMP_TYPE_OPERATION_LEVELS);
   g_type_class_ref (GIMP_TYPE_OPERATION_POSTERIZE);
diff --git a/app/gegl/gimpoperationfindoutline.c b/app/gegl/gimpoperationfindoutline.c
new file mode 100644
index 0000000..b54bc72
--- /dev/null
+++ b/app/gegl/gimpoperationfindoutline.c
@@ -0,0 +1,430 @@
+/* GIMP - The GNU Image Manipulation Program
+ *
+ * gimpoperationfindoutline.c
+ * Copyright (C) 2011 Barak Itkin <lightningismyname gmail com>
+ *
+ * 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 "gimp-gegl-types.h"
+
+#include "gimpoperationfindoutline.h"
+
+#include <stdio.h> /* TODO: get rid of this debugging way! */
+
+enum
+{
+  PROP0,
+  PROP_POINTS,
+  PROP_THRESHOLD,
+  PROP_X,
+  PROP_Y,
+  PROP_WIDTH,
+  PROP_HEIGHT
+};
+
+static void
+gimp_operation_find_outline_init (GimpOperationFindOutline *self);
+
+static void
+gimp_operation_find_outline_get_property (GObject    *object,
+                                          guint       property_id,
+                                          GValue     *value,
+                                          GParamSpec *pspec);
+
+static void
+gimp_operation_find_outline_set_property (GObject      *object,
+                                          guint         property_id,
+                                          const GValue *value,
+                                          GParamSpec   *pspec);
+
+
+static gboolean gimp_operation_find_outline_process (GeglOperation       *operation,
+                                                     GeglBuffer          *in_buf,
+                                                     const GeglRectangle *roi);
+
+static void
+gimp_operation_find_outline_prepare (GeglOperation *operation);
+
+G_DEFINE_TYPE (GimpOperationFindOutline, gimp_operation_find_outline,
+               GEGL_TYPE_OPERATION_SINK)
+
+#define parent_class gimp_operation_find_outline_parent_class
+
+static void
+gimp_operation_find_outline_class_init (GimpOperationFindOutlineClass *klass)
+{
+  GObjectClass           *object_class    = G_OBJECT_CLASS (klass);
+  GeglOperationClass     *operation_class = GEGL_OPERATION_CLASS (klass);
+  GeglOperationSinkClass *sink_class      = GEGL_OPERATION_SINK_CLASS (klass);
+
+  object_class->set_property = gimp_operation_find_outline_set_property;
+  object_class->get_property = gimp_operation_find_outline_get_property;
+
+  operation_class->prepare     = gimp_operation_find_outline_prepare;
+  operation_class->name        = "gimp:find-outline";
+  operation_class->categories  = "programming";
+  operation_class->description = "GIMP Outline Finding operation";
+
+  sink_class->process    = gimp_operation_find_outline_process;
+  sink_class->needs_full = TRUE;
+
+  g_object_class_install_property (object_class, PROP_POINTS,
+                                   g_param_spec_pointer ("points",
+                                                         "Points",
+                                                         "A GPtrArray* of struct {gint x, y;} containing the points",
+                                                         G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class, PROP_THRESHOLD,
+                                   g_param_spec_double ("threshold",
+                                                         "Threshold",
+                                                         "The threshold for determining the difference between black and white (white >= thres)",
+                                                         -G_MAXDOUBLE, G_MAXDOUBLE, 0.5,
+                                                         G_PARAM_READWRITE));
+
+  /* Workaround around wrong ROI calculation in GEGL for Sink ops when needs_full is set */
+  g_object_class_install_property (object_class, PROP_X,
+                                   g_param_spec_int ("x",
+                                                     "X",
+                                                     "The minimal x of the scaning rect",
+                                                     -G_MAXINT, G_MAXINT, 0,
+                                                     G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class, PROP_Y,
+                                   g_param_spec_int ("y",
+                                                     "Y",
+                                                     "The minimal Y of the scaning rect",
+                                                     -G_MAXINT, G_MAXINT, 0,
+                                                     G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class, PROP_WIDTH,
+                                   g_param_spec_int ("width",
+                                                     "Width",
+                                                     "The width of the scaning rect",
+                                                     0, G_MAXINT, 0,
+                                                     G_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class, PROP_HEIGHT,
+                                   g_param_spec_int ("height",
+                                                     "Height",
+                                                     "The height of the scaning rect",
+                                                     0, G_MAXINT, 0,
+                                                     G_PARAM_READWRITE));
+}
+
+static void
+gimp_operation_find_outline_init (GimpOperationFindOutline *self)
+{
+}
+
+static void
+gimp_operation_find_outline_get_property (GObject    *object,
+                                          guint       property_id,
+                                          GValue     *value,
+                                          GParamSpec *pspec)
+{
+  GimpOperationFindOutline *self = GIMP_OPERATION_FIND_OUTLINE (object);
+
+  switch (property_id)
+    {
+    case PROP_POINTS:
+      g_value_set_pointer (value, self->ptList);
+      break;
+    case PROP_THRESHOLD:
+      g_value_set_double (value, self->threshold);
+      break;
+    case PROP_X:
+      g_value_set_int (value, self->x);
+      break;
+    case PROP_Y:
+      g_value_set_int (value, self->y);
+      break;
+    case PROP_WIDTH:
+      g_value_set_int (value, self->width);
+      break;
+    case PROP_HEIGHT:
+      g_value_set_int (value, self->height);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_operation_find_outline_set_property (GObject      *object,
+                                          guint         property_id,
+                                          const GValue *value,
+                                          GParamSpec   *pspec)
+{
+  GimpOperationFindOutline *self = GIMP_OPERATION_FIND_OUTLINE (object);
+
+  switch (property_id)
+    {
+    case PROP_POINTS:
+      self->ptList = g_value_get_pointer (value);
+      break;
+    case PROP_THRESHOLD:
+      self->threshold = g_value_get_double (value);
+      break;
+    case PROP_X:
+      self->x = g_value_get_int (value);
+      break;
+    case PROP_Y:
+      self->y = g_value_get_int (value);
+      break;
+    case PROP_WIDTH:
+      self->width = g_value_get_int (value);
+      break;
+    case PROP_HEIGHT:
+      self->height = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+/*******************************************************************/
+/* Real operation logic begins here                                */
+/*******************************************************************/
+
+/* Define the directions
+ *
+ *          0
+ *         
+ *    7     N     1
+ *          ^
+ *          |
+ *          |           
+ * 6  W<----+---->E  2
+ *          |              =====>X
+ *          |             ||
+ *          v             ||
+ *    5     S     3       ||
+ *                        vv
+ *          4             Y
+ */
+typedef enum {
+  D_N = 0,    /* 000 */
+  D_NE = 1,   /* 001 */
+  D_E = 2,    /* 010 */
+  D_SE = 3,   /* 011 */
+  D_S = 4,    /* 100 */
+  D_SW = 5,   /* 101 */
+  D_W = 6,    /* 110 */
+  D_NW = 7    /* 111 */
+} OUTLINE_DIRECTION;
+
+#define cwdirection(t)       (((t)+1)%8)
+#define ccwdirection(t)      (((t)+7)%8)
+#define oppositedirection(t) (((t)+4)%8)
+
+#define isSouth(s) (((s) == D_S) || ((s) == D_SE) || ((s) == D_SW))
+#define isNorth(s) (((s) == D_N) || ((s) == D_NE) || ((s) == D_NW))
+
+#define isEast(s) (((s) == D_NE) || ((s) == D_E) || ((s) == D_SE))
+#define isWest(s) (((s) == D_NW) || ((s) == D_W) || ((s) == D_SW))
+
+typedef struct {
+  gint x, y;
+} SPoint;
+
+/**
+ * Add a COPY of the given point into the array pts. The original point CAN
+ * be freed later!
+ */
+static void
+gimp_operation_find_outline_add_point (GPtrArray* pts, SPoint *pt)
+{
+  printf ("Added %d,%d\n", pt->x, pt->y);
+  if (pts == NULL)
+    return;
+  SPoint *cpy = g_new (SPoint, 1);
+  cpy->x = pt->x;
+  cpy->y = pt->y;
+
+  g_ptr_array_add (pts, cpy);
+}
+
+static inline void
+gimp_operation_find_outline_move (SPoint *pt, OUTLINE_DIRECTION t, SPoint *dest)
+{
+  dest->x = pt->x + (isEast(t) ? 1 : (isWest(t) ? -1 : 0));
+  dest->y = pt->y + (isSouth(t) ? 1 : (isNorth(t) ? -1 : 0));
+}
+
+#define in_range(val,min,max)  (((min) <= (val)) && ((val) <= (max)))
+
+static inline gboolean
+gimp_operation_find_outline_is_inside (OutlineProcPrivate *OPP, SPoint *pt)
+{
+  return in_range (pt->x, OPP->xmin, OPP->xmax)
+         && in_range (pt->y, OPP->ymin, OPP->ymax);
+}
+
+#define get_value(OPP,x,y)  (((OPP)->im)[((y)-(OPP)->ymin)*(OPP)->rowstride+(x)-(OPP)->xmin])
+#define get_valuePT(OPP,pt) get_value(OPP,(pt)->x,(pt)->y)
+
+static inline gboolean
+gimp_operation_find_outline_is_white (OutlineProcPrivate *OPP, SPoint *pt)
+{
+  return gimp_operation_find_outline_is_inside (OPP, pt) && get_valuePT (OPP,pt) >= OPP->threshold;
+}
+
+/* This function receives a white pixel (pt) and the direction of the movement
+ * that lead to it (prevdirection). It will return the direction leading to the
+ * next white pixel (while following the edges in CW order), and the pixel
+ * itself would be stored in dest.
+ *
+ * The logic is simple:
+ * 1. Try to continue in the same direction that lead us to the current pixel
+ * 2. Dprev = oppposite(prevdirection)
+ * 3. Dnow  = cw(Dprev)
+ * 4. While moving to Dnow is white:
+ * 4.1. Dprev = Dnow
+ * 4.2. Dnow  = cw(D)
+ * 5. Return the result - moving by Dprev
+ */
+static inline OUTLINE_DIRECTION
+gimp_operation_find_outline_walk_cw (OutlineProcPrivate *OPP,
+                                     OUTLINE_DIRECTION   prevdirection,
+                                     SPoint             *pt,
+                                     SPoint             *dest)
+{
+  OUTLINE_DIRECTION Dprev = oppositedirection(prevdirection);
+  OUTLINE_DIRECTION Dnow = cwdirection (Dprev);
+ 
+  SPoint ptN, ptP;
+
+  gimp_operation_find_outline_move (pt, Dprev, &ptP);
+  gimp_operation_find_outline_move (pt, Dnow, &ptN);
+
+  while (gimp_operation_find_outline_is_white (OPP, &ptN))
+    {
+       Dprev = Dnow;
+       ptP.x = ptN.x;
+       ptP.y = ptN.y;
+       Dnow = cwdirection (Dprev);
+       gimp_operation_find_outline_move (pt, Dnow, &ptN);
+    }
+
+  dest->x = ptP.x;
+  dest->y = ptP.y;
+  return Dprev;
+}
+
+#define pteq(pt1,pt2) (((pt1)->x == (pt2)->x) && ((pt1)->y == (pt2)->y))
+
+static void
+gimp_operation_find_outline_find_outline_ccw (OutlineProcPrivate *OPP, GPtrArray *pts)
+{
+  gint x = OPP->xmin;
+  gint y;
+  gboolean found = FALSE;
+  SPoint START, pt, ptN;
+  OUTLINE_DIRECTION DIR, DIRN;
+  
+  /* First of all try to find a white pixel */
+  for (y = OPP->ymin; y < OPP->ymax; y++)
+    {
+      for (x = OPP->xmin; x < OPP->xmax; x++)
+        {
+          if (get_value (OPP, x, y) >= OPP->threshold)
+            {
+               printf ("Found first white on %d,%d\n",x,y);
+               found = TRUE;
+               break;
+            }
+        }
+      if (found) break;
+    }
+
+  if (!found)
+    return;
+  
+  pt.x = START.x = x;
+  pt.y = START.y = y;
+  DIR = D_NW;
+
+  gimp_operation_find_outline_add_point (pts, &START);
+
+  DIRN = gimp_operation_find_outline_walk_cw (OPP, DIR,&pt,&ptN);
+
+  while (! pteq(&ptN,&START))
+    {
+      gimp_operation_find_outline_add_point (pts, &ptN);
+      pt.x = ptN.x;
+      pt.y = ptN.y;
+      DIR = DIRN;
+      DIRN = gimp_operation_find_outline_walk_cw (OPP, DIR,&pt,&ptN);
+    }
+}
+
+static gboolean
+gimp_operation_find_outline_process (GeglOperation       *operation,
+                                     GeglBuffer          *input,
+                                     const GeglRectangle *result)
+{
+  GimpOperationFindOutline *self = GIMP_OPERATION_FIND_OUTLINE (operation);
+  OutlineProcPrivate *OPP = (OutlineProcPrivate *) &GIMP_OPERATION_FIND_OUTLINE(operation)->opp;
+  GeglRectangle rect;
+
+  rect.x = OPP->xmin = self->x;
+  rect.width = self->width;
+  OPP->xmax = self->x + self->width - 1;
+
+  rect.y = OPP->ymin = self->y;
+  rect.height = self->height;
+  OPP->ymax = self->y + self->height - 1;
+
+  OPP->threshold = self->threshold;
+  OPP->im = g_new (gdouble,(rect.width) * rect.height);
+  OPP->rowstride = rect.width;
+
+  gegl_buffer_get (input, 1.0, &rect, babl_format("Y double"), OPP->im, GEGL_AUTO_ROWSTRIDE);
+
+  gimp_operation_find_outline_find_outline_ccw (OPP, self->ptList);
+
+//  gint x, y;
+//  /* First of all try to find a white pixel */
+//  for (y = OPP->ymin; y < OPP->ymax; y++)
+//  {
+//    for (x = OPP->xmin; x < OPP->xmax; x++)
+//    {
+//      if (get_value (OPP, x, y) >= OPP->threshold)
+//        printf ("1");
+//      else
+//        printf ("0");
+//    }
+//    printf("\n");
+//  }
+
+  g_free (OPP->im);
+  OPP->im = NULL;
+
+  return  TRUE;
+}
+
+static void
+gimp_operation_find_outline_prepare (GeglOperation *operation)
+{
+  printf ("Preparing!\n");
+
+  gegl_operation_set_format (operation, "input", babl_format("Y double"));
+}
diff --git a/app/gegl/gimpoperationfindoutline.h b/app/gegl/gimpoperationfindoutline.h
new file mode 100644
index 0000000..ba80bc9
--- /dev/null
+++ b/app/gegl/gimpoperationfindoutline.h
@@ -0,0 +1,68 @@
+/* GIMP - The GNU Image Manipulation Program
+ *
+ * gimpoperationfindoutline.h
+ * Copyright (C) 2011 Barak Itkin <lightningismyname gmail com>
+ *
+ * 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_OPERATION_FIND_OUTLINE_H__
+#define __GIMP_OPERATION_FIND_OUTLINE_H__
+
+
+#include <gegl-plugin.h>
+#include <operation/gegl-operation-sink.h>
+
+
+#define GIMP_TYPE_OPERATION_FIND_OUTLINE            (gimp_operation_find_outline_get_type ())
+#define GIMP_OPERATION_FIND_OUTLINE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_FIND_OUTLINE, GimpOperationFindOutline))
+#define GIMP_OPERATION_FIND_OUTLINE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GIMP_TYPE_OPERATION_FIND_OUTLINE, GimpOperationFindOutlineClass))
+#define GIMP_IS_OPERATION_FIND_OUTLINE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_FIND_OUTLINE))
+#define GIMP_IS_OPERATION_FIND_OUTLINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  GIMP_TYPE_OPERATION_FIND_OUTLINE))
+#define GIMP_OPERATION_FIND_OUTLINE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  GIMP_TYPE_OPERATION_FIND_OUTLINE, GimpOperationFindOutlineClass))
+
+
+typedef struct _GimpOperationFindOutlineClass GimpOperationFindOutlineClass;
+
+typedef struct
+{
+  gint    xmin, xmax;
+  gint    ymin, ymax;
+  gint    rowstride;
+  gdouble  threshold;
+  gdouble *im;
+} OutlineProcPrivate;
+
+struct _GimpOperationFindOutline
+{
+  GeglOperationSink      parent_instance;
+
+  GPtrArray             *ptList;
+  gint                   x, y, width, height;
+  gdouble                threshold;
+
+  /* Remains from old versions. Merge with properties above one day */
+  OutlineProcPrivate    *opp;
+};
+
+struct _GimpOperationFindOutlineClass
+{
+  GeglOperationSinkClass  parent_class;
+};
+
+
+GType   gimp_operation_find_outline_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_OPERATION_FIND_OUTLINE_H__ */
diff --git a/app/tools/gimpseamlessclonetool.c b/app/tools/gimpseamlessclonetool.c
index 0774ec4..0354d42 100644
--- a/app/tools/gimpseamlessclonetool.c
+++ b/app/tools/gimpseamlessclonetool.c
@@ -213,6 +213,7 @@ gimp_seamless_clone_tool_init (GimpSeamlessCloneTool *self)
   self->render_node     = NULL;
   self->image_map       = NULL;
   self->translate_op    = NULL;
+  self->outline         = NULL;
 }
 
 static void
@@ -244,6 +245,13 @@ gimp_seamless_clone_tool_control (GimpTool       *tool,
           sct->translate_op = NULL;
         }
 
+      if (sct->outline)
+        {
+          /* The array was created with a free func, so no need to free */
+          g_ptr_array_free (sct->outline, TRUE);
+          sct->outline  = NULL;
+        }
+
       if (sct->image_map)
         {
           gimp_tool_control_set_preserve (tool->control, TRUE);
@@ -328,6 +336,17 @@ gimp_seamless_clone_tool_options_notify (GimpTool         *tool,
 }
 
 static void
+gimp_seamless_clone_tool_start (GimpSeamlessCloneTool *sct,
+                                GimpDisplay           *display)
+{
+  DBG_CALL_NAME();
+  GIMP_TOOL(sct)->display = display;
+  gimp_draw_tool_start (GIMP_DRAW_TOOL (sct), display);
+  // TODO free and update stuff
+
+
+}
+static void
 gimp_seamless_clone_tool_button_press (GimpTool            *tool,
                                        const GimpCoords    *coords,
                                        guint32              time,
@@ -337,8 +356,16 @@ gimp_seamless_clone_tool_button_press (GimpTool            *tool,
 {
   GimpSeamlessCloneTool *sct = GIMP_SEAMLESS_CLONE_TOOL (tool);
 
+  DBG_CALL_NAME();
+
+  if (tool->display != display)
+    {
+       gimp_seamless_clone_tool_start (sct, display);
+    }
+
   if (sct->state == SEAMLESS_CLONE_STATE_NOTHING)
     {
+      gimp_draw_tool_start (GIMP_DRAW_TOOL (sct), display);
       if (! sct->render_node)
         {
           gimp_seamless_clone_tool_create_render_node (sct);
@@ -474,11 +501,15 @@ gimp_seamless_clone_tool_cursor_update (GimpTool         *tool,
   GIMP_TOOL_CLASS (parent_class)->cursor_update (tool, coords, state, display);
 }
 
+typedef struct {
+  gint x, y;
+} SPoint;
+
 static void
 gimp_seamless_clone_tool_draw (GimpDrawTool *draw_tool)
 {
   GimpSeamlessCloneTool    *sct        = GIMP_SEAMLESS_CLONE_TOOL (draw_tool);
-
+  gint i;
   GimpCanvasGroup          *stroke_group;
 
   DBG_CALL_NAME();
@@ -487,23 +518,36 @@ gimp_seamless_clone_tool_draw (GimpDrawTool *draw_tool)
 
   gimp_draw_tool_push_group (draw_tool, stroke_group);
 
+  if (sct->outline)
+    {
+      printf ("Outline exists!\n");
+      if (sct->state != SEAMLESS_CLONE_STATE_MOTION)
+        for (i = 0; i < sct->outline->len; i++)
+        {
+           SPoint *n1 = (SPoint*)g_ptr_array_index (sct->outline, i);
+           SPoint *n2 = (SPoint*)g_ptr_array_index (sct->outline, (i+1) % sct->outline->len);
+           gimp_draw_tool_add_line (draw_tool, n1->x+sct->paste_x, n1->y+sct->paste_y, n2->x+sct->paste_x, n2->y+sct->paste_y);
+        }
+    }
+
   /* Draw the corner of the paste */
   if (sct->state == SEAMLESS_CLONE_STATE_MOTION)
     gimp_draw_tool_add_crosshair (draw_tool,
-        (gdouble)(sct->paste_x + (gint)(sct->cursor_x - sct->movement_start_x)),
-        (gdouble)(sct->paste_y + (gint)(sct->cursor_y - sct->movement_start_y)));
+        (gdouble)(sct->paste_x + (gint)(sct->cursor_x - sct->movement_start_x + sct->paste_w / 2)),
+        (gdouble)(sct->paste_y + (gint)(sct->cursor_y - sct->movement_start_y + sct->paste_h / 2)));
 
   gimp_draw_tool_pop_group (draw_tool);
 }
 
-/* TODO - extract this logic for general gimp->gegl buffer conversion */
+/* TODO - extract this logic for general gimp->gegl buffer conversion.
+ * Note this also computes and saves the outline of the buffer */
 static void
 gimp_buffer_to_gegl_buffer_with_progress (GimpSeamlessCloneTool *sct)
 {
   GimpProgress   *progress;
   GeglNode       *gegl;
   GeglNode       *input;
-  GeglNode       *output;
+  GeglNode       *output, *outline;
   GeglProcessor  *processor;
   GeglBuffer     *buffer;
   gdouble         value;
@@ -535,9 +579,20 @@ gimp_buffer_to_gegl_buffer_with_progress (GimpSeamlessCloneTool *sct)
                                 "buffer",    &buffer,
                                 NULL);
 
+  sct->outline = g_ptr_array_new_with_free_func (g_free);
+  outline = gegl_node_new_child (gegl,
+                                 "operation", "gimp:find-outline",
+                                 "points",    sct->outline,
+                                 "width",     gimp_buffer_get_width (gimpbuf),
+                                 "height",    gimp_buffer_get_height (gimpbuf),
+                                 NULL);
+
   gegl_node_connect_to (input, "output",
                         output, "input");
 
+  gegl_node_connect_to (input, "output",
+                        outline, "input");
+
   processor = gegl_node_new_processor (output, NULL);
 
   while (gegl_processor_work (processor, &value))
@@ -551,6 +606,21 @@ gimp_buffer_to_gegl_buffer_with_progress (GimpSeamlessCloneTool *sct)
 
   gegl_processor_destroy (processor);
 
+
+  processor = gegl_node_new_processor (outline, NULL);
+
+  while (gegl_processor_work (processor, &value))
+    {
+      if (progress)
+        gimp_progress_set_value (progress, value);
+    }
+
+  if (progress)
+    gimp_progress_end (progress);
+
+  gegl_processor_destroy (processor);
+
+
   sct->paste_buf = buffer;
   tempR = * gegl_buffer_get_extent (buffer);
   sct->paste_w = tempR.width;
diff --git a/app/tools/gimpseamlessclonetool.h b/app/tools/gimpseamlessclonetool.h
index ace2f58..dedfb35 100644
--- a/app/tools/gimpseamlessclonetool.h
+++ b/app/tools/gimpseamlessclonetool.h
@@ -65,6 +65,8 @@ struct _GimpSeamlessCloneTool
   GeglNode       *translate_op;
 
   GimpImageMap   *image_map;   /* Used for preview of the resulting drawable */
+
+  GPtrArray      *outline;
 };
 
 #define gimp_seamless_clone_coords_in_paste(sct,c)   \



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