[gegl] recursive-transform: merge back recursive-transform-plus changes



commit 6be0a86583f9c10c7710c96c21c261e4227c4727
Author: Ell <ell_se yahoo com>
Date:   Sun Jun 17 14:44:11 2018 -0400

    recursive-transform: merge back recursive-transform-plus changes
    
    ... which add support for applying multiple transformations
    simultaneously, by specifiying a semicolon-separated list of
    matrices through the "transform" property.
    
    Note that, currently, the "fade-color" and "fade-opacity" properties
    are applied to all transforms; in the future, we might want to add
    per-transform fade properties.  This can be done without breaking
    backward-compatibility, and the global fade properties can still be
    useful.

 operations/common/recursive-transform.c        | 286 ++++++++++++------
 operations/workshop/Makefile.am                |   1 -
 operations/workshop/recursive-transform-plus.c | 392 -------------------------
 po/POTFILES.in                                 |   1 -
 4 files changed, 203 insertions(+), 477 deletions(-)
---
diff --git a/operations/common/recursive-transform.c b/operations/common/recursive-transform.c
index d0d254814..cca5b3030 100644
--- a/operations/common/recursive-transform.c
+++ b/operations/common/recursive-transform.c
@@ -20,12 +20,14 @@
 #include <glib/gi18n-lib.h>
 
 #define MAX_ITERATIONS 20
+#define MAX_TRANSFORMS 10
 #define EPSILON        1e-6
 
 #ifdef GEGL_PROPERTIES
 
-property_string  (transform, _("Transform"), "")
-    description  (_("Transformation matrix, using SVG syntax"))
+property_string  (transform, _("Transform"), "matrix (1, 0, 0, 0, 1, 0, 0, 0, 1)")
+    description  (_("Transformation matrix, using SVG syntax "
+                    "(or multiple matrices, separated by semicolons)"))
 
 property_int     (first_iteration, _("First iteration"), 0)
     description  (_("First iteration"))
