[gimp] app: turn GimpApplicator into a general-purpose "input + aux -> output" thing
- From: Michael Natterer <mitch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] app: turn GimpApplicator into a general-purpose "input + aux -> output" thing
- Date: Sun, 14 Apr 2013 20:47:43 +0000 (UTC)
commit 69a321ac29eebcc64399c64c2f2e28ad412079b0
Author: Michael Natterer <mitch gimp org>
Date: Sun Apr 14 22:44:21 2013 +0200
app: turn GimpApplicator into a general-purpose "input + aux -> output" thing
which means adding a lot of proper API. Input, output and aux can be
pads or buffers. Make sure it uses the minimum possible graph in all
cases and doesn't reconfigure nodes unless needed. Port GimpPaintCore
to the new API.
app/gegl/gimpapplicator.c | 333 +++++++++++++++++++++++++++++++++-------------
app/gegl/gimpapplicator.h | 77 ++++++++---
app/paint/gimppaintcore.c | 76 ++++++-----
3 files changed, 341 insertions(+), 145 deletions(-)
---
diff --git a/app/gegl/gimpapplicator.c b/app/gegl/gimpapplicator.c
index 9a94073..fee2482 100644
--- a/app/gegl/gimpapplicator.c
+++ b/app/gegl/gimpapplicator.c
@@ -1,6 +1,9 @@
/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
+ * gimpapplicator.c
+ * Copyright (C) 2012-2013 Michael Natterer <mitch gimp org>
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
@@ -56,6 +59,7 @@ gimp_applicator_init (GimpApplicator *applicator)
{
applicator->opacity = 1.0;
applicator->paint_mode = GIMP_NORMAL_MODE;
+ applicator->affect = GIMP_COMPONENT_ALL;
}
static void
@@ -101,149 +105,279 @@ gimp_applicator_get_property (GObject *object,
}
GimpApplicator *
-gimp_applicator_new (GeglBuffer *dest_buffer,
- GimpComponentMask affect,
- GeglBuffer *mask_buffer,
- gint mask_offset_x,
- gint mask_offset_y)
+gimp_applicator_new (GeglNode *parent)
{
GimpApplicator *applicator;
- g_return_val_if_fail (GEGL_IS_BUFFER (dest_buffer), NULL);
- g_return_val_if_fail (mask_buffer == NULL || GEGL_IS_BUFFER (mask_buffer),
- NULL);
+ g_return_val_if_fail (parent == NULL || GEGL_IS_NODE (parent), NULL);
applicator = g_object_new (GIMP_TYPE_APPLICATOR, NULL);
- applicator->node = gegl_node_new ();
+ if (parent)
+ applicator->node = g_object_ref (parent);
+ else
+ applicator->node = gegl_node_new ();
+
+ applicator->input_node =
+ gegl_node_get_input_proxy (applicator->node, "input");
+
+ applicator->aux_node =
+ gegl_node_get_input_proxy (applicator->node, "aux");
+
+ applicator->output_node =
+ gegl_node_get_output_proxy (applicator->node, "output");
applicator->mode_node = gegl_node_new_child (applicator->node,
"operation", "gimp:normal-mode",
NULL);
- applicator->src_node =
+ gimp_gegl_mode_node_set (applicator->mode_node,
+ applicator->paint_mode,
+ applicator->opacity,
+ FALSE);
+
+ gegl_node_connect_to (applicator->input_node, "output",
+ applicator->mode_node, "input");
+
+ applicator->apply_offset_node =
gegl_node_new_child (applicator->node,
- "operation", "gegl:buffer-source",
+ "operation", "gegl:translate",
NULL);
- gegl_node_connect_to (applicator->src_node, "output",
- applicator->mode_node, "input");
+ gegl_node_connect_to (applicator->aux_node, "output",
+ applicator->apply_offset_node, "input");
+ gegl_node_connect_to (applicator->apply_offset_node, "output",
+ applicator->mode_node, "aux");
- applicator->apply_src_node =
+ applicator->mask_node =
gegl_node_new_child (applicator->node,
"operation", "gegl:buffer-source",
NULL);
- applicator->apply_offset_node =
+ applicator->mask_offset_node =
gegl_node_new_child (applicator->node,
"operation", "gegl:translate",
NULL);
- gegl_node_connect_to (applicator->apply_src_node, "output",
- applicator->apply_offset_node, "input");
- gegl_node_connect_to (applicator->apply_offset_node, "output",
- applicator->mode_node, "aux");
+ gegl_node_connect_to (applicator->mask_node, "output",
+ applicator->mask_offset_node, "input");
+ /* don't connect the the mask offset node to mode's aux2 yet */
- if (mask_buffer)
- {
- GeglNode *mask_src;
+ applicator->affect_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gimp:mask-components",
+ "mask", applicator->affect,
+ NULL);
- mask_src = gegl_node_new_child (applicator->node,
- "operation", "gegl:buffer-source",
- "buffer", mask_buffer,
- NULL);
+ gegl_node_connect_to (applicator->input_node, "output",
+ applicator->affect_node, "input");
+ gegl_node_connect_to (applicator->mode_node, "output",
+ applicator->affect_node, "aux");
+ gegl_node_connect_to (applicator->affect_node, "output",
+ applicator->output_node, "input");
+
+ return applicator;
+}
+
+void
+gimp_applicator_set_src_buffer (GimpApplicator *applicator,
+ GeglBuffer *src_buffer)
+{
+ g_return_if_fail (src_buffer == NULL || GEGL_IS_BUFFER (src_buffer));
- if (mask_offset_x != 0 || mask_offset_y != 0)
+ if (src_buffer == applicator->src_buffer)
+ return;
+
+ if (src_buffer)
+ {
+ if (! applicator->src_node)
{
- GeglNode *offset;
-
- offset = gegl_node_new_child (applicator->node,
- "operation", "gegl:translate",
- "x", (gdouble) mask_offset_x,
- "y", (gdouble) mask_offset_y,
- NULL);
-
- gegl_node_connect_to (mask_src, "output",
- offset, "input");
- gegl_node_connect_to (offset, "output",
- applicator->mode_node, "aux2");
+ applicator->src_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:buffer-source",
+ "buffer", src_buffer,
+ NULL);
}
else
{
- gegl_node_connect_to (mask_src, "output",
- applicator->mode_node, "aux2");
+ gegl_node_set (applicator->src_node,
+ "buffer", src_buffer,
+ NULL);
+ }
+
+ if (! applicator->src_buffer)
+ {
+ gegl_node_connect_to (applicator->src_node, "output",
+ applicator->mode_node, "input");
+ gegl_node_connect_to (applicator->src_node, "output",
+ applicator->affect_node, "input");
}
}
+ else if (applicator->src_buffer)
+ {
+ gegl_node_connect_to (applicator->input_node, "output",
+ applicator->mode_node, "input");
+ gegl_node_connect_to (applicator->input_node, "output",
+ applicator->affect_node, "input");
+ }
- applicator->dest_node =
- gegl_node_new_child (applicator->node,
- "operation", "gegl:write-buffer",
- "buffer", dest_buffer,
- "flush", FALSE,
+ applicator->src_buffer = src_buffer;
+}
+
+void
+gimp_applicator_set_dest_buffer (GimpApplicator *applicator,
+ GeglBuffer *dest_buffer)
+{
+ g_return_if_fail (dest_buffer == NULL || GEGL_IS_BUFFER (dest_buffer));
+
+ if (dest_buffer == applicator->dest_buffer)
+ return;
+
+ if (dest_buffer)
+ {
+ if (! applicator->dest_node)
+ {
+ applicator->dest_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:write-buffer",
+ "buffer", dest_buffer,
+ "flush", FALSE,
+ NULL);
+ }
+ else
+ {
+ gegl_node_set (applicator->dest_node,
+ "buffer", dest_buffer,
NULL);
+ }
+
+ if (! applicator->dest_buffer)
+ {
+ gegl_node_disconnect (applicator->output_node, "input");
- if (affect == GIMP_COMPONENT_ALL)
+ gegl_node_connect_to (applicator->affect_node, "output",
+ applicator->dest_node, "input");
+ }
+ }
+ else if (applicator->dest_buffer)
{
- gegl_node_connect_to (applicator->mode_node, "output",
- applicator->dest_node, "input");
+ gegl_node_disconnect (applicator->dest_node, "input");
+
+ gegl_node_connect_to (applicator->affect_node, "output",
+ applicator->output_node, "input");
+ }
+
+ applicator->dest_buffer = dest_buffer;
+}
+
+void
+gimp_applicator_set_mask_buffer (GimpApplicator *applicator,
+ GeglBuffer *mask_buffer)
+{
+ if (applicator->mask_buffer == mask_buffer)
+ return;
+
+ gegl_node_set (applicator->mask_node,
+ "buffer", mask_buffer,
+ NULL);
+
+ if (mask_buffer)
+ {
+ gegl_node_connect_to (applicator->mask_offset_node, "output",
+ applicator->mode_node, "aux2");
}
else
{
- GeglNode *affect_node;
-
- affect_node = gegl_node_new_child (applicator->node,
- "operation", "gimp:mask-components",
- "mask", affect,
- NULL);
-
- gegl_node_connect_to (applicator->src_node, "output",
- affect_node, "input");
- gegl_node_connect_to (applicator->mode_node, "output",
- affect_node, "aux");
- gegl_node_connect_to (affect_node, "output",
- applicator->dest_node, "input");
+ gegl_node_disconnect (applicator->mode_node, "aux2");
}
- return applicator;
+ applicator->mask_buffer = mask_buffer;
}
void
-gimp_applicator_apply (GimpApplicator *applicator,
- GeglBuffer *src_buffer,
- GeglBuffer *apply_buffer,
- gint apply_buffer_x,
- gint apply_buffer_y,
- gdouble opacity,
- GimpLayerModeEffects paint_mode)
+gimp_applicator_set_mask_offset (GimpApplicator *applicator,
+ gint mask_offset_x,
+ gint mask_offset_y)
{
- gint width = gegl_buffer_get_width (apply_buffer);
- gint height = gegl_buffer_get_height (apply_buffer);
-
- if (applicator->src_buffer != src_buffer)
+ if (applicator->mask_offset_x != mask_offset_x ||
+ applicator->mask_offset_y != mask_offset_y)
{
- applicator->src_buffer = src_buffer;
+ applicator->mask_offset_x = mask_offset_x;
+ applicator->mask_offset_y = mask_offset_y;
- gegl_node_set (applicator->src_node,
- "buffer", src_buffer,
+ gegl_node_set (applicator->mask_offset_node,
+ "x", (gdouble) mask_offset_x,
+ "y", (gdouble) mask_offset_y,
NULL);
}
+}
+
+void
+gimp_applicator_set_apply_buffer (GimpApplicator *applicator,
+ GeglBuffer *apply_buffer)
+{
+ g_return_if_fail (apply_buffer == NULL || GEGL_IS_BUFFER (apply_buffer));
- if (applicator->apply_buffer != apply_buffer)
+ if (apply_buffer == applicator->apply_buffer)
+ return;
+
+ if (apply_buffer)
{
- applicator->apply_buffer = apply_buffer;
+ if (! applicator->apply_src_node)
+ {
+ applicator->apply_src_node =
+ gegl_node_new_child (applicator->node,
+ "operation", "gegl:buffer-source",
+ "buffer", apply_buffer,
+ NULL);
+ }
+ else
+ {
+ gegl_node_set (applicator->apply_src_node,
+ "buffer", apply_buffer,
+ NULL);
+ }
- gegl_node_set (applicator->apply_src_node,
- "buffer", apply_buffer,
- NULL);
+ if (! applicator->apply_buffer)
+ {
+ gegl_node_connect_to (applicator->apply_src_node, "output",
+ applicator->apply_offset_node, "input");
+ }
+ }
+ else if (applicator->apply_buffer)
+ {
+ gegl_node_connect_to (applicator->aux_node, "output",
+ applicator->apply_offset_node, "input");
}
- gegl_node_set (applicator->apply_offset_node,
- "x", (gdouble) apply_buffer_x,
- "y", (gdouble) apply_buffer_y,
- NULL);
+ applicator->apply_buffer = apply_buffer;
+}
+
+void
+gimp_applicator_set_apply_offset (GimpApplicator *applicator,
+ gint apply_offset_x,
+ gint apply_offset_y)
+{
+ if (applicator->apply_offset_x != apply_offset_x ||
+ applicator->apply_offset_y != apply_offset_y)
+ {
+ applicator->apply_offset_x = apply_offset_x;
+ applicator->apply_offset_y = apply_offset_y;
+
+ gegl_node_set (applicator->apply_offset_node,
+ "x", (gdouble) apply_offset_x,
+ "y", (gdouble) apply_offset_y,
+ NULL);
+ }
+}
- if ((applicator->opacity != opacity) ||
- (applicator->paint_mode != paint_mode))
+void
+gimp_applicator_set_mode (GimpApplicator *applicator,
+ gdouble opacity,
+ GimpLayerModeEffects paint_mode)
+{
+ if (applicator->opacity != opacity ||
+ applicator->paint_mode != paint_mode)
{
applicator->opacity = opacity;
applicator->paint_mode = paint_mode;
@@ -251,9 +385,26 @@ gimp_applicator_apply (GimpApplicator *applicator,
gimp_gegl_mode_node_set (applicator->mode_node,
paint_mode, opacity, FALSE);
}
+}
+
+void
+gimp_applicator_set_affect (GimpApplicator *applicator,
+ GimpComponentMask affect)
+{
+ if (applicator->affect != affect)
+ {
+ applicator->affect = affect;
- gegl_node_blit (applicator->dest_node, 1.0,
- GEGL_RECTANGLE (apply_buffer_x, apply_buffer_y,
- width, height),
+ gegl_node_set (applicator->affect_node,
+ "mask", affect,
+ NULL);
+ }
+}
+
+void
+gimp_applicator_blit (GimpApplicator *applicator,
+ const GeglRectangle *rect)
+{
+ gegl_node_blit (applicator->dest_node, 1.0, rect,
NULL, NULL, 0, GEGL_BLIT_DEFAULT);
}
diff --git a/app/gegl/gimpapplicator.h b/app/gegl/gimpapplicator.h
index 7b88609..cf624d9 100644
--- a/app/gegl/gimpapplicator.h
+++ b/app/gegl/gimpapplicator.h
@@ -2,7 +2,7 @@
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* gimpapplicator.h
- * Copyright (C) 2012 Michael Natterer <mitch gimp org>
+ * Copyright (C) 2012-2013 Michael Natterer <mitch gimp org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,18 +37,36 @@ struct _GimpApplicator
GObject parent_instance;
GeglNode *node;
- GeglNode *mode_node;
- GeglNode *src_node;
+ GeglNode *input_node;
+ GeglNode *aux_node;
+ GeglNode *output_node;
+
+ GeglBuffer *apply_buffer;
GeglNode *apply_src_node;
+
+ gint apply_offset_x;
+ gint apply_offset_y;
GeglNode *apply_offset_node;
- GeglNode *dest_node;
- GeglBuffer *src_buffer;
- GeglBuffer *apply_buffer;
- gint apply_buffer_x;
- gint apply_buffer_y;
gdouble opacity;
GimpLayerModeEffects paint_mode;
+ GeglNode *mode_node;
+
+ GimpComponentMask affect;
+ GeglNode *affect_node;
+
+ GeglBuffer *src_buffer;
+ GeglNode *src_node;
+
+ GeglBuffer *dest_buffer;
+ GeglNode *dest_node;
+
+ GeglBuffer *mask_buffer;
+ GeglNode *mask_node;
+
+ gint mask_offset_x;
+ gint mask_offset_y;
+ GeglNode *mask_offset_node;
};
struct _GimpApplicatorClass
@@ -57,20 +75,35 @@ struct _GimpApplicatorClass
};
-GType gimp_applicator_get_type (void) G_GNUC_CONST;
-
-GimpApplicator * gimp_applicator_new (GeglBuffer *dest_buffer,
- GimpComponentMask affect,
- GeglBuffer *mask_buffer,
- gint mask_offset_x,
- gint mask_offset_y);
-void gimp_applicator_apply (GimpApplicator *applicator,
- GeglBuffer *src_buffer,
- GeglBuffer *apply_buffer,
- gint apply_buffer_x,
- gint apply_buffer_y,
- gdouble opacity,
- GimpLayerModeEffects paint_mode);
+GType gimp_applicator_get_type (void) G_GNUC_CONST;
+
+GimpApplicator * gimp_applicator_new (GeglNode *parent);
+
+void gimp_applicator_set_src_buffer (GimpApplicator *applicator,
+ GeglBuffer *dest_buffer);
+void gimp_applicator_set_dest_buffer (GimpApplicator *applicator,
+ GeglBuffer *dest_buffer);
+
+void gimp_applicator_set_mask_buffer (GimpApplicator *applicator,
+ GeglBuffer *mask_buffer);
+void gimp_applicator_set_mask_offset (GimpApplicator *applicator,
+ gint mask_offset_x,
+ gint mask_offset_y);
+
+void gimp_applicator_set_apply_buffer (GimpApplicator *applicator,
+ GeglBuffer *apply_buffer);
+void gimp_applicator_set_apply_offset (GimpApplicator *applicator,
+ gint apply_offset_x,
+ gint apply_offset_y);
+
+void gimp_applicator_set_mode (GimpApplicator *applicator,
+ gdouble opacity,
+ GimpLayerModeEffects paint_mode);
+void gimp_applicator_set_affect (GimpApplicator *applicator,
+ GimpComponentMask affect);
+
+void gimp_applicator_blit (GimpApplicator *applicator,
+ const GeglRectangle *rect);
#endif /* __GIMP_APPLICATOR_H__ */
diff --git a/app/paint/gimppaintcore.c b/app/paint/gimppaintcore.c
index b5d44b5..50ecd9e 100644
--- a/app/paint/gimppaintcore.c
+++ b/app/paint/gimppaintcore.c
@@ -327,8 +327,9 @@ gimp_paint_core_start (GimpPaintCore *core,
const GimpCoords *coords,
GError **error)
{
- GimpImage *image;
- GimpItem *item;
+ GimpImage *image;
+ GimpItem *item;
+ GimpChannel *mask;
g_return_val_if_fail (GIMP_IS_PAINT_CORE (core), FALSE);
g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
@@ -398,29 +399,32 @@ gimp_paint_core_start (GimpPaintCore *core,
core->last_paint.x = -1e6;
core->last_paint.y = -1e6;
- {
- GimpChannel *mask = gimp_image_get_mask (image);
- GeglBuffer *mask_buffer = NULL;
- gint offset_x = 0;
- gint offset_y = 0;
+ mask = gimp_image_get_mask (image);
+
+ /* don't apply the mask to itself and don't apply an empty mask */
+ if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
+ mask = NULL;
- /* don't apply the mask to itself and don't apply an empty mask */
- if (GIMP_DRAWABLE (mask) == drawable || gimp_channel_is_empty (mask))
- mask = NULL;
+ core->applicator = gimp_applicator_new (NULL);
- if (mask)
- {
- mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
+ if (mask)
+ {
+ GeglBuffer *mask_buffer;
+ gint offset_x;
+ gint offset_y;
- gimp_item_get_offset (item, &offset_x, &offset_y);
- }
+ mask_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask));
+ gimp_item_get_offset (item, &offset_x, &offset_y);
- core->applicator =
- gimp_applicator_new (gimp_drawable_get_buffer (drawable),
- gimp_drawable_get_active_mask (drawable),
- mask_buffer,
- -offset_x, -offset_y);
- }
+ gimp_applicator_set_mask_buffer (core->applicator, mask_buffer);
+ gimp_applicator_set_mask_offset (core->applicator,
+ -offset_x, -offset_y);
+ }
+
+ gimp_applicator_set_affect (core->applicator,
+ gimp_drawable_get_active_mask (drawable));
+ gimp_applicator_set_dest_buffer (core->applicator,
+ gimp_drawable_get_buffer (drawable));
/* Freeze the drawable preview so that it isn't constantly updated. */
gimp_viewable_preview_freeze (GIMP_VIEWABLE (drawable));
@@ -740,9 +744,8 @@ gimp_paint_core_paste (GimpPaintCore *core,
GimpLayerModeEffects paint_mode,
GimpPaintApplicationMode mode)
{
- GeglBuffer *base_buffer = NULL;
- gint width = gegl_buffer_get_width (core->paint_buffer);
- gint height = gegl_buffer_get_height (core->paint_buffer);
+ gint width = gegl_buffer_get_width (core->paint_buffer);
+ gint height = gegl_buffer_get_height (core->paint_buffer);
/* If the mode is CONSTANT:
* combine the canvas buf, the paint mask to the canvas buffer
@@ -771,7 +774,8 @@ gimp_paint_core_paste (GimpPaintCore *core,
GEGL_RECTANGLE (0, 0, width, height),
1.0);
- base_buffer = core->undo_buffer;
+ gimp_applicator_set_src_buffer (core->applicator,
+ core->undo_buffer);
}
/* Otherwise:
* combine the canvas buf and the paint mask to the canvas buf
@@ -783,16 +787,24 @@ gimp_paint_core_paste (GimpPaintCore *core,
GEGL_RECTANGLE (0, 0, width, height),
paint_opacity);
- base_buffer = gimp_drawable_get_buffer (drawable);
+ gimp_applicator_set_src_buffer (core->applicator,
+ gimp_drawable_get_buffer (drawable));
}
+ gimp_applicator_set_apply_buffer (core->applicator,
+ core->paint_buffer);
+ gimp_applicator_set_apply_offset (core->applicator,
+ core->paint_buffer_x,
+ core->paint_buffer_y);
+
+ gimp_applicator_set_mode (core->applicator,
+ image_opacity, paint_mode);
+
/* apply the paint area to the image */
- gimp_applicator_apply (core->applicator,
- base_buffer,
- core->paint_buffer,
- core->paint_buffer_x,
- core->paint_buffer_y,
- image_opacity, paint_mode);
+ gimp_applicator_blit (core->applicator,
+ GEGL_RECTANGLE (core->paint_buffer_x,
+ core->paint_buffer_y,
+ width, height));
/* Update the undo extents */
core->x1 = MIN (core->x1, core->paint_buffer_x);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]