[gegl/soc-2011-warp] add a wip operator warp in the workshop, and dedicated enum in gegl-types



commit 502b757af4547e283eb6bea52ed4415eae7b4928
Author: Michael Murà <mure michael gmail com>
Date:   Sat Jul 9 19:15:54 2011 +0200

    add a wip operator warp in the workshop, and dedicated enum in gegl-types

 gegl/gegl-types.c          |   20 +++
 gegl/gegl-types.h          |   12 ++
 operations/workshop/warp.c |  368 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 400 insertions(+), 0 deletions(-)
---
diff --git a/gegl/gegl-types.c b/gegl/gegl-types.c
index 1bf2d39..0292ed2 100644
--- a/gegl/gegl-types.c
+++ b/gegl/gegl-types.c
@@ -37,3 +37,23 @@ gegl_sampler_type_get_type (void)
     }
     return etype;
 }
+
+GType
+gegl_warp_behavior_get_type (void)
+{
+    static GType etype = 0;
+    if (etype == 0) {
+        static const GEnumValue values[] = {
+            { GEGL_WARP_BEHAVIOR_MOVE,      "Move pixels",              "move"       },
+            { GEGL_WARP_BEHAVIOR_GROW,      "Grow area",                "grow"       },
+            { GEGL_WARP_BEHAVIOR_SHRINK,    "Shrink area",              "shrink"     },
+            { GEGL_WARP_BEHAVIOR_SWIRL_CW,  "Swirl clockwise",          "swirl_cw"   },
+            { GEGL_WARP_BEHAVIOR_SWIRL_CCW, "Swirl counter-clockwise",  "swirl_ccw"  },
+            { GEGL_WARP_BEHAVIOR_ERASE,     "Erase warping",            "erase"      },
+            { GEGL_WARP_BEHAVIOR_SMOOTH,    "Smooth warping",           "smooth"     },
+            { 0, NULL, NULL }
+        };
+        etype = g_enum_register_static ("GeglWarpBehaviorType", values);
+    }
+    return etype;
+}
diff --git a/gegl/gegl-types.h b/gegl/gegl-types.h
index 6e1f594..da6456f 100644
--- a/gegl/gegl-types.h
+++ b/gegl/gegl-types.h
@@ -74,6 +74,18 @@ typedef enum {
 GType gegl_sampler_type_get_type   (void) G_GNUC_CONST;
 #define GEGL_TYPE_SAMPLER_TYPE (gegl_sampler_type_get_type())
 
+typedef enum
+{
+  GEGL_WARP_BEHAVIOR_MOVE,
+  GEGL_WARP_BEHAVIOR_GROW,
+  GEGL_WARP_BEHAVIOR_SHRINK,
+  GEGL_WARP_BEHAVIOR_SWIRL_CW,
+  GEGL_WARP_BEHAVIOR_SWIRL_CCW,
+  GEGL_WARP_BEHAVIOR_ERASE,
+  GEGL_WARP_BEHAVIOR_SMOOTH
+} GeglWarpBehavior;
+GType gegl_warp_behavior_get_type (void) G_GNUC_CONST;
+#define GEGL_TYPE_WARP_BEHAVIOR (gegl_warp_behavior_get_type ())
 
 G_END_DECLS
 
diff --git a/operations/workshop/warp.c b/operations/workshop/warp.c
new file mode 100644
index 0000000..1a06487
--- /dev/null
+++ b/operations/workshop/warp.c
@@ -0,0 +1,368 @@
+/* This file is an image processing operation for GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2011 Michael Murà <batolettre gmail com>
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+#include <math.h>
+#include <stdio.h> /* for test only */
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+gegl_chant_double (strength, _("Strength"), 0.0, 100.0, 1.0,
+                   _("Effect Strength"))
+gegl_chant_double (size, _("Size"), 1.0, 10000.0, 40.0,
+                   _("Effect Size"))
+gegl_chant_double (hardness, _("Harness"), 0.0, 1.0, 0.5,
+                   _("Effect Harness"))
+gegl_chant_path (stroke, _("Stroke"), _("Effect Strength"))
+gegl_chant_enum (behavior, _("Behavior"), GeglWarpBehavior, GEGL_TYPE_WARP_BEHAVIOR,
+                 GEGL_WARP_BEHAVIOR_MOVE, _("Behavior of the op"))
+
+#else
+
+#define GEGL_CHANT_TYPE_FILTER
+#define GEGL_CHANT_C_FILE       "warp.c"
+
+#include "gegl-plugin.h"
+#include "gegl-path.h"
+static void path_changed (GeglPath            *path,
+                          const GeglRectangle *roi,
+                          gpointer             userdata);
+#include "gegl-chant.h"
+
+#ifdef HAVE_RINT
+#define RINT(x) rint(x)
+#else
+#define RINT(x) floor ((x) + 0.5)
+#endif
+
+typedef struct {
+  gfloat      *lookup;
+  GeglBuffer  *buffer;
+  gdouble      last_x;
+  gdouble      last_y;
+  gboolean     last_point_set;
+} warp_private;
+
+static void
+path_changed (GeglPath            *path,
+              const GeglRectangle *roi,
+              gpointer             userdata)
+{
+  GeglRectangle rect = *roi;
+  GeglChantO    *o   = GEGL_CHANT_PROPERTIES (userdata);
+  /* invalidate the incoming rectangle */
+
+  rect.x -= o->size/2;
+  rect.y -= o->size/2;
+  rect.width += o->size;
+  rect.height += o->size;
+
+  gegl_operation_invalidate (userdata, &rect, FALSE);
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+  GeglChantO    *o = GEGL_CHANT_PROPERTIES (operation);
+  warp_private  *priv;
+
+  Babl *format = babl_format_n (babl_type ("float"), 2);
+  gegl_operation_set_format (operation, "input", format);
+  gegl_operation_set_format (operation, "output", format);
+
+  if (!o->chant_data)
+    {
+      o->chant_data = g_slice_new (warp_private);
+    }
+
+  priv = (warp_private*) o->chant_data;
+  priv->last_point_set = FALSE;
+  priv->lookup = NULL
+  priv->buffer = NULL;
+}
+
+static void
+finalize (GObject *object)
+{
+  GeglChantO *o = GEGL_CHANT_PROPERTIES (object);
+
+  if (o->chant_data)
+    {
+      g_slice_free (warp_private, o->chant_data);
+      o->chant_data = NULL;
+    }
+
+  G_OBJECT_CLASS (gegl_chant_parent_class)->finalize (object);
+}
+
+static gdouble
+gauss (gdouble f)
+{
+  /* This is not a real gauss function. */
+  /* Approximation is valid if -1 < f < 1 */
+  if (f < -0.5)
+    {
+      f = -1.0 - f;
+      return (2.0 * f*f);
+    }
+
+  if (f < 0.5)
+    return (1.0 - 2.0 * f*f);
+
+  f = 1.0 - f;
+  return (2.0 * f*f);
+}
+
+/* set up lookup table */
+static void
+calc_lut (GeglChantO  *o)
+{
+  warp_private *priv = (warp_private*) o->chant_data;
+  gint          length;
+  gint          x;
+  gdouble       exponent;
+
+  length = ceil (0.5 * o->size + 1.0);
+
+  priv->lookup = g_malloc (length * sizeof (gfloat));
+
+  if ((1.0 - o->hardness) < 0.0000004)
+    exponent = 1000000.0;
+  else
+    exponent = 0.4 / (1.0 - o->hardness);
+
+  for (x = 0; x < length; x++)
+    {
+      priv->lookup[x] = gauss (pow (2.0 * x / o->size, exponent));
+    }
+}
+
+static gdouble
+get_influence (GeglChantO *o,
+               gdouble     x,
+               gdouble     y)
+{
+  warp_private *priv = (warp_private*) o->chant_data;
+  gfloat        radius;
+
+  if (!priv->lookup)
+    {
+      calc_lut (o);
+    }
+
+  radius = sqrt(x*x+y*y);
+
+  if (radius < 0.5 * o->size + 1)
+    return o->strength * priv->lookup[(gint) RINT (radius)];
+  else
+    return 0.0;
+}
+
+static void
+stamp (GeglChantO *o,
+       gdouble     x,
+       gdouble     y)
+{
+  warp_private        *priv = (warp_private*) o->chant_data;
+  GeglBufferIterator  *it;
+  Babl                *format;
+  gdouble              influence;
+  gdouble              x_mean = 0.0;
+  gdouble              y_mean = 0.0;
+  gint                 x_iter, y_iter;
+  GeglRectangle        area = {x - o->size / 2.0,
+                               y - o->size / 2.0,
+                               o->size,
+                               o->size};
+
+  /* first point of the stroke */
+  if (!priv->last_point_set)
+    {
+      priv->last_x = x;
+      priv->last_y = y;
+      priv->last_point_set = TRUE;
+      return;
+    }
+
+  format = babl_format_n (babl_type ("float"), 2);
+
+  /* If needed, compute the mean deformation */
+  if (o->behavior == GEGL_WARP_BEHAVIOR_SMOOTH)
+    {
+      gint pixel_count = 0;
+
+      it = gegl_buffer_iterator_new (priv->buffer, &area, format, GEGL_BUFFER_READ);
+
+      while (gegl_buffer_iterator_next (it))
+        {
+          gint    n_pixels    = it->length;
+          gfloat *coords      = it->data[0];
+
+          while (n_pixels--)
+            {
+              x_mean += coords[0];
+              y_mean += coords[1];
+              coords += 2;
+            }
+          pixel_count += it->roi->width * it->roi->height;
+        }
+      x_mean /= pixel_count;
+      y_mean /= pixel_count;
+    }
+
+  it = gegl_buffer_iterator_new (priv->buffer, &area, format, GEGL_BUFFER_READWRITE);
+
+  while (gegl_buffer_iterator_next (it))
+    {
+      /* iterate inside the stamp roi */
+      gint    n_pixels = it->length;
+      gfloat *coords   = it->data[0];
+
+      x_iter = it->roi->x; /* initial x         */
+      y_iter = it->roi->y; /* and y coordinates */
+
+      while (n_pixels--)
+        {
+          influence = get_influence (o,
+                                     x_iter - x,
+                                     y_iter - y);
+
+          switch (o->behavior)
+            {
+              case GEGL_WARP_BEHAVIOR_MOVE:
+                coords[0] += influence * (priv->last_x - x);
+                coords[1] += influence * (priv->last_y - y);
+                break;
+              case GEGL_WARP_BEHAVIOR_GROW:
+                coords[0] -= influence * (x_iter - x) / o->size;
+                coords[1] -= influence * (y_iter - y) / o->size;
+                break;
+              case GEGL_WARP_BEHAVIOR_SHRINK:
+                coords[0] += influence * (x_iter - x) / o->size;
+                coords[1] += influence * (y_iter - y) / o->size;
+                break;
+              case GEGL_WARP_BEHAVIOR_SWIRL_CW:
+                coords[0] += influence * (y_iter - y) / o->size;
+                coords[1] -= influence * (x_iter - x) / o->size;
+                break;
+              case GEGL_WARP_BEHAVIOR_SWIRL_CCW:
+                coords[0] -= influence * (y_iter - y) / o->size;
+                coords[1] += influence * (x_iter - x) / o->size;
+                break;
+              case GEGL_WARP_BEHAVIOR_ERASE:
+                coords[0] *= 1.0 - MIN (influence, 1.0);
+                coords[1] *= 1.0 - MIN (influence, 1.0);
+                break;
+              case GEGL_WARP_BEHAVIOR_SMOOTH:
+                coords[0] -= influence * (coords[0] - x_mean);
+                coords[1] -= influence * (coords[1] - y_mean);
+                break;
+            }
+
+          coords += 2;
+
+          /* update x and y coordinates */
+          x_iter++;
+          if (x_iter >= (it->roi->x + it->roi->width))
+            {
+              x_iter = it->roi->x;
+              y_iter++;
+            }
+        }
+    }
+
+  /* Memorize the stamp location for movement dependant behavior like move */
+  priv->last_x = x;
+  priv->last_y = y;
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *input,
+         GeglBuffer          *output,
+         const GeglRectangle *result)
+{
+  GeglChantO           *o = GEGL_CHANT_PROPERTIES (operation);
+  warp_private         *priv = (warp_private*) o->chant_data;
+  gdouble              dist;
+  gdouble              stamps;
+  gdouble              spacing = MAX (o->size * 0.01, 0.5); /*1% spacing for starters*/
+
+  Point                prev, next, lerp;
+  gulong               i;
+  GeglPathList        *event;
+
+  printf("Process %p\n", operation);
+
+  priv->buffer = gegl_buffer_dup (input);
+
+  event = gegl_path_get_path (o->stroke);
+
+  prev = *(event->d.point);
+
+  while (event->next)
+    {
+      event = event->next;
+      next = *(event->d.point);
+      dist = point_dist (&next, &prev);
+      stamps = dist / spacing;
+
+      if (stamps < 1)
+       {
+        stamp (o, next.x, next.y);
+        prev = next;
+       }
+      else
+       {
+        for (i = 0; i < stamps; i++)
+          {
+            point_lerp (&lerp, &prev, &next, (i * spacing) / dist);
+            stamp (o, lerp.x, lerp.y);
+          }
+         prev = lerp;
+       }
+    }
+
+  /* Affect the output buffer */
+  gegl_buffer_copy (priv->buffer, result, output, result);
+  gegl_buffer_set_extent (output, gegl_buffer_get_extent (input));
+  gegl_buffer_destroy (priv->buffer);
+
+  /* prepare for the recomputing of the op */
+  priv->last_point_set = FALSE;
+
+  return TRUE;
+}
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+  GObjectClass               *object_class    = G_OBJECT_CLASS (klass);
+  GeglOperationClass         *operation_class = GEGL_OPERATION_CLASS (klass);
+  GeglOperationFilterClass   *filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);
+
+  object_class->finalize = finalize;
+  operation_class->prepare = prepare;
+  filter_class->process = process;
+
+  operation_class->name        = "gegl:warp";
+  operation_class->categories  = "transform";
+  operation_class->description = _("Compute a relative displacement mapping from a stroke");
+}
+#endif



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