Commit 3635cf04 authored by Ell's avatar Ell

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.
parent 1ca1e15d
......@@ -668,24 +668,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,
......
......@@ -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;
GimpLayerCompositeRegion affected_region;
};
......@@ -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,
.affected_region = GIMP_LAYER_COMPOSITE_REGION_SOURCE
},
{ 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,
.affected_region = GIMP_LAYER_COMPOSITE_REGION_DESTINATION
},
{ GIMP_LAYER_MODE_ANTI_ERASE,
......@@ -880,7 +883,8 @@ static const GimpLayerModeInfo layer_mode_infos[] =
GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE,
.context = GIMP_LAYER_MODE_CONTEXT_FADE,
.paint_composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
.composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER
.composite_mode = GIMP_LAYER_COMPOSITE_SRC_OVER,
.affected_region = GIMP_LAYER_COMPOSITE_REGION_SOURCE
}
};
......@@ -1276,12 +1280,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
......@@ -1460,6 +1459,17 @@ gimp_layer_mode_get_format (GimpLayerMode mode,
g_return_val_if_reached (babl_format ("RGBA float"));
}
GimpLayerCompositeRegion
gimp_layer_mode_get_affected_region (GimpLayerMode mode)
{
const GimpLayerModeInfo *info = gimp_layer_mode_info (mode);
if (! info)
return GIMP_LAYER_COMPOSITE_REGION_INTERSECTION;
return info->affected_region;
}
GimpLayerCompositeRegion
gimp_layer_mode_get_included_region (GimpLayerMode mode,
GimpLayerCompositeMode composite_mode)
......
......@@ -62,6 +62,8 @@ const Babl * gimp_layer_mode_get_format (GimpLayer
GimpLayerColorSpace blend_space,
const Babl *preferred_format);
GimpLayerCompositeRegion gimp_layer_mode_get_affected_region (GimpLayerMode mode);
GimpLayerCompositeRegion gimp_layer_mode_get_included_region (GimpLayerMode mode,
GimpLayerCompositeMode composite_mode);
......
......@@ -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 GimpLayerCompositeRegion
gimp_operation_layer_mode_real_get_affected_region (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_affected_region = gimp_operation_layer_mode_real_get_affected_region;
......@@ -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_affected_region (self->layer_mode) &
GIMP_LAYER_COMPOSITE_REGION_SOURCE))
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;
......@@ -403,19 +449,28 @@ gimp_operation_layer_mode_process (GeglOperation *operation,
gegl_buffer_get_extent (GEGL_BUFFER (aux)),
result);
included_region = gimp_layer_mode_get_included_region (point->layer_mode,
point->composite_mode);
if (point->is_last_node)
{
included_region = GIMP_LAYER_COMPOSITE_REGION_SOURCE;
}
else
{
included_region = gimp_layer_mode_get_included_region (point->layer_mode,
point->composite_mode);
}
/* 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) ...
*/
if (has_aux && (included_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE))
{
GimpLayerCompositeRegion affected_region;
affected_region =
gimp_operation_layer_mode_get_affected_region (point);
gimp_layer_mode_get_affected_region (point->layer_mode);
/* ... and the op doesn't otherwise affect 'aux', or changes its
* alpha ...
......@@ -452,7 +507,7 @@ gimp_operation_layer_mode_process (GeglOperation *operation,
GimpLayerCompositeRegion affected_region;
affected_region =
gimp_operation_layer_mode_get_affected_region (point);
gimp_layer_mode_get_affected_region (point->layer_mode);
/* ... and the op doesn't otherwise affect 'input' ... */
if (! (affected_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION))
......@@ -497,6 +552,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 GimpLayerCompositeRegion
gimp_operation_layer_mode_real_get_affected_region (GimpOperationLayerMode *layer_mode)
{
......@@ -548,6 +640,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,
......
......@@ -58,7 +58,8 @@ struct _GimpOperationLayerMode
GimpLayerColorSpace blend_space;
GimpLayerColorSpace composite_space;
GimpLayerCompositeMode composite_mode;
GimpBlendFunc blend_func;
GimpLayerModeFunc func;
gboolean is_last_node;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment