gimp r27207 - in trunk: . app/core



Author: mitch
Date: Fri Oct 10 12:24:56 2008
New Revision: 27207
URL: http://svn.gnome.org/viewvc/gimp?rev=27207&view=rev

Log:
2008-10-10  Michael Natterer  <mitch gimp org>

	Bug 554983 â Layers Projection using GEGL

	First projection using GEGL, wheeeee. Disabled by default because
	it doesn't work with floating selection (and will not, FS
	refactoring is in the queue).

	* app/core/gimpimage.[ch]: add gimp_image_get_graph() which
	returns a GeglNode representing the image's projection.

	(gimp_image_add_layer_node)
	(gimp_image_remove_layer_node): new utility functions to add and
	remove layer nodes to/from the graph.

	(gimp_image_add_layer)
	(gimp_image_remove_layer)
	(gimp_image_position_layer): call them to keep the graph up to date.

	* app/core/gimpdrawable.c (gimp_drawable_real_update): invalidate
	the source node.

	* app/core/gimpprojection.[ch]: keep a projection graph around and
	add gimp_projection_get_sink_node() which returns the node that
	writes to the projection tiles.

	* app/core/gimpprojection-construct.c: add
	gimp_projection_construct_gegl() which is a few-liner that uses a
	GeglProcessor to run the projection graph.

	(gimp_projection_construct): call the new function (disabled by
	default).



Modified:
   trunk/ChangeLog
   trunk/app/core/gimpdrawable.c
   trunk/app/core/gimpimage.c
   trunk/app/core/gimpimage.h
   trunk/app/core/gimpprojection-construct.c
   trunk/app/core/gimpprojection.c
   trunk/app/core/gimpprojection.h

Modified: trunk/app/core/gimpdrawable.c
==============================================================================
--- trunk/app/core/gimpdrawable.c	(original)
+++ trunk/app/core/gimpdrawable.c	Fri Oct 10 12:24:56 2008
@@ -642,6 +642,25 @@
                            gint          width,
                            gint          height)
 {
+  if (drawable->source_node)
+    {
+      GObject       *operation;
+      GeglRectangle  rect;
+
+      g_object_get (drawable->source_node,
+                    "gegl-operation", &operation,
+                    NULL);
+
+      rect.x      = x;
+      rect.y      = y;
+      rect.width  = width;
+      rect.height = height;
+
+      gegl_operation_invalidate (operation, &rect);
+
+      g_object_unref (operation);
+    }
+
   gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable));
 }
 

Modified: trunk/app/core/gimpimage.c
==============================================================================
--- trunk/app/core/gimpimage.c	(original)
+++ trunk/app/core/gimpimage.c	Fri Oct 10 12:24:56 2008
@@ -119,6 +119,19 @@
 };
 
 
+#ifdef __GNUC__
+#warning FIXME: gegl_node_add_child() needs to be public
+#endif
+GeglNode * gegl_node_add_child (GeglNode *self,
+                                GeglNode *child);
+
+#ifdef __GNUC__
+#warning FIXME: gegl_node_remove_child() needs to be public
+#endif
+GeglNode * gegl_node_remove_child (GeglNode *self,
+                                   GeglNode *child);
+
+
 /*  local function prototypes  */
 
 static void     gimp_color_managed_iface_init    (GimpColorManagedInterface *iface);
@@ -2537,6 +2550,155 @@
   return image->projection;
 }
 
