[gimp/pippin/linear-is-the-new-black: 9/9] app: add abstraction for separate blend and composite modes, like LCH mods already do



commit 208b3f0082f2e9ca9a6c5713839945093ca3cfe4
Author: Øyvind Kolås <pippin gimp org>
Date:   Sun Jan 15 21:11:00 2017 +0100

    app: add abstraction for separate blend and composite modes, like LCH mods already do

 app/operations/layer-modes/gimpoperationaddition.c |    1 -
 .../layer-modes/gimpoperationpointlayermode.h      |  410 ++++++++++++++++++++
 app/operations/layer-modes/gimpoperationscreen.c   |   50 +--
 3 files changed, 418 insertions(+), 43 deletions(-)
---
diff --git a/app/operations/layer-modes/gimpoperationaddition.c 
b/app/operations/layer-modes/gimpoperationaddition.c
index df412f9..4b18832 100644
--- a/app/operations/layer-modes/gimpoperationaddition.c
+++ b/app/operations/layer-modes/gimpoperationaddition.c
@@ -76,7 +76,6 @@ gimp_operation_addition_process (GeglOperation       *operation,
                                  gint                 level)
 {
   gfloat opacity  = GIMP_OPERATION_POINT_LAYER_MODE (operation)->opacity;
-
   return gimp_operation_addition_process_pixels (in_buf, aux_buf, aux2_buf, out_buf, opacity, samples, roi, 
level);
 }
 
diff --git a/app/operations/layer-modes/gimpoperationpointlayermode.h 
b/app/operations/layer-modes/gimpoperationpointlayermode.h
index af0a6e0..7ab229f 100644
--- a/app/operations/layer-modes/gimpoperationpointlayermode.h
+++ b/app/operations/layer-modes/gimpoperationpointlayermode.h
@@ -88,6 +88,416 @@ gimp_operation_layer_composite (const gfloat *in,
     }
 }
 
+typedef enum {
+  GIMP_LAYER_BLEND_RGB_LINEAR,
+  GIMP_LAYER_BLEND_RGB_PERCEPTUAL,
+  GIMP_LAYER_BLEND_LAB
+} GimpBlendTRC;
 
