[gimp] app: add interpolation, abyss policy, and high quality preview options ...



commit f400bdc04924952abdd19418ef95a690676eb81b
Author: Ell <ell_se yahoo com>
Date:   Fri May 19 18:14:45 2017 -0400

    app: add interpolation, abyss policy, and high quality preview options ...
    
    ... to the warp tool
    
    The interpolation and abyss policy options control the sampler type
    and abyss policy of the map-relative node.  The high quality preview
    option determines whether to use the same sampler for map-relative
    during preview as the one used during commit, or whether to use a
    fast nearest-neighbor sampler.
    
    A bit too much?  Maybe :)

 app/tools/gimpwarpoptions.c |   63 +++++++++++++++++++-
 app/tools/gimpwarpoptions.h |   25 ++++----
 app/tools/gimpwarptool.c    |  138 ++++++++++++++++++++++++++++++++++---------
 3 files changed, 185 insertions(+), 41 deletions(-)
---
diff --git a/app/tools/gimpwarpoptions.c b/app/tools/gimpwarpoptions.c
index 1f87a43..9230c3d 100644
--- a/app/tools/gimpwarpoptions.c
+++ b/app/tools/gimpwarpoptions.c
@@ -44,6 +44,9 @@ enum
   PROP_EFFECT_HARDNESS,
   PROP_EFFECT_STRENGTH,
   PROP_STROKE_SPACING,
+  PROP_INTERPOLATION,
+  PROP_ABYSS_POLICY,
+  PROP_HIGH_QUALITY_PREVIEW,
   PROP_STROKE_DURING_MOTION,
   PROP_STROKE_PERIODICALLY,
   PROP_STROKE_PERIODICALLY_RATE,
@@ -111,6 +114,29 @@ gimp_warp_options_class_init (GimpWarpOptionsClass *klass)
                            1.0, 100.0, 20.0,
                            GIMP_PARAM_STATIC_STRINGS);
 
+  GIMP_CONFIG_PROP_ENUM (object_class, PROP_INTERPOLATION,
+                         "interpolation",
+                         _("Interpolation"),
+                         _("Interpolation method"),
+                         GIMP_TYPE_INTERPOLATION_TYPE,
+                         GIMP_INTERPOLATION_CUBIC,
+                         GIMP_PARAM_STATIC_STRINGS);
+
+  GIMP_CONFIG_PROP_ENUM (object_class, PROP_ABYSS_POLICY,
+                         "abyss-policy",
+                         _("Abyss policy"),
+                         _("Out-of-bounds sampling behavior"),
+                         GEGL_TYPE_ABYSS_POLICY,
+                         GEGL_ABYSS_NONE,
+                         GIMP_PARAM_STATIC_STRINGS);
+
+  GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_HIGH_QUALITY_PREVIEW,
+                            "high-quality-preview",
+                            _("High quality preview"),
+                            _("Use an accurate but slower preview"),
+                            FALSE,
+                            GIMP_PARAM_STATIC_STRINGS);
+
   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_STROKE_DURING_MOTION,
                             "stroke-during-motion",
                             _("During motion"),
@@ -128,7 +154,7 @@ gimp_warp_options_class_init (GimpWarpOptionsClass *klass)
   GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_STROKE_PERIODICALLY_RATE,
                            "stroke-periodically-rate",
                            _("Rate"),
-                           _("Periodical stroke rate"),
+                           _("Periodic stroke rate"),
                            0.0, 100.0, 50.0,
                            GIMP_PARAM_STATIC_STRINGS);
 
