[gimp] app: properly implement "spacing" option in the warp tool



commit e8a39d5c49a01d128f4237100845eda7523255f0
Author: Ell <ell_se yahoo com>
Date:   Sun Mar 3 15:53:28 2019 -0500

    app: properly implement "spacing" option in the warp tool
    
    The "spacing" option of the warp tool used to be handled by the
    gegl:warp op, and have little effect.  Instead, implement it in the
    warp tool directly, having the same effect as the other paint
    tools.
    
    Having a properly-working "spacing" option allows us to use EXACT
    motion mode without cirppling down performance, which means that
    the stroke now follows the pointer exactly, even when processing
    takes a while.
    
    Decrease the default "spacing" value to 10.

 app/tools/gimpwarpoptions.c |   2 +-
 app/tools/gimpwarptool.c    | 139 +++++++++++++++++++++++++++++---------------
 app/tools/gimpwarptool.h    |   6 +-
 3 files changed, 98 insertions(+), 49 deletions(-)
---
diff --git a/app/tools/gimpwarpoptions.c b/app/tools/gimpwarpoptions.c
index de0cbe67b1..f534c279c4 100644
--- a/app/tools/gimpwarpoptions.c
+++ b/app/tools/gimpwarpoptions.c
@@ -111,7 +111,7 @@ gimp_warp_options_class_init (GimpWarpOptionsClass *klass)
                            "stroke-spacing",
                            _("Spacing"),
                            _("Stroke Spacing"),
