[gimp/metadata-browser] app: modified gegl blending modes to take mask and opacity inputs



commit 7e4eb4a14f4938822b46094a2821dc1775a12c4d
Author: Ville Sokk <ville sokk gmail com>
Date:   Fri May 18 23:35:00 2012 +0300

    app: modified gegl blending modes to take mask and opacity inputs

 app/core/gimplayer.c                           |    2 +-
 app/gegl/gimp-gegl-nodes.c                     |   15 ---
 app/operations/gimpoperationadditionmode.c     |  110 ++++++++++++++++++-----
 app/operations/gimpoperationantierasemode.c    |   77 +++++++++++++----
 app/operations/gimpoperationbehindmode.c       |  115 +++++++++++++++++++-----
 app/operations/gimpoperationburnmode.c         |   55 ++++++++---
 app/operations/gimpoperationcolorerasemode.c   |    8 +-
 app/operations/gimpoperationcolormode.c        |   65 +++++++++----
 app/operations/gimpoperationdarkenonlymode.c   |   54 ++++++++---
 app/operations/gimpoperationdifferencemode.c   |  108 +++++++++++++++++-----
 app/operations/gimpoperationdissolvemode.c     |  108 ++++++++++++++++-------
 app/operations/gimpoperationdividemode.c       |   55 ++++++++---
 app/operations/gimpoperationdodgemode.c        |   55 ++++++++---
 app/operations/gimpoperationerasemode.c        |   34 +++++--
 app/operations/gimpoperationgrainextractmode.c |   55 ++++++++---
 app/operations/gimpoperationgrainmergemode.c   |   55 ++++++++---
 app/operations/gimpoperationhardlightmode.c    |   67 ++++++++++-----
 app/operations/gimpoperationhuemode.c          |   79 +++++++++++------
 app/operations/gimpoperationlightenonlymode.c  |   54 ++++++++---
 app/operations/gimpoperationmultiplymode.c     |  106 +++++++++++++++++-----
 app/operations/gimpoperationnormalmode.c       |  110 +++++++++++++++++-----
 app/operations/gimpoperationoverlaymode.c      |  106 +++++++++++++++++-----
 app/operations/gimpoperationpointlayermode.c   |   43 ++++++++--
 app/operations/gimpoperationpointlayermode.h   |    5 +-
 app/operations/gimpoperationreplacemode.c      |   94 ++------------------
 app/operations/gimpoperationreplacemode.h      |    7 +-
 app/operations/gimpoperationsaturationmode.c   |   63 +++++++++----
 app/operations/gimpoperationscreenmode.c       |  103 +++++++++++++++++-----
 app/operations/gimpoperationsoftlightmode.c    |   58 +++++++++----
 app/operations/gimpoperationsubtractmode.c     |   56 +++++++++---
 app/operations/gimpoperationvaluemode.c        |   63 +++++++++----
 31 files changed, 1403 insertions(+), 582 deletions(-)