@@ -170,6 +196,15 @@ gimp_warp_options_set_property (GObject      *object,
     case PROP_STROKE_SPACING:
       options->stroke_spacing = g_value_get_double (value);
       break;
+    case PROP_INTERPOLATION:
+      options->interpolation = g_value_get_enum (value);
+      break;
+    case PROP_ABYSS_POLICY:
+      options->abyss_policy = g_value_get_enum (value);
+      break;
+    case PROP_HIGH_QUALITY_PREVIEW:
+      options->high_quality_preview = g_value_get_boolean (value);
+      break;
     case PROP_STROKE_DURING_MOTION:
       options->stroke_during_motion = g_value_get_boolean (value);
       break;
@@ -214,6 +249,15 @@ gimp_warp_options_get_property (GObject    *object,
     case PROP_STROKE_SPACING:
       g_value_set_double (value, options->stroke_spacing);
       break;
+    case PROP_INTERPOLATION:
+      g_value_set_enum (value, options->interpolation);
+      break;
+    case PROP_ABYSS_POLICY:
+      g_value_set_enum (value, options->abyss_policy);
+      break;
+    case PROP_HIGH_QUALITY_PREVIEW:
+      g_value_set_boolean (value, options->high_quality_preview);
+      break;
     case PROP_STROKE_DURING_MOTION:
       g_value_set_boolean (value, options->stroke_during_motion);
       break;
@@ -274,6 +318,23 @@ gimp_warp_options_gui (GimpToolOptions *tool_options)
   gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
   gtk_widget_show (scale);
 
+  combo = gimp_prop_enum_combo_box_new (config, "interpolation", 0, 0);
+  gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (combo), _("Interpolation"));
+  g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+  gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
+  gtk_widget_show (combo);
+
+  combo = gimp_prop_enum_combo_box_new (config, "abyss-policy",
+                                        GEGL_ABYSS_NONE, GEGL_ABYSS_LOOP);
+  gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (combo), _("Abyss policy"));
+  g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+  gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
+  gtk_widget_show (combo);
+
+  button = gimp_prop_check_button_new (config, "high-quality-preview", NULL);
+  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+  gtk_widget_show (button);
+
   /*  the stroke frame  */
   frame = gimp_frame_new (_("Stroke"));
   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
diff --git a/app/tools/gimpwarpoptions.h b/app/tools/gimpwarpoptions.h
index 9d143d7..af9ad4a 100644
--- a/app/tools/gimpwarpoptions.h
+++ b/app/tools/gimpwarpoptions.h
@@ -37,22 +37,25 @@ typedef struct _GimpWarpOptionsClass GimpWarpOptionsClass;
 
 struct _GimpWarpOptions
 {
-  GimpToolOptions   parent_instance;
+  GimpToolOptions        parent_instance;
 
-  GimpWarpBehavior  behavior;
-  gdouble           effect_size;
-  gdouble           effect_hardness;
-  gdouble           effect_strength;
-  gdouble           stroke_spacing;
+  GimpWarpBehavior       behavior;
+  gdouble                effect_size;
+  gdouble                effect_hardness;
+  gdouble                effect_strength;
+  gdouble                stroke_spacing;
+  GimpInterpolationType  interpolation;
+  GeglAbyssPolicy        abyss_policy;
+  gboolean               high_quality_preview;
 
-  gboolean          stroke_during_motion;
-  gboolean          stroke_periodically;
-  gdouble           stroke_periodically_rate;
+  gboolean               stroke_during_motion;
+  gboolean               stroke_periodically;
+  gdouble                stroke_periodically_rate;
 
-  gint              n_animation_frames;
+  gint                   n_animation_frames;
 
   /*  options gui  */
-  GtkWidget        *animate_button;
+  GtkWidget             *animate_button;
 };
 
 struct _GimpWarpOptionsClass
diff --git a/app/tools/gimpwarptool.c b/app/tools/gimpwarptool.c
index 4cdf358..d2d6179 100644
--- a/app/tools/gimpwarptool.c
+++ b/app/tools/gimpwarptool.c
@@ -54,7 +54,6 @@
 
 #define STROKE_TIMER_MAX_FPS 20
 #define PREVIEW_SAMPLER      GEGL_SAMPLER_NEAREST
