diff --git a/ChangeLog b/ChangeLog index 3778d7e83d..648c6f3ae5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2008-10-09 Michael Natterer + + Address Bug 554983 – Layers Projection using GEGL + + * app/gegl/gimp-gegl-utils.[ch]: add (imcomplete) function + gimp_layer_mode_to_gegl_operation() from bug #554983. + + * app/core/gimpdrawable.[ch]: add gimp_drawable_get_source_node() + which returns a GimpOperationTileSource for the drawable's + tiles. + + (gimp_drawable_real_set_tiles) + (gimp_drawable_configure): set the node's "tiles" property. + + * app/core/gimplayer.[ch]: add gimp_layer_get_node() which returns + a GeglNode with proxy "input" and "output" pads to be plugged + into the projection graph. The node has children for opacity, + mask, layer mode and layer offset. + + (gimp_layer_translate) + (gimp_layer_add_mask) + (gimp_layer_apply_mask) + (gimp_layer_set_opacity) + (gimp_layer_set_mode): reconfigure the respective nodes. + + * app/core/gimpimage.[ch]: keep a "graph" node around and destroy + it in finalize(). Not even a stub, just a silly GEGL dependency. + 2008-10-09 Michael Natterer Add GEGL_CFLAGS and #includes as if gimpdrawable.h and gimpimage.h diff --git a/app/core/gimpdrawable.c b/app/core/gimpdrawable.c index 13ea496e49..0faca57d43 100644 --- a/app/core/gimpdrawable.c +++ b/app/core/gimpdrawable.c @@ -261,6 +261,12 @@ gimp_drawable_finalize (GObject *object) gimp_drawable_free_shadow_tiles (drawable); + if (drawable->source_node) + { + g_object_unref (drawable->source_node); + drawable->source_node = NULL; + } + if (drawable->preview_cache) gimp_preview_cache_invalidate (&drawable->preview_cache); @@ -702,6 +708,11 @@ gimp_drawable_real_set_tiles (GimpDrawable *drawable, if (old_has_alpha != gimp_drawable_has_alpha (drawable)) gimp_drawable_alpha_changed (drawable); + + if (drawable->source_node) + gegl_node_set (drawable->source_node, + "tile-manager", drawable->tiles, + NULL); } static void @@ -839,6 +850,11 @@ gimp_drawable_configure (GimpDrawable *drawable, /* preview variables */ drawable->preview_cache = NULL; drawable->preview_valid = FALSE; + + if (drawable->source_node) + gegl_node_set (drawable->source_node, + "tile-manager", drawable->tiles, + NULL); } void @@ -1012,6 +1028,25 @@ gimp_drawable_set_tiles_full (GimpDrawable *drawable, gimp_item_height (item)); } +GeglNode * +gimp_drawable_get_source_node (GimpDrawable *drawable) +{ + g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL); + + if (drawable->source_node) + return drawable->source_node; + + drawable->source_node = g_object_new (GEGL_TYPE_NODE, + "operation", "gimp-tilemanager-source", + NULL); + gegl_node_set (drawable->source_node, + "tile-manager", drawable->tiles, + "linear", TRUE, + NULL); + + return drawable->source_node; +} + void gimp_drawable_swap_pixels (GimpDrawable *drawable, TileManager *tiles, diff --git a/app/core/gimpdrawable.h b/app/core/gimpdrawable.h index 92a89fb07f..3654eedacc 100644 --- a/app/core/gimpdrawable.h +++ b/app/core/gimpdrawable.h @@ -40,6 +40,8 @@ struct _GimpDrawable TileManager *tiles; /* tiles for drawable data */ TileManager *shadow; /* shadow buffer tiles */ + GeglNode *source_node; + gint bytes; /* bytes per pixel */ GimpImageType type; /* type of drawable */ gboolean has_alpha; /* drawable has alpha */ @@ -169,6 +171,8 @@ void gimp_drawable_set_tiles_full (GimpDrawable *drawable, gint offset_x, gint offset_y); +GeglNode * gimp_drawable_get_source_node (GimpDrawable *drawable); + void gimp_drawable_swap_pixels (GimpDrawable *drawable, TileManager *tiles, gboolean sparse, diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c index a695de14f1..6334ab3958 100644 --- a/app/core/gimpimage.c +++ b/app/core/gimpimage.c @@ -891,6 +891,12 @@ gimp_image_finalize (GObject *object) image->projection = NULL; } + if (image->graph) + { + g_object_unref (image->graph); + image->graph = NULL; + } + if (image->colormap) { g_free (image->colormap); diff --git a/app/core/gimpimage.h b/app/core/gimpimage.h index 8c8975de92..09d193d33e 100644 --- a/app/core/gimpimage.h +++ b/app/core/gimpimage.h @@ -126,6 +126,7 @@ struct _GimpImage GimpTattoo tattoo_state; /* the last used tattoo */ GimpProjection *projection; /* projection layers & channels */ + GeglNode *graph; /* GEGL projection graph */ GList *guides; /* guides */ GimpGrid *grid; /* grid */ diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c index a216d9bbfb..8cd42de1cf 100644 --- a/app/core/gimplayer.c +++ b/app/core/gimplayer.c @@ -35,6 +35,8 @@ #include "paint-funcs/paint-funcs.h" +#include "gegl/gimp-gegl-utils.h" + #include "gimpcontext.h" #include "gimpcontainer.h" #include "gimpdrawable-convert.h" @@ -69,6 +71,19 @@ enum }; +#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); + + static void gimp_layer_pickable_iface_init (GimpPickableInterface *iface); static void gimp_layer_set_property (GObject *object, @@ -376,6 +391,12 @@ gimp_layer_finalize (GObject *object) layer->mask = NULL; } + if (layer->node) + { + g_object_unref (layer->node); + layer->node = NULL; + } + if (layer->fs.backing_store) { tile_manager_unref (layer->fs.backing_store); @@ -692,6 +713,12 @@ gimp_layer_translate (GimpItem *item, if (gimp_layer_is_floating_sel (layer)) floating_sel_rigor (layer, FALSE); + if (layer->shift_node) + gegl_node_set (layer->shift_node, + "x", item->offset_x, + "y", item->offset_y, + NULL); + /* update the new region */ gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, @@ -1286,6 +1313,27 @@ gimp_layer_add_mask (GimpLayer *layer, gimp_layer_mask_set_layer (mask, layer); + if (layer->node) + { + GeglNode *source; + GeglNode *mask; + + layer->mask_node = gegl_node_new_child (layer->node, + "operation", "opacity", + NULL); + + source = gimp_drawable_get_source_node (GIMP_DRAWABLE (layer)); + gegl_node_connect_to (source, "output", + layer->mask_node, "input"); + + mask = gimp_drawable_get_source_node (GIMP_DRAWABLE (layer->mask)); + gegl_node_connect_to (mask, "output", + layer->mask_node, "aux"); + + gegl_node_connect_to (layer->mask_node, "output", + layer->shift_node, "input"); + } + if (gimp_layer_mask_get_apply (mask) || gimp_layer_mask_get_show (mask)) { @@ -1610,6 +1658,18 @@ gimp_layer_apply_mask (GimpLayer *layer, if (push_undo) gimp_image_undo_group_end (image); + if (layer->node) + { + GeglNode *source; + + gegl_node_remove_child (layer->node, layer->mask_node); + layer->mask_node = NULL; + + source = gimp_drawable_get_source_node (GIMP_DRAWABLE (layer)); + gegl_node_connect_to (source, "output", + layer->shift_node, "input"); + } + /* If applying actually changed the view */ if (view_changed) { @@ -1836,6 +1896,77 @@ gimp_layer_is_floating_sel (const GimpLayer *layer) return (layer->fs.drawable != NULL); } +GeglNode * +gimp_layer_get_node (GimpLayer *layer) +{ + GeglNode *source; + gint off_x, off_y; + GeglNode *input; + GeglNode *output; + + g_return_val_if_fail (GIMP_IS_LAYER (layer), NULL); + + if (layer->node) + return layer->node; + + layer->node = gegl_node_new (); + + source = gimp_drawable_get_source_node (GIMP_DRAWABLE (layer)); + gegl_node_add_child (layer->node, source); + + if (layer->mask) + { + GeglNode *mask; + + mask = gimp_drawable_get_source_node (GIMP_DRAWABLE (layer->mask)); + + layer->mask_node = gegl_node_new_child (layer->node, + "operation", "opacity", + NULL); + gegl_node_connect_to (mask, "output", + layer->mask_node, "aux"); + gegl_node_connect_to (source, "output", + layer->mask_node, "input"); + } + + gimp_item_offsets (GIMP_ITEM (layer), &off_x, &off_y); + layer->shift_node = gegl_node_new_child (layer->node, + "operation", "shift", + "x", off_x, + "y", off_y, + NULL); + + if (layer->mask_node) + gegl_node_connect_to (layer->mask_node, "output", + layer->shift_node, "input"); + else + gegl_node_connect_to (source, "output", + layer->shift_node, "input"); + + layer->opacity_node = gegl_node_new_child (layer->node, + "operation", "opacity", + "value", layer->opacity, + NULL); + gegl_node_connect_to (layer->shift_node, "output", + layer->opacity_node, "input"); + + layer->mode_node = gegl_node_new_child (layer->node, + "operation", gimp_layer_mode_to_gegl_operation (layer->mode), + NULL); + gegl_node_connect_to (layer->opacity_node, "output", + layer->mode_node, "aux"); + + input = gegl_node_get_input_proxy (layer->node, "input"); + gegl_node_connect_to (input, "output", + layer->mode_node, "input"); + + output = gegl_node_get_output_proxy (layer->node, "output"); + gegl_node_connect_to (layer->mode_node, "output", + output, "input"); + + return layer->node; +} + void gimp_layer_set_opacity (GimpLayer *layer, gdouble opacity, @@ -1859,6 +1990,11 @@ gimp_layer_set_opacity (GimpLayer *layer, g_signal_emit (layer, layer_signals[OPACITY_CHANGED], 0); g_object_notify (G_OBJECT (layer), "opacity"); + if (layer->opacity_node) + gegl_node_set (layer->opacity_node, + "opacity", layer->opacity, + NULL); + gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, gimp_item_width (GIMP_ITEM (layer)), @@ -1895,6 +2031,11 @@ gimp_layer_set_mode (GimpLayer *layer, g_signal_emit (layer, layer_signals[MODE_CHANGED], 0); g_object_notify (G_OBJECT (layer), "mode"); + if (layer->mode_node) + gegl_node_set (layer->mode_node, + "operation", gimp_layer_mode_to_gegl_operation (layer->mode), + NULL); + gimp_drawable_update (GIMP_DRAWABLE (layer), 0, 0, gimp_item_width (GIMP_ITEM (layer)), diff --git a/app/core/gimplayer.h b/app/core/gimplayer.h index 87ec267fac..5661d641fd 100644 --- a/app/core/gimplayer.h +++ b/app/core/gimplayer.h @@ -43,6 +43,12 @@ struct _GimpLayer GimpLayerMask *mask; /* possible layer mask */ + GeglNode *node; + GeglNode *mask_node; + GeglNode *shift_node; + GeglNode *opacity_node; + GeglNode *mode_node; + /* Floating selections */ struct { @@ -121,6 +127,8 @@ GimpLayerMask * gimp_layer_get_mask (const GimpLayer *layer); gboolean gimp_layer_is_floating_sel (const GimpLayer *layer); +GeglNode * gimp_layer_get_node (GimpLayer *layer); + void gimp_layer_set_opacity (GimpLayer *layer, gdouble opacity, gboolean push_undo); diff --git a/app/gegl/gimp-gegl-utils.c b/app/gegl/gimp-gegl-utils.c index cc5e4a2915..ab34f31238 100644 --- a/app/gegl/gimp-gegl-utils.c +++ b/app/gegl/gimp-gegl-utils.c @@ -85,3 +85,42 @@ gimp_bpp_to_babl_format_linear (guint bpp) return NULL; } + +const gchar * +gimp_layer_mode_to_gegl_operation (GimpLayerModeEffects mode) +{ +#ifdef __GNUC__ +#warning FIXME: add all layer modes as GEGL operations +#endif + + switch (mode) + { + case GIMP_NORMAL_MODE: return "normal"; + case GIMP_DISSOLVE_MODE: return "normal"; + case GIMP_BEHIND_MODE: return "normal"; + case GIMP_MULTIPLY_MODE: return "gimp-multiply-mode"; + case GIMP_SCREEN_MODE: return "gimp-screen_mode"; + case GIMP_OVERLAY_MODE: return "gimp-overlay-mode"; + case GIMP_DIFFERENCE_MODE: return "gimp-difference-mode"; + case GIMP_ADDITION_MODE: return "gimp-addition-mode"; + case GIMP_SUBTRACT_MODE: return "gimp-subtract-mode"; + case GIMP_DARKEN_ONLY_MODE: return "gimp-darken-mode"; + case GIMP_LIGHTEN_ONLY_MODE: return "gimp-lighten-mode"; + case GIMP_HUE_MODE: return "normal"; + case GIMP_SATURATION_MODE: return "normal"; + case GIMP_COLOR_MODE: return "normal"; + case GIMP_VALUE_MODE: return "normal"; + case GIMP_DIVIDE_MODE: return "gimp-divide-mode"; + case GIMP_DODGE_MODE: return "gimp-dodge-mode"; + case GIMP_BURN_MODE: return "gimp-burn-mode"; + case GIMP_HARDLIGHT_MODE: return "gimp-hardlight-mode"; + case GIMP_SOFTLIGHT_MODE: return "gimp-softlight-mode"; + case GIMP_GRAIN_EXTRACT_MODE: return "gimp-grain-extract-mode"; + case GIMP_GRAIN_MERGE_MODE: return "gimp-grain-merge-mode"; + case GIMP_COLOR_ERASE_MODE: return "normal"; + default: + break; + } + + return "normal"; +} diff --git a/app/gegl/gimp-gegl-utils.h b/app/gegl/gimp-gegl-utils.h index 4196d7c97e..546dd46d69 100644 --- a/app/gegl/gimp-gegl-utils.h +++ b/app/gegl/gimp-gegl-utils.h @@ -23,9 +23,10 @@ #define __GIMP_GEGL_UTILS_H__ -const Babl * gimp_bpp_to_babl_format (guint bpp) G_GNUC_CONST; -const Babl * gimp_bpp_to_babl_format_linear (guint bpp) G_GNUC_CONST; +const Babl * gimp_bpp_to_babl_format (guint bpp) G_GNUC_CONST; +const Babl * gimp_bpp_to_babl_format_linear (guint bpp) G_GNUC_CONST; +const gchar * gimp_layer_mode_to_gegl_operation (GimpLayerModeEffects mode) G_GNUC_CONST; #endif /* __GIMP_GEGL_UTILS_H__ */