---
diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c
index a40d194..a98c46b 100644
--- a/app/core/gimplayer.c
+++ b/app/core/gimplayer.c
@@ -1942,7 +1942,7 @@ gimp_layer_set_opacity (GimpLayer *layer,
       if (gimp_item_peek_node (GIMP_ITEM (layer)))
         {
           gegl_node_set (gimp_drawable_get_mode_node (GIMP_DRAWABLE (layer)),
-                         "value", layer->opacity,
+                         "opacity", layer->opacity,
                          NULL);
         }
 
diff --git a/app/gegl/gimp-gegl-nodes.c b/app/gegl/gimp-gegl-nodes.c
index 21035f3..11e3d11 100644
--- a/app/gegl/gimp-gegl-nodes.c
+++ b/app/gegl/gimp-gegl-nodes.c
@@ -318,21 +318,6 @@ gimp_gegl_node_set_layer_mode (GeglNode             *node,
 
   switch (mode)
     {
-    case GIMP_COLOR_ERASE_MODE:
-    case GIMP_ANTI_ERASE_MODE:
-      gegl_node_set (node,
-                     "operation",     "gimp:point-layer-mode",
-                     "blend-mode",    mode,
-                     "premultiplied", premultiplied,
-                     NULL);
-      return;
-
-    default:
-      break;
-    }
-
-  switch (mode)
-    {
     case GIMP_NORMAL_MODE:        operation = "gimp:normal-mode"; break;
     case GIMP_DISSOLVE_MODE:      operation = "gimp:dissolve-mode"; break;
     case GIMP_BEHIND_MODE:        operation = "gimp:behind-mode"; break;
diff --git a/app/operations/gimpoperationadditionmode.c b/app/operations/gimpoperationadditionmode.c
index ce606e5..dda4585 100644
--- a/app/operations/gimpoperationadditionmode.c
+++ b/app/operations/gimpoperationadditionmode.c
@@ -33,6 +33,7 @@ static void gimp_operation_addition_mode_prepare     (GeglOperation       *opera
 static gboolean gimp_operation_addition_mode_process (GeglOperation       *operation,
                                                       void                *in_buf,
                                                       void                *aux_buf,
+                                                      void                *aux2_buf,
                                                       void                *out_buf,
                                                       glong                samples,
                                                       const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationAdditionMode, gimp_operation_addition_mode,
 static void
 gimp_operation_addition_mode_class_init (GimpOperationAdditionModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:addition-mode",
@@ -73,6 +74,7 @@ gimp_operation_addition_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -80,35 +82,95 @@ static gboolean
 gimp_operation_addition_mode_process (GeglOperation       *operation,
                                       void                *in_buf,
                                       void                *aux_buf,
+                                      void                *aux2_buf,
                                       void                *out_buf,
                                       glong                samples,
                                       const GeglRectangle *roi,
                                       gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
-
-  while (samples--)
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
+
+  if (mask)
     {
-      gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
-
-      for (b = RED; b < ALPHA; b++)
+      while (samples--)
         {
-          gfloat comp = in[b] + layer[b];
-          comp = CLAMP (comp, 0, 1);
-
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+          gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity * (*mask);
+          gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+          if (comp_alpha && new_alpha)
+            {
+              gfloat ratio = comp_alpha / new_alpha;
+              gint   b;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  gfloat comp = in[b] + layer[b];
+                  comp = CLAMP (comp, 0, 1);
+
+                  out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+                }
+
+              out[ALPHA] = in[ALPHA];
+            }
+          else
+            {
+              gint b;
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          in    += 4;
+          layer += 4;
+          mask  += 1;
+          out   += 4;
+        }
+    }
+  else
+    {
+      while (samples--)
+        {
+          gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+          gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+          if (comp_alpha && new_alpha)
+            {
+              gfloat ratio = comp_alpha / new_alpha;
+              gint   b;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  gfloat comp = in[b] + layer[b];
+                  comp = CLAMP (comp, 0, 1);
+
+                  out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+                }
+
+              out[ALPHA] = in[ALPHA];
+            }
+          else
+            {
+              gint b;
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          out[ALPHA] = in[ALPHA];
+
+          in    += 4;
+          layer += 4;
+          out   += 4;
         }
-
-      out[ALPHA] = in[ALPHA];
-
-      in    += 4;
-      layer += 4;
-      out   += 4;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationantierasemode.c b/app/operations/gimpoperationantierasemode.c
index 4116ef5..3553613 100644
--- a/app/operations/gimpoperationantierasemode.c
+++ b/app/operations/gimpoperationantierasemode.c
@@ -3,6 +3,7 @@
  *
  * gimpoperationantierasemode.c
  * Copyright (C) 2008 Michael Natterer <mitch gimp org>
+ *               2012 Ville Sokk <ville sokk gmail com>
  *
  * 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
@@ -28,9 +29,11 @@
 #include "gimpoperationantierasemode.h"
 
 
+static void     gimp_operation_anti_erase_mode_prepare (GeglOperation       *operation);
 static gboolean gimp_operation_anti_erase_mode_process (GeglOperation       *operation,
                                                         void                *in_buf,
                                                         void                *aux_buf,
+                                                        void                *aux2_buf,
                                                         void                *out_buf,
                                                         glong                samples,
                                                         const GeglRectangle *roi,
@@ -45,17 +48,18 @@ static void
 gimp_operation_anti_erase_mode_class_init (GimpOperationAntiEraseModeClass *klass)
 {
   GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:anti-erase-mode",
                                  "description", "GIMP anti erase mode operation",
                                  NULL);
 
-  point_class->process         = gimp_operation_anti_erase_mode_process;
+  operation_class->prepare = gimp_operation_anti_erase_mode_prepare;
+  point_class->process     = gimp_operation_anti_erase_mode_process;
 }
 
 static void
@@ -63,29 +67,70 @@ gimp_operation_anti_erase_mode_init (GimpOperationAntiEraseMode *self)
 {
 }
 
+static void
+gimp_operation_anti_erase_mode_prepare (GeglOperation *operation)
+{
+  const Babl *format = babl_format ("R'G'B'A float");
+
+  gegl_operation_set_format (operation, "input",  format);
+  gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
+  gegl_operation_set_format (operation, "output", format);
+}
+
 static gboolean
 gimp_operation_anti_erase_mode_process (GeglOperation       *operation,
                                         void                *in_buf,
                                         void                *aux_buf,
+                                        void                *aux2_buf,
                                         void                *out_buf,
                                         glong                samples,
                                         const GeglRectangle *roi,
                                         gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
-
-  while (samples--)
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
+
+  if (mask)
     {
-      out[RED]   = in[RED];
-      out[GREEN] = in[GREEN];
-      out[BLUE]  = in[BLUE];
-      out[ALPHA] = in[ALPHA];
-
-      in    += 4;
-      layer += 4;
-      out   += 4;
+      while (samples--)
+        {
+          gint b;
+
+          for (b = RED; b < ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+
+          out[ALPHA] = in[ALPHA] + (1 - in[ALPHA]) * layer[ALPHA] * opacity * (*mask);
+
+          in    += 4;
+          layer += 4;
+          mask  += 1;
+          out   += 4;
+        }
+    }
+  else
+    {
+      while (samples--)
+        {
+          gint b;
+
+          for (b = RED; b < ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+
+          out[ALPHA] = in[ALPHA] + (1 - in[ALPHA]) * layer[ALPHA] * opacity;
+
+          in    += 4;
+          layer += 4;
+          out   += 4;
+        }
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationbehindmode.c b/app/operations/gimpoperationbehindmode.c
index 9412579..857cc30 100644
--- a/app/operations/gimpoperationbehindmode.c
+++ b/app/operations/gimpoperationbehindmode.c
@@ -32,6 +32,7 @@
 static gboolean gimp_operation_behind_mode_process (GeglOperation       *operation,
                                                     void                *in_buf,
                                                     void                *aux_buf,
+                                                    void                *aux2_buf,
                                                     void                *out_buf,
                                                     glong                samples,
                                                     const GeglRectangle *roi,
@@ -46,10 +47,10 @@ static void
 gimp_operation_behind_mode_class_init (GimpOperationBehindModeClass *klass)
 {
   GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:behind-mode",
@@ -68,47 +69,113 @@ static gboolean
 gimp_operation_behind_mode_process (GeglOperation       *operation,
                                     void                *in_buf,
                                     void                *aux_buf,
+                                    void                *aux2_buf,
                                     void                *out_buf,
                                     glong                samples,
                                     const GeglRectangle *roi,
                                     gint                 level)
 {
-  GimpOperationPointLayerMode *point  = GIMP_OPERATION_POINT_LAYER_MODE (operation);
-  gfloat                      *in    = in_buf;
-  gfloat                      *layer = aux_buf;
-  gfloat                      *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   if (point->premultiplied)
     {
-      while (samples--)
+      if (mask)
         {
-          gint b;
-
-          for (b = RED; b <= ALPHA; b++)
+          while (samples--)
             {
-              out[b] = in[b] + layer[b] * (1 - in[ALPHA]);
+              gint b;
+              gfloat value = opacity * (*mask);
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b] + layer[b] * value * (1 - in[ALPHA]);
+                }
+
+              in    += 4;
+              layer += 4;
+              mask  += 1;
+              out   += 4;
             }
+        }
+      else
+        {
+          while (samples--)
+            {
+              gint b;
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b] + layer[b] * opacity * (1 - in[ALPHA]);
+                }
 
-          in    += 4;
-          layer += 4;
-          out   += 4;
+              in    += 4;
+              layer += 4;
+              out   += 4;
+            }
         }
     }
   else
     {
-      while (samples--)
+      if (mask)
         {
-          gint b;
-
-          out[ALPHA] = in[ALPHA] + (1 - in[ALPHA]) * layer[ALPHA];
-          for (b = RED; b < ALPHA; b++)
+          while (samples--)
             {
-              out[b] = (in[b] * in[ALPHA] + layer[b] * layer[ALPHA] * (1 - in[ALPHA])) / out[ALPHA];
+              gint b;
+              gfloat value = opacity * (*mask);
+
+              out[ALPHA] = in[ALPHA] + (1 - in[ALPHA]) * layer[ALPHA] * value;
+              if (out[ALPHA])
+                {
+                  for (b = RED; b < ALPHA; b++)
+                    {
+                      out[b] = (in[b] * in[ALPHA] + layer[b] * value * layer[ALPHA] * value * (1 - in[ALPHA])) / out[ALPHA];
+                    }
+                }
+              else
+                {
+                  for (b = RED; b <= ALPHA; b++)
+                    {
+                      out[b] = in[b];
+                    }
+                }
+
+              in    += 4;
+              layer += 4;
+              mask  += 1;
+              out   += 4;
+            }
+        }
+      else
+        {
+          while (samples--)
+            {
+              gint b;
+
+              out[ALPHA] = in[ALPHA] + (1 - in[ALPHA]) * layer[ALPHA] * opacity;
+              if (out[ALPHA])
+                {
+                  for (b = RED; b < ALPHA; b++)
+                    {
+                      out[b] = (in[b] * in[ALPHA] + layer[b] * opacity * layer[ALPHA] * opacity * (1 - in[ALPHA])) / out[ALPHA];
+                    }
+                }
+              else
+                {
+                  for (b = RED; b <= ALPHA; b++)
+                    {
+                      out[b] = in[b];
+                    }
+                }
+
+              in    += 4;
+              layer += 4;
+              out   += 4;
             }
-
-          in    += 4;
-          layer += 4;
-          out   += 4;
         }
     }
 
diff --git a/app/operations/gimpoperationburnmode.c b/app/operations/gimpoperationburnmode.c
index 3c8147f..f2ea7fb 100644
--- a/app/operations/gimpoperationburnmode.c
+++ b/app/operations/gimpoperationburnmode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_burn_mode_prepare (GeglOperation       *operation
 static gboolean gimp_operation_burn_mode_process (GeglOperation       *operation,
                                                   void                *in_buf,
                                                   void                *aux_buf,
+                                                  void                *aux2_buf,
                                                   void                *out_buf,
                                                   glong                samples,
                                                   const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationBurnMode, gimp_operation_burn_mode,
 static void
 gimp_operation_burn_mode_class_init (GimpOperationBurnModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:burn-mode",
@@ -73,6 +74,7 @@ gimp_operation_burn_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -80,35 +82,58 @@ static gboolean
 gimp_operation_burn_mode_process (GeglOperation       *operation,
                                   void                *in_buf,
                                   void                *aux_buf,
+                                  void                *aux2_buf,
                                   void                *out_buf,
                                   glong                samples,
                                   const GeglRectangle *roi,
                                   gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
       gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
 
-      for (b = RED; b < ALPHA; b++)
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
+
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+      if (comp_alpha && new_alpha)
         {
-          gfloat comp = (1 - in[b]) / layer[b];
-          comp = CLAMP (1 - comp, 0, 1);
+          ratio      = comp_alpha / new_alpha;
 
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
-        }
+          for (b = RED; b < ALPHA; b++)
+            {
+              gfloat comp = (1 - in[b]) / layer[b];
+              comp = CLAMP (1 - comp, 0, 1);
+
+              out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+            }
 
-      out[ALPHA] = in[ALPHA];
+          out[ALPHA] = in[ALPHA];
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationcolorerasemode.c b/app/operations/gimpoperationcolorerasemode.c
index 4c8cf4c..cce0ce9 100644
--- a/app/operations/gimpoperationcolorerasemode.c
+++ b/app/operations/gimpoperationcolorerasemode.c
@@ -31,6 +31,7 @@
 static gboolean gimp_operation_color_erase_mode_process (GeglOperation       *operation,
                                                          void                *in_buf,
                                                          void                *aux_buf,
+                                                         void                *aux2_buf,
                                                          void                *out_buf,
                                                          glong                samples,
                                                          const GeglRectangle *roi,
@@ -44,11 +45,11 @@ G_DEFINE_TYPE (GimpOperationColorEraseMode, gimp_operation_color_erase_mode,
 static void
 gimp_operation_color_erase_mode_class_init (GimpOperationColorEraseModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:color-erase-mode",
@@ -67,6 +68,7 @@ static gboolean
 gimp_operation_color_erase_mode_process (GeglOperation       *operation,
                                          void                *in_buf,
                                          void                *aux_buf,
+                                         void                *aux2_buf,
                                          void                *out_buf,
                                          glong                samples,
                                          const GeglRectangle *roi,
diff --git a/app/operations/gimpoperationcolormode.c b/app/operations/gimpoperationcolormode.c
index 762753f..caa19f6 100644
--- a/app/operations/gimpoperationcolormode.c
+++ b/app/operations/gimpoperationcolormode.c
@@ -37,6 +37,7 @@ static void     gimp_operation_color_mode_prepare (GeglOperation       *operatio
 static gboolean gimp_operation_color_mode_process (GeglOperation       *operation,
                                                    void                *in_buf,
                                                    void                *aux_buf,
+                                                   void                *aux2_buf,
                                                    void                *out_buf,
                                                    glong                samples,
                                                    const GeglRectangle *roi,
@@ -50,11 +51,11 @@ G_DEFINE_TYPE (GimpOperationColorMode, gimp_operation_color_mode,
 static void
 gimp_operation_color_mode_class_init (GimpOperationColorModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:color-mode",
@@ -77,6 +78,7 @@ gimp_operation_color_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -84,14 +86,18 @@ static gboolean
 gimp_operation_color_mode_process (GeglOperation       *operation,
                                    void                *in_buf,
                                    void                *aux_buf,
+                                   void                *aux2_buf,
                                    void                *out_buf,
                                    glong                samples,
                                    const GeglRectangle *roi,
                                    gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
@@ -99,28 +105,47 @@ gimp_operation_color_mode_process (GeglOperation       *operation,
       GimpHSL layer_hsl, out_hsl;
       GimpRGB layer_rgb  = {layer[0], layer[1], layer[2]};
       GimpRGB out_rgb    = {in[0], in[1], in[2]};
-      gfloat  comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat  new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat  ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
 
-      gimp_rgb_to_hsl (&layer_rgb, &layer_hsl);
-      gimp_rgb_to_hsl (&out_rgb, &out_hsl);
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
 
-      out_hsl.h = layer_hsl.h;
-      out_hsl.s = layer_hsl.s;
-      gimp_hsl_to_rgb (&out_hsl, &out_rgb);
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
 
-      out[0] = out_rgb.r;
-      out[1] = out_rgb.g;
-      out[2] = out_rgb.b;
-      out[3] = in[3];
+      if (comp_alpha && new_alpha)
+        {
+          ratio      = comp_alpha / new_alpha;
 
-      for (b = RED; b < ALPHA; b++)
-        out[b] = out[b] * ratio + in[b] * (1 - ratio) + 0.0001;
+          gimp_rgb_to_hsl (&layer_rgb, &layer_hsl);
+          gimp_rgb_to_hsl (&out_rgb, &out_hsl);
+
+          out_hsl.h = layer_hsl.h;
+          out_hsl.s = layer_hsl.s;
+          gimp_hsl_to_rgb (&out_hsl, &out_rgb);
+
+          out[0] = out_rgb.r;
+          out[1] = out_rgb.g;
+          out[2] = out_rgb.b;
+          out[3] = in[3];
+
+          for (b = RED; b < ALPHA; b++)
+            out[b] = out[b] * ratio + in[b] * (1 - ratio) + 0.0001;
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationdarkenonlymode.c b/app/operations/gimpoperationdarkenonlymode.c
index 5f82bdf..b4a6e74 100644
--- a/app/operations/gimpoperationdarkenonlymode.c
+++ b/app/operations/gimpoperationdarkenonlymode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_darken_only_mode_prepare (GeglOperation       *op
 static gboolean gimp_operation_darken_only_mode_process (GeglOperation       *operation,
                                                          void                *in_buf,
                                                          void                *aux_buf,
+                                                         void                *aux2_buf,
                                                          void                *out_buf,
                                                          glong                samples,
                                                          const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationDarkenOnlyMode, gimp_operation_darken_only_mode,
 static void
 gimp_operation_darken_only_mode_class_init (GimpOperationDarkenOnlyModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:darken-only-mode",
@@ -58,7 +59,6 @@ gimp_operation_darken_only_mode_class_init (GimpOperationDarkenOnlyModeClass *kl
                                  NULL);
 
   operation_class->prepare = gimp_operation_darken_only_mode_prepare;
-
   point_class->process     = gimp_operation_darken_only_mode_process;
 }
 
@@ -74,6 +74,7 @@ gimp_operation_darken_only_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -81,34 +82,57 @@ static gboolean
 gimp_operation_darken_only_mode_process (GeglOperation       *operation,
                                          void                *in_buf,
                                          void                *aux_buf,
+                                         void                *aux2_buf,
                                          void                *out_buf,
                                          glong                samples,
                                          const GeglRectangle *roi,
                                          gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
       gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
+
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
+
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
 
-      for (b = RED; b < ALPHA; b++)
+      if (new_alpha && comp_alpha)
         {
-          gfloat comp = MIN (in[b], layer[b]);
+          ratio = comp_alpha / new_alpha;
 
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
-        }
+          for (b = RED; b < ALPHA; b++)
+            {
+              gfloat comp = MIN (in[b], layer[b]);
 
-      out[ALPHA] = in[ALPHA];
+              out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+            }
+
+          out[ALPHA] = in[ALPHA];
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationdifferencemode.c b/app/operations/gimpoperationdifferencemode.c
index 143188b..dcca241 100644
--- a/app/operations/gimpoperationdifferencemode.c
+++ b/app/operations/gimpoperationdifferencemode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_difference_mode_prepare (GeglOperation       *ope
 static gboolean gimp_operation_difference_mode_process (GeglOperation       *operation,
                                                         void                *in_buf,
                                                         void                *aux_buf,
+                                                        void                *aux2_buf,
                                                         void                *out_buf,
                                                         glong                samples,
                                                         const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationDifferenceMode, gimp_operation_difference_mode,
 static void
 gimp_operation_difference_mode_class_init (GimpOperationDifferenceModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:difference-mode",
@@ -73,6 +74,7 @@ gimp_operation_difference_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -80,35 +82,93 @@ static gboolean
 gimp_operation_difference_mode_process (GeglOperation       *operation,
                                         void                *in_buf,
                                         void                *aux_buf,
+                                        void                *aux2_buf,
                                         void                *out_buf,
                                         glong                samples,
                                         const GeglRectangle *roi,
                                         gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
-
-  while (samples--)
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
+
+  if (mask)
     {
-      gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
-
-      for (b = RED; b < ALPHA; b++)
+      while (samples--)
         {
-          gfloat comp = in[b] - layer[b];
-          comp = (comp < 0) ? -comp : comp;
-
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+          gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity * (*mask);
+          gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+          if (comp_alpha && new_alpha)
+            {
+              gfloat ratio = comp_alpha / new_alpha;
+              gint   b;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  gfloat comp = in[b] - layer[b];
+                  comp = (comp < 0) ? -comp : comp;
+
+                  out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+                }
+
+              out[ALPHA] = in[ALPHA];
+            }
+          else
+            {
+              gint b;
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          in    += 4;
+          layer += 4;
+          mask  += 1;
+          out   += 4;
+        }
+    }
+  else
+    {
+      while (samples--)
+        {
+          gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+          gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+          if (comp_alpha && new_alpha)
+            {
+              gfloat ratio = comp_alpha / new_alpha;
+              gint   b;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  gfloat comp = in[b] - layer[b];
+                  comp = (comp < 0) ? -comp : comp;
+
+                  out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+                }
+
+              out[ALPHA] = in[ALPHA];
+            }
+          else
+            {
+              gint b;
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          in    += 4;
+          layer += 4;
+          out   += 4;
         }
-
-      out[ALPHA] = in[ALPHA];
-
-      in    += 4;
-      layer += 4;
-      out   += 4;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationdissolvemode.c b/app/operations/gimpoperationdissolvemode.c
index f3de692..c906416 100644
--- a/app/operations/gimpoperationdissolvemode.c
+++ b/app/operations/gimpoperationdissolvemode.c
@@ -36,6 +36,7 @@ static void     gimp_operation_dissolve_mode_prepare (GeglOperation       *opera
 static gboolean gimp_operation_dissolve_mode_process (GeglOperation       *operation,
                                                       void                *in_buf,
                                                       void                *aux_buf,
+                                                      void                *aux2_buf,
                                                       void                *out_buf,
                                                       glong                samples,
                                                       const GeglRectangle *result,
@@ -51,13 +52,13 @@ static gint32 random_table[RANDOM_TABLE_SIZE];
 static void
 gimp_operation_dissolve_mode_class_init (GimpOperationDissolveModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_composer_class;
-  GRand                           *gr;
-  gint                             i;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_composer_class;
+  GRand                            *gr;
+  gint                              i;
 
   operation_class      = GEGL_OPERATION_CLASS (klass);
-  point_composer_class = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_composer_class = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:dissolve-mode",
@@ -88,6 +89,7 @@ gimp_operation_dissolve_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -95,45 +97,89 @@ static gboolean
 gimp_operation_dissolve_mode_process (GeglOperation       *operation,
                                       void                *in_buf,
                                       void                *aux_buf,
+                                      void                *aux2_buf,
                                       void                *out_buf,
                                       glong                samples,
                                       const GeglRectangle *result,
                                       gint                 level)
 {
-  gint    x, y;
-  gfloat *in  = in_buf;
-  gfloat *out = out_buf;
-  gfloat *aux = aux_buf;
-
-  for (y = result->y; y < result->y + result->height; y++)
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *out     = out_buf;
+  gfloat                      *aux     = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gint                         x, y;
+
+  if (mask)
     {
-      GRand *gr = g_rand_new_with_seed (random_table[y % RANDOM_TABLE_SIZE]);
+      for (y = result->y; y < result->y + result->height; y++)
+        {
+          GRand *gr = g_rand_new_with_seed (random_table[y % RANDOM_TABLE_SIZE]);
 
-      /* fast forward through the rows pseudo random sequence */
-      for (x = 0; x < result->x; x++)
-        g_rand_int (gr);
+          /* fast forward through the rows pseudo random sequence */
+          for (x = 0; x < result->x; x++)
+            g_rand_int (gr);
 
-      for (x = result->x; x < result->x + result->width; x++)
-        {
-          if (g_rand_int_range (gr, 0, 255) >= aux[3] * 255)
+          for (x = result->x; x < result->x + result->width; x++)
             {
-              out[0] = in[0];
-              out[1] = in[1];
-              out[2] = in[2];
-              out[3] = in[3];
+              gfloat value = opacity * (*mask);
+
+              if (g_rand_int_range (gr, 0, 255) >= aux[3] * value * 255)
+                {
+                  out[0] = in[0];
+                  out[1] = in[1];
+                  out[2] = in[2];
+                  out[3] = in[3];
+                }
+              else
+                {
+                  out[0] = aux[0];
+                  out[1] = aux[1];
+                  out[2] = aux[2];
+                  out[3] = 1.0;
+                }
+
+              in   += 4;
+              out  += 4;
+              aux  += 4;
+              mask += 1;
             }
-          else
+          g_rand_free (gr);
+        }
+    }
+  else
+    {
+      for (y = result->y; y < result->y + result->height; y++)
+        {
+          GRand *gr = g_rand_new_with_seed (random_table[y % RANDOM_TABLE_SIZE]);
+
+          /* fast forward through the rows pseudo random sequence */
+          for (x = 0; x < result->x; x++)
+            g_rand_int (gr);
+
+          for (x = result->x; x < result->x + result->width; x++)
             {
-              out[0] = aux[0];
-              out[1] = aux[1];
-              out[2] = aux[2];
-              out[3] = 1.0;
+              if (g_rand_int_range (gr, 0, 255) >= aux[3] * opacity * 255)
+                {
+                  out[0] = in[0];
+                  out[1] = in[1];
+                  out[2] = in[2];
+                  out[3] = in[3];
+                }
+              else
+                {
+                  out[0] = aux[0];
+                  out[1] = aux[1];
+                  out[2] = aux[2];
+                  out[3] = 1.0;
+                }
+              in   += 4;
+              out  += 4;
+              aux  += 4;
             }
-          in  += 4;
-          out += 4;
-          aux += 4;
+          g_rand_free (gr);
         }
-      g_rand_free (gr);
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationdividemode.c b/app/operations/gimpoperationdividemode.c
index 1d4a27a..7840821 100644
--- a/app/operations/gimpoperationdividemode.c
+++ b/app/operations/gimpoperationdividemode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_divide_mode_prepare (GeglOperation       *operati
 static gboolean gimp_operation_divide_mode_process (GeglOperation       *operation,
                                                     void                *in_buf,
                                                     void                *aux_buf,
+                                                    void                *aux2_buf,
                                                     void                *out_buf,
                                                     glong                samples,
                                                     const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationDivideMode, gimp_operation_divide_mode,
 static void
 gimp_operation_divide_mode_class_init (GimpOperationDivideModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:divide-mode",
@@ -73,6 +74,7 @@ gimp_operation_divide_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -80,35 +82,58 @@ static gboolean
 gimp_operation_divide_mode_process (GeglOperation       *operation,
                                     void                *in_buf,
                                     void                *aux_buf,
+                                    void                *aux2_buf,
                                     void                *out_buf,
                                     glong                samples,
                                     const GeglRectangle *roi,
                                     gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
       gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
 
-      for (b = RED; b < ALPHA; b++)
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
+
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+      if (comp_alpha && new_alpha)
         {
-          gfloat comp = (256 / 255.0 * in[b]) / (1 / 255.0 + layer[b]);
-          comp = MIN (comp, 1);
+          ratio      = comp_alpha / new_alpha;
 
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
-        }
+          for (b = RED; b < ALPHA; b++)
+            {
+              gfloat comp = (256 / 255.0 * in[b]) / (1 / 255.0 + layer[b]);
+              comp = MIN (comp, 1);
+
+              out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+            }
 
-      out[ALPHA] = in[ALPHA];
+          out[ALPHA] = in[ALPHA];
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationdodgemode.c b/app/operations/gimpoperationdodgemode.c
index 8f28928..992532e 100644
--- a/app/operations/gimpoperationdodgemode.c
+++ b/app/operations/gimpoperationdodgemode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_dodge_mode_prepare (GeglOperation       *operatio
 static gboolean gimp_operation_dodge_mode_process (GeglOperation       *operation,
                                                    void                *in_buf,
                                                    void                *aux_buf,
+                                                   void                *aux2_buf,
                                                    void                *out_buf,
                                                    glong                samples,
                                                    const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationDodgeMode, gimp_operation_dodge_mode,
 static void
 gimp_operation_dodge_mode_class_init (GimpOperationDodgeModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:dodge-mode",
@@ -73,6 +74,7 @@ gimp_operation_dodge_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -80,35 +82,58 @@ static gboolean
 gimp_operation_dodge_mode_process (GeglOperation       *operation,
                                    void                *in_buf,
                                    void                *aux_buf,
+                                   void                *aux2_buf,
                                    void                *out_buf,
                                    glong                samples,
                                    const GeglRectangle *roi,
                                    gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
       gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
 
-      for (b = RED; b < ALPHA; b++)
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
+
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+      if (comp_alpha && new_alpha)
         {
-          gfloat comp = in[b] / (1 - layer[b]);
-          comp = MIN (comp, 1);
+          ratio      = comp_alpha / new_alpha;
 
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
-        }
+          for (b = RED; b < ALPHA; b++)
+            {
+              gfloat comp = in[b] / (1 - layer[b]);
+              comp = MIN (comp, 1);
+
+              out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+            }
 
-      out[ALPHA] = in[ALPHA];
+          out[ALPHA] = in[ALPHA];
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationerasemode.c b/app/operations/gimpoperationerasemode.c
index 8ded88b..b027474 100644
--- a/app/operations/gimpoperationerasemode.c
+++ b/app/operations/gimpoperationerasemode.c
@@ -32,6 +32,7 @@
 static gboolean gimp_operation_erase_mode_process (GeglOperation       *operation,
                                                    void                *in_buf,
                                                    void                *aux_buf,
+                                                   void                *aux2_buf,
                                                    void                *out_buf,
                                                    glong                samples,
                                                    const GeglRectangle *roi,
@@ -45,11 +46,11 @@ G_DEFINE_TYPE (GimpOperationEraseMode, gimp_operation_erase_mode,
 static void
 gimp_operation_erase_mode_class_init (GimpOperationEraseModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:erase-mode",
@@ -68,23 +69,29 @@ static gboolean
 gimp_operation_erase_mode_process (GeglOperation       *operation,
                                    void                *in_buf,
                                    void                *aux_buf,
+                                   void                *aux2_buf,
                                    void                *out_buf,
                                    glong                samples,
                                    const GeglRectangle *roi,
                                    gint                 level)
 {
-  GimpOperationPointLayerMode *point = GIMP_OPERATION_POINT_LAYER_MODE (operation);
-  gfloat                      *in    = in_buf;
-  gfloat                      *layer = aux_buf;
-  gfloat                      *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   if (point->premultiplied)
     {
       while (samples--)
         {
           gint b;
+          gfloat value = opacity;
+          if (mask)
+            value *= (*mask);
 
-          out[ALPHA] = in[ALPHA] - in[ALPHA] * layer[ALPHA];
+          out[ALPHA] = in[ALPHA] - in[ALPHA] * layer[ALPHA] * value;
           for (b = RED; b < ALPHA; b++)
             {
               out[b] = in[b] / in[ALPHA] * out[ALPHA];
@@ -93,6 +100,9 @@ gimp_operation_erase_mode_process (GeglOperation       *operation,
           in    += 4;
           layer += 4;
           out   += 4;
+
+          if (mask)
+            mask += 1;
         }
     }
   else
@@ -100,16 +110,22 @@ gimp_operation_erase_mode_process (GeglOperation       *operation,
       while (samples--)
         {
           gint b;
+          gfloat value = opacity;
+          if (mask)
+            value *= (*mask);
 
           for (b = RED; b < ALPHA; b++)
             {
               out[b] = in[b];
             }
-          out[ALPHA] = in[ALPHA] - in[ALPHA] * layer[ALPHA];;
+          out[ALPHA] = in[ALPHA] - in[ALPHA] * layer[ALPHA] * value;
 
           in    += 4;
           layer += 4;
           out   += 4;
+
+          if (mask)
+            mask += 1;
         }
     }
 
diff --git a/app/operations/gimpoperationgrainextractmode.c b/app/operations/gimpoperationgrainextractmode.c
index 3acccae..c30a55f 100644
--- a/app/operations/gimpoperationgrainextractmode.c
+++ b/app/operations/gimpoperationgrainextractmode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_grain_extract_mode_prepare (GeglOperation       *
 static gboolean gimp_operation_grain_extract_mode_process (GeglOperation       *operation,
                                                            void                *in_buf,
                                                            void                *aux_buf,
+                                                           void                *aux2_buf,
                                                            void                *out_buf,
                                                            glong                samples,
                                                            const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationGrainExtractMode, gimp_operation_grain_extract_mode,
 static void
 gimp_operation_grain_extract_mode_class_init (GimpOperationGrainExtractModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:grain-extract-mode",
@@ -73,6 +74,7 @@ gimp_operation_grain_extract_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -81,35 +83,58 @@ static gboolean
 gimp_operation_grain_extract_mode_process (GeglOperation       *operation,
                                            void                *in_buf,
                                            void                *aux_buf,
+                                           void                *aux2_buf,
                                            void                *out_buf,
                                            glong                samples,
                                            const GeglRectangle *roi,
                                            gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
       gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
 
-      for (b = RED; b < ALPHA; b++)
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
+
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+      if (comp_alpha && new_alpha)
         {
-          gfloat comp = in[b] - layer[b] + 0.5;
-          comp = CLAMP (comp, 0, 1);
+          ratio      = comp_alpha / new_alpha;
 
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
-        }
+          for (b = RED; b < ALPHA; b++)
+            {
+              gfloat comp = in[b] - layer[b] + 0.5;
+              comp = CLAMP (comp, 0, 1);
+
+              out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+            }
 
-      out[ALPHA] = in[ALPHA];
+          out[ALPHA] = in[ALPHA];
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationgrainmergemode.c b/app/operations/gimpoperationgrainmergemode.c
index fe9903c..5c707ba 100644
--- a/app/operations/gimpoperationgrainmergemode.c
+++ b/app/operations/gimpoperationgrainmergemode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_grain_merge_mode_prepare (GeglOperation       *op
 static gboolean gimp_operation_grain_merge_mode_process (GeglOperation       *operation,
                                                          void                *in_buf,
                                                          void                *aux_buf,
+                                                         void                *aux2_buf,
                                                          void                *out_buf,
                                                          glong                samples,
                                                          const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationGrainMergeMode, gimp_operation_grain_merge_mode,
 static void
 gimp_operation_grain_merge_mode_class_init (GimpOperationGrainMergeModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:grain-merge-mode",
@@ -73,6 +74,7 @@ gimp_operation_grain_merge_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -81,35 +83,58 @@ static gboolean
 gimp_operation_grain_merge_mode_process (GeglOperation       *operation,
                                          void                *in_buf,
                                          void                *aux_buf,
+                                         void                *aux2_buf,
                                          void                *out_buf,
                                          glong                samples,
                                          const GeglRectangle *roi,
                                          gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
       gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
 
-      for (b = RED; b < ALPHA; b++)
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
+
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+      if (comp_alpha && new_alpha)
         {
-          gfloat comp = in[b] + layer[b] - 0.5;
-          comp = CLAMP (comp, 0, 1);
+          ratio      = comp_alpha / new_alpha;
 
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
-        }
+          for (b = RED; b < ALPHA; b++)
+            {
+              gfloat comp = in[b] + layer[b] - 0.5;
+              comp = CLAMP (comp, 0, 1);
+
+              out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+            }
 
-      out[ALPHA] = in[ALPHA];
+          out[ALPHA] = in[ALPHA];
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationhardlightmode.c b/app/operations/gimpoperationhardlightmode.c
index 2706ea4..b682cb7 100644
--- a/app/operations/gimpoperationhardlightmode.c
+++ b/app/operations/gimpoperationhardlightmode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_hardlight_mode_prepare (GeglOperation       *oper
 static gboolean gimp_operation_hardlight_mode_process (GeglOperation       *operation,
                                                        void                *in_buf,
                                                        void                *aux_buf,
+                                                       void                *aux2_buf,
                                                        void                *out_buf,
                                                        glong                samples,
                                                        const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationHardlightMode, gimp_operation_hardlight_mode,
 static void
 gimp_operation_hardlight_mode_class_init (GimpOperationHardlightModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:hardlight-mode",
@@ -73,6 +74,7 @@ gimp_operation_hardlight_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -80,45 +82,68 @@ static gboolean
 gimp_operation_hardlight_mode_process (GeglOperation       *operation,
                                        void                *in_buf,
                                        void                *aux_buf,
+                                       void                *aux2_buf,
                                        void                *out_buf,
                                        glong                samples,
                                        const GeglRectangle *roi,
                                        gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
       gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
 
-      for (b = RED; b < ALPHA; b++)
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
+
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+      if (comp_alpha && new_alpha)
         {
-          gfloat comp;
+          ratio      = comp_alpha / new_alpha;
 
-          if (layer[b] > 0.5)
+          for (b = RED; b < ALPHA; b++)
             {
-              comp = (1 - in[b]) * (1 - (layer[b] - 0.5) * 2);
-              comp = MIN (1 - comp, 1);
+              gfloat comp;
+
+              if (layer[b] > 0.5)
+                {
+                  comp = (1 - in[b]) * (1 - (layer[b] - 0.5) * 2);
+                  comp = MIN (1 - comp, 1);
+                }
+              else
+                {
+                  comp = in[b] * (layer[b] * 2);
+                  comp = MIN (comp, 1);
+                }
+
+              out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
             }
-          else
+
+          out[ALPHA] = in[ALPHA];
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
             {
-              comp = in[b] * (layer[b] * 2);
-              comp = MIN (comp, 1);
+              out[b] = in[b];
             }
-
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
         }
 
-      out[ALPHA] = in[ALPHA];
-
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationhuemode.c b/app/operations/gimpoperationhuemode.c
index 2483f8f..aaae343 100644
--- a/app/operations/gimpoperationhuemode.c
+++ b/app/operations/gimpoperationhuemode.c
@@ -37,6 +37,7 @@ static void     gimp_operation_hue_mode_prepare (GeglOperation       *operation)
 static gboolean gimp_operation_hue_mode_process (GeglOperation       *operation,
                                                  void                *in_buf,
                                                  void                *aux_buf,
+                                                 void                *aux2_buf,
                                                  void                *out_buf,
                                                  glong                samples,
                                                  const GeglRectangle *roi,
@@ -50,11 +51,11 @@ G_DEFINE_TYPE (GimpOperationHueMode, gimp_operation_hue_mode,
 static void
 gimp_operation_hue_mode_class_init (GimpOperationHueModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:hue-mode",
@@ -77,6 +78,7 @@ gimp_operation_hue_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -84,14 +86,18 @@ static gboolean
 gimp_operation_hue_mode_process (GeglOperation       *operation,
                                  void                *in_buf,
                                  void                *aux_buf,
+                                 void                *aux2_buf,
                                  void                *out_buf,
                                  glong                samples,
                                  const GeglRectangle *roi,
                                  gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
@@ -99,31 +105,50 @@ gimp_operation_hue_mode_process (GeglOperation       *operation,
       GimpHSV layer_hsv, out_hsv;
       GimpRGB layer_rgb  = {layer[0], layer[1], layer[2]};
       GimpRGB out_rgb    = {in[0], in[1], in[2]};
-      gfloat  comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat  new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat  ratio      = comp_alpha / new_alpha;
-
-      gimp_rgb_to_hsv (&layer_rgb, &layer_hsv);
-      gimp_rgb_to_hsv (&out_rgb, &out_hsv);
-
-      /*  Composition should have no effect if saturation is zero.
-       *  otherwise, black would be painted red (see bug #123296).
-       */
-      if (layer_hsv.s)
-        out_hsv.h = layer_hsv.h;
-      gimp_hsv_to_rgb (&out_hsv, &out_rgb);
-
-      out[0] = out_rgb.r;
-      out[1] = out_rgb.g;
-      out[2] = out_rgb.b;
-      out[3] = in[3];
-
-      for (b = RED; b < ALPHA; b++)
-        out[b] = out[b] * ratio + in[b] * (1 - ratio) + 0.0001;
+      gfloat comp_alpha, new_alpha, ratio;
+
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
+
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+      if (comp_alpha && new_alpha)
+        {
+          ratio      = comp_alpha / new_alpha;
+
+          gimp_rgb_to_hsv (&layer_rgb, &layer_hsv);
+          gimp_rgb_to_hsv (&out_rgb, &out_hsv);
+
+          /*  Composition should have no effect if saturation is zero.
+           *  otherwise, black would be painted red (see bug #123296).
+           */
+          if (layer_hsv.s)
+            out_hsv.h = layer_hsv.h;
+          gimp_hsv_to_rgb (&out_hsv, &out_rgb);
+
+          out[0] = out_rgb.r;
+          out[1] = out_rgb.g;
+          out[2] = out_rgb.b;
+          out[3] = in[3];
+
+          for (b = RED; b < ALPHA; b++)
+            out[b] = out[b] * ratio + in[b] * (1 - ratio) + 0.0001;
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationlightenonlymode.c b/app/operations/gimpoperationlightenonlymode.c
index 6cca8a1..9bd7343 100644
--- a/app/operations/gimpoperationlightenonlymode.c
+++ b/app/operations/gimpoperationlightenonlymode.c
@@ -32,6 +32,7 @@ static void     gimp_operation_lighten_only_mode_prepare (GeglOperation       *o
 static gboolean gimp_operation_lighten_only_mode_process (GeglOperation       *operation,
                                                           void                *in_buf,
                                                           void                *aux_buf,
+                                                          void                *aux2_buf,
                                                           void                *out_buf,
                                                           glong                samples,
                                                           const GeglRectangle *roi,
@@ -45,11 +46,11 @@ G_DEFINE_TYPE (GimpOperationLightenOnlyMode, gimp_operation_lighten_only_mode,
 static void
 gimp_operation_lighten_only_mode_class_init (GimpOperationLightenOnlyModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:lighten-only-mode",
@@ -57,7 +58,6 @@ gimp_operation_lighten_only_mode_class_init (GimpOperationLightenOnlyModeClass *
                                  NULL);
 
   operation_class->prepare = gimp_operation_lighten_only_mode_prepare;
-
   point_class->process     = gimp_operation_lighten_only_mode_process;
 }
 
@@ -73,6 +73,7 @@ gimp_operation_lighten_only_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -80,34 +81,57 @@ static gboolean
 gimp_operation_lighten_only_mode_process (GeglOperation       *operation,
                                           void                *in_buf,
                                           void                *aux_buf,
+                                          void                *aux2_buf,
                                           void                *out_buf,
                                           glong                samples,
                                           const GeglRectangle *result,
                                           gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
       gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
+
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
+
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
 
-      for (b = RED; b < ALPHA; b++)
+      if (comp_alpha && new_alpha)
         {
-          gfloat comp = MAX (layer[b], in[b]);
+          ratio = comp_alpha / new_alpha;
 
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
-        }
+          for (b = RED; b < ALPHA; b++)
+            {
+              gfloat comp = MAX (layer[b], in[b]);
 
-      out[ALPHA] = in[ALPHA];
+              out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+            }
+
+          out[ALPHA] = in[ALPHA];
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationmultiplymode.c b/app/operations/gimpoperationmultiplymode.c
index 6fba66e..8d690c9 100644
--- a/app/operations/gimpoperationmultiplymode.c
+++ b/app/operations/gimpoperationmultiplymode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_multiply_mode_prepare (GeglOperation       *opera
 static gboolean gimp_operation_multiply_mode_process (GeglOperation       *operation,
                                                       void                *in_buf,
                                                       void                *aux_buf,
+                                                      void                *aux2_buf,
                                                       void                *out_buf,
                                                       glong                samples,
                                                       const GeglRectangle *roi,
@@ -47,10 +48,10 @@ static void
 gimp_operation_multiply_mode_class_init (GimpOperationMultiplyModeClass *klass)
 {
   GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:multiply-mode",
@@ -73,6 +74,7 @@ gimp_operation_multiply_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -80,35 +82,93 @@ static gboolean
 gimp_operation_multiply_mode_process (GeglOperation       *operation,
                                       void                *in_buf,
                                       void                *aux_buf,
+                                      void                *aux2_buf,
                                       void                *out_buf,
                                       glong                samples,
                                       const GeglRectangle *roi,
                                       gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
-
-  while (samples--)
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
+
+  if (mask)
     {
-      gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
-
-      for (b = RED; b < ALPHA; b++)
+      while (samples--)
         {
-          gfloat comp = layer[b] * in[b];
-          comp = CLAMP (comp, 0, 1);
-
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+          gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity * (*mask);
+          gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+          if (comp_alpha && new_alpha)
+            {
+              gfloat ratio = comp_alpha / new_alpha;
+              gint   b;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  gfloat comp = layer[b] * in[b];
+                  comp = CLAMP (comp, 0, 1);
+
+                  out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+                }
+
+              out[ALPHA] = in[ALPHA];
+            }
+          else
+            {
+              gint b;
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          in    += 4;
+          layer += 4;
+          mask  += 1;
+          out   += 4;
+        }
+    }
+  else
+    {
+      while (samples--)
+        {
+          gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+          gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+          if (comp_alpha && new_alpha)
+            {
+              gfloat ratio = comp_alpha / new_alpha;
+              gint   b;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  gfloat comp = layer[b] * in[b];
+                  comp = CLAMP (comp, 0, 1);
+
+                  out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+                }
+
+              out[ALPHA] = in[ALPHA];
+            }
+          else
+            {
+              gint b;
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          in    += 4;
+          layer += 4;
+          out   += 4;
         }
-
-      out[ALPHA] = in[ALPHA];
-
-      in    += 4;
-      layer += 4;
-      out   += 4;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationnormalmode.c b/app/operations/gimpoperationnormalmode.c
index d503738..5321e7c 100644
--- a/app/operations/gimpoperationnormalmode.c
+++ b/app/operations/gimpoperationnormalmode.c
@@ -36,6 +36,7 @@ static gboolean gimp_operation_normal_parent_process (GeglOperation        *oper
 static gboolean gimp_operation_normal_mode_process   (GeglOperation        *operation,
                                                       void                 *in_buf,
                                                       void                 *aux_buf,
+                                                      void                 *aux2_buf,
                                                       void                 *out_buf,
                                                       glong                 samples,
                                                       const GeglRectangle  *roi,
@@ -51,11 +52,11 @@ G_DEFINE_TYPE (GimpOperationNormalMode, gimp_operation_normal_mode,
 static void
 gimp_operation_normal_mode_class_init (GimpOperationNormalModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:normal-mode",
@@ -124,42 +125,101 @@ static gboolean
 gimp_operation_normal_mode_process (GeglOperation       *operation,
                                     void                *in_buf,
                                     void                *aux_buf,
+                                    void                *aux2_buf,
                                     void                *out_buf,
                                     glong                samples,
                                     const GeglRectangle *roi,
                                     gint                 level)
 {
-  GimpOperationPointLayerMode *point = GIMP_OPERATION_POINT_LAYER_MODE (operation);
-  gfloat                      *in    = in_buf;
-  gfloat                      *aux   = aux_buf;
-  gfloat                      *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                      *in      = in_buf;
+  gfloat                      *aux     = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
+  gdouble                      opacity = point->opacity;
 
   if (point->premultiplied)
     {
-      while (samples--)
+      if (mask)
         {
-          out[0] = aux[0] + in[0] * (1.0f - aux[3]);
-          out[1] = aux[1] + in[1] * (1.0f - aux[3]);
-          out[2] = aux[2] + in[2] * (1.0f - aux[3]);
-          out[3] = aux[3] + in[3] - aux[3] * in[3];
-
-          in  += 4;
-          aux += 4;
-          out += 4;
+          while (samples--)
+            {
+              gfloat value     = opacity * (*mask);
+              gfloat aux_alpha = aux[ALPHA] * value;
+              gint   b;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = aux[b] * value + in[b] * (1.0f - aux_alpha);
+                }
+
+              out[ALPHA] = aux_alpha + in[ALPHA] - aux_alpha * in[ALPHA];
+
+              in   += 4;
+              aux  += 4;
+              mask += 1;
+              out  += 4;
+            }
+        }
+      else
+        {
+          while (samples--)
+            {
+              gfloat aux_alpha = aux[ALPHA] * opacity;
+              gint   b;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = aux[b] * opacity + in[b] * (1.0f - aux_alpha);
+                }
+
+              out[ALPHA] = aux_alpha + in[ALPHA] - aux_alpha * in[ALPHA];
+
+              in   += 4;
+              aux  += 4;
+              out  += 4;
+            }
         }
     }
   else
     {
-      while (samples--)
+      if (mask)
+        {
+          while (samples--)
+            {
+              gfloat value     = opacity * (*mask);
+              gfloat aux_alpha = aux[ALPHA] * value;
+              gint   b;
+
+              out[ALPHA] = aux_alpha + in[ALPHA] - aux_alpha * in[ALPHA];
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = (aux[b] * aux_alpha + in[b] * in[ALPHA] * (1.0 - aux_alpha)) / out[ALPHA];
+                }
+
+              in   += 4;
+              aux  += 4;
+              mask += 1;
+              out  += 4;
+            }
+        }
+      else
         {
-          out[0] = aux[0] * aux[3] + in[0] * in[3] * (1.0 - aux[3]);
-          out[1] = aux[1] * aux[3] + in[1] * in[3] * (1.0 - aux[3]);
-          out[2] = aux[2] * aux[3] + in[2] * in[3] * (1.0 - aux[3]);
-          out[3] = aux[3] + in[3] - aux[3] * in[3];
-
-          in  += 4;
-          aux += 4;
-          out += 4;
+          while (samples--)
+            {
+              gfloat aux_alpha = aux[ALPHA] * opacity;
+              gint   b;
+
+              out[ALPHA] = aux_alpha + in[ALPHA] - aux_alpha * in[ALPHA];
+              for (b = RED; b < ALPHA; b++)
+                {
+                  out[b] = (aux[b] * aux_alpha + in[b] * in[ALPHA] * (1.0 - aux_alpha)) / out[ALPHA];
+                }
+
+              in  += 4;
+              aux += 4;
+              out += 4;
+            }
         }
     }
 
diff --git a/app/operations/gimpoperationoverlaymode.c b/app/operations/gimpoperationoverlaymode.c
index 49f068a..3174a60 100644
--- a/app/operations/gimpoperationoverlaymode.c
+++ b/app/operations/gimpoperationoverlaymode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_overlay_mode_prepare (GeglOperation       *operat
 static gboolean gimp_operation_overlay_mode_process (GeglOperation       *operation,
                                                      void                *in_buf,
                                                      void                *aux_buf,
+                                                     void                *aux2_buf,
                                                      void                *out_buf,
                                                      glong                samples,
                                                      const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationOverlayMode, gimp_operation_overlay_mode,
 static void
 gimp_operation_overlay_mode_class_init (GimpOperationOverlayModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:overlay-mode",
@@ -58,7 +59,6 @@ gimp_operation_overlay_mode_class_init (GimpOperationOverlayModeClass *klass)
                                  NULL);
 
   operation_class->prepare = gimp_operation_overlay_mode_prepare;
-
   point_class->process     = gimp_operation_overlay_mode_process;
 }
 
@@ -74,6 +74,7 @@ gimp_operation_overlay_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -81,34 +82,91 @@ static gboolean
 gimp_operation_overlay_mode_process (GeglOperation       *operation,
                                      void                *in_buf,
                                      void                *aux_buf,
+                                     void                *aux2_buf,
                                      void                *out_buf,
                                      glong                samples,
                                      const GeglRectangle *roi,
                                      gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
-
-  while (samples--)
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
+
+  if (mask)
     {
-      gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
-
-      for (b = RED; b < ALPHA; b++)
+      while (samples--)
         {
-          gfloat comp = in[b] * (in[b] + (2 * layer[b]) * (1 - in[b]));
-
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+          gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity * (*mask);
+          gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+          if (comp_alpha && new_alpha)
+            {
+              gint   b;
+              gfloat ratio = comp_alpha / new_alpha;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  gfloat comp = in[b] * (in[b] + (2 * layer[b]) * (1 - in[b]));
+
+                  out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+                }
+
+              out[ALPHA] = in[ALPHA];
+            }
+          else
+            {
+              gint b;
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          in    += 4;
+          layer += 4;
+          mask  += 1;
+          out   += 4;
+        }
+    }
+  else
+    {
+      while (samples--)
+        {
+          gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+          gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+          if (comp_alpha && new_alpha)
+            {
+              gfloat ratio = comp_alpha / new_alpha;
+              gint   b;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  gfloat comp = in[b] * (in[b] + (2 * layer[b]) * (1 - in[b]));
+
+                  out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+                }
+
+              out[ALPHA] = in[ALPHA];
+            }
+          else
+            {
+              gint b;
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          in    += 4;
+          layer += 4;
+          out   += 4;
         }
-
-      out[ALPHA] = in[ALPHA];
-
-      in    += 4;
-      layer += 4;
-      out   += 4;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationpointlayermode.c b/app/operations/gimpoperationpointlayermode.c
index 3b100c1..09c513a 100644
--- a/app/operations/gimpoperationpointlayermode.c
+++ b/app/operations/gimpoperationpointlayermode.c
@@ -72,7 +72,8 @@ enum
 {
   PROP_0,
   PROP_BLEND_MODE,
-  PROP_PREMULTIPLIED
+  PROP_PREMULTIPLIED,
+  PROP_OPACITY
 };
 
 
@@ -89,6 +90,7 @@ static void     gimp_operation_point_layer_mode_prepare      (GeglOperation
 static gboolean gimp_operation_point_layer_mode_process      (GeglOperation       *operation,
                                                               void                *in_buf,
                                                               void                *aux_buf,
+                                                              void                *aux2_buf,
                                                               void                *out_buf,
                                                               glong                samples,
                                                               const GeglRectangle *roi,
@@ -96,7 +98,7 @@ static gboolean gimp_operation_point_layer_mode_process      (GeglOperation
 
 
 G_DEFINE_TYPE (GimpOperationPointLayerMode, gimp_operation_point_layer_mode,
-               GEGL_TYPE_OPERATION_POINT_COMPOSER)
+               GEGL_TYPE_OPERATION_POINT_COMPOSER3)
 
 
 static guint32 dissolve_lut[DISSOLVE_REPEAT_WIDTH * DISSOLVE_REPEAT_HEIGHT];
@@ -105,11 +107,11 @@ static guint32 dissolve_lut[DISSOLVE_REPEAT_WIDTH * DISSOLVE_REPEAT_HEIGHT];
 static void
 gimp_operation_point_layer_mode_class_init (GimpOperationPointLayerModeClass *klass)
 {
-  GObjectClass                    *object_class    = G_OBJECT_CLASS (klass);
-  GeglOperationClass              *operation_class = GEGL_OPERATION_CLASS (klass);
-  GeglOperationPointComposerClass *point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
-  GRand                           *rand            = g_rand_new_with_seed (DISSOLVE_SEED);
-  int                              i;
+  GObjectClass                     *object_class    = G_OBJECT_CLASS (klass);
+  GeglOperationClass               *operation_class = GEGL_OPERATION_CLASS (klass);
+  GeglOperationPointComposer3Class *point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
+  GRand                            *rand            = g_rand_new_with_seed (DISSOLVE_SEED);
+  int                               i;
 
   object_class->set_property   = gimp_operation_point_layer_mode_set_property;
   object_class->get_property   = gimp_operation_point_layer_mode_get_property;
@@ -138,6 +140,13 @@ gimp_operation_point_layer_mode_class_init (GimpOperationPointLayerModeClass *kl
                                                          GIMP_PARAM_READWRITE |
                                                          G_PARAM_CONSTRUCT));
 
+  g_object_class_install_property (object_class, PROP_OPACITY,
+                                   g_param_spec_double ("opacity",
+                                                        NULL, NULL,
+                                                        0.0, 1.0, 1.0,
+                                                        GIMP_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT));
+
   for (i = 0; i < DISSOLVE_REPEAT_WIDTH * DISSOLVE_REPEAT_HEIGHT; i++)
     dissolve_lut[i] = g_rand_int (rand);
 
@@ -167,6 +176,10 @@ gimp_operation_point_layer_mode_set_property (GObject      *object,
       self->premultiplied = g_value_get_boolean (value);
       break;
 
+    case PROP_OPACITY:
+      self->opacity = g_value_get_double (value);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -191,6 +204,10 @@ gimp_operation_point_layer_mode_get_property (GObject    *object,
       g_value_set_boolean (value, self->premultiplied);
       break;
 
+    case PROP_OPACITY:
+      g_value_set_double (value, self->opacity);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -211,6 +228,7 @@ gimp_operation_point_layer_mode_prepare (GeglOperation *operation)
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "output", format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
 }
 
 static void
@@ -294,6 +312,7 @@ static gboolean
 gimp_operation_point_layer_mode_process (GeglOperation       *operation,
                                          void                *in_buf,
                                          void                *aux_buf,
+                                         void                *aux2_buf,
                                          void                *out_buf,
                                          glong                samples,
                                          const GeglRectangle *roi,
@@ -301,9 +320,11 @@ gimp_operation_point_layer_mode_process (GeglOperation       *operation,
 {
   GimpOperationPointLayerMode *self       = GIMP_OPERATION_POINT_LAYER_MODE (operation);
   GimpLayerModeEffects         blend_mode = self->blend_mode;
+  gdouble                      opacity    = self->opacity;
 
   gfloat *in     = in_buf;     /* composite of layers below */
   gfloat *lay    = aux_buf;    /* layer */
+  gfloat *mask   = aux2_buf;   /* mask */
   gfloat *out    = out_buf;    /* resulting composite */
   glong   sample = samples;
   gint    c      = 0;
@@ -313,6 +334,11 @@ gimp_operation_point_layer_mode_process (GeglOperation       *operation,
 
   while (sample--)
     {
+      if (mask)
+          in[ALPHA] *= (*mask) * opacity;
+      else
+        in[ALPHA] *= opacity;
+
       /* XXX: having such a switch in an innerloop is a horrible idea */
       switch (blend_mode)
         {
@@ -584,6 +610,9 @@ gimp_operation_point_layer_mode_process (GeglOperation       *operation,
       in  += 4;
       lay += 4;
       out += 4;
+
+      if (mask)
+        mask += 4;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationpointlayermode.h b/app/operations/gimpoperationpointlayermode.h
index f077024..a9ccec1 100644
--- a/app/operations/gimpoperationpointlayermode.h
+++ b/app/operations/gimpoperationpointlayermode.h
@@ -34,15 +34,16 @@ typedef struct _GimpOperationPointLayerModeClass GimpOperationPointLayerModeClas
 
 struct _GimpOperationPointLayerModeClass
 {
-  GeglOperationPointComposerClass  parent_class;
+  GeglOperationPointComposer3Class  parent_class;
 };
 
 struct _GimpOperationPointLayerMode
 {
-  GeglOperationPointComposer  parent_instance;
+  GeglOperationPointComposer3  parent_instance;
 
   GimpLayerModeEffects        blend_mode;
   gboolean                    premultiplied;
+  gdouble                     opacity;
 };
 
 
diff --git a/app/operations/gimpoperationreplacemode.c b/app/operations/gimpoperationreplacemode.c
index 30c64c1..6a38896 100644
--- a/app/operations/gimpoperationreplacemode.c
+++ b/app/operations/gimpoperationreplacemode.c
@@ -28,22 +28,6 @@
 #include "gimpoperationreplacemode.h"
 
 
-enum
-{
-  PROP_0,
-  PROP_PREMULTIPLIED,
-  PROP_OPACITY
-};
-
-
-static void     gimp_operation_replace_mode_set_property (GObject             *object,
-                                                          guint                property_id,
-                                                          const GValue        *value,
-                                                          GParamSpec          *pspec);
-static void     gimp_operation_replace_mode_get_property (GObject             *object,
-                                                          guint                property_id,
-                                                          GValue              *value,
-                                                          GParamSpec          *pspec);
 static void     gimp_operation_replace_mode_prepare      (GeglOperation       *operation);
 static gboolean gimp_operation_replace_mode_process      (GeglOperation       *operation,
                                                           void                *in_buf,
@@ -56,23 +40,18 @@ static gboolean gimp_operation_replace_mode_process      (GeglOperation       *o
 
 
 G_DEFINE_TYPE (GimpOperationReplaceMode, gimp_operation_replace_mode,
-               GEGL_TYPE_OPERATION_POINT_COMPOSER3)
+               GIMP_TYPE_OPERATION_POINT_LAYER_MODE)
 
 
 static void
 gimp_operation_replace_mode_class_init (GimpOperationReplaceModeClass *klass)
 {
-  GObjectClass                     *object_class;
   GeglOperationClass               *operation_class;
   GeglOperationPointComposer3Class *point_class;
 
-  object_class    = G_OBJECT_CLASS (klass);
   operation_class = GEGL_OPERATION_CLASS (klass);
   point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
-  object_class->set_property = gimp_operation_replace_mode_set_property;
-  object_class->get_property = gimp_operation_replace_mode_get_property;
-
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:replace-mode",
                                  "description", "GIMP replace mode operation",
@@ -80,21 +59,6 @@ gimp_operation_replace_mode_class_init (GimpOperationReplaceModeClass *klass)
 
   operation_class->prepare = gimp_operation_replace_mode_prepare;
   point_class->process     = gimp_operation_replace_mode_process;
-
-  g_object_class_install_property (object_class, PROP_PREMULTIPLIED,
-                                   g_param_spec_boolean ("premultiplied",
-                                                         NULL, NULL,
-                                                         TRUE,
-                                                         GIMP_PARAM_READWRITE |
-                                                         G_PARAM_CONSTRUCT));
-
-  g_object_class_install_property (object_class, PROP_OPACITY,
-                                   g_param_spec_double ("opacity",
-                                                        NULL, NULL,
-                                                        0.0, 1.0,
-                                                        1.0,
-                                                        GIMP_PARAM_READWRITE |
-                                                        G_PARAM_CONSTRUCT));
 }
 
 static void
@@ -103,50 +67,6 @@ gimp_operation_replace_mode_init (GimpOperationReplaceMode *self)
 }
 
 static void
-gimp_operation_replace_mode_set_property (GObject      *object,
-                                          guint         property_id,
-                                          const GValue *value,
-                                          GParamSpec   *pspec)
-{
-  GimpOperationReplaceMode *self = GIMP_OPERATION_REPLACE_MODE (object);
-
-  switch (property_id)
-    {
-    case PROP_PREMULTIPLIED:
-      self->premultiplied = g_value_get_boolean (value);
-      break;
-    case PROP_OPACITY:
-      self->opacity = g_value_get_double (value);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-    }
-}
-
-static void
-gimp_operation_replace_mode_get_property (GObject      *object,
-                                          guint         property_id,
-                                          GValue       *value,
-                                          GParamSpec   *pspec)
-{
-  GimpOperationReplaceMode *self = GIMP_OPERATION_REPLACE_MODE (object);
-
-  switch (property_id)
-    {
-    case PROP_PREMULTIPLIED:
-      g_value_set_boolean (value, self->premultiplied);
-      break;
-    case PROP_OPACITY:
-      g_value_set_double (value, self->opacity);
-      break;
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
-      break;
-    }
-}
-
-static void
 gimp_operation_replace_mode_prepare (GeglOperation *operation)
 {
   const Babl *format = babl_format ("RGBA float");
@@ -167,12 +87,12 @@ gimp_operation_replace_mode_process (GeglOperation       *operation,
                                      const GeglRectangle *roi,
                                      gint                 level)
 {
-  GimpOperationReplaceMode *self = GIMP_OPERATION_REPLACE_MODE (operation);
-  gfloat opacity                 = self->opacity;
-  gfloat *in                     = in_buf;
-  gfloat *layer                  = aux_buf;
-  gfloat *mask                   = aux2_buf;
-  gfloat *out                    = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
diff --git a/app/operations/gimpoperationreplacemode.h b/app/operations/gimpoperationreplacemode.h
index 3d09c34..46712b4 100644
--- a/app/operations/gimpoperationreplacemode.h
+++ b/app/operations/gimpoperationreplacemode.h
@@ -23,6 +23,9 @@
 #define __GIMP_OPERATION_REPLACE_MODE_H__
 
 
+#include "gimpoperationpointlayermode.h"
+
+
 #define GIMP_TYPE_OPERATION_REPLACE_MODE            (gimp_operation_replace_mode_get_type ())
 #define GIMP_OPERATION_REPLACE_MODE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_REPLACE_MODE, GimpOperationReplaceMode))
 #define GIMP_OPERATION_REPLACE_MODE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  GIMP_TYPE_OPERATION_REPLACE_MODE, GimpOperationReplaceModeClass))
@@ -36,7 +39,7 @@ typedef struct _GimpOperationReplaceModeClass GimpOperationReplaceModeClass;
 
 struct _GimpOperationReplaceMode
 {
-  GeglOperationPointComposer3 parent_instance;
+  GimpOperationPointLayerMode parent_instance;
 
   gdouble  opacity;
   gboolean premultiplied;
@@ -44,7 +47,7 @@ struct _GimpOperationReplaceMode
 
 struct _GimpOperationReplaceModeClass
 {
-  GeglOperationPointComposer3Class parent_class;
+  GimpOperationPointLayerModeClass parent_class;
 };
 
 
diff --git a/app/operations/gimpoperationsaturationmode.c b/app/operations/gimpoperationsaturationmode.c
index 20f142b..f9cdfe6 100644
--- a/app/operations/gimpoperationsaturationmode.c
+++ b/app/operations/gimpoperationsaturationmode.c
@@ -37,6 +37,7 @@ static void     gimp_operation_saturation_mode_prepare (GeglOperation       *ope
 static gboolean gimp_operation_saturation_mode_process (GeglOperation       *operation,
                                                         void                *in_buf,
                                                         void                *aux_buf,
+                                                        void                *aux2_buf,
                                                         void                *out_buf,
                                                         glong                samples,
                                                         const GeglRectangle *roi,
@@ -50,11 +51,11 @@ G_DEFINE_TYPE (GimpOperationSaturationMode, gimp_operation_saturation_mode,
 static void
 gimp_operation_saturation_mode_class_init (GimpOperationSaturationModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:saturation-mode",
@@ -77,6 +78,7 @@ gimp_operation_saturation_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -84,14 +86,18 @@ static gboolean
 gimp_operation_saturation_mode_process (GeglOperation       *operation,
                                         void                *in_buf,
                                         void                *aux_buf,
+                                        void                *aux2_buf,
                                         void                *out_buf,
                                         glong                samples,
                                         const GeglRectangle *roi,
                                         gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
@@ -99,27 +105,46 @@ gimp_operation_saturation_mode_process (GeglOperation       *operation,
       GimpHSV layer_hsv, out_hsv;
       GimpRGB layer_rgb  = {layer[0], layer[1], layer[2]};
       GimpRGB out_rgb    = {in[0], in[1], in[2]};
-      gfloat  comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat  new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat  ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
 
-      gimp_rgb_to_hsv (&layer_rgb, &layer_hsv);
-      gimp_rgb_to_hsv (&out_rgb, &out_hsv);
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
 
-      out_hsv.s = layer_hsv.s;
-      gimp_hsv_to_rgb (&out_hsv, &out_rgb);
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
 
-      out[0] = out_rgb.r;
-      out[1] = out_rgb.g;
-      out[2] = out_rgb.b;
-      out[3] = in[3];
+      if (comp_alpha && new_alpha)
+        {
+          ratio      = comp_alpha / new_alpha;
 
-      for (b = RED; b < ALPHA; b++)
-        out[b] = out[b] * ratio + in[b] * (1 - ratio) + 0.0001;
+          gimp_rgb_to_hsv (&layer_rgb, &layer_hsv);
+          gimp_rgb_to_hsv (&out_rgb, &out_hsv);
+
+          out_hsv.s = layer_hsv.s;
+          gimp_hsv_to_rgb (&out_hsv, &out_rgb);
+
+          out[0] = out_rgb.r;
+          out[1] = out_rgb.g;
+          out[2] = out_rgb.b;
+          out[3] = in[3];
+
+          for (b = RED; b < ALPHA; b++)
+            out[b] = out[b] * ratio + in[b] * (1 - ratio) + 0.0001;
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationscreenmode.c b/app/operations/gimpoperationscreenmode.c
index 975d0d2..5cffcaa 100644
--- a/app/operations/gimpoperationscreenmode.c
+++ b/app/operations/gimpoperationscreenmode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_screen_mode_prepare (GeglOperation       *operati
 static gboolean gimp_operation_screen_mode_process (GeglOperation       *operation,
                                                     void                *in_buf,
                                                     void                *aux_buf,
+                                                    void                *aux2_buf,
                                                     void                *out_buf,
                                                     glong                samples,
                                                     const GeglRectangle *roi,
@@ -47,10 +48,10 @@ static void
 gimp_operation_screen_mode_class_init (GimpOperationScreenModeClass *klass)
 {
   GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:screen-mode",
@@ -73,6 +74,7 @@ gimp_operation_screen_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -80,34 +82,91 @@ static gboolean
 gimp_operation_screen_mode_process (GeglOperation       *operation,
                                     void                *in_buf,
                                     void                *aux_buf,
+                                    void                *aux2_buf,
                                     void                *out_buf,
                                     glong                samples,
                                     const GeglRectangle *roi,
                                     gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
-
-  while (samples--)
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
+
+  if (mask)
     {
-      gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio = comp_alpha / new_alpha;
-
-      for (b = RED; b < ALPHA; b++)
+      while (samples--)
         {
-          gfloat comp = 1 - (1 - in[b]) * (1 - layer[b]);
-
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+          gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity * (*mask);
+          gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+          if (comp_alpha && new_alpha)
+            {
+              gfloat ratio = comp_alpha / new_alpha;
+              gint   b;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  gfloat comp = 1 - (1 - in[b]) * (1 - layer[b]);
+
+                  out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+                }
+
+              out[ALPHA] = in[ALPHA];
+            }
+          else
+            {
+              gint b;
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          in    += 4;
+          layer += 4;
+          mask  += 1;
+          out   += 4;
+        }
+    }
+  else
+    {
+      while (samples--)
+        {
+          gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+          gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+          if (comp_alpha && new_alpha)
+            {
+              gfloat ratio = comp_alpha / new_alpha;
+              gint   b;
+
+              for (b = RED; b < ALPHA; b++)
+                {
+                  gfloat comp = 1 - (1 - in[b]) * (1 - layer[b]);
+
+                  out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+                }
+
+              out[ALPHA] = in[ALPHA];
+            }
+          else
+            {
+              gint b;
+
+              for (b = RED; b <= ALPHA; b++)
+                {
+                  out[b] = in[b];
+                }
+            }
+
+          in    += 4;
+          layer += 4;
+          out   += 4;
         }
-
-      out[ALPHA] = in[ALPHA];
-
-      in    += 4;
-      layer += 4;
-      out   += 4;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationsoftlightmode.c b/app/operations/gimpoperationsoftlightmode.c
index e9c1b82..d4d32bb 100644
--- a/app/operations/gimpoperationsoftlightmode.c
+++ b/app/operations/gimpoperationsoftlightmode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_softlight_mode_prepare (GeglOperation       *oper
 static gboolean gimp_operation_softlight_mode_process (GeglOperation       *operation,
                                                        void                *in_buf,
                                                        void                *aux_buf,
+                                                       void                *aux2_buf,
                                                        void                *out_buf,
                                                        glong                samples,
                                                        const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationSoftlightMode, gimp_operation_softlight_mode,
 static void
 gimp_operation_softlight_mode_class_init (GimpOperationSoftlightModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:softlight-mode",
@@ -58,7 +59,6 @@ gimp_operation_softlight_mode_class_init (GimpOperationSoftlightModeClass *klass
                                  NULL);
 
   operation_class->prepare = gimp_operation_softlight_mode_prepare;
-
   point_class->process     = gimp_operation_softlight_mode_process;
 }
 
@@ -74,6 +74,7 @@ gimp_operation_softlight_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -81,36 +82,59 @@ static gboolean
 gimp_operation_softlight_mode_process (GeglOperation       *operation,
                                        void                *in_buf,
                                        void                *aux_buf,
+                                       void                *aux2_buf,
                                        void                *out_buf,
                                        glong                samples,
                                        const GeglRectangle *roi,
                                        gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
       gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
+
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
+
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
 
-      for (b = RED; b < ALPHA; b++)
+      if (comp_alpha && new_alpha)
         {
-          gfloat multiply = in[b] * layer[b];
-          gfloat screen = 1 - (1 - in[b]) * (1 - layer[b]);
-          gfloat comp = (1 - in[b]) * multiply + in[b] * screen;
+          ratio      = comp_alpha / new_alpha;
 
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
-        }
+          for (b = RED; b < ALPHA; b++)
+            {
+              gfloat multiply = in[b] * layer[b];
+              gfloat screen = 1 - (1 - in[b]) * (1 - layer[b]);
+              gfloat comp = (1 - in[b]) * multiply + in[b] * screen;
 
-      out[ALPHA] = in[ALPHA];
+              out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+            }
+
+          out[ALPHA] = in[ALPHA];
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationsubtractmode.c b/app/operations/gimpoperationsubtractmode.c
index 3c22d08..a1de134 100644
--- a/app/operations/gimpoperationsubtractmode.c
+++ b/app/operations/gimpoperationsubtractmode.c
@@ -33,6 +33,7 @@ static void     gimp_operation_subtract_mode_prepare (GeglOperation       *opera
 static gboolean gimp_operation_subtract_mode_process (GeglOperation       *operation,
                                                       void                *in_buf,
                                                       void                *aux_buf,
+                                                      void                *aux2_buf,
                                                       void                *out_buf,
                                                       glong                samples,
                                                       const GeglRectangle *roi,
@@ -46,11 +47,11 @@ G_DEFINE_TYPE (GimpOperationSubtractMode, gimp_operation_subtract_mode,
 static void
 gimp_operation_subtract_mode_class_init (GimpOperationSubtractModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:subtract-mode",
@@ -73,6 +74,7 @@ gimp_operation_subtract_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -80,35 +82,59 @@ static gboolean
 gimp_operation_subtract_mode_process (GeglOperation       *operation,
                                       void                *in_buf,
                                       void                *aux_buf,
+                                      void                *aux2_buf,
                                       void                *out_buf,
                                       glong                samples,
                                       const GeglRectangle *roi,
                                       gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
       gint b;
-      gfloat comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
 
-      for (b = RED; b < ALPHA; b++)
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+
+      if (mask)
+        comp_alpha *= (*mask);
+
+      new_alpha = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
+
+      if (comp_alpha && new_alpha)
         {
-          gfloat comp = in[b] - layer[b];
-          comp = (comp < 0) ? 0 : comp;
+          ratio = comp_alpha / new_alpha;
 
-          out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
-        }
+          for (b = RED; b < ALPHA; b++)
+            {
+              gfloat comp = in[b] - layer[b];
+              comp = (comp < 0) ? 0 : comp;
 
-      out[ALPHA] = in[ALPHA];
+              out[b] = comp * ratio + in[b] * (1 - ratio) + 0.0001;
+            }
+
+          out[ALPHA] = in[ALPHA];
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;
diff --git a/app/operations/gimpoperationvaluemode.c b/app/operations/gimpoperationvaluemode.c
index e336901..c4eb389 100644
--- a/app/operations/gimpoperationvaluemode.c
+++ b/app/operations/gimpoperationvaluemode.c
@@ -37,6 +37,7 @@ static void     gimp_operation_value_mode_prepare (GeglOperation       *operatio
 static gboolean gimp_operation_value_mode_process (GeglOperation       *operation,
                                                    void                *in_buf,
                                                    void                *aux_buf,
+                                                   void                *aux2_buf,
                                                    void                *out_buf,
                                                    glong                samples,
                                                    const GeglRectangle *roi,
@@ -50,11 +51,11 @@ G_DEFINE_TYPE (GimpOperationValueMode, gimp_operation_value_mode,
 static void
 gimp_operation_value_mode_class_init (GimpOperationValueModeClass *klass)
 {
-  GeglOperationClass              *operation_class;
-  GeglOperationPointComposerClass *point_class;
+  GeglOperationClass               *operation_class;
+  GeglOperationPointComposer3Class *point_class;
 
   operation_class = GEGL_OPERATION_CLASS (klass);
-  point_class     = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
+  point_class     = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
 
   gegl_operation_class_set_keys (operation_class,
                                  "name",        "gimp:value-mode",
@@ -77,6 +78,7 @@ gimp_operation_value_mode_prepare (GeglOperation *operation)
 
   gegl_operation_set_format (operation, "input",  format);
   gegl_operation_set_format (operation, "aux",    format);
+  gegl_operation_set_format (operation, "aux2",   babl_format ("Y float"));
   gegl_operation_set_format (operation, "output", format);
 }
 
@@ -84,14 +86,18 @@ static gboolean
 gimp_operation_value_mode_process (GeglOperation       *operation,
                                    void                *in_buf,
                                    void                *aux_buf,
+                                   void                *aux2_buf,
                                    void                *out_buf,
                                    glong                samples,
                                    const GeglRectangle *roi,
                                    gint                 level)
 {
-  gfloat *in    = in_buf;
-  gfloat *layer = aux_buf;
-  gfloat *out   = out_buf;
+  GimpOperationPointLayerMode *point   = GIMP_OPERATION_POINT_LAYER_MODE (operation);
+  gfloat                       opacity = point->opacity;
+  gfloat                      *in      = in_buf;
+  gfloat                      *layer   = aux_buf;
+  gfloat                      *mask    = aux2_buf;
+  gfloat                      *out     = out_buf;
 
   while (samples--)
     {
@@ -99,27 +105,46 @@ gimp_operation_value_mode_process (GeglOperation       *operation,
       GimpHSV layer_hsv, out_hsv;
       GimpRGB layer_rgb  = {layer[0], layer[1], layer[2]};
       GimpRGB out_rgb    = {in[0], in[1], in[2]};
-      gfloat  comp_alpha = MIN (in[ALPHA], layer[ALPHA]);
-      gfloat  new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
-      gfloat  ratio      = comp_alpha / new_alpha;
+      gfloat comp_alpha, new_alpha, ratio;
 
-      gimp_rgb_to_hsv (&layer_rgb, &layer_hsv);
-      gimp_rgb_to_hsv (&out_rgb, &out_hsv);
+      comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity;
+      if (mask)
+        comp_alpha *= (*mask);
 
-      out_hsv.v = layer_hsv.v;
-      gimp_hsv_to_rgb (&out_hsv, &out_rgb);
+      new_alpha  = in[ALPHA] + (1 - in[ALPHA]) * comp_alpha;
 
-      out[0] = out_rgb.r;
-      out[1] = out_rgb.g;
-      out[2] = out_rgb.b;
-      out[3] = in[3];
+      if (comp_alpha && new_alpha)
+        {
+          ratio      = comp_alpha / new_alpha;
 
-      for (b = RED; b < ALPHA; b++)
-        out[b] = out[b] * ratio + in[b] * (1 - ratio) + 0.0001;
+          gimp_rgb_to_hsv (&layer_rgb, &layer_hsv);
+          gimp_rgb_to_hsv (&out_rgb, &out_hsv);
+
+          out_hsv.v = layer_hsv.v;
+          gimp_hsv_to_rgb (&out_hsv, &out_rgb);
+
+          out[0] = out_rgb.r;
+          out[1] = out_rgb.g;
+          out[2] = out_rgb.b;
+          out[3] = in[3];
+
+          for (b = RED; b < ALPHA; b++)
+            out[b] = out[b] * ratio + in[b] * (1 - ratio) + 0.0001;
+        }
+      else
+        {
+          for (b = RED; b <= ALPHA; b++)
+            {
+              out[b] = in[b];
+            }
+        }
 
       in    += 4;
       layer += 4;
       out   += 4;
+
+      if (mask)
+        mask += 1;
     }
 
   return TRUE;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]