-#define COMMIT_SAMPLER       GEGL_SAMPLER_CUBIC
 
 
 static void       gimp_warp_tool_control            (GimpTool              *tool,
@@ -119,6 +118,10 @@ static gboolean   gimp_warp_tool_stroke_timer       (GimpWarpTool          *wt);
 static void       gimp_warp_tool_create_graph       (GimpWarpTool          *wt);
 static void       gimp_warp_tool_create_filter      (GimpWarpTool          *wt,
                                                      GimpDrawable          *drawable);
+static void       gimp_warp_tool_set_sampler        (GimpWarpTool          *wt,
+                                                     gboolean               commit);
+static GeglRectangle
+                  gimp_warp_tool_get_stroke_bounds  (GeglNode              *node);
 static void       gimp_warp_tool_update_stroke      (GimpWarpTool          *wt,
                                                      GeglNode              *node);
 static void       gimp_warp_tool_stroke_changed     (GeglPath              *stroke,
@@ -555,6 +558,9 @@ gimp_warp_tool_options_notify (GimpTool         *tool,
                                GimpToolOptions  *options,
                                const GParamSpec *pspec)
 {
+  GimpWarpTool    *wt         = GIMP_WARP_TOOL (tool);
+  GimpWarpOptions *wt_options = GIMP_WARP_OPTIONS (options);
+
   GIMP_TOOL_CLASS (parent_class)->options_notify (tool, options, pspec);
 
   if (! strcmp (pspec->name, "effect-size"))
@@ -562,6 +568,32 @@ gimp_warp_tool_options_notify (GimpTool         *tool,
       gimp_draw_tool_pause (GIMP_DRAW_TOOL (tool));
       gimp_draw_tool_resume (GIMP_DRAW_TOOL (tool));
     }
+  else if (! strcmp (pspec->name, "interpolation"))
+    {
+      if (wt_options->high_quality_preview)
+        {
+          gimp_warp_tool_set_sampler (wt, /* commit = */ FALSE);
+
+          gimp_warp_tool_update_stroke (wt, NULL);
+        }
+    }
+  else if (! strcmp (pspec->name, "abyss-policy"))
+    {
+      if (wt->render_node)
+        {
+          gegl_node_set (wt->render_node,
+                         "abyss-policy", wt_options->abyss_policy,
+                         NULL);
+
+          gimp_warp_tool_update_stroke (wt, NULL);
+        }
+    }
+  else if (! strcmp (pspec->name, "high-quality-preview"))
+    {
+      gimp_warp_tool_set_sampler (wt, /* commit = */ FALSE);
+
+      gimp_warp_tool_update_stroke (wt, NULL);
+    }
 }
 
 static void
@@ -743,12 +775,7 @@ gimp_warp_tool_commit (GimpWarpTool *wt)
     {
       gimp_tool_control_push_preserve (tool->control, TRUE);
 
-      if (COMMIT_SAMPLER != PREVIEW_SAMPLER)
-        {
-          gegl_node_set (wt->render_node,
-                         "sampler-type", COMMIT_SAMPLER,
-                         NULL);
-        }
+      gimp_warp_tool_set_sampler (wt, /* commit = */ TRUE);
 
       gimp_drawable_filter_commit (wt->filter, GIMP_PROGRESS (tool), FALSE);
       g_object_unref (wt->filter);
@@ -808,9 +835,10 @@ gimp_warp_tool_stroke_timer (GimpWarpTool *wt)
 static void
 gimp_warp_tool_create_graph (GimpWarpTool *wt)
 {
-  GeglNode *graph;           /* Wraper to be returned */
-  GeglNode *input, *output;  /* Proxy nodes */
-  GeglNode *coords, *render; /* Render nodes */
+  GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
+  GeglNode        *graph;           /* Wraper to be returned */
+  GeglNode        *input, *output;  /* Proxy nodes */
+  GeglNode        *coords, *render; /* Render nodes */
 
   /* render_node is not supposed to be recreated */
   g_return_if_fail (wt->graph == NULL);
@@ -827,7 +855,7 @@ gimp_warp_tool_create_graph (GimpWarpTool *wt)
 
   render = gegl_node_new_child (graph,
                                 "operation",    "gegl:map-relative",
-                                "sampler-type", PREVIEW_SAMPLER,
+                                "abyss-policy", options->abyss_policy,
                                 NULL);
 
   gegl_node_connect_to (input,  "output",
@@ -850,12 +878,7 @@ gimp_warp_tool_create_filter (GimpWarpTool *wt,
   if (! wt->graph)
     gimp_warp_tool_create_graph (wt);
 
-  if (PREVIEW_SAMPLER != COMMIT_SAMPLER)
-    {
-      gegl_node_set (wt->render_node,
-                     "sampler-type", PREVIEW_SAMPLER,
-                     NULL);
-    }
+  gimp_warp_tool_set_sampler (wt, /* commit = */ FALSE);
 
   wt->filter = gimp_drawable_filter_new (drawable,
                                          _("Warp transform"),
@@ -874,11 +897,39 @@ gimp_warp_tool_create_filter (GimpWarpTool *wt,
 }
 
 static void
-gimp_warp_tool_update_stroke (GimpWarpTool *wt,
-                              GeglNode     *node)
+gimp_warp_tool_set_sampler (GimpWarpTool *wt,
+                            gboolean      commit)
 {
-  GeglPath *stroke;
-  gdouble   size;
+  GimpWarpOptions *options = GIMP_WARP_TOOL_GET_OPTIONS (wt);
+  GeglSamplerType  sampler;
+  GeglSamplerType  old_sampler;
+
+  if (! wt->render_node)
+    return;
+
+  if (commit || options->high_quality_preview)
+    sampler = (GeglSamplerType) options->interpolation;
+  else
+    sampler = PREVIEW_SAMPLER;
+
+  gegl_node_get (wt->render_node,
+                 "sampler-type", &old_sampler,
+                 NULL);
+
+  if (sampler != old_sampler)
+    {
+      gegl_node_set (wt->render_node,
+                     "sampler-type", sampler,
+                     NULL);
+    }
+}
+
+static GeglRectangle
+gimp_warp_tool_get_stroke_bounds (GeglNode *node)
+{
+  GeglRectangle  bbox = {0, 0, 0, 0};
+  GeglPath      *stroke;
+  gdouble        size;
 
   gegl_node_get (node,
                  "stroke", &stroke,
@@ -891,7 +942,6 @@ gimp_warp_tool_update_stroke (GimpWarpTool *wt,
       gdouble        max_x;
       gdouble        min_y;
       gdouble        max_y;
-      GeglRectangle  bbox;
 
       gegl_path_get_bounds (stroke, &min_x, &max_x, &min_y, &max_y);
       g_object_unref (stroke);
@@ -900,7 +950,42 @@ gimp_warp_tool_update_stroke (GimpWarpTool *wt,
       bbox.y      = floor (min_y - size * 0.5);
       bbox.width  = ceil (max_x + size * 0.5) - bbox.x;
       bbox.height = ceil (max_y + size * 0.5) - bbox.y;
+    }
+
+  return bbox;
+}
+
+static void
+gimp_warp_tool_update_stroke (GimpWarpTool *wt,
+                              GeglNode     *node)
+{
+  GeglRectangle bbox = {0, 0, 0, 0};
 
+  if (! wt->filter)
+    return;
+
+  if (node)
+    {
+      /* update just this stroke */
+      bbox = gimp_warp_tool_get_stroke_bounds (node);
+    }
+  else if (wt->render_node)
+    {
+      /* update all strokes */
+      for (node = gegl_node_get_producer (wt->render_node, "aux", NULL);
+           ! strcmp (gegl_node_get_operation (node), "gegl:warp");
+           node = gegl_node_get_producer (node, "input", NULL))
+        {
+          GeglRectangle node_bbox;
+
+          node_bbox = gimp_warp_tool_get_stroke_bounds (node);
+
+          gegl_rectangle_bounding_box (&bbox, &bbox, &node_bbox);
+        }
+    }
+
+  if (! gegl_rectangle_is_empty (&bbox))
+    {
 #ifdef WARP_DEBUG
   g_printerr ("update stroke: (%d,%d), %dx%d\n",
               bbox.x, bbox.y,
@@ -1021,12 +1106,7 @@ gimp_warp_tool_animate (GimpWarpTool *wt)
       wt->filter = NULL;
     }
 
-  if (COMMIT_SAMPLER != PREVIEW_SAMPLER)
-    {
-      gegl_node_set (wt->render_node,
-                     "sampler-type", COMMIT_SAMPLER,
-                     NULL);
-    }
+  gimp_warp_tool_set_sampler (wt, /* commit = */ TRUE);
 
   gimp_progress_start (GIMP_PROGRESS (tool), FALSE,
                        _("Rendering Frame %d"), 1);
@@ -1098,7 +1178,7 @@ gimp_warp_tool_animate (GimpWarpTool *wt)
 
   /*  recreate the image map  */
   gimp_warp_tool_create_filter (wt, tool->drawable);
-  gimp_drawable_filter_apply (wt->filter, NULL);
+  gimp_warp_tool_update_stroke (wt, NULL);
 
   widget = GTK_WIDGET (gimp_display_get_shell (tool->display));
   gimp_create_display (orig_image->gimp, image, GIMP_UNIT_PIXEL, 1.0,


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