+typedef enum {
+  GIMP_LAYER_COMPOSITE_SRC_ATOP,
+  GIMP_LAYER_COMPOSITE_SRC_OVER,
+  GIMP_LAYER_COMPOSITE_SRC_IN,
+  GIMP_LAYER_COMPOSITE_DST_OVER
+} GimpLayerComposite;
+
+static inline void
+gimp_composite_blend (gfloat              *in,
+                      gfloat              *layer,
+                      gfloat              *mask,
+                      gfloat              *out,
+                      gfloat               opacity,
+                      glong                samples,
+                      GimpBlendTRC         blend_trc,
+                      GimpLayerComposite   composite_mode,
+                      void (*blendfun) (const float *dst,
+                                        const float *src,
+                                              float *out,
+                                              int samples))
+{
+  gfloat *blend_in    = in;
+  gfloat *blend_layer = layer;
+
+  if (blend_trc == GIMP_LAYER_BLEND_RGB_LINEAR || blendfun == NULL)
+  {
+    if (blendfun)
+       blendfun (blend_in, blend_layer, out, samples);
+    else
+       memcpy (out, blend_layer, sizeof (gfloat) * 4 * samples);
+  }
+  else if (blend_trc == GIMP_LAYER_BLEND_RGB_PERCEPTUAL)
+  {
+    static const Babl *fish_to_perceptual = NULL;
+    static const Babl *fish_to_linear = NULL;
+    if (!fish_to_perceptual)
+      fish_to_perceptual = babl_fish("RGBA float", "R'G'B'A float");
+    if (!fish_to_linear)
+      fish_to_linear = babl_fish("R'G'B'A float", "RGBA float");
+
+    blend_in    = alloca (sizeof (gfloat) * 4 * samples);
+    babl_process (fish_to_perceptual, in, blend_in, samples);
+    blend_layer = alloca (sizeof (gfloat) * 4 * samples);
+    babl_process (fish_to_perceptual, layer, blend_layer, samples);
+
+    blendfun (blend_in, blend_layer, out, samples);
+
+    babl_process (fish_to_linear, out, out, samples);
+  }
+  else if (blend_trc == GIMP_LAYER_BLEND_LAB)
+  {
+    static const Babl *fish_to_lab = NULL;
+    static const Babl *fish_to_rgb = NULL;
+    if (!fish_to_lab)
+      fish_to_lab = babl_fish("RGBA float", "CIE Lab alpha float");
+    if (!fish_to_rgb)
+      fish_to_rgb = babl_fish("CIE Lab alpha float", "RGBA float");
+
+    blend_in    = alloca (sizeof (gfloat) * 4 * samples);
+    babl_process (fish_to_lab, in, blend_in, samples);
+    blend_layer = alloca (sizeof (gfloat) * 4 * samples);
+    babl_process (fish_to_lab, layer, blend_layer, samples);
+
+    blendfun (blend_in, blend_layer, out, samples);
+
+    babl_process (fish_to_rgb, out, out, samples);
+  }
+
+  switch (composite_mode)
+  {
+    case GIMP_LAYER_COMPOSITE_SRC_ATOP:
+    default:
+      while (samples--)
+        {
+          gfloat comp_alpha = out[ALPHA] * opacity;
+          if (mask)
+            comp_alpha *= *mask;
+
+          if (comp_alpha == 0.0f)
+            {
+              out[RED]   = in[RED];
+              out[GREEN] = in[GREEN];
+              out[BLUE]  = in[BLUE];
+            }
+            else
+            {
+              gint   b;
+              for (b = RED; b < ALPHA; b++)
+                out[b] = out[b] * comp_alpha + in[b] * (1.0 - comp_alpha);
+            }
+
+          out[ALPHA] = in[ALPHA];
+
+          in          += 4;
+          out         += 4;
+
+          if (mask)
+            mask++;
+        }
+      break;
+    case GIMP_LAYER_COMPOSITE_SRC_OVER:
+      while (samples--)
+        {
+          gfloat comp_alpha = out[ALPHA] * opacity;
+          if (mask)
+            comp_alpha *= *mask;
+
+          if (comp_alpha == 0.0f)
+            {
+              out[RED]   = in[RED];
+              out[GREEN] = in[GREEN];
+              out[BLUE]  = in[BLUE];
+            }
+            else
+            {
+              gint   b;
+              for (b = RED; b < ALPHA; b++)
+                out[b] = out[b] * comp_alpha + in[b] * (1.0 - comp_alpha);
+            }
+
+          out[ALPHA] = comp_alpha + in[ALPHA] * (1.0 - comp_alpha);
+
+          in          += 4;
+          out         += 4;
+
+          if (mask)
+            mask++;
+        }
+      break;
+    case GIMP_LAYER_COMPOSITE_DST_OVER:  // XXX: strong need to verify visual results of this mode
+      while (samples--)
+        {
+          gfloat comp_alpha = out[ALPHA] * opacity;
+          if (mask)
+            comp_alpha *= *mask;
+
+          if (comp_alpha == 0.0f)
+            {
+              out[RED]   = in[RED];
+              out[GREEN] = in[GREEN];
+              out[BLUE]  = in[BLUE];
+            }
+            else
+            {
+              gint   b;
+              for (b = RED; b < ALPHA; b++)
+                out[b] = out[b] * (1.0-comp_alpha) + in[b] * (comp_alpha);
+            }
+
+          out[ALPHA] = (1.0-comp_alpha) + in[ALPHA] * (comp_alpha);
+
+          in          += 4;
+          out         += 4;
+
+          if (mask)
+            mask++;
+        }
+      break;
+    case GIMP_LAYER_COMPOSITE_SRC_IN:
+      while (samples--)
+        {
+          gfloat comp_alpha = out[ALPHA] * opacity;
+          if (mask)
+            comp_alpha *= *mask;
+
+          if (comp_alpha == 0.0f)
+            {
+              out[RED]   = in[RED];
+              out[GREEN] = in[GREEN];
+              out[BLUE]  = in[BLUE];
+            }
+          else
+            {
+              gint   b;
+              for (b = RED; b < ALPHA; b++)
+                out[b] = out[b] * comp_alpha + in[b] * (1.0 - comp_alpha);
+            }
+          out[ALPHA] = comp_alpha + in[ALPHA];
+          in          += 4;
+          out         += 4;
+
+          if (mask)
+            mask++;
+        }
+      break;
+  }
+}
+
+
+static inline void
+blendfun_screen (const float *dest,
+                 const float *src,
+                 float       *out,
+                 int          samples)
+{
+  while (--samples)
+  {
+    if (src[ALPHA] != 0.0f)
+    {
+      int c;
+      for (c = 0; c < 3; c++)
+        out[c] = 1.0f - (1.0f - dest[c])   * (1.0f - src[c]);
+    }
+    out[ALPHA] = dest[ALPHA];
+    out  += 4;
+    src  += 4;
+    dest += 4;
+  }
+}
+
+static inline void
+blendfun_addition (const float *dest,
+                   const float *src,
+                   float       *out,
+                   int          samples)
+{
+  while (--samples)
+  {
+    if (src[ALPHA] != 0.0f)
+    {
+      int c;
+      for (c = 0; c < 3; c++)
+        out[c] = dest[c] + src[c];
+    }
+    out[ALPHA] = dest[ALPHA];
+    out  += 4;
+    src  += 4;
+    dest += 4;
+  }
+}
+
+static inline void
+blendfun_subtract (const float *dest,
+                   const float *src,
+                   float       *out,
+                   int          samples)
+{
+  while (--samples)
+  {
+    if (src[ALPHA] != 0.0f)
+    {
+      int c;
+      for (c = 0; c < 3; c++)
+        out[c] = dest[c] - src[c];
+    }
+    out[ALPHA] = dest[ALPHA];
+    out  += 4;
+    src  += 4;
+    dest += 4;
+  }
+}
+
+static inline void
+blendfun_burn (const float *dest,
+               const float *src,
+               float       *out,
+               int          samples)
+{
+  while (--samples)
+  {
+    if (src[ALPHA] != 0.0f)
+    {
+      int c;
+      for (c = 0; c < 3; c++)
+      {
+        gfloat comp = 1.0 - (1.0 - dest[c]) / src[c];
+        /* The CLAMP macro is deliberately inlined and written to map comp ==
+         * NAN (0 / 0) -> 1 */
+        out[c] = comp < 0 ? 0.0 : comp < 1.0 ? comp : 1.0;
+      }
+    }
+    out[ALPHA] = dest[ALPHA];
+    out  += 4;
+    src  += 4;
+    dest += 4;
+  }
+}
+
+static inline void
+blendfun_darken_only (const float *dest,
+                      const float *src,
+                      float       *out,
+                      int          samples)
+{
+  while (--samples)
+  {
+    if (src[ALPHA] != 0.0f)
+    {
+      int c;
+      for (c = 0; c < 3; c++)
+      {
+        out[c] = MIN(dest[c], src[c]);
+      }
+    }
+    out[ALPHA] = dest[ALPHA];
+    out  += 4;
+    src  += 4;
+    dest += 4;
+  }
+}
+
+static inline void
+blendfun_lighten_only (const float *dest,
+                       const float *src,
+                       float       *out,
+                       int          samples)
+{
+  while (--samples)
+  {
+    if (src[ALPHA] != 0.0f)
+    {
+      int c;
+      for (c = 0; c < 3; c++)
+      {
+        out[c] = MAX(dest[c], src[c]);
+      }
+    }
+    out[ALPHA] = dest[ALPHA];
+    out  += 4;
+    src  += 4;
+    dest += 4;
+  }
+}
+
+static inline void
+blendfun_difference (const float *dest,
+                     const float *src,
+                     float       *out,
+                     int          samples)
+{
+  while (--samples)
+  {
+    if (src[ALPHA] != 0.0f)
+    {
+      int c;
+      for (c = 0; c < 3; c++)
+      {
+        out[c] = dest[c] - src[c];
+        if (out[c] < 0)
+          out[c] = -out[c];
+      }
+    }
+    out[ALPHA] = dest[ALPHA];
+    out  += 4;
+    src  += 4;
+    dest += 4;
+  }
+}
+
+
+static inline void
+blendfun_divide (const float *dest,
+                 const float *src,
+                 float       *out,
+                 int          samples)
+{
+  while (--samples)
+  {
+    if (src[ALPHA] != 0.0f)
+    {
+      int c;
+      for (c = 0; c < 3; c++)
+      {
+        gfloat comp = dest[c] / src[c];
+
+        /* make infitinities(or NaN) correspond to a really high number, 
+         * to get more predictable math */ 
+        if (!(comp > -4294967296.0f && comp < 4294967296.0f)) 
+          comp = 4294967296.0f; 
+
+        out[c] = comp;
+      }
+    }
+    out[ALPHA] = dest[ALPHA];
+    out  += 4;
+    src  += 4;
+    dest += 4;
+  }
+}
+
+static inline void
+blendfun_dodge (const float *dest,
+                const float *src,
+                float       *out,
+                int          samples)
+{
+  while (--samples)
+  {
+    if (src[ALPHA] != 0.0f)
+    {
+      int c;
+      for (c = 0; c < 3; c++)
+      {
+        gfloat comp = dest[c] / (1.0 - src[c]);
+        comp = MIN (comp, 1.0);
+
+        out[c] = comp;
+      }
+    }
+    out[ALPHA] = dest[ALPHA];
+    out  += 4;
+    src  += 4;
+    dest += 4;
+  }
+}
 
 #endif /* __GIMP_OPERATION_POINT_LAYER_MODE_H__ */