@@ -62,23 +64,24 @@ property_enum    (sampler_type, _("Resampling method"),
 
 typedef struct
 {
-  GeglNode *transform_node;
+  GeglNode *transform_nodes[MAX_TRANSFORMS];
   GeglNode *color_overlay_node;
   GeglNode *opacity_node;
-  GeglNode *over_node;
+  GeglNode *over_nodes[MAX_TRANSFORMS];
 } Iteration;
 
 static void
 update_graph (GeglOperation *operation)
 {
-  GeglProperties *o     = GEGL_PROPERTIES (operation);
-  Iteration      *iters = o->user_data;
-  GeglNode       *node  = operation->node;
-  GeglNode       *input;
-  GeglNode       *output;
-  GeglMatrix3     transform;
-  gdouble         fade_color[4];
-  gint            i;
+  GeglProperties  *o     = GEGL_PROPERTIES (operation);
+  Iteration       *iters = o->user_data;
+  GeglNode        *node  = operation->node;
+  GeglNode        *input;
+  GeglNode        *output;
+  gchar          **matrix_strs;
+  gdouble          fade_color[4];
+  gint             i;
+  gint             j;
 
   if (! iters)
     return;
@@ -90,17 +93,30 @@ update_graph (GeglOperation *operation)
 
   for (i = 0; i <= MAX_ITERATIONS; i++)
     {
-      gegl_node_disconnect (iters[i].over_node,          "input");
-      gegl_node_disconnect (iters[i].over_node,          "aux");
-      gegl_node_disconnect (iters[i].opacity_node,       "input");
-      gegl_node_disconnect (iters[i].color_overlay_node, "input");
-      gegl_node_disconnect (iters[i].transform_node,     "input");
+      for (j = MAX_TRANSFORMS - 1; j >= 0; j--)
+        {
+          gegl_node_disconnect (iters[i].over_nodes[j],    "input");
+          gegl_node_disconnect (iters[i].over_nodes[j],    "aux");
+        }
+
+      gegl_node_disconnect (iters[i].opacity_node,         "input");
+      gegl_node_disconnect (iters[i].color_overlay_node,   "input");
+
+      for (j = 0; j < MAX_TRANSFORMS; j++)
+        gegl_node_disconnect (iters[i].transform_nodes[j], "input");
     }
 
   if (o->first_iteration == 0 && o->iterations == 0)
     return;
 
-  gegl_matrix3_parse_string (&transform, o->transform);
+  matrix_strs = g_strsplit (o->transform, ";", MAX_TRANSFORMS + 1);
+
+  if (! matrix_strs[0])
+    {
+      g_strfreev (matrix_strs);
+
+      return;
+    }
 
   gegl_color_get_rgba (o->fade_color,
                        &fade_color[0],
@@ -108,78 +124,172 @@ update_graph (GeglOperation *operation)
                        &fade_color[2],
                        &fade_color[3]);
 
-  for (i = o->iterations; i >= 0; i--)
+  if (! matrix_strs[1])
     {
-      GeglNode    *source_node;
-      GeglMatrix3  matrix;
-      gchar       *matrix_str;
-      gint         n = o->first_iteration + i;
-      gint         j;
-
-      gegl_matrix3_identity (&matrix);
+      GeglMatrix3 transform;
 
-      for (j = 0; j < n; j++)
-        gegl_matrix3_multiply (&matrix, &transform, &matrix);
+      gegl_matrix3_parse_string (&transform, matrix_strs[0]);
 
-      matrix_str = gegl_matrix3_to_string (&matrix);
+      for (i = o->iterations; i >= 0; i--)
+        {
+          GeglNode    *source_node;
+          GeglMatrix3  matrix;
+          gchar       *matrix_str;
+          gint         n = o->first_iteration + i;
 
-      gegl_node_set (iters[i].transform_node,
-                     "transform", matrix_str,
-                     "sampler",   o->sampler_type,
-                     NULL);
+          gegl_matrix3_identity (&matrix);
 
-      g_free (matrix_str);
+          for (j = 0; j < n; j++)
+            gegl_matrix3_multiply (&matrix, &transform, &matrix);
 
-      gegl_node_link (input, iters[i].transform_node);
-      source_node = iters[i].transform_node;
+          matrix_str = gegl_matrix3_to_string (&matrix);
 
-      if (n > 0 && fabs (fade_color[3]) > EPSILON)
-        {
-          GeglColor *color = gegl_color_new (NULL);
-          gdouble    a = 1.0 - pow (1.0 - fade_color[3], n);
-
-          gegl_color_set_rgba (color,
-                               fade_color[0],
-                               fade_color[1],
-                               fade_color[2],
-                               a);
-
-          gegl_node_set (iters[i].color_overlay_node,
-                         "value", color,
-                         "srgb",  TRUE,
+          gegl_node_set (iters[i].transform_nodes[0],
+                         "transform", matrix_str,
+                         "sampler",   o->sampler_type,
                          NULL);
 
-          g_object_unref (color);
+          g_free (matrix_str);
 
-          gegl_node_link (source_node, iters[i].color_overlay_node);
-          source_node = iters[i].color_overlay_node;
-        }
+          gegl_node_link (input, iters[i].transform_nodes[0]);
+          source_node = iters[i].transform_nodes[0];
 
-      if (n > 0 && fabs (o->fade_opacity - 1.0) > EPSILON)
-        {
-          gegl_node_set (iters[i].opacity_node,
-                         "value", pow (o->fade_opacity, n),
-                         NULL);
+          if (n > 0 && fabs (fade_color[3]) > EPSILON)
+            {
+              GeglColor *color = gegl_color_new (NULL);
+              gdouble    a = 1.0 - pow (1.0 - fade_color[3], n);
 
-          gegl_node_link (source_node, iters[i].opacity_node);
-          source_node = iters[i].opacity_node;
-        }
+              gegl_color_set_rgba (color,
+                                   fade_color[0],
+                                   fade_color[1],
+                                   fade_color[2],
+                                   a);
 
-      gegl_node_connect_to (source_node,        "output",
-                            iters[i].over_node, ! o->paste_below ? "input" :
-                                                                   "aux");
+              gegl_node_set (iters[i].color_overlay_node,
+                             "value", color,
+                             "srgb",  TRUE,
+                             NULL);
 
-      if (i == 0)
-        {
-          gegl_node_link (iters[i].over_node, output);
+              g_object_unref (color);
+
+              gegl_node_link (source_node, iters[i].color_overlay_node);
+              source_node = iters[i].color_overlay_node;
+            }
+
+          if (n > 0 && fabs (o->fade_opacity - 1.0) > EPSILON)
+            {
+              gegl_node_set (iters[i].opacity_node,
+                             "value", pow (o->fade_opacity, n),
+                             NULL);
+
+              gegl_node_link (source_node, iters[i].opacity_node);
+              source_node = iters[i].opacity_node;
+            }
+
+          gegl_node_connect_to (source_node,            "output",
+                                iters[i].over_nodes[0], ! o->paste_below ? "input" :
+                                                                           "aux");
+
+          if (i == 0)
+            {
+              gegl_node_link (iters[i].over_nodes[0], output);
+            }
+          else
+            {
+              gegl_node_connect_to (iters[i].over_nodes[0],     "output",
+                                    iters[i - 1].over_nodes[0], ! o->paste_below ? "aux" :
+                                                                                   "input");
+            }
         }
-      else
+    }
+  else
+    {
+      gint n_iterations = MIN (o->first_iteration + o->iterations, MAX_ITERATIONS);
+      gint n_transforms;
+
+      for (n_transforms = 0;
+           n_transforms < MAX_TRANSFORMS && matrix_strs[n_transforms];
+           n_transforms++);
+
+      for (i = n_iterations; i >= 0; i--)
         {
-          gegl_node_connect_to (iters[i].over_node,     "output",
-                                iters[i - 1].over_node, ! o->paste_below ? "aux" :
-                                                                           "input");
+          if (i < n_iterations)
+            {
+              GeglNode *source_node = NULL;
+
+              for (j = 0; j < n_transforms; j++)
+                {
+                  gegl_node_set (iters[i].transform_nodes[j],
+                                 "transform", matrix_strs[j],
+                                 "sampler",   o->sampler_type,
+                                 NULL);
+
+                  gegl_node_link (iters[i + 1].over_nodes[n_transforms - 1],
+                                  iters[i].transform_nodes[j]);
+
+                  if (j == 0)
+                    {
+                      source_node = iters[i].transform_nodes[j];
+                    }
+                  else
+                    {
+                      if (! o->paste_below)
+                        {
+                          gegl_node_connect_to (source_node,                 "output",
+                                                iters[i].over_nodes[j - 1],  "input");
+                          gegl_node_connect_to (iters[i].transform_nodes[j], "output",
+                                                iters[i].over_nodes[j - 1],  "aux");
+                        }
+                      else
+                        {
+                          gegl_node_connect_to (source_node,                 "output",
+                                                iters[i].over_nodes[j - 1],  "aux");
+                          gegl_node_connect_to (iters[i].transform_nodes[j], "output",
+                                                iters[i].over_nodes[j - 1],  "input");
+                        }
+
+                      source_node = iters[i].over_nodes[j - 1];
+                    }
+                }
+
+              if (fabs (fade_color[3]) > EPSILON)
+                {
+                  gegl_node_set (iters[i].color_overlay_node,
+                                 "value", o->fade_color,
+                                 "srgb",  TRUE,
+                                 NULL);
+
+                  gegl_node_link (source_node, iters[i].color_overlay_node);
+                  source_node = iters[i].color_overlay_node;
+                }
+
+              if (fabs (o->fade_opacity - 1.0) > EPSILON)
+                {
+                  gegl_node_set (iters[i].opacity_node,
+                                 "value", o->fade_opacity,
+                                 NULL);
+
+                  gegl_node_link (source_node, iters[i].opacity_node);
+                  source_node = iters[i].opacity_node;
+                }
+
+              gegl_node_connect_to (source_node,                           "output",
+                                    iters[i].over_nodes[n_transforms - 1], ! o->paste_below ? "aux" :
+                                                                                              "input");
+            }
+
+          if (i >= o->first_iteration)
+            {
+              gegl_node_connect_to (input,                                 "output",
+                                    iters[i].over_nodes[n_transforms - 1], ! o->paste_below ? "input" :
+                                                                                              "aux");
+            }
         }
+
+      gegl_node_link (iters[0].over_nodes[n_transforms - 1], output);
     }
+
+  g_strfreev (matrix_strs);
 }
 
 static void
@@ -189,16 +299,23 @@ attach (GeglOperation *operation)
   Iteration      *iters = o->user_data;
   GeglNode       *node  = operation->node;
   gint            i;
+  gint            j;
 
   if (! iters)
     iters = o->user_data = g_new (Iteration, MAX_ITERATIONS + 1);
 
   for (i = 0; i <= MAX_ITERATIONS; i++)
     {
-      iters[i].transform_node =
-        gegl_node_new_child (node,
-                             "operation", "gegl:transform",
-                             NULL);
+      for (j = 0; j < MAX_TRANSFORMS; j++)
+        {
+          iters[i].transform_nodes[j] =
+            gegl_node_new_child (node,
+                                 "operation", "gegl:transform",
+                                 NULL);
+
+          gegl_operation_meta_watch_node (operation,
+                                          iters[i].transform_nodes[j]);
+        }
 
       iters[i].color_overlay_node =
         gegl_node_new_child (node,
@@ -210,17 +327,20 @@ attach (GeglOperation *operation)
                              "operation", "gegl:opacity",
                              NULL);
 
-      iters[i].over_node =
-        gegl_node_new_child (node,
-                             "operation", "gegl:over",
-                             NULL);
-
       gegl_operation_meta_watch_nodes (operation,
-                                       iters[i].transform_node,
                                        iters[i].color_overlay_node,
                                        iters[i].opacity_node,
-                                       iters[i].over_node,
                                        NULL);
+
+      for (j = 0; j < MAX_TRANSFORMS; j++)
+        {
+          iters[i].over_nodes[j] =
+            gegl_node_new_child (node,
+                                 "operation", "gegl:over",
+                                 NULL);
+
+          gegl_operation_meta_watch_node (operation, iters[i].over_nodes[j]);
+        }
     }
 
   update_graph (operation);
diff --git a/operations/workshop/Makefile.am b/operations/workshop/Makefile.am
index 5f6107a10..52a3ce1b3 100644
--- a/operations/workshop/Makefile.am
+++ b/operations/workshop/Makefile.am
@@ -24,6 +24,5 @@ op_LTLIBRARIES = \
        integral-image.la \
        linear-sinusoid.la \
        rawbayer-load.la  \
-       recursive-transform-plus.la \
        segment-kmeans.la \
        selective-hue-saturation.la
diff --git a/po/POTFILES.in b/po/POTFILES.in
index efb2c6b53..819f38466 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -259,6 +259,5 @@ operations/workshop/hstack.c
 operations/workshop/integral-image.c
 operations/workshop/linear-sinusoid.c
 operations/workshop/rawbayer-load.c
-operations/workshop/recursive-transform-plus.c
 operations/workshop/segment-kmeans.c
 operations/workshop/selective-hue-saturation.c


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