-                           1.0, 100.0, 20.0,
+                           1.0, 100.0, 10.0,
                            GIMP_PARAM_STATIC_STRINGS);
 
   GIMP_CONFIG_PROP_ENUM (object_class, PROP_INTERPOLATION,
diff --git a/app/tools/gimpwarptool.c b/app/tools/gimpwarptool.c
index 7ae3766e9e..f480003c11 100644
--- a/app/tools/gimpwarptool.c
+++ b/app/tools/gimpwarptool.c
@@ -131,9 +131,10 @@ static void       gimp_warp_tool_update_area        (GimpWarpTool          *wt,
                                                      const GeglRectangle   *area);
 static void       gimp_warp_tool_update_stroke      (GimpWarpTool          *wt,
                                                      GeglNode              *node);
-static void       gimp_warp_tool_stroke_changed     (GeglPath              *stroke,
-                                                     const GeglRectangle   *roi,
-                                                     GimpWarpTool          *wt);
+static void       gimp_warp_tool_stroke_append      (GimpWarpTool          *wt,
+                                                     gchar                  type,
+                                                     gdouble                x,
+                                                     gdouble                y);
 static void       gimp_warp_tool_filter_flush       (GimpDrawableFilter    *filter,
                                                      GimpTool              *tool);
 static void       gimp_warp_tool_add_op             (GimpWarpTool          *wt,
@@ -194,6 +195,7 @@ gimp_warp_tool_init (GimpWarpTool *self)
 {
   GimpTool *tool = GIMP_TOOL (self);
 
+  gimp_tool_control_set_motion_mode     (tool->control, GIMP_MOTION_MODE_EXACT);
   gimp_tool_control_set_scroll_lock     (tool->control, TRUE);
   gimp_tool_control_set_preserve        (tool->control, FALSE);
   gimp_tool_control_set_dirty_mask      (tool->control,
@@ -266,27 +268,32 @@ gimp_warp_tool_button_press (GimpTool            *tool,
 
   wt->current_stroke = gegl_path_new ();
 
+  wt->last_pos.x = coords->x;
+  wt->last_pos.y = coords->y;
+
+  wt->total_dist = 0.0;
+
   new_op = gegl_node_new_child (NULL,
                                 "operation", "gegl:warp",
                                 "behavior",  options->behavior,
                                 "size",      options->effect_size,
                                 "hardness",  options->effect_hardness / 100.0,
                                 "strength",  options->effect_strength,
-                                "spacing",   options->stroke_spacing / 100.0,
+                                /* we implement spacing manually.
+                                 * anything > 1 will do.
+                                 */
+                                "spacing",   10.0,
                                 "stroke",    wt->current_stroke,
                                 NULL);
 
   gimp_warp_tool_add_op (wt, new_op);
   g_object_unref (new_op);
 
-  g_signal_connect (wt->current_stroke, "changed",
-                    G_CALLBACK (gimp_warp_tool_stroke_changed),
-                    wt);
-
   gimp_item_get_offset (GIMP_ITEM (tool->drawable), &off_x, &off_y);
 
-  gegl_path_append (wt->current_stroke,
-                    'M', coords->x - off_x, coords->y - off_y);
+  gimp_warp_tool_stroke_append (wt,
+                                'M', wt->last_pos.x - off_x,
+                                     wt->last_pos.y - off_y);
 
   gimp_warp_tool_start_stroke_timer (wt);
 
@@ -309,10 +316,6 @@ gimp_warp_tool_button_release (GimpTool              *tool,
 
   gimp_warp_tool_stop_stroke_timer (wt);
 
-  g_signal_handlers_disconnect_by_func (wt->current_stroke,
-                                        gimp_warp_tool_stroke_changed,
-                                        wt);
-
 #ifdef WARP_DEBUG
   g_printerr ("%s\n", gegl_path_to_string (wt->current_stroke));
 #endif
@@ -354,27 +357,64 @@ gimp_warp_tool_motion (GimpTool         *tool,
                        GdkModifierType   state,
                        GimpDisplay      *display)
 {
-  GimpWarpTool    *wt = GIMP_WARP_TOOL (tool);
-  GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
+  GimpWarpTool    *wt             = GIMP_WARP_TOOL (tool);
+  GimpWarpOptions *options        = GIMP_WARP_TOOL_GET_OPTIONS (wt);
+  GimpVector2      old_cursor_pos;
+  GimpVector2      delta;
+  gdouble          dist;
+  gdouble          step;
+  gboolean         stroke_changed = FALSE;
+
+  old_cursor_pos = wt->cursor_pos;
 
-  gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
+  wt->cursor_pos.x = coords->x;
+  wt->cursor_pos.y = coords->y;
 
-  wt->cursor_x = coords->x;
-  wt->cursor_y = coords->y;
+  gimp_vector2_sub (&delta, &wt->cursor_pos, &old_cursor_pos);
+  dist = gimp_vector2_length (&delta);
 
-  if (options->stroke_during_motion)
+  step = options->effect_size * options->stroke_spacing / 100.0;
+
+  while (wt->total_dist + dist >= step)
     {
-      gint off_x, off_y;
+      gdouble diff = step - wt->total_dist;
 
-      gimp_item_get_offset (GIMP_ITEM (tool->drawable), &off_x, &off_y);
+      gimp_vector2_mul (&delta, diff / dist);
+      gimp_vector2_add (&old_cursor_pos, &old_cursor_pos, &delta);
 
-      gegl_path_append (wt->current_stroke,
-                        'L', wt->cursor_x - off_x, wt->cursor_y - off_y);
+      gimp_vector2_sub (&delta, &wt->cursor_pos, &old_cursor_pos);
+      dist -= diff;
 
-      gimp_warp_tool_start_stroke_timer (wt);
+      wt->last_pos   = old_cursor_pos;
+      wt->total_dist = 0.0;
+
+      if (options->stroke_during_motion)
+        {
+          gint off_x, off_y;
+
+          if (! stroke_changed)
+            {
+              stroke_changed = TRUE;
+
+              gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
+            }
+
+          gimp_item_get_offset (GIMP_ITEM (tool->drawable), &off_x, &off_y);
+
+          gimp_warp_tool_stroke_append (wt,
+                                        'L', wt->last_pos.x - off_x,
+                                             wt->last_pos.y - off_y);
+        }
     }
 
-  gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
+  wt->total_dist += dist;
+
+  if (stroke_changed)
+    {
+      gimp_warp_tool_start_stroke_timer (wt);
+
+      gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
+    }
 }
 
 static gboolean
@@ -420,8 +460,10 @@ gimp_warp_tool_oper_update (GimpTool         *tool,
 
       if (! tool->display || display == tool->display)
         {
-          wt->cursor_x = coords->x;
-          wt->cursor_y = coords->y;
+          wt->cursor_pos.x = coords->x;
+          wt->cursor_pos.y = coords->y;
+
+          wt->last_pos = wt->cursor_pos;
         }
 
       if (! gimp_draw_tool_is_active (draw_tool))
@@ -607,8 +649,8 @@ gimp_warp_tool_draw (GimpDrawTool *draw_tool)
 
   gimp_draw_tool_add_arc (draw_tool,
                           FALSE,
-                          wt->cursor_x - options->effect_size * 0.5,
-                          wt->cursor_y - options->effect_size * 0.5,
+                          wt->last_pos.x - options->effect_size * 0.5,
+                          wt->last_pos.y - options->effect_size * 0.5,
                           options->effect_size,
                           options->effect_size,
                           0.0, 2.0 * G_PI);
@@ -859,8 +901,9 @@ gimp_warp_tool_stroke_timer (GimpWarpTool *wt)
 
   gimp_item_get_offset (GIMP_ITEM (tool->drawable), &off_x, &off_y);
 
-  gegl_path_append (wt->current_stroke,
-                    'L', wt->cursor_x - off_x, wt->cursor_y - off_y);
+  gimp_warp_tool_stroke_append (wt,
+                                'L', wt->last_pos.x - off_x,
+                                     wt->last_pos.y - off_y);
 
   return TRUE;
 }
@@ -1099,24 +1142,28 @@ gimp_warp_tool_update_stroke (GimpWarpTool *wt,
 }
 
 static void
-gimp_warp_tool_stroke_changed (GeglPath            *path,
-                               const GeglRectangle *roi,
-                               GimpWarpTool        *wt)
+gimp_warp_tool_stroke_append (GimpWarpTool *wt,
+                              gchar         type,
+                              gdouble       x,
+                              gdouble       y)
 {
-  GimpWarpOptions *options       = GIMP_WARP_TOOL_GET_OPTIONS (wt);
-  GeglRectangle    update_region;
+  GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
+  GeglRectangle    area;
+
+  if (! wt->filter)
+    return;
+
+  gegl_path_append (wt->current_stroke, type, x, y);
 
-  update_region.x      = floor (roi->x - options->effect_size * 0.5);
-  update_region.y      = floor (roi->y - options->effect_size * 0.5);
-  update_region.width  = ceil (roi->x + roi->width  +
-                               options->effect_size * 0.5) - update_region.x;
-  update_region.height = ceil (roi->y + roi->height +
-                               options->effect_size * 0.5) - update_region.y;
+  area.x      = floor (x - options->effect_size * 0.5);
+  area.y      = floor (y - options->effect_size * 0.5);
+  area.width  = ceil  (x + options->effect_size * 0.5) - area.x;
+  area.height = ceil  (y + options->effect_size * 0.5) - area.y;
 
 #ifdef WARP_DEBUG
   g_printerr ("update rect: (%d,%d), %dx%d\n",
-              update_region.x, update_region.y,
-              update_region.width, update_region.height);
+              area.x, area.y,
+              area.width, area.height);
 #endif
 
   if (wt->render_node)
@@ -1128,7 +1175,7 @@ gimp_warp_tool_stroke_changed (GeglPath            *path,
       gimp_warp_tool_update_bounds (wt);
     }
 
-  gimp_warp_tool_update_area (wt, &update_region);
+  gimp_warp_tool_update_area (wt, &area);
 }
 
 static void
diff --git a/app/tools/gimpwarptool.h b/app/tools/gimpwarptool.h
index 4cf4031c61..89f0ef4749 100644
--- a/app/tools/gimpwarptool.h
+++ b/app/tools/gimpwarptool.h
@@ -41,8 +41,7 @@ struct _GimpWarpTool
 {
   GimpDrawTool        parent_instance;
 
-  gdouble             cursor_x;      /* Hold the cursor x position */
-  gdouble             cursor_y;      /* Hold the cursor y position */
+  GimpVector2         cursor_pos;    /* Hold the cursor position */
 
   GeglBuffer         *coords_buffer; /* Buffer where coordinates are stored */
 
@@ -52,6 +51,9 @@ struct _GimpWarpTool
   GeglPath           *current_stroke;
   guint               stroke_timer;
 
+  GimpVector2         last_pos;
+  gdouble             total_dist;
+
   GimpDrawableFilter *filter;
 
   GList              *redo_stack;


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