+GeglNode *
+gimp_image_get_graph (GimpImage *image)
+{
+  GList    *list;
+  GList    *reverse_list = NULL;
+  GeglNode *previous     = NULL;
+
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
+
+  if (image->graph)
+    return image->graph;
+
+  for (list = GIMP_LIST (image->layers)->list;
+       list;
+       list = g_list_next (list))
+    {
+      GimpLayer *layer = list->data;
+
+      if (! gimp_layer_is_floating_sel (layer))
+        reverse_list = g_list_prepend (reverse_list, layer);
+    }
+
+  image->graph = gegl_node_new ();
+
+  for (list = reverse_list; list; list = g_list_next (list))
+    {
+      GimpLayer *layer = list->data;
+      GeglNode  *node  = gimp_layer_get_node (layer);
+
+      gegl_node_add_child (image->graph, node);
+
+      if (previous)
+        gegl_node_connect_to (previous, "output",
+                              node,     "input");
+
+      previous = node;
+    }
+
+  if (previous)
+    {
+      GeglNode *output;
+
+      output = gegl_node_get_output_proxy (image->graph, "output");
+
+      gegl_node_connect_to (previous, "output",
+                            output,   "input");
+    }
+
+  return image->graph;
+}
+
+/*  layer must be part of image->layers !!!  */
+static void
+gimp_image_add_layer_node (GimpImage *image,
+                           GimpLayer *layer)
+{
+  GimpLayer *layer_below;
+  GeglNode  *node;
+  gint       index;
+
+  index = gimp_image_get_layer_index (image, layer);
+
+  node = gimp_layer_get_node (layer);
+
+  if (index == 0)
+    {
+      GeglNode *output;
+
+      output = gegl_node_get_output_proxy (image->graph, "output");
+
+      gegl_node_connect_to (node,   "output",
+                            output, "input");
+    }
+  else
+    {
+      GimpLayer *layer_above;
+      GeglNode  *node_above;
+
+      layer_above = gimp_image_get_layer_by_index (image, index - 1);
+
+      node_above = gimp_layer_get_node (layer_above);
+
+      gegl_node_connect_to (node,       "output",
+                            node_above, "input");
+    }
+
+  layer_below = gimp_image_get_layer_by_index (image, index + 1);
+
+  if (layer_below)
+    {
+      GeglNode *node_below = gimp_layer_get_node (layer_below);
+
+      gegl_node_connect_to (node_below, "output",
+                            node,       "input");
+    }
+}
+
+/*  layer must be part of image->layers !!!  */
+static void
+gimp_image_remove_layer_node (GimpImage *image,
+                              GimpLayer *layer)
+{
+  GimpLayer *layer_below;
+  GeglNode  *node;
+  gint       index;
+
+  index = gimp_image_get_layer_index (image, layer);
+
+  node = gimp_layer_get_node (layer);
+
+  layer_below = gimp_image_get_layer_by_index (image, index + 1);
+
+  if (index == 0)
+    {
+      if (layer_below)
+        {
+          GeglNode *node_below = gimp_layer_get_node (layer_below);
+          GeglNode *output;
+
+          output = gegl_node_get_output_proxy (image->graph, "output");
+
+          gegl_node_disconnect (node,       "input");
+          gegl_node_connect_to (node_below, "output",
+                                output,     "input");
+        }
+    }
+  else
+    {
+      GimpLayer *layer_above;
+      GeglNode  *node_above;
+
+      layer_above = gimp_image_get_layer_by_index (image, index - 1);
+      node_above = gimp_layer_get_node (layer_above);
+
+      if (layer_below)
+        {
+          GeglNode *node_below = gimp_layer_get_node (layer_below);
+
+          gegl_node_disconnect (node,       "input");
+          gegl_node_connect_to (node_below, "output",
+                                node_above, "input");
+        }
+      else
+        {
+          gegl_node_disconnect (node_above, "input");
+        }
+    }
+}
+
 
 /*  layers / channels / vectors  */
 
@@ -2941,6 +3103,9 @@
   gimp_container_insert (image->layers, GIMP_OBJECT (layer), position);
   g_object_unref (layer);
 
+  if (! gimp_layer_is_floating_sel (layer) && image->graph)
+    gimp_image_add_layer_node (image, layer);
+
   /*  notify the layers dialog of the currently active layer  */
   gimp_image_set_active_layer (image, layer);
 
@@ -3003,6 +3168,13 @@
   if (layer == active_layer)
     gimp_drawable_invalidate_boundary (GIMP_DRAWABLE (layer));
 
+  if (! gimp_layer_is_floating_sel (layer) && image->graph)
+    {
+      gimp_image_remove_layer_node (image, layer);
+
+      gegl_node_remove_child (image->graph, gimp_layer_get_node (layer));
+    }
+
   gimp_container_remove (image->layers, GIMP_OBJECT (layer));
   image->layer_stack = g_slist_remove (image->layer_stack, layer);
 
@@ -3226,8 +3398,14 @@
   if (push_undo)
     gimp_image_undo_push_layer_reposition (image, undo_desc, layer);
 
+  if (! gimp_layer_is_floating_sel (layer) && image->graph)
+    gimp_image_remove_layer_node (image, layer);
+
   gimp_container_reorder (image->layers, GIMP_OBJECT (layer), new_index);
 
