[gimp] app: move bottom-layer special casing to GimpOperationLayerMode



commit 3635cf04ab69bafb76d7583da804f580f2d5fbf3
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/gimplayer.c                               |   22 +---
 app/operations/layer-modes/gimp-layer-modes.c      |   46 ++++---
 app/operations/layer-modes/gimp-layer-modes.h      |    2 +
 .../layer-modes/gimpoperationlayermode.c           |  162 +++++++++++++++++---
 .../layer-modes/gimpoperationlayermode.h           |    3 +-
 5 files changed, 178 insertions(+), 57 deletions(-)
---
diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c
index d608611..a9b97b9 100644
--- a/app/core/gimplayer.c
+++ b/app/core/gimplayer.c
@@ -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,
diff --git a/app/operations/layer-modes/gimp-layer-modes.c b/app/operations/layer-modes/gimp-layer-modes.c
index e1fd152..efaee4d 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;
+  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
@@ -1461,6 +1460,17 @@ gimp_layer_mode_get_format (GimpLayerMode        mode,
 }
 
 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)
 {
diff --git a/app/operations/layer-modes/gimp-layer-modes.h b/app/operations/layer-modes/gimp-layer-modes.h
index 3661a93..a8463cd 100644
--- a/app/operations/layer-modes/gimp-layer-modes.h
+++ b/app/operations/layer-modes/gimp-layer-modes.h
@@ -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);
 
diff --git a/app/operations/layer-modes/gimpoperationlayermode.c 
b/app/operations/layer-modes/gimpoperationlayermode.c
index 75768a0..513705f 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 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,
diff --git a/app/operations/layer-modes/gimpoperationlayermode.h 
b/app/operations/layer-modes/gimpoperationlayermode.h
index 4544f87..c2b044f 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]