[gimp/wip/passthrough: 10/10] app: move bottom-layer special casing to GimpOperationLayerMode
- From: N/A <ell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/passthrough: 10/10] app: move bottom-layer special casing to GimpOperationLayerMode
- Date: Sat, 22 Apr 2017 23:59:23 +0000 (UTC)
commit 5378493eaba360595a5c13fcf62aa7f47f9162d8
Author: Ell <ell_se yahoo com>
Date: Fri Apr 21 19:42:04 2017 -0400
app: move bottom-layer special casing to GimpOperationLayerMode
GimpFilter's is_last_node field only reflects the item's position
within the parent stack. When a layer is contained in a pass-
through group, it can be the last layer of the group, while not
being the last layer in the graph as a whole (paticularly, if
there are visible layers below the group). In fact, when we have
nested pass-through groups, whether or not a layer is the last
node depends on which group we're considering as the root (since
we exclude the backdrop from the group's projection, resulting in
different graphs for different groups).
Instead of rolling our own graph traversal, just move the relevant
logic to GimpOperationLayerMode, and let GEGL do the work for us.
At processing time, we can tell if we're the last node by checking
if we have any input.
For this to work, GimpOperationLayerMode's process() function needs
to have control over what's going on. Replace the derived op
classes, which override process(), with a call to the layer mode's
function (as per gimp_layer_mode_get_function()) in
GimpOperationLayerMode's process() function. (Well, actually, this
commit keeps the ops around, and just hacks around them in
gimp_layer_mode_get_operation(), because laziness :P)
Keep using the layer's is_last_node property to do the invalidation.
app/core/gimpimage-merge.c | 17 +--
app/core/gimplayer.c | 22 +---
app/operations/layer-modes/gimp-layer-modes.c | 43 ++++---
app/operations/layer-modes/gimp-layer-modes.h | 2 +
.../layer-modes/gimpoperationlayermode.c | 153 +++++++++++++++++---
.../layer-modes/gimpoperationlayermode.h | 3 +-
6 files changed, 170 insertions(+), 70 deletions(-)
---
diff --git a/app/core/gimpimage-merge.c b/app/core/gimpimage-merge.c
index a6f8675..3298d07 100644
--- a/app/core/gimpimage-merge.c
+++ b/app/core/gimpimage-merge.c
@@ -610,25 +610,11 @@ gimp_image_merge_layers (GimpImage *image,
gimp_item_get_offset (GIMP_ITEM (layer), &off_x, &off_y);
- /* MODE_DISSOLVE is special since it is the only mode that does not
- * work on the projection with the lower layer, but only locally on
- * the layers alpha channel.
- */
mode = gimp_layer_get_mode (layer);
blend_space = gimp_layer_get_blend_space (layer);
composite_space = gimp_layer_get_composite_space (layer);
composite_mode = gimp_layer_get_composite_mode (layer);
- if (layer == bottom_layer)
- {
- if (mode != GIMP_LAYER_MODE_DISSOLVE)
- mode = GIMP_LAYER_MODE_NORMAL_LEGACY;
-
- blend_space = GIMP_LAYER_COLOR_SPACE_AUTO;
- composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
- composite_mode = GIMP_LAYER_COMPOSITE_AUTO;
- }
-
merge_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (merge_layer));
layer_buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
@@ -647,7 +633,8 @@ gimp_image_merge_layers (GimpImage *image,
- (y1 - off_y));
}
- gimp_applicator_set_src_buffer (applicator, merge_buffer);
+ if (layer != bottom_layer)
+ gimp_applicator_set_src_buffer (applicator, merge_buffer);
gimp_applicator_set_dest_buffer (applicator, merge_buffer);
gimp_applicator_set_apply_buffer (applicator, layer_buffer);
diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c
index 8f00663..85ce26c 100644
--- a/app/core/gimplayer.c
+++ b/app/core/gimplayer.c
@@ -596,24 +596,10 @@ gimp_layer_update_mode_node (GimpLayer *layer)
}
else
{
- if (gimp_filter_get_is_last_node (GIMP_FILTER (layer)))
- {
- if (layer->mode != GIMP_LAYER_MODE_DISSOLVE)
- visible_mode = GIMP_LAYER_MODE_NORMAL_LEGACY;
- else
- visible_mode = GIMP_LAYER_MODE_DISSOLVE;
-
- visible_blend_space = GIMP_LAYER_COLOR_SPACE_AUTO;
- visible_composite_space = GIMP_LAYER_COLOR_SPACE_AUTO;
- visible_composite_mode = GIMP_LAYER_COMPOSITE_AUTO;
- }
- else
- {
- visible_mode = layer->mode;
- visible_blend_space = layer->blend_space;
- visible_composite_space = layer->composite_space;
- visible_composite_mode = layer->composite_mode;
- }
+ visible_mode = layer->mode;
+ visible_blend_space = layer->blend_space;
+ visible_composite_space = layer->composite_space;
+ visible_composite_mode = layer->composite_mode;
}
gimp_gegl_mode_node_set_mode (mode_node,
diff --git a/app/operations/layer-modes/gimp-layer-modes.c b/app/operations/layer-modes/gimp-layer-modes.c
index 12a47e3..80e234b 100644
--- a/app/operations/layer-modes/gimp-layer-modes.c
+++ b/app/operations/layer-modes/gimp-layer-modes.c
@@ -60,15 +60,16 @@ typedef struct _GimpLayerModeInfo GimpLayerModeInfo;
struct _GimpLayerModeInfo
{
- GimpLayerMode layer_mode;
- const gchar *op_name;
- GimpLayerModeFunc function;
- GimpLayerModeFlags flags;
- GimpLayerModeContext context;
- GimpLayerCompositeMode paint_composite_mode;
- GimpLayerCompositeMode composite_mode;
- GimpLayerColorSpace composite_space;
- GimpLayerColorSpace blend_space;
+ GimpLayerMode layer_mode;
+ const gchar *op_name;
+ GimpLayerModeFunc function;
+ GimpLayerModeFlags flags;
+ GimpLayerModeContext context;
+ GimpLayerCompositeMode paint_composite_mode;
+ GimpLayerCompositeMode composite_mode;
+ GimpLayerColorSpace composite_space;
+ GimpLayerColorSpace blend_space;
+ GimpLayerModeAffectMask affect_mask;
};
@@ -98,7 +99,8 @@ static const GimpLayerModeInfo layer_mode_infos[] =
GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE,
.context = GIMP_LAYER_MODE_CONTEXT_ALL,
.paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
- .composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER
+ .composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
+ .affect_mask = GIMP_LAYER_MODE_AFFECT_SRC
},
{ GIMP_LAYER_MODE_BEHIND_LEGACY,
@@ -869,7 +871,8 @@ static const GimpLayerModeInfo layer_mode_infos[] =
.context = GIMP_LAYER_MODE_CONTEXT_FADE,
.paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
.composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
- .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR
+ .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR,
+ .affect_mask = GIMP_LAYER_MODE_AFFECT_DST
},
{ GIMP_LAYER_MODE_ANTI_ERASE,
@@ -1276,12 +1279,7 @@ gimp_layer_mode_get_paint_composite_mode (GimpLayerMode mode)
const gchar *
gimp_layer_mode_get_operation (GimpLayerMode mode)
{
- const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
-
- if (! info)
- return "gimp:layer-mode";
-
- return info->op_name;
+ return "gimp:layer-mode";
}
GimpLayerModeFunc
@@ -1295,6 +1293,17 @@ gimp_layer_mode_get_function (GimpLayerMode mode)
return info->function;
}
+GimpLayerModeAffectMask
+gimp_layer_mode_get_affect_mask (GimpLayerMode mode)
+{
+ const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
+
+ if (! info)
+ return GIMP_LAYER_MODE_AFFECT_NONE;
+
+ return info->affect_mask;
+}
+
GimpLayerModeContext
gimp_layer_mode_get_context (GimpLayerMode mode)
{
diff --git a/app/operations/layer-modes/gimp-layer-modes.h b/app/operations/layer-modes/gimp-layer-modes.h
index 9b49fb6..bf8991f 100644
--- a/app/operations/layer-modes/gimp-layer-modes.h
+++ b/app/operations/layer-modes/gimp-layer-modes.h
@@ -43,6 +43,8 @@ const gchar * gimp_layer_mode_get_operation (GimpLayerMode
GimpLayerModeFunc gimp_layer_mode_get_function (GimpLayerMode mode);
+GimpLayerModeAffectMask gimp_layer_mode_get_affect_mask (GimpLayerMode mode);
+
GimpLayerModeContext gimp_layer_mode_get_context (GimpLayerMode mode);
GimpLayerMode * gimp_layer_mode_get_context_array (GimpLayerMode mode,
diff --git a/app/operations/layer-modes/gimpoperationlayermode.c
b/app/operations/layer-modes/gimpoperationlayermode.c
index 7706a76..bedeb6f 100644
--- a/app/operations/layer-modes/gimpoperationlayermode.c
+++ b/app/operations/layer-modes/gimpoperationlayermode.c
@@ -76,14 +76,24 @@ static void gimp_operation_layer_mode_get_property (GObject *
guint property_id,
GValue *value,
GParamSpec *pspec);
-
+
static void gimp_operation_layer_mode_prepare (GeglOperation *operation);
-static gboolean gimp_operation_layer_mode_process (GeglOperation *operation,
+static gboolean
+ gimp_operation_layer_mode_parent_process (GeglOperation *operation,
GeglOperationContext *context,
const gchar *output_prop,
const GeglRectangle *result,
gint level);
+static gboolean gimp_operation_layer_mode_process (GeglOperation *operation,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
static GimpLayerModeAffectMask
gimp_operation_layer_mode_real_get_affect_mask (GimpOperationLayerMode *layer_mode);
@@ -155,6 +165,15 @@ static inline void composite_func_src_atop_sse2 (gfloat *in,
gint samples);
#endif
+static gboolean process_layer_only (GeglOperation *operation,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level);
+
G_DEFINE_TYPE (GimpOperationLayerMode, gimp_operation_layer_mode,
GEGL_TYPE_OPERATION_POINT_COMPOSER3)
@@ -193,8 +212,8 @@ gimp_operation_layer_mode_class_init (GimpOperationLayerModeClass *klass)
object_class->get_property = gimp_operation_layer_mode_get_property;
operation_class->prepare = gimp_operation_layer_mode_prepare;
- operation_class->process = gimp_operation_layer_mode_process;
- point_composer3_class->process = gimp_operation_layer_mode_process_pixels;
+ operation_class->process = gimp_operation_layer_mode_parent_process;
+ point_composer3_class->process = gimp_operation_layer_mode_process;
klass->get_affect_mask = gimp_operation_layer_mode_real_get_affect_mask;
@@ -352,15 +371,42 @@ static void
gimp_operation_layer_mode_prepare (GeglOperation *operation)
{
GimpOperationLayerMode *self = GIMP_OPERATION_LAYER_MODE (operation);
- const Babl *in_format;
+ const GeglRectangle *input_extent;
+ const Babl *preferred_format;
const Babl *format;
- in_format = gegl_operation_get_source_format (operation, "input");
+ self->func = gimp_layer_mode_get_function (self->layer_mode);
+
+ input_extent = gegl_operation_source_get_bounding_box (operation, "input");
+
+ /* if the input pad has data, work as usual. */
+ if (input_extent && ! gegl_rectangle_is_empty (input_extent))
+ {
+ self->is_last_node = FALSE;
+
+ preferred_format = gegl_operation_get_source_format (operation, "input");
+ }
+ /* otherwise, we're the last node (corresponding to the bottom layer).
+ * in this case, we render the layer (as if) using src-over mode.
+ */
+ else
+ {
+ self->is_last_node = TRUE;
+
+ /* if the layer mode doesn't affect the source, use a shortcut
+ * function that only applies the opacity/mask to the layer.
+ */
+ if (! (gimp_layer_mode_get_affect_mask (self->layer_mode) &
+ GIMP_LAYER_MODE_AFFECT_SRC))
+ self->func = process_layer_only;
- format = gimp_layer_mode_get_format (self->layer_mode,
- self->composite_space,
- self->blend_space,
- in_format);
+ preferred_format = gegl_operation_get_source_format (operation, "aux");
+ }
+
+ format = gimp_layer_mode_get_format (self->layer_mode,
+ self->composite_space,
+ self->blend_space,
+ preferred_format);
gegl_operation_set_format (operation, "input", format);
gegl_operation_set_format (operation, "output", format);
@@ -369,11 +415,11 @@ gimp_operation_layer_mode_prepare (GeglOperation *operation)
}
static gboolean
-gimp_operation_layer_mode_process (GeglOperation *operation,
- GeglOperationContext *context,
- const gchar *output_prop,
- const GeglRectangle *result,
- gint level)
+gimp_operation_layer_mode_parent_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
{
GimpOperationLayerMode *point = GIMP_OPERATION_LAYER_MODE (operation);
GObject *input;
@@ -405,14 +451,16 @@ gimp_operation_layer_mode_process (GeglOperation *operation,
/* if there's no 'input' ... */
if (! has_input)
{
- /* ... and there's 'aux', and the composite mode includes it ... */
+ /* ... and there's 'aux', and the composite mode includes it (or we're
+ * the last node, which is equivalent to src-over) ... */
if (has_aux &&
(point->composite_mode == GIMP_LAYER_COMPOSITE_SRC_OVER ||
- point->composite_mode == GIMP_LAYER_COMPOSITE_DST_ATOP))
+ point->composite_mode == GIMP_LAYER_COMPOSITE_DST_ATOP ||
+ point->is_last_node))
{
GimpLayerModeAffectMask affect_mask;
- affect_mask = gimp_operation_layer_mode_get_affect_mask (point);
+ affect_mask = gimp_layer_mode_get_affect_mask (point->layer_mode);
/* ... and the op doesn't otherwise affect 'aux', or changes its
* alpha ...
@@ -449,7 +497,7 @@ gimp_operation_layer_mode_process (GeglOperation *operation,
{
GimpLayerModeAffectMask affect_mask;
- affect_mask = gimp_operation_layer_mode_get_affect_mask (point);
+ affect_mask = gimp_layer_mode_get_affect_mask (point->layer_mode);
/* ... and the op doesn't otherwise affect 'input' ... */
if (! (affect_mask & GIMP_LAYER_MODE_AFFECT_DST))
@@ -494,6 +542,43 @@ gimp_operation_layer_mode_process (GeglOperation *operation,
level);
}
+static gboolean
+gimp_operation_layer_mode_process (GeglOperation *operation,
+ void *in,
+ void *layer,
+ void *mask,
+ void *out,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ GimpOperationLayerMode *point = GIMP_OPERATION_LAYER_MODE (operation);
+
+ /* if we're not the last node, or we're using the opacity/mask shortcut
+ * function, forward directly to the real process function.
+ */
+ if (! point->is_last_node || point->func == process_layer_only)
+ {
+ return point->func (operation, in, layer, mask, out, samples, roi, level);
+ }
+ /* otherwise, switch the composite mode temporarily to src-over, before
+ * handing processing over to the real process function.
+ */
+ else
+ {
+ GimpLayerCompositeMode composite_mode = point->composite_mode;
+ gboolean result;
+
+ point->composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER;
+
+ result = point->func (operation, in, layer, mask, out, samples, roi, level);
+
+ point->composite_mode = composite_mode;
+
+ return result;
+ }
+}
+
static GimpLayerModeAffectMask
gimp_operation_layer_mode_real_get_affect_mask (GimpOperationLayerMode *layer_mode)
{
@@ -545,6 +630,36 @@ gimp_operation_layer_mode_process_pixels (GeglOperation *operation,
return TRUE;
}
+static gboolean
+process_layer_only (GeglOperation *operation,
+ void *in_buf,
+ void *layer_buf,
+ void *mask_buf,
+ void *out_buf,
+ glong samples,
+ const GeglRectangle *roi,
+ gint level)
+{
+ gfloat *out = out_buf;
+ gfloat *layer = layer_buf;
+ gfloat *mask = mask_buf;
+ gfloat opacity = GIMP_OPERATION_LAYER_MODE (operation)->opacity;
+
+ while (samples--)
+ {
+ memcpy (out, layer, 3 * sizeof (gfloat));
+
+ out[ALPHA] = layer[ALPHA] * opacity;
+ if (mask)
+ out[ALPHA] *= *mask++;
+
+ layer += 4;
+ out += 4;
+ }
+
+ return TRUE;
+}
+
/* non-subtractive compositing functions. these functions expect comp[ALPHA]
* to be the same as layer[ALPHA]. when in[ALPHA] or layer[ALPHA] are zero,
diff --git a/app/operations/layer-modes/gimpoperationlayermode.h
b/app/operations/layer-modes/gimpoperationlayermode.h
index c4383ca..29a9d00 100644
--- a/app/operations/layer-modes/gimpoperationlayermode.h
+++ b/app/operations/layer-modes/gimpoperationlayermode.h
@@ -58,7 +58,8 @@ struct _GimpOperationLayerMode
GimpLayerColorSpace blend_space;
GimpLayerColorSpace composite_space;
GimpLayerCompositeMode composite_mode;
- GimpBlendFunc blend_func;
+ GimpLayerModeFunc func;
+ gboolean is_last_node;
};
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]