[gimp/wip/passthrough: 5/10] app: implement pass-through mode in GimpGroupLayer



commit 1f29b487473050adf4cce9c61daaf6b85452916f
Author: Ell <ell_se yahoo com>
Date:   Fri Apr 21 18:04:49 2017 -0400

    app: implement pass-through mode in GimpGroupLayer
    
    Override GimpDrawable::get_source_node() for GimpGroupLayer.  Use
    a node that contains both the drawable's buffer-source node, and the
    layer stack's graph node.  Choose which one of these to connect to
    the source node's output based on the group's layer mode: the stack
    graph for pass-through mode, and the buffer-source node for all the
    rest.
    
    When in pass-through mode, connect the source node's input (which
    receives the backdrop) to the stack graph's input.  Keep maintaining
    the projection in pass-through mode.  ATM, the projection uses the
    same graph as the source node, so it's rendered against the group's
    backdrop -- we don't want that.  The next few commits fix it.
    
    Update the group's drawable directly upon filter stack update in
    pass-though mode, because the group's graph doesn't go through the
    projection.
    
    TODO: if any of the group's children (or a child of a nested pass-
    through group, etc.) uses dst-atop/src-in, this needs special
    attention.

 app/core/gimpgrouplayer.c |  124 ++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 117 insertions(+), 7 deletions(-)
