Address Bug 554983 – Layers Projection using GEGL

2008-10-09  Michael Natterer  <mitch@gimp.org>

	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.


svn path=/trunk/; revision=27204
This commit is contained in:
Michael Natterer 2008-10-09 20:44:23 +00:00 committed by Michael Natterer
parent 511d9c6581
commit 517e58cdeb
9 changed files with 265 additions and 2 deletions

View file

@ -1,3 +1,31 @@
2008-10-09 Michael Natterer <mitch@gimp.org>
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 <mitch@gimp.org>
Add GEGL_CFLAGS and #includes as if gimpdrawable.h and gimpimage.h

View file

@ -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,

View file

@ -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,

View file

@ -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);

View file

@ -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 */

View file

@ -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)),

View file

@ -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);

View file

@ -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";
}

View file

@ -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__ */