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



commit df026e49b5fb05b63355efa08dc658f2f9bf49bf
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

 .../layer-modes/gimpoperationpointlayermode.h      |  178 ++++++++++++++++++++
 app/operations/layer-modes/gimpoperationscreen.c   |   66 +++-----
 2 files changed, 202 insertions(+), 42 deletions(-)
---
diff --git a/app/operations/layer-modes/gimpoperationpointlayermode.h 
b/app/operations/layer-modes/gimpoperationpointlayermode.h
index af0a6e0..33569de 100644
--- a/app/operations/layer-modes/gimpoperationpointlayermode.h
+++ b/app/operations/layer-modes/gimpoperationpointlayermode.h
@@ -90,4 +90,182 @@ 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_ATOP,
+  GIMP_LAYER_COMPOSITE_OVER,
+  GIMP_LAYER_COMPOSITE_IN
+} GimpLayerComposite;
+
+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));
+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_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_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_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;
+  }
+}
+
+
 #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..b386417 100644
--- a/app/operations/layer-modes/gimpoperationscreen.c
+++ b/app/operations/layer-modes/gimpoperationscreen.c
@@ -65,6 +65,23 @@ gimp_operation_screen_init (GimpOperationScreen *self)
 {
 }
 
+static void blendfun_screen (const float *dest, const float *src, float *out, int samples)
+{
+  while (--samples)
+  {
+    if (src[ALPHA] != 0.0f)
+    {
+      out[RED]   = 1.0f - (1.0f - dest[RED])   * (1.0f - src[RED]);
+      out[GREEN] = 1.0f - (1.0f - dest[GREEN]) * (1.0f - src[GREEN]);
+      out[BLUE]  = 1.0f - (1.0f - dest[BLUE])  * (1.0f - src[BLUE]);
+    }
+    out[ALPHA] = dest[ALPHA];
+    out  += 4;
+    src  += 4;
+    dest += 4;
+  }
+}
+
 static gboolean
 gimp_operation_screen_process (GeglOperation       *operation,
                                void                *in_buf,
@@ -76,7 +93,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 +106,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_ATOP,
+     blendfun_screen
+     );
   return TRUE;
 }
+


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