---
diff --git a/app/core/gimpgrouplayer.c b/app/core/gimpgrouplayer.c
index 3ac678b..cb590d2 100644
--- a/app/core/gimpgrouplayer.c
+++ b/app/core/gimpgrouplayer.c
@@ -49,6 +49,8 @@ struct _GimpGroupLayerPrivate
 {
   GimpContainer  *children;
   GimpProjection *projection;
+  GeglNode       *source_node;
+  GeglNode       *parent_source_node;
   GeglNode       *graph;
   GeglNode       *offset_node;
   gint            suspend_resize;
@@ -145,6 +147,9 @@ static void            gimp_group_layer_convert_type (GimpDrawable      *drawabl
                                                       GeglDitherMethod   mask_dither_type,
                                                       gboolean           push_undo,
                                                       GimpProgress      *progress);
+static GeglNode   * gimp_group_layer_get_source_node (GimpDrawable      *drawable);
+
+static void            gimp_group_layer_mode_changed (GimpLayer         *layer);
 
 static const Babl    * gimp_group_layer_get_format   (GimpProjectable *projectable);
 static GeglNode      * gimp_group_layer_get_graph    (GimpProjectable *projectable);
@@ -167,6 +172,7 @@ static void            gimp_group_layer_child_resize (GimpLayer       *child,
 
 static void            gimp_group_layer_update       (GimpGroupLayer  *group);
 static void            gimp_group_layer_update_size  (GimpGroupLayer  *group);
+static void      gimp_group_layer_update_source_node (GimpGroupLayer  *group);
 
 static void            gimp_group_layer_stack_update (GimpDrawableStack *stack,
                                                       gint               x,
@@ -201,6 +207,7 @@ gimp_group_layer_class_init (GimpGroupLayerClass *klass)
   GimpViewableClass *viewable_class    = GIMP_VIEWABLE_CLASS (klass);
   GimpItemClass     *item_class        = GIMP_ITEM_CLASS (klass);
   GimpDrawableClass *drawable_class    = GIMP_DRAWABLE_CLASS (klass);
+  GimpLayerClass    *layer_class    = GIMP_LAYER_CLASS (klass);
 
   object_class->set_property        = gimp_group_layer_set_property;
   object_class->get_property        = gimp_group_layer_get_property;
@@ -235,6 +242,9 @@ gimp_group_layer_class_init (GimpGroupLayerClass *klass)
 
   drawable_class->estimate_memsize  = gimp_group_layer_estimate_memsize;
   drawable_class->convert_type      = gimp_group_layer_convert_type;
+  drawable_class->get_source_node   = gimp_group_layer_get_source_node;
+
+  layer_class->mode_changed         = gimp_group_layer_mode_changed;
 
   g_type_class_add_private (klass, sizeof (GimpGroupLayerPrivate));
 }
@@ -319,6 +329,12 @@ gimp_group_layer_finalize (GObject *object)
       private->projection = NULL;
     }
 
+  if (private->source_node)
+    {
+      g_object_unref (private->source_node);
+      private->source_node = NULL;
+    }
+
   if (private->graph)
     {
       g_object_unref (private->graph);
@@ -941,6 +957,51 @@ gimp_group_layer_convert_type (GimpDrawable     *drawable,
     }
 }
 
+static GeglNode *
+gimp_group_layer_get_source_node (GimpDrawable *drawable)
+{
+  GimpGroupLayerPrivate *private = GET_PRIVATE (drawable);
+  GeglNode              *input;
+
+  g_warn_if_fail (private->source_node == NULL);
+
+  private->source_node = gegl_node_new ();
+
+  input = gegl_node_get_input_proxy (private->source_node, "input");
+
+  private->parent_source_node =
+    GIMP_DRAWABLE_CLASS (parent_class)->get_source_node (drawable);
+
+  gegl_node_add_child (private->source_node, private->parent_source_node);
+
+  g_object_unref (private->parent_source_node);
+
+  if (gegl_node_has_pad (private->parent_source_node, "input"))
+    {
+      gegl_node_connect_to (input,                       "output",
+                            private->parent_source_node, "input");
+    }
+
+  gimp_group_layer_get_graph (GIMP_PROJECTABLE (drawable));
+
+  gegl_node_add_child (private->source_node, private->graph);
+
+  gimp_group_layer_update_source_node (GIMP_GROUP_LAYER (drawable));
+
+  return g_object_ref (private->source_node);
+}
+
+static void
+gimp_group_layer_mode_changed (GimpLayer *layer)
+{
+  GimpGroupLayer *group = GIMP_GROUP_LAYER (layer);
+
+  gimp_group_layer_update_source_node (group);
+
+  if (GIMP_LAYER_CLASS (parent_class)->mode_changed)
+    GIMP_LAYER_CLASS (parent_class)->mode_changed (layer);
+}
+
 static const Babl *
 gimp_group_layer_get_format (GimpProjectable *projectable)
 {
@@ -962,6 +1023,7 @@ gimp_group_layer_get_graph (GimpProjectable *projectable)
 {
   GimpGroupLayer        *group   = GIMP_GROUP_LAYER (projectable);
   GimpGroupLayerPrivate *private = GET_PRIVATE (projectable);
+  GeglNode              *input;
   GeglNode              *layers_node;
   GeglNode              *output;
   gint                   off_x;
@@ -972,11 +1034,16 @@ gimp_group_layer_get_graph (GimpProjectable *projectable)
 
   private->graph = gegl_node_new ();
 
+  input = gegl_node_get_input_proxy (private->graph, "input");
+
   layers_node =
     gimp_filter_stack_get_graph (GIMP_FILTER_STACK (private->children));
 
   gegl_node_add_child (private->graph, layers_node);
 
+  gegl_node_connect_to (input,       "output",
+                        layers_node, "input");
+
   gimp_item_get_offset (GIMP_ITEM (group), &off_x, &off_y);
 
   private->offset_node = gegl_node_new_child (private->graph,
@@ -1243,6 +1310,35 @@ gimp_group_layer_update_size (GimpGroupLayer *group)
 }
 
 static void
+gimp_group_layer_update_source_node (GimpGroupLayer *group)
+{
+  GimpGroupLayerPrivate *private = GET_PRIVATE (group);
+  GeglNode              *input;
+  GeglNode              *output;
+
+  if (private->source_node == NULL)
+    return;
+
+  input  = gegl_node_get_input_proxy  (private->source_node, "input");
+  output = gegl_node_get_output_proxy (private->source_node, "output");
+
+  if (gimp_layer_get_mode (GIMP_LAYER (group)) == GIMP_LAYER_MODE_PASS_THROUGH)
+    {
+      gegl_node_connect_to (input,          "output",
+                            private->graph, "input");
+      gegl_node_connect_to (private->graph, "output",
+                            output,         "input");
+    }
+  else
+    {
+      gegl_node_disconnect (private->graph, "input");
+
+      gegl_node_connect_to (private->parent_source_node, "output",
+                            output,                      "input");
+    }
+}
+
+static void
 gimp_group_layer_stack_update (GimpDrawableStack *stack,
                                gint               x,
                                gint               y,
@@ -1256,6 +1352,17 @@ gimp_group_layer_stack_update (GimpDrawableStack *stack,
               x, y, width, height);
 #endif
 
+  if (gimp_layer_get_mode (GIMP_LAYER (group)) == GIMP_LAYER_MODE_PASS_THROUGH)
+    {
+      /*  the layer stack's update signal speaks in image coordinates,
+       *  transform to layer coordinates when emitting our own update signal.
+       */
+      gimp_drawable_update (GIMP_DRAWABLE (group),
+                            x - gimp_item_get_offset_x (GIMP_ITEM (group)),
+                            y - gimp_item_get_offset_y (GIMP_ITEM (group)),
+                            width, height);
+    }
+
   /*  the layer stack's update signal speaks in image coordinates,
    *  pass to the projection as-is.
    */
@@ -1286,11 +1393,14 @@ gimp_group_layer_proj_update (GimpProjection *proj,
               x, y, width, height);
 #endif
 
-  /*  the projection speaks in image coordinates, transform to layer
-   *  coordinates when emitting our own update signal.
-   */
-  gimp_drawable_update (GIMP_DRAWABLE (group),
-                        x - gimp_item_get_offset_x (GIMP_ITEM (group)),
-                        y - gimp_item_get_offset_y (GIMP_ITEM (group)),
-                        width, height);
+  if (gimp_layer_get_mode (GIMP_LAYER (group)) != GIMP_LAYER_MODE_PASS_THROUGH)
+    {
+      /*  the projection speaks in image coordinates, transform to layer
+       *  coordinates when emitting our own update signal.
+       */
+      gimp_drawable_update (GIMP_DRAWABLE (group),
+                            x - gimp_item_get_offset_x (GIMP_ITEM (group)),
+                            y - gimp_item_get_offset_y (GIMP_ITEM (group)),
+                            width, height);
+    }
 }


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