+  if (! gimp_layer_is_floating_sel (layer) && image->graph)
+    gimp_image_add_layer_node (image, layer);
+
   if (gimp_item_get_visible (GIMP_ITEM (layer)))
     {
       gint off_x, off_y;

Modified: trunk/app/core/gimpimage.h
==============================================================================
--- trunk/app/core/gimpimage.h	(original)
+++ trunk/app/core/gimpimage.h	Fri Oct 10 12:24:56 2008
@@ -411,6 +411,7 @@
 /*  projection  */
 
 GimpProjection * gimp_image_get_projection       (const GimpImage    *image);
+GeglNode       * gimp_image_get_graph            (GimpImage          *image);
 
 
 /*  layers / channels / vectors  */

Modified: trunk/app/core/gimpprojection-construct.c
==============================================================================
--- trunk/app/core/gimpprojection-construct.c	(original)
+++ trunk/app/core/gimpprojection-construct.c	Fri Oct 10 12:24:56 2008
@@ -41,6 +41,11 @@
 
 /*  local function prototypes  */
 
+static void   gimp_projection_construct_gegl     (GimpProjection *proj,
+                                                  gint            x,
+                                                  gint            y,
+                                                  gint            w,
+                                                  gint            h);
 static void   gimp_projection_construct_layers   (GimpProjection *proj,
                                                   gint            x,
                                                   gint            y,
@@ -150,7 +155,11 @@
   /*  call functions which process the list of layers and
    *  the list of channels
    */
-  gimp_projection_construct_layers (proj, x, y, w, h);
+  if (FALSE)
+    gimp_projection_construct_gegl (proj, x, y, w, h);
+  else
+    gimp_projection_construct_layers (proj, x, y, w, h);
+
   gimp_projection_construct_channels (proj, x, y, w, h);
 }
 
@@ -158,6 +167,33 @@
 /*  private functions  */
 
 static void
+gimp_projection_construct_gegl (GimpProjection *proj,
+                                gint            x,
+                                gint            y,
+                                gint            w,
+                                gint            h)
+{
+  GeglNode      *sink;
+  GeglProcessor *processor;
+  GeglRectangle  rect;
+
+  sink = gimp_projection_get_sink_node (proj);
+
+  rect.x      = x;
+  rect.y      = y;
+  rect.width  = w;
+  rect.height = h;
+
+  processor = gegl_node_new_processor (sink, &rect);
+
+  while (gegl_processor_work (processor, NULL));
+
+  g_object_unref (processor);
+
+  proj->construct_flag = TRUE;
+}
+
+static void
 gimp_projection_construct_layers (GimpProjection *proj,
                                   gint            x,
                                   gint            y,

Modified: trunk/app/core/gimpprojection.c
==============================================================================
--- trunk/app/core/gimpprojection.c	(original)
+++ trunk/app/core/gimpprojection.c	Fri Oct 10 12:24:56 2008
@@ -46,6 +46,13 @@
 };
 
 
+#ifdef __GNUC__
+#warning FIXME: gegl_node_add_child() needs to be public
+#endif
+GeglNode * gegl_node_add_child (GeglNode *self,
+                                GeglNode *child);
+
+
 /*  local function prototypes  */
 
 static void   gimp_projection_pickable_iface_init (GimpPickableInterface *iface);
@@ -185,6 +192,13 @@
       proj->pyramid = NULL;
     }
 
+  if (proj->graph)
+    {
+      g_object_unref (proj->graph);
+      proj->graph     = NULL;
+      proj->sink_node = NULL;
+    }
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -317,6 +331,38 @@
 
 }
 
+GeglNode *
+gimp_projection_get_sink_node (GimpProjection *proj)
+{
+  GeglNode *image_graph;
+
+  g_return_val_if_fail (GIMP_IS_PROJECTION (proj), NULL);
+
+  if (proj->sink_node)
+    return proj->sink_node;
+
+  proj->graph = gegl_node_new ();
+
+  g_object_set (proj->graph,
+                "dont-cache", TRUE,
+                NULL);
+
+  image_graph = gimp_image_get_graph (proj->image);
+  gegl_node_add_child (proj->graph, image_graph);
+
+  proj->sink_node =
+    gegl_node_new_child (proj->graph,
+                         "operation",    "gimp-tilemanager-sink",
+                         "tile-manager", gimp_projection_get_tiles (proj),
+                         "linear",       TRUE,
+                         NULL);
+
+  gegl_node_connect_to (image_graph,     "output",
+                        proj->sink_node, "input");
+
+  return proj->sink_node;
+}
+
 TileManager *
 gimp_projection_get_tiles_at_level (GimpProjection *proj,
                                     gint            level,
@@ -333,6 +379,15 @@
       tile_pyramid_set_validate_proc (proj->pyramid,
                                       (TileValidateProc) gimp_projection_validate_tile,
                                       proj);
+
+      if (proj->sink_node)
+        {
+          TileManager *tiles = tile_pyramid_get_tiles (proj->pyramid, 0, NULL);
+
+          gegl_node_set (proj->sink_node,
+                         "tile-manager", tiles,
+                         NULL);
+        }
     }
 
   return tile_pyramid_get_tiles (proj->pyramid, level, is_premult);

Modified: trunk/app/core/gimpprojection.h
==============================================================================
--- trunk/app/core/gimpprojection.h	(original)
+++ trunk/app/core/gimpprojection.h	Fri Oct 10 12:24:56 2008
@@ -56,6 +56,8 @@
   GimpImage                *image;
 
   TilePyramid              *pyramid;
+  GeglNode                 *graph;
+  GeglNode                 *sink_node;
 
   GSList                   *update_areas;
   GimpProjectionIdleRender  idle_render;
@@ -82,6 +84,7 @@
 GimpProjection * gimp_projection_new              (GimpImage            *image);
 
 TileManager    * gimp_projection_get_tiles        (GimpProjection       *proj);
+GeglNode       * gimp_projection_get_sink_node    (GimpProjection       *proj);
 
 TileManager    * gimp_projection_get_tiles_at_level
                                                   (GimpProjection       *proj,



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