diff --git a/app/operations/layer-modes/gimpoperationscreen.c 
b/app/operations/layer-modes/gimpoperationscreen.c
index d2622c9..ecad8d6 100644
--- a/app/operations/layer-modes/gimpoperationscreen.c
+++ b/app/operations/layer-modes/gimpoperationscreen.c
@@ -65,6 +65,7 @@ gimp_operation_screen_init (GimpOperationScreen *self)
 {
 }
 
+
 static gboolean
 gimp_operation_screen_process (GeglOperation       *operation,
                                void                *in_buf,
@@ -76,7 +77,6 @@ gimp_operation_screen_process (GeglOperation       *operation,
                                gint                 level)
 {
   gfloat opacity = GIMP_OPERATION_POINT_LAYER_MODE (operation)->opacity;
-
   return gimp_operation_screen_process_pixels (in_buf, aux_buf, aux2_buf, out_buf, opacity, samples, roi, 
level);
 }
 
@@ -90,46 +90,12 @@ gimp_operation_screen_process_pixels (gfloat              *in,
                                       const GeglRectangle *roi,
                                       gint                 level)
 {
-  const gboolean  has_mask = mask != NULL;
-
-  while (samples--)
-    {
-      gfloat comp_alpha;
-
-      comp_alpha = layer[ALPHA] * opacity;
-      if (has_mask)
-        comp_alpha *= *mask;
-
-      if (comp_alpha != 0.0f)
-        {
-          gint   b;
-
-          for (b = RED; b < ALPHA; b++)
-            {
-              gfloat comp = 1.0 - (1.0 - in[b]) * (1.0 - layer[b]);
-
-              out[b] = comp * comp_alpha + in[b] * (1.0 - comp_alpha);
-            }
-        }
-      else
-        {
-          gint b;
-
-          for (b = RED; b < ALPHA; b++)
-            {
-              out[b] = in[b];
-            }
-        }
-
-      out[ALPHA] = in[ALPHA];
-
-      in    += 4;
-      layer += 4;
-      out   += 4;
-
-      if (has_mask)
-        mask++;
-    }
-
+  gimp_composite_blend (
+     in, layer, mask, out, opacity, samples,
+     GIMP_LAYER_BLEND_RGB_LINEAR,
+     GIMP_LAYER_COMPOSITE_SRC_ATOP,
+     blendfun_screen
+     );
   return TRUE;
 }
+


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