[gegl] workshop: complete rewrite of shadows-highlights operation



commit 59cbe20b204c84e13d94c2900b7aa8d1197a193f
Author: Thomas Manni <thomas manni free fr>
Date:   Tue Jun 27 16:47:02 2017 +0200

    workshop: complete rewrite of shadows-highlights operation
    
    A partial port of the darktable shadows-highlights filter.
    Opencl support still in wip state.

 opencl/shadows-highlights-correction.cl            |   81 +++++
 opencl/shadows-highlights-correction.cl.h          |   83 +++++
 .../workshop/shadows-highlights-correction.c       |  358 ++++++++++++--------
 operations/workshop/shadows-highlights.c           |   90 +++---
 4 files changed, 424 insertions(+), 188 deletions(-)
---
diff --git a/opencl/shadows-highlights-correction.cl b/opencl/shadows-highlights-correction.cl
new file mode 100644
index 0000000..88f35f0
--- /dev/null
+++ b/opencl/shadows-highlights-correction.cl
@@ -0,0 +1,81 @@
+float3 overlay(const float3 in_a,
+               const float3 in_b,
+               const float  opacity,
+               const float  transform,
+               const float  ccorrect,
+               const float  low_approximation)
+{
+  /* a contains underlying image; b contains mask */
+
+  const float3 scale = (float3)(100.0f, 128.0f, 128.0f);
+  const float lmin = 0.0f;
+  const float lmax = 1.0f;
+  const float halfmax = 0.5f;
+  const float doublemax = 2.0f;
+
+  float3 a = in_a / scale;
+  float3 b = in_b / scale;
+
+
+  float opacity2 = opacity*opacity;
+
+  while(opacity2 > 0.0f)
+  {
+    float la = a.x;
+    float lb = (b.x - halfmax) * sign(opacity)*sign(lmax - la) + halfmax;
+    float lref = copysign(fabs(la) > low_approximation ? 1.0f/fabs(la) : 1.0f/low_approximation, la);
+    float href = copysign(fabs(1.0f - la) > low_approximation ? 1.0f/fabs(1.0f - la) : 
1.0f/low_approximation, 1.0f - la);
+
+    float chunk = opacity2 > 1.0f ? 1.0f : opacity2;
+    float optrans = chunk * transform;
+    opacity2 -= 1.0f;
+
+    a.x = la * (1.0f - optrans) + (la > halfmax ? lmax - (lmax - doublemax * (la - halfmax)) * (lmax-lb) : 
doublemax * la * lb) * optrans;
+    a.y = a.y * (1.0f - optrans) + (a.y + b.y) * (a.x*lref * ccorrect + (1.0f - a.x)*href * (1.0f - 
ccorrect)) * optrans;
+    a.z = a.z * (1.0f - optrans) + (a.z + b.z) * (a.x*lref * ccorrect + (1.0f - a.x)*href * (1.0f - 
ccorrect)) * optrans;
+  }
+  /* output scaled back pixel */
+  return a * scale;
+}
+
+
+__kernel void shadows_highlights(__global const float4  *in,
+                                 __global const float3  *aux,
+                                 __global       float4  *out,
+                                          const float    shadows,
+                                          const float    highlights,
+                                          const float    compress,
+                                          const float    shadows_ccorrect,
+                                          const float    highlights_ccorrect,
+                                          const float    whitepoint)
+{
+  int gid = get_global_id(0);
+  const float low_approximation = 0.01f;
+
+  float4 io = in[gid];
+  float3 m = (float3)0.0f;
+  float xform;
+
+  if (! aux)
+    {
+      out[gid] = io;
+      return;
+    }
+
+  /* blurred, inverted and desaturaed mask in m */
+  m.x = 100.0f - aux[gid].x;
+
+  /* white point adjustment */
+  io.x = io.x > 0.0f ? io.x/whitepoint : io.x;
+  m.x = m.x > 0.0f ? m.x/whitepoint : m.x;
+
+  /* overlay highlights */
+  xform = clamp(1.0f - 0.01f * m.x/(1.0f-compress), 0.0f, 1.0f);
+  io.xyz = overlay(io.xyz, m, -highlights, xform, 1.0f - highlights_ccorrect, low_approximation);
+
+  /* overlay shadows */
+  xform = clamp(0.01f * m.x/(1.0f-compress) - compress/(1.0f-compress), 0.0f, 1.0f);
+  io.xyz = overlay(io.xyz, m, shadows, xform, shadows_ccorrect, low_approximation);
+
+  out[gid] = io;
+}
\ No newline at end of file
diff --git a/opencl/shadows-highlights-correction.cl.h b/opencl/shadows-highlights-correction.cl.h
new file mode 100644
index 0000000..11cf477
--- /dev/null
+++ b/opencl/shadows-highlights-correction.cl.h
@@ -0,0 +1,83 @@
+static const char* shadows_highlights_correction_cl_source =
+"float3 overlay(const float3 in_a,                                             \n"
+"               const float3 in_b,                                             \n"
+"               const float  opacity,                                          \n"
+"               const float  transform,                                        \n"
+"               const float  ccorrect,                                         \n"
+"               const float  low_approximation)                                \n"
+"{                                                                             \n"
+"  /* a contains underlying image; b contains mask */                          \n"
+"                                                                              \n"
+"  const float3 scale = (float3)(100.0f, 128.0f, 128.0f);                      \n"
+"  const float lmin = 0.0f;                                                    \n"
+"  const float lmax = 1.0f;                                                    \n"
+"  const float halfmax = 0.5f;                                                 \n"
+"  const float doublemax = 2.0f;                                               \n"
+"                                                                              \n"
+"  float3 a = in_a / scale;                                                    \n"
+"  float3 b = in_b / scale;                                                    \n"
+"                                                                              \n"
+"                                                                              \n"
+"  float opacity2 = opacity*opacity;                                           \n"
+"                                                                              \n"
+"  while(opacity2 > 0.0f)                                                      \n"
+"  {                                                                           \n"
+"    float la = a.x;                                                           \n"
+"    float lb = (b.x - halfmax) * sign(opacity)*sign(lmax - la) + halfmax;     \n"
+"    float lref = copysign(fabs(la) > low_approximation ? 1.0f/fabs(la) : 1.0f/low_approximation, la);\n"
+"    float href = copysign(fabs(1.0f - la) > low_approximation ? 1.0f/fabs(1.0f - la) : 
1.0f/low_approximation, 1.0f - la);\n"
+"                                                                              \n"
+"    float chunk = opacity2 > 1.0f ? 1.0f : opacity2;                          \n"
+"    float optrans = chunk * transform;                                        \n"
+"    opacity2 -= 1.0f;                                                         \n"
+"                                                                              \n"
+"    a.x = la * (1.0f - optrans) + (la > halfmax ? lmax - (lmax - doublemax * (la - halfmax)) * (lmax-lb) : 
doublemax * la * lb) * optrans;\n"
+"    a.y = a.y * (1.0f - optrans) + (a.y + b.y) * (a.x*lref * ccorrect + (1.0f - a.x)*href * (1.0f - 
ccorrect)) * optrans;\n"
+"    a.z = a.z * (1.0f - optrans) + (a.z + b.z) * (a.x*lref * ccorrect + (1.0f - a.x)*href * (1.0f - 
ccorrect)) * optrans;\n"
+"  }                                                                           \n"
+"  /* output scaled back pixel */                                              \n"
+"  return a * scale;                                                           \n"
+"}                                                                             \n"
+"                                                                              \n"
+"                                                                              \n"
+"__kernel void shadows_highlights(__global const float4  *in,                  \n"
+"                                 __global const float3  *aux,                 \n"
+"                                 __global       float4  *out,                 \n"
+"                                          const float    shadows,             \n"
+"                                          const float    highlights,          \n"
+"                                          const float    compress,            \n"
+"                                          const float    shadows_ccorrect,    \n"
+"                                          const float    highlights_ccorrect, \n"
+"                                          const float    whitepoint)          \n"
+"{                                                                             \n"
+"  int gid = get_global_id(0);                                                 \n"
+"  const float low_approximation = 0.01f;                                      \n"
+"                                                                              \n"
+"  float4 io = in[gid];                                                        \n"
+"  float3 m = (float3)0.0f;                                                    \n"
+"  float xform;                                                                \n"
+"                                                                              \n"
+"  if (! aux)                                                                  \n"
+"    {                                                                         \n"
+"      out[gid] = io;                                                          \n"
+"      return;                                                                 \n"
+"    }                                                                         \n"
+"                                                                              \n"
+"  /* blurred, inverted and desaturaed mask in m */                            \n"
+"  m.x = 100.0f - aux[gid].x;                                                  \n"
+"                                                                              \n"
+"  /* white point adjustment */                                                \n"
+"  io.x = io.x > 0.0f ? io.x/whitepoint : io.x;                                \n"
+"  m.x = m.x > 0.0f ? m.x/whitepoint : m.x;                                    \n"
+"                                                                              \n"
+"  /* overlay highlights */                                                    \n"
+"  xform = clamp(1.0f - 0.01f * m.x/(1.0f-compress), 0.0f, 1.0f);              \n"
+"  io.xyz = overlay(io.xyz, m, -highlights, xform, 1.0f - highlights_ccorrect, low_approximation);\n"
+"                                                                              \n"
+"  /* overlay shadows */                                                       \n"
+"  xform = clamp(0.01f * m.x/(1.0f-compress) - compress/(1.0f-compress), 0.0f, 1.0f);\n"
+"  io.xyz = overlay(io.xyz, m, shadows, xform, shadows_ccorrect, low_approximation);\n"
+"                                                                              \n"
+"  out[gid] = io;                                                              \n"
+"}                                                                             \n"
+;
diff --git a/operations/workshop/shadows-highlights-correction.c 
b/operations/workshop/shadows-highlights-correction.c
index 0690380..b5295e6 100644
--- a/operations/workshop/shadows-highlights-correction.c
+++ b/operations/workshop/shadows-highlights-correction.c
@@ -1,16 +1,22 @@
 /* This file is an image processing operation for GEGL
- * GEGL is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
  *
- * GEGL is distributed in the hope that it will be useful,
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ * This operation is a port of the Darktable Shadows Highlights filter
+ * copyright (c) 2012--2015 Ulrich Pegelow.
+ *
+ * GEGL port: Thomas Manni <thomas manni free fr>
  *
  */
 
@@ -20,118 +26,82 @@
 
 #ifdef GEGL_PROPERTIES
 
-property_double (s_amount, _("Shadows amount"), 0.2)
-    value_range (0.0, 1.0)
+property_double (shadows, _("Shadows"), 50.0)
+    value_range (-100.0, 100.0)
+
+property_double (highlights, _("Highlights"), -50.0)
+    value_range (-100.0, 100.0)
 
-property_double (s_tonalwidth, _("Shadows tonal width"), 0.1)
-    value_range (0.001, 1.0)
+property_double (whitepoint, _("White point adjustment"), 0.0)
+    value_range (-10.0, 10.0)
 
-property_double (h_amount, _("Highlights amount"), 0.2)
-    value_range (0.0, 1.0)
+property_double (compress, _("Compress"), 50.0)
+    value_range (0.0, 100.0)
 
-property_double (h_tonalwidth, _("Highlights tonal width"), 0.1)
-    value_range (0.001, 1.0)
+property_double (shadows_ccorrect, _("Shadows color adjustment"), 100.0)
+    value_range (0.0, 100.0)
+
+property_double (highlights_ccorrect, _("Highlights color adjustment"), 50.0)
+    value_range (0.0, 100.0)
 
 #else
 
-#define GEGL_OP_POINT_COMPOSER3
+#define GEGL_OP_POINT_COMPOSER
 #define GEGL_OP_NAME     shadows_highlights_correction
 #define GEGL_OP_C_SOURCE shadows-highlights-correction.c
 
 #include "gegl-op.h"
+#include "gegl-debug.h"
 #include <math.h>
 
-#define LUT_SIZE 2048
-
-typedef struct
-{
-  gdouble shadows[LUT_SIZE];
-  gdouble highlights[LUT_SIZE];
-} Luts;
-
-static void
-initialize_luts (GeglProperties *o)
-{
-  gint     i, scale = LUT_SIZE - 1;
-  Luts    *luts = (Luts *) o->user_data;
-  gdouble  s_scaled = o->s_tonalwidth * scale;
-  gdouble  h_scaled = (1.0 - o->h_tonalwidth) * scale;
-
-  for (i = 0; i < LUT_SIZE; i++)
-    {
-      /* shadows */
-      if (i < s_scaled)
-        {
-          luts->shadows[i] = 1.0 - pow((i / s_scaled), 2.0);
-        }
-      else
-        {
-          luts->shadows[i] = 0.0;
-        }
-
-      /* highlights */
-      if (i > h_scaled)
-        {
-          luts->highlights[i] = 1.0 - pow((scale - i) / (scale - h_scaled), 2.0);
-        }
-      else
-        {
-          luts->highlights[i] = 0.0;
-        }
-    }
-}
+#define SIGN(x) (((x) < 0) ? -1.f : 1.f)
 
 static void
 prepare (GeglOperation *operation)
 {
-  GeglProperties *o  = GEGL_PROPERTIES (operation);
-  const Babl *rgba_f = babl_format ("R'G'B'A float");
-  const Babl *y_f  = babl_format ("Y' float");
-
-  if (o->user_data == NULL)
-    o->user_data = g_slice_new0 (Luts);
+  const Babl *laba = babl_format ("CIE Lab alpha float");
+  const Babl *lab  = babl_format ("CIE Lab float");
 
-  initialize_luts (o);
-
-  gegl_operation_set_format (operation, "input",  rgba_f);
-  gegl_operation_set_format (operation, "aux",    y_f);
-  gegl_operation_set_format (operation, "aux2",   y_f);
-  gegl_operation_set_format (operation, "output", rgba_f);
-}
-
-static void
-finalize (GObject *object)
-{
-  GeglProperties *o = GEGL_PROPERTIES (object);
-
-  if (o->user_data)
-    {
-      g_slice_free (Luts, o->user_data);
-      o->user_data = NULL;
-    }
-
-  G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object);
+  gegl_operation_set_format (operation, "input",  laba);
+  gegl_operation_set_format (operation, "aux",    lab);
+  gegl_operation_set_format (operation, "output", laba);
 }
 
 static gboolean
 process (GeglOperation       *operation,
          void                *in_buf,
          void                *aux_buf,
-         void                *aux2_buf,
          void                *out_buf,
          glong                n_pixels,
          const GeglRectangle *roi,
          gint                 level)
 {
   GeglProperties *o = GEGL_PROPERTIES (operation);
-  Luts *luts = (Luts *) o->user_data;
 
   gfloat *src  = in_buf;
   gfloat *dst  = out_buf;
   gfloat *aux  = aux_buf;
-  gfloat *aux2 = aux2_buf;
 
-  if (!aux || !aux2)
+  gfloat shadows    = 2.f * fminf (fmaxf (-1.0, (o->shadows / 100.f)), 1.f);
+  gfloat highlights = 2.f * fminf (fmaxf (-1.0, (o->highlights / 100.f)), 1.f);
+  gfloat whitepoint = fmaxf (1.f - o->whitepoint / 100.f, 0.01f);
+  gfloat compress   = fminf (fmaxf (0, (o->compress / 100.f)), 0.99f);
+
+  gfloat shadows_ccorrect = (fminf (fmaxf (0.0f, (o->shadows_ccorrect / 100.f)), 1.f) - 0.5f)
+                             * SIGN(shadows) + 0.5f;
+
+  gfloat highlights_ccorrect = (fminf (fmaxf (0.0f, (o->highlights_ccorrect / 100.f)), 1.f) - 0.5f)
+                                * SIGN(-highlights) + 0.5f;
+
+  gfloat max[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+  gfloat min[4] = { 0.0f, -1.0f, -1.0f, 0.0f };
+  gfloat lmin = 0.0f;
+  gfloat lmax = max[0] + fabs(min[0]);
+  gfloat halfmax = lmax / 2.0;
+  gfloat doublemax = lmax * 2.0;
+  gfloat low_approximation = 0.01f;
+
+  if (!aux)
     {
       memcpy (out_buf, in_buf, sizeof (gfloat) * 4 * n_pixels);
       return TRUE;
@@ -139,76 +109,172 @@ process (GeglOperation       *operation,
 
   while (n_pixels--)
     {
-      gfloat *src_pix               = src;
-      gfloat  shadows_estimation    = *aux;
-      gfloat  highlights_estimation = *aux2;
-
-      gdouble correction;
-      gdouble lut_value;
-      gint    b;
+      gfloat ta[3];
+      gfloat tb[3];
+      gfloat highlights2;
+      gfloat highlights_xform;
+      gfloat shadows2;
+      gfloat shadows_xform;
 
-      /* shadows correction */
-
-      if (o->s_amount)
-        {
-          lut_value = luts->shadows[(gint) (shadows_estimation * (LUT_SIZE - 1))];
+      ta[0] = src[0] / 100.f;
+      ta[1] = src[1] / 128.f;
+      ta[2] = src[2] / 128.f;
 
-          if (lut_value > 0.0)
-            {
-              correction = o->s_amount * lut_value;
+      tb[0] = (100.f - aux[0]) / 100.f;
+      tb[1] = 0.f;
+      tb[2] = 0.f;
 
-              for (b = 0; b < 3; b++)
-                {
-                  gfloat new_shadow = 1.0 - shadows_estimation;
+      ta[0] = ta[0] > 0.0f ? ta[0] / whitepoint : ta[0];
+      tb[0] = tb[0] > 0.0f ? tb[0] / whitepoint : tb[0];
 
-                  if (src_pix[b] < 0.5)
-                    new_shadow = 2.0 * src_pix[b] * new_shadow;
-                  else
-                    new_shadow = 1.0 - 2.0 * (1.0 - src_pix[b]) * (1.0 - new_shadow);
+      highlights2 = highlights * highlights;
+      highlights_xform = CLAMP(1.0f - tb[0] / (1.0f - compress), 0.0f, 1.0f);
 
-                  src_pix[b] = correction * new_shadow + (1.0 - correction) * src_pix[b];
-                }
-            }
+      while (highlights2 > 0.0f)
+        {
+          gfloat lref, href;
+          gfloat chunk, optrans;
+
+          gfloat la = ta[0];
+          gfloat lb = (tb[0] - halfmax) * SIGN(-highlights) * SIGN(lmax - la) + halfmax;
+          lb = CLAMP(lb, lmin, lmax);
+          lref = copysignf(fabs(la) > low_approximation ? 1.0f / fabs(la) : 1.0f / low_approximation, la);
+          href = copysignf(
+              fabs(1.0f - la) > low_approximation ? 1.0f / fabs(1.0f - la) : 1.0f / low_approximation, 1.0f 
- la);
+
+          chunk = highlights2 > 1.0f ? 1.0f : highlights2;
+          optrans = chunk * highlights_xform;
+          highlights2 -= 1.0f;
+
+          ta[0] = la * (1.0 - optrans)
+                  + (la > halfmax ? lmax - (lmax - doublemax * (la - halfmax)) * (lmax - lb) : doublemax * la
+                                                                                               * lb) * 
optrans;
+
+          ta[1] = ta[1] * (1.0f - optrans)
+                  + (ta[1] + tb[1]) * (ta[0] * lref * (1.0f - highlights_ccorrect)
+                                       + (1.0f - ta[0]) * href * highlights_ccorrect) * optrans;
+
+          ta[2] = ta[2] * (1.0f - optrans)
+                  + (ta[2] + tb[2]) * (ta[0] * lref * (1.0f - highlights_ccorrect)
+                                       + (1.0f - ta[0]) * href * highlights_ccorrect) * optrans;
         }
 
-      /* highlights correction */
+    shadows2 = shadows * shadows;
+    shadows_xform = CLAMP(tb[0] / (1.0f - compress) - compress / (1.0f - compress), 0.0f, 1.0f);
 
-      if (o->h_amount)
-        {
-          lut_value = luts->highlights[(gint) (highlights_estimation * (LUT_SIZE - 1))];
+    while (shadows2 > 0.0f)
+      {
+        gfloat lref, href;
+        gfloat chunk, optrans;
 
-          if (lut_value > 0.0)
-            {
-              correction = o->h_amount * lut_value;
+        gfloat la = ta[0];
+        gfloat lb = (tb[0] - halfmax) * SIGN(shadows) * SIGN(lmax - la) + halfmax;
+        lref = copysignf(fabs(la) > low_approximation ? 1.0f / fabs(la) : 1.0f / low_approximation, la);
+        href = copysignf(
+            fabs(1.0f - la) > low_approximation ? 1.0f / fabs(1.0f - la) : 1.0f / low_approximation, 1.0f - 
la);
 
-              for (b = 0; b < 3; b++)
-                {
-                  gfloat new_highlight = 1.0 - highlights_estimation;
+        chunk = shadows2 > 1.0f ? 1.0f : shadows2;
+        optrans = chunk * shadows_xform;
+        shadows2 -= 1.0f;
 
-                  if (src_pix[b] < 0.5)
-                    new_highlight = 2.0 * src_pix[b] * new_highlight;
-                  else
-                    new_highlight = 1.0 - 2.0 * (1.0 - src_pix[b]) * (1.0 - new_highlight);
+        ta[0] = la * (1.0 - optrans)
+                + (la > halfmax ? lmax - (lmax - doublemax * (la - halfmax)) * (lmax - lb) : doublemax * la
+                                                                                             * lb) * optrans;
 
-                  src_pix[b] = correction * new_highlight + (1.0 - correction) * src_pix[b];
-                }
-            }
-        }
+        ta[1] = ta[1] * (1.0f - optrans)
+                + (ta[1] + tb[1]) * (ta[0] * lref * shadows_ccorrect
+                                     + (1.0f - ta[0]) * href * (1.0f - shadows_ccorrect)) * optrans;
+
+        ta[2] = ta[2] * (1.0f - optrans)
+                + (ta[2] + tb[2]) * (ta[0] * lref * shadows_ccorrect
+                                     + (1.0f - ta[0]) * href * (1.0f - shadows_ccorrect)) * optrans;
+      }
 
-      dst[0] = src_pix[0];
-      dst[1] = src_pix[1];
-      dst[2] = src_pix[2];
+      dst[0] = ta[0] * 100.f;
+      dst[1] = ta[1] * 128.f;
+      dst[2] = ta[2] * 128.f;
       dst[3] = src[3];
 
       src += 4;
       dst += 4;
-      aux += 1;
-      aux2 += 1;
+      aux += 3;
     }
 
   return TRUE;
 }
 
+/*
+
+#include "opencl/gegl-cl.h"
+
+#include "opencl/shadows-highlights-correction.cl.h"
+
+static GeglClRunData *cl_data = NULL;
+
+static gboolean
+cl_process (GeglOperation       *op,
+            cl_mem               in_tex,
+            cl_mem               aux_tex,
+            cl_mem               out_tex,
+            size_t               global_worksize,
+            const GeglRectangle *roi,
+            gint                 level)
+{
+  GeglProperties *o = GEGL_PROPERTIES (op);
+
+  cl_int cl_err = 0;
+
+  gfloat shadows    = 2.f * fminf (fmaxf (-1.0, (o->shadows / 100.f)), 1.f);
+  gfloat highlights = 2.f * fminf (fmaxf (-1.0, (o->highlights / 100.f)), 1.f);
+  gfloat whitepoint = fmaxf (1.f - o->whitepoint / 100.f, 0.01f);
+  gfloat compress   = fminf (fmaxf (0, (o->compress / 100.f)), 0.99f);
+
+  gfloat shadows_ccorrect = (fminf (fmaxf (0.0f, (o->shadows_ccorrect / 100.f)), 1.f) - 0.5f)
+                             * SIGN(shadows) + 0.5f;
+
+  gfloat highlights_ccorrect = (fminf (fmaxf (0.0f, (o->highlights_ccorrect / 100.f)), 1.f) - 0.5f)
+                                * SIGN(-highlights) + 0.5f;
+
+  if (!cl_data)
+    {
+      const char *kernel_name[] = {"shadows_highlights", NULL};
+      cl_data = gegl_cl_compile_and_build (shadows_highlights_correction_cl_source, kernel_name);
+    }
+  if (!cl_data) return TRUE;
+
+  cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 0, sizeof(cl_mem),   (void*)&in_tex);
+  CL_CHECK;
+  cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 1, sizeof(cl_mem),   (aux_tex)? (void*)&aux_tex : NULL);
+  CL_CHECK;
+  cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 2, sizeof(cl_mem),   (void*)&out_tex);
+  CL_CHECK;
+  cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 3, sizeof(cl_float), (void*)&shadows);
+  CL_CHECK;
+  cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 4, sizeof(cl_float), (void*)&highlights);
+  CL_CHECK;
+  cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 5, sizeof(cl_float), (void*)&compress);
+  CL_CHECK;
+  cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 6, sizeof(cl_float), (void*)&shadows_ccorrect);
+  CL_CHECK;
+  cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 7, sizeof(cl_float), (void*)&highlights_ccorrect);
+  CL_CHECK;
+  cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 8, sizeof(cl_float), (void*)&whitepoint);
+  CL_CHECK;
+
+  cl_err = gegl_clEnqueueNDRangeKernel(gegl_cl_get_command_queue (),
+                                        cl_data->kernel[0], 1,
+                                        NULL, &global_worksize, NULL,
+                                        0, NULL, NULL);
+  CL_CHECK;
+
+  return FALSE;
+
+error:
+  return TRUE;
+}
+
+*/
+
 static GeglRectangle
 get_bounding_box (GeglOperation *self)
 {
@@ -224,25 +290,27 @@ get_bounding_box (GeglOperation *self)
 static void
 gegl_op_class_init (GeglOpClass *klass)
 {
-  GObjectClass                     *object_class;
-  GeglOperationClass               *operation_class;
-  GeglOperationPointComposer3Class *point_composer3_class;
-
-  object_class          = G_OBJECT_CLASS (klass);
-  operation_class       = GEGL_OPERATION_CLASS (klass);
-  point_composer3_class = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass);
+  GeglOperationClass              *operation_class;
+  GeglOperationPointComposerClass *point_composer_class;
 
-  object_class->finalize            = finalize;
+  operation_class      = GEGL_OPERATION_CLASS (klass);
+  point_composer_class = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass);
 
   operation_class->prepare          = prepare;
   operation_class->get_bounding_box = get_bounding_box;
-  operation_class->opencl_support   = FALSE;
+  
+
+  point_composer_class->process     = process;
 
-  point_composer3_class->process    = process;
+  /*
+  point_composer_class->cl_process  = cl_process;
+  operation_class->opencl_support   = TRUE;
+   */
 
   gegl_operation_class_set_keys (operation_class,
     "name",        "gegl:shadows-highlights-correction",
     "categories",  "hidden",
+    "license",     "GPL3+",
     "description", _("Lighten shadows and darken highlights"),
     NULL);
 }
diff --git a/operations/workshop/shadows-highlights.c b/operations/workshop/shadows-highlights.c
index 9793374..67e2b48 100644
--- a/operations/workshop/shadows-highlights.c
+++ b/operations/workshop/shadows-highlights.c
@@ -1,16 +1,22 @@
 /* This file is an image processing operation for GEGL
- * GEGL is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
  *
- * GEGL is distributed in the hope that it will be useful,
+ * 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
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  *
- * You should have received a copy of the GNU Lesser General Public
- * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ * This operation is a port of the Darktable Shadows Highlights filter
+ * copyright (c) 2012--2015 Ulrich Pegelow.
+ *
+ * GEGL port: Thomas Manni <thomas manni free fr>
  *
  */
 
@@ -19,22 +25,26 @@
 
 #ifdef GEGL_PROPERTIES
 
-property_double (s_amount, _("Shadows amount"), 0.2)
-    value_range (0.0, 1.0)
+property_double (shadows, _("Shadows"), 50.0)
+    value_range (-100.0, 100.0)
 
-property_double (s_tonalwidth, _("Shadows tonal width"), 0.1)
-    value_range (0.001, 1.0)
+property_double (highlights, _("Highlights"), -50.0)
+    value_range (-100.0, 100.0)
 
-property_double (s_radius, _("Shadows radius"), 5.0)
-    value_range (0.0, 100.0)
+property_double (whitepoint, _("White point adjustment"), 0.0)
+    value_range (-10.0, 10.0)
 
-property_double (h_amount, _("Highlights amount"), 0.2)
-    value_range (0.0, 1.0)
+property_double (radius, _("Radius"), 100.0)
+    value_range (0.1, G_MAXDOUBLE)
+    ui_range    (0.1, 200.0)
 
-property_double (h_tonalwidth, _("Highlights tonal width"), 0.1)
-    value_range (0.001, 1.0)
+property_double (compress, _("Compress"), 50.0)
+    value_range (0.0, 100.0)
+
+property_double (shadows_ccorrect, _("Shadows color adjustment"), 100.0)
+    value_range (0.0, 100.0)
 
-property_double (h_radius, _("Highlights radius"), 5.0)
+property_double (highlights_ccorrect, _("Highlights color adjustment"), 50.0)
     value_range (0.0, 100.0)
 
 #else
@@ -51,45 +61,38 @@ attach (GeglOperation *operation)
   GeglNode *gegl;
   GeglNode *input;
   GeglNode *output;
-  GeglNode *s_blur;
-  GeglNode *h_blur;
+  GeglNode *blur;
   GeglNode *shprocess;
 
   gegl   = operation->node;
   input  = gegl_node_get_input_proxy (gegl, "input");
   output = gegl_node_get_output_proxy (gegl, "output");
 
-  s_blur = gegl_node_new_child (gegl,
-                                "operation",    "gegl:gaussian-blur",
-                                "abyss-policy", 1,
-                                NULL);
+  blur = gegl_node_new_child (gegl,
+                              "operation",    "gegl:gaussian-blur",
+                              "abyss-policy", 1,
+                               NULL);
 
-  h_blur = gegl_node_new_child (gegl,
-                                "operation",    "gegl:gaussian-blur",
-                                "abyss-policy", 1,
-                                NULL);
 
   shprocess = gegl_node_new_child (gegl,
                                    "operation", "gegl:shadows-highlights-correction",
                                    NULL);
 
-  gegl_node_link (input, s_blur);
-  gegl_node_link (input, h_blur);
+  gegl_node_link (input, blur);
   gegl_node_link_many (input, shprocess, output, NULL);
 
-  gegl_node_connect_to (s_blur, "output", shprocess, "aux");
-  gegl_node_connect_to (h_blur, "output", shprocess, "aux2");
+  gegl_node_connect_to (blur, "output", shprocess, "aux");
 
-  gegl_operation_meta_redirect (operation, "s-amount", shprocess, "s-amount");
-  gegl_operation_meta_redirect (operation, "s-tonalwidth", shprocess, "s-tonalwidth");
-  gegl_operation_meta_redirect (operation, "s-radius", s_blur, "std-dev-x");
-  gegl_operation_meta_redirect (operation, "s-radius", s_blur, "std-dev-y");
-  gegl_operation_meta_redirect (operation, "h-amount", shprocess, "h-amount");
-  gegl_operation_meta_redirect (operation, "h-tonalwidth", shprocess, "h-tonalwidth");
-  gegl_operation_meta_redirect (operation, "h-radius", h_blur, "std-dev-x");
-  gegl_operation_meta_redirect (operation, "h-radius", h_blur, "std-dev-y");
+  gegl_operation_meta_redirect (operation, "radius", blur, "std-dev-x");
+  gegl_operation_meta_redirect (operation, "radius", blur, "std-dev-y");
+  gegl_operation_meta_redirect (operation, "shadows", shprocess, "shadows");
+  gegl_operation_meta_redirect (operation, "highlights", shprocess, "highlights");
+  gegl_operation_meta_redirect (operation, "whitepoint", shprocess, "whitepoint");
+  gegl_operation_meta_redirect (operation, "compress", shprocess, "compress");
+  gegl_operation_meta_redirect (operation, "shadows-ccorrect", shprocess, "shadows-ccorrect");
+  gegl_operation_meta_redirect (operation, "highlights-ccorrect", shprocess, "highlights-ccorrect");
 
-  gegl_operation_meta_watch_nodes (operation, s_blur, h_blur, shprocess, NULL);
+  gegl_operation_meta_watch_nodes (operation, blur, shprocess, NULL);
 }
 
 static void
@@ -105,6 +108,7 @@ gegl_op_class_init (GeglOpClass *klass)
     "name",        "gegl:shadows-highlights",
     "title",       _("Shadows-Highlights"),
     "categories",  "light",
+    "license",     "GPL3+",
     "description", _("Perform shadows and highlights correction"),
     NULL);
 }


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