[gegl] operations: add a cell noise operation



commit 07aacf7337b5449a6606aa4eb3b029a515763359
Author: Dimitris Papavasiliou <dpapavas gmail com>
Date:   Fri Mar 21 12:07:43 2014 +0200

    operations: add a cell noise operation
    
    Added a cell noise operation implementing the texture function described in
    
        Steven Worley. 1996. A cellular texture basis function.
        In Proceedings of the 23rd annual conference on Computer
        graphics and interactive techniques (SIGGRAPH '96).

 opencl/noise-cell.cl                        |  194 +++++++++++++
 opencl/noise-cell.cl.h                      |  196 +++++++++++++
 operations/common/Makefile.am               |    3 +-
 operations/common/noise-cell.c              |  418 +++++++++++++++++++++++++++
 po/POTFILES.in                              |    1 +
 tests/compositions/Makefile.am              |    1 +
 tests/compositions/noise-cell.xml           |  152 ++++++++++
 tests/compositions/reference/noise-cell.png |  Bin 0 -> 169951 bytes
 8 files changed, 964 insertions(+), 1 deletions(-)
---
diff --git a/opencl/noise-cell.cl b/opencl/noise-cell.cl
new file mode 100644
index 0000000..1e55585
--- /dev/null
+++ b/opencl/noise-cell.cl
@@ -0,0 +1,194 @@
+#define MAX_RANK 3
+
+/* Random feature counts following the Poisson distribution with
+   lambda equal to 7. */
+
+static const __constant char poisson[256] = {
+  7, 9, 12, 12, 8, 7, 5, 5, 6, 7, 8, 6, 10, 7, 6, 2, 8, 3, 9, 5, 13, 10, 9,
+  8, 8, 9, 3, 8, 9, 6, 8, 7, 4, 9, 6, 3, 10, 7, 7, 7, 6, 7, 4, 14, 7, 6, 11,
+  7, 7, 7, 12, 7, 10, 6, 8, 11, 3, 5, 7, 7, 8, 7, 9, 8, 5, 8, 11, 3, 4, 5, 8,
+  8, 7, 8, 9, 2, 7, 8, 12, 4, 8, 2, 11, 8, 14, 7, 8, 2, 3, 10, 4, 6, 9, 5, 8,
+  7, 10, 10, 10, 14, 5, 7, 6, 4, 5, 6, 11, 8, 7, 3, 11, 5, 5, 2, 9, 7, 7, 7,
+  9, 2, 7, 6, 9, 7, 6, 5, 12, 5, 3, 11, 9, 12, 8, 6, 8, 6, 8, 5, 5, 7, 5, 2,
+  9, 5, 5, 8, 11, 8, 8, 10, 6, 4, 7, 14, 7, 3, 10, 7, 7, 4, 9, 10, 10, 9, 8,
+  8, 7, 6, 5, 10, 10, 5, 10, 7, 7, 10, 7, 4, 9, 9, 6, 8, 5, 10, 7, 3, 9, 9,
+  7, 8, 9, 7, 5, 7, 6, 5, 5, 12, 4, 7, 5, 5, 4, 5, 7, 10, 8, 7, 9, 4, 6, 11,
+  6, 3, 7, 8, 9, 5, 8, 6, 7, 8, 7, 7, 3, 7, 7, 9, 4, 5, 5, 6, 9, 7, 6, 12, 4,
+  9, 10, 8, 8, 6, 4, 9, 9, 8, 11, 6, 8, 13, 8, 9, 12, 6, 9, 8
+};
+
+static uint
+philox (uint s,
+        uint t,
+        uint k)
+{
+  ulong p;
+  int   i;
+
+  for (i = 0 ; i < 3 ; i += 1)
+    {
+      p = s * 0xcd9e8d57ul;
+
+      s = ((uint)(p >> 32)) ^ t ^ k;
+      t = (uint)p;
+
+      k += 0x9e3779b9u;
+    }
+
+  return s;
+}
+
+static float
+lcg (uint *hash)
+{
+  return (*hash = *hash * 1664525u + 1013904223u) / 4294967296.0f;
+}
+
+static void
+search_box (float              *closest,
+            uint               *feature,
+            int                 s,
+            int                 t,
+            float               x,
+            float               y,
+            float               shape,
+            uint                rank,
+            uint                seed)
+{
+  uint hash;
+  int  i, n;
+
+  hash = philox ((uint)s, (uint)t, seed);
+  n = poisson[hash >> 24];
+
+  for (i = 0 ; i < n ; i += 1)
+    {
+      float delta_x, delta_y, d;
+      int   j, k;
+
+      /* Calculate the distance to each feature point. */
+
+      delta_x = s + lcg (&hash) - x;
+      delta_y = t + lcg (&hash) - y;
+
+      if (shape == 2)
+        d = delta_x * delta_x + delta_y * delta_y;
+      else if (shape == 1)
+        d = fabs (delta_x) + fabs (delta_y);
+      else
+        d = pow (fabs (delta_x), shape) +
+          pow (fabs (delta_y), shape);
+
+      /* Insert it into the list of n closest distances if needed. */
+
+      for (j = 0 ; j < rank && d > closest[j] ; j += 1);
+
+      if (j < rank)
+        {
+          for (k = rank - 1 ; k > j ; k -= 1)
+            {
+              closest[k] = closest[k - 1];
+            }
+
+          closest[j] = d;
+
+          if (j == rank - 1)
+            *feature = hash;
+        }
+    }
+}
+
+__kernel void kernel_noise (__global float *out,
+                            const int       x_0,
+                            const int       y_0,
+                            const uint      iterations,
+                            float           scale,
+                            float           shape,
+                            uint            rank,
+                            uint            seed,
+                            int             palettize)
+{
+  const int gidx = get_global_id(0);
+  const int gidy = get_global_id(1);
+
+  float c, d, n, closest[MAX_RANK], *d_0 = &closest[MAX_RANK - 1];
+  uint  feature;
+  int   i, j;
+
+  for (j = 0, n = 0, c = 1, d = scale;
+       j < iterations;
+       c *= 2, d *= 2, j += 1)
+    {
+      float d_l, d_r, d_t, d_b;
+      float x = (float)(gidx + x_0) * d;
+      float y = (float)(gidy + y_0) * d;
+      int   s = (int)floor(x);
+      int   t = (int)floor(y);
+
+      for (i = 0 ; i < rank ; closest[i] = 1.0 / 0.0, i += 1);
+
+      /* Search the box the point is in. */
+
+      search_box (closest, &feature, s, t, x, y, shape, rank, seed);
+
+      d_0 = &closest[rank - 1];
+      d_l = x - s; d_l *= d_l;
+      d_r = 1.0 - x + s; d_r *= d_r;
+      d_b = y - t; d_b *= d_b;
+      d_t = 1.0 - y + t; d_t *= d_t;
+
+      /* Search adjacent boxes if it is possible for them to contain a
+       * nearby feature point. */
+
+      if (d_l < *d_0)
+        {
+          if (d_l + d_b < *d_0)
+            search_box (closest, &feature, s - 1, t - 1, x, y,
+                        shape, rank, seed);
+
+          search_box (closest, &feature, s - 1, t, x, y,
+                      shape, rank, seed);
+
+          if (d_l + d_t < *d_0)
+              search_box (closest, &feature, s - 1, t + 1, x, y,
+                          shape, rank, seed);
+        }
+
+      if (d_b < *d_0)
+          search_box (closest, &feature, s, t - 1, x, y,
+                      shape, rank, seed);
+
+      if (d_t < *d_0)
+          search_box (closest, &feature, s, t + 1, x, y,
+                      shape, rank, seed);
+
+      if (d_r < *d_0)
+        {
+          if (d_r + d_b < *d_0)
+              search_box (closest, &feature, s + 1, t - 1, x, y,
+                          shape, rank, seed);
+
+          search_box (closest, &feature, s + 1, t, x, y,
+                      shape, rank, seed);
+
+          if (d_r + d_t < *d_0)
+              search_box (closest, &feature, s + 1, t + 1, x, y,
+                          shape, rank, seed);
+        }
+
+      /* If palettized output is requested return the normalized hash of
+       * the closest feature point, otherwise return the closest
+       * distance. */
+
+      if(palettize)
+        {
+          n += feature / 4294967295.0f / c;
+        }
+      else
+        {
+          n += pow(closest[rank - 1], 1 / shape) / c;
+        }
+    }
+
+  out[gidy * get_global_size(0) + gidx] = n;
+}
diff --git a/opencl/noise-cell.cl.h b/opencl/noise-cell.cl.h
new file mode 100644
index 0000000..775f591
--- /dev/null
+++ b/opencl/noise-cell.cl.h
@@ -0,0 +1,196 @@
+static const char* noise_cell_cl_source =
+"#define MAX_RANK 3                                                            \n"
+"                                                                              \n"
+"/* Random feature counts following the Poisson distribution with              \n"
+"   lambda equal to 7. */                                                      \n"
+"                                                                              \n"
+"static const __constant char poisson[256] = {                                 \n"
+"  7, 9, 12, 12, 8, 7, 5, 5, 6, 7, 8, 6, 10, 7, 6, 2, 8, 3, 9, 5, 13, 10, 9,   \n"
+"  8, 8, 9, 3, 8, 9, 6, 8, 7, 4, 9, 6, 3, 10, 7, 7, 7, 6, 7, 4, 14, 7, 6, 11,  \n"
+"  7, 7, 7, 12, 7, 10, 6, 8, 11, 3, 5, 7, 7, 8, 7, 9, 8, 5, 8, 11, 3, 4, 5, 8, \n"
+"  8, 7, 8, 9, 2, 7, 8, 12, 4, 8, 2, 11, 8, 14, 7, 8, 2, 3, 10, 4, 6, 9, 5, 8, \n"
+"  7, 10, 10, 10, 14, 5, 7, 6, 4, 5, 6, 11, 8, 7, 3, 11, 5, 5, 2, 9, 7, 7, 7,  \n"
+"  9, 2, 7, 6, 9, 7, 6, 5, 12, 5, 3, 11, 9, 12, 8, 6, 8, 6, 8, 5, 5, 7, 5, 2,  \n"
+"  9, 5, 5, 8, 11, 8, 8, 10, 6, 4, 7, 14, 7, 3, 10, 7, 7, 4, 9, 10, 10, 9, 8,  \n"
+"  8, 7, 6, 5, 10, 10, 5, 10, 7, 7, 10, 7, 4, 9, 9, 6, 8, 5, 10, 7, 3, 9, 9,   \n"
+"  7, 8, 9, 7, 5, 7, 6, 5, 5, 12, 4, 7, 5, 5, 4, 5, 7, 10, 8, 7, 9, 4, 6, 11,  \n"
+"  6, 3, 7, 8, 9, 5, 8, 6, 7, 8, 7, 7, 3, 7, 7, 9, 4, 5, 5, 6, 9, 7, 6, 12, 4, \n"
+"  9, 10, 8, 8, 6, 4, 9, 9, 8, 11, 6, 8, 13, 8, 9, 12, 6, 9, 8                 \n"
+"};                                                                            \n"
+"                                                                              \n"
+"static uint                                                                   \n"
+"philox (uint s,                                                               \n"
+"        uint t,                                                               \n"
+"        uint k)                                                               \n"
+"{                                                                             \n"
+"  ulong p;                                                                    \n"
+"  int   i;                                                                    \n"
+"                                                                              \n"
+"  for (i = 0 ; i < 3 ; i += 1)                                                \n"
+"    {                                                                         \n"
+"      p = s * 0xcd9e8d57ul;                                                   \n"
+"                                                                              \n"
+"      s = ((uint)(p >> 32)) ^ t ^ k;                                          \n"
+"      t = (uint)p;                                                            \n"
+"                                                                              \n"
+"      k += 0x9e3779b9u;                                                       \n"
+"    }                                                                         \n"
+"                                                                              \n"
+"  return s;                                                                   \n"
+"}                                                                             \n"
+"                                                                              \n"
+"static float                                                                  \n"
+"lcg (uint *hash)                                                              \n"
+"{                                                                             \n"
+"  return (*hash = *hash * 1664525u + 1013904223u) / 4294967296.0f;            \n"
+"}                                                                             \n"
+"                                                                              \n"
+"static void                                                                   \n"
+"search_box (float              *closest,                                      \n"
+"            uint               *feature,                                      \n"
+"            int                 s,                                            \n"
+"            int                 t,                                            \n"
+"            float               x,                                            \n"
+"            float               y,                                            \n"
+"            float               shape,                                        \n"
+"            uint                rank,                                         \n"
+"            uint                seed)                                         \n"
+"{                                                                             \n"
+"  uint hash;                                                                  \n"
+"  int  i, n;                                                                  \n"
+"                                                                              \n"
+"  hash = philox ((uint)s, (uint)t, seed);                                     \n"
+"  n = poisson[hash >> 24];                                                    \n"
+"                                                                              \n"
+"  for (i = 0 ; i < n ; i += 1)                                                \n"
+"    {                                                                         \n"
+"      float delta_x, delta_y, d;                                              \n"
+"      int   j, k;                                                             \n"
+"                                                                              \n"
+"      /* Calculate the distance to each feature point. */                     \n"
+"                                                                              \n"
+"      delta_x = s + lcg (&hash) - x;                                          \n"
+"      delta_y = t + lcg (&hash) - y;                                          \n"
+"                                                                              \n"
+"      if (shape == 2)                                                         \n"
+"        d = delta_x * delta_x + delta_y * delta_y;                            \n"
+"      else if (shape == 1)                                                    \n"
+"        d = fabs (delta_x) + fabs (delta_y);                                  \n"
+"      else                                                                    \n"
+"        d = pow (fabs (delta_x), shape) +                                     \n"
+"          pow (fabs (delta_y), shape);                                        \n"
+"                                                                              \n"
+"      /* Insert it into the list of n closest distances if needed. */         \n"
+"                                                                              \n"
+"      for (j = 0 ; j < rank && d > closest[j] ; j += 1);                      \n"
+"                                                                              \n"
+"      if (j < rank)                                                           \n"
+"        {                                                                     \n"
+"          for (k = rank - 1 ; k > j ; k -= 1)                                 \n"
+"            {                                                                 \n"
+"              closest[k] = closest[k - 1];                                    \n"
+"            }                                                                 \n"
+"                                                                              \n"
+"          closest[j] = d;                                                     \n"
+"                                                                              \n"
+"          if (j == rank - 1)                                                  \n"
+"            *feature = hash;                                                  \n"
+"        }                                                                     \n"
+"    }                                                                         \n"
+"}                                                                             \n"
+"                                                                              \n"
+"__kernel void kernel_noise (__global float *out,                              \n"
+"                            const int       x_0,                              \n"
+"                            const int       y_0,                              \n"
+"                            const uint      iterations,                       \n"
+"                            float           scale,                            \n"
+"                            float           shape,                            \n"
+"                            uint            rank,                             \n"
+"                            uint            seed,                             \n"
+"                            int             palettize)                        \n"
+"{                                                                             \n"
+"  const int gidx = get_global_id(0);                                          \n"
+"  const int gidy = get_global_id(1);                                          \n"
+"                                                                              \n"
+"  float c, d, n, closest[MAX_RANK], *d_0 = &closest[MAX_RANK - 1];            \n"
+"  uint  feature;                                                              \n"
+"  int   i, j;                                                                 \n"
+"                                                                              \n"
+"  for (j = 0, n = 0, c = 1, d = scale;                                        \n"
+"       j < iterations;                                                        \n"
+"       c *= 2, d *= 2, j += 1)                                                \n"
+"    {                                                                         \n"
+"      float d_l, d_r, d_t, d_b;                                               \n"
+"      float x = (float)(gidx + x_0) * d;                                      \n"
+"      float y = (float)(gidy + y_0) * d;                                      \n"
+"      int   s = (int)floor(x);                                                \n"
+"      int   t = (int)floor(y);                                                \n"
+"                                                                              \n"
+"      for (i = 0 ; i < rank ; closest[i] = 1.0 / 0.0, i += 1);                \n"
+"                                                                              \n"
+"      /* Search the box the point is in. */                                   \n"
+"                                                                              \n"
+"      search_box (closest, &feature, s, t, x, y, shape, rank, seed);          \n"
+"                                                                              \n"
+"      d_0 = &closest[rank - 1];                                               \n"
+"      d_l = x - s; d_l *= d_l;                                                \n"
+"      d_r = 1.0 - x + s; d_r *= d_r;                                          \n"
+"      d_b = y - t; d_b *= d_b;                                                \n"
+"      d_t = 1.0 - y + t; d_t *= d_t;                                          \n"
+"                                                                              \n"
+"      /* Search adjacent boxes if it is possible for them to contain a        \n"
+"       * nearby feature point. */                                             \n"
+"                                                                              \n"
+"      if (d_l < *d_0)                                                         \n"
+"        {                                                                     \n"
+"          if (d_l + d_b < *d_0)                                               \n"
+"            search_box (closest, &feature, s - 1, t - 1, x, y,                \n"
+"                        shape, rank, seed);                                   \n"
+"                                                                              \n"
+"          search_box (closest, &feature, s - 1, t, x, y,                      \n"
+"                      shape, rank, seed);                                     \n"
+"                                                                              \n"
+"          if (d_l + d_t < *d_0)                                               \n"
+"              search_box (closest, &feature, s - 1, t + 1, x, y,              \n"
+"                          shape, rank, seed);                                 \n"
+"        }                                                                     \n"
+"                                                                              \n"
+"      if (d_b < *d_0)                                                         \n"
+"          search_box (closest, &feature, s, t - 1, x, y,                      \n"
+"                      shape, rank, seed);                                     \n"
+"                                                                              \n"
+"      if (d_t < *d_0)                                                         \n"
+"          search_box (closest, &feature, s, t + 1, x, y,                      \n"
+"                      shape, rank, seed);                                     \n"
+"                                                                              \n"
+"      if (d_r < *d_0)                                                         \n"
+"        {                                                                     \n"
+"          if (d_r + d_b < *d_0)                                               \n"
+"              search_box (closest, &feature, s + 1, t - 1, x, y,              \n"
+"                          shape, rank, seed);                                 \n"
+"                                                                              \n"
+"          search_box (closest, &feature, s + 1, t, x, y,                      \n"
+"                      shape, rank, seed);                                     \n"
+"                                                                              \n"
+"          if (d_r + d_t < *d_0)                                               \n"
+"              search_box (closest, &feature, s + 1, t + 1, x, y,              \n"
+"                          shape, rank, seed);                                 \n"
+"        }                                                                     \n"
+"                                                                              \n"
+"      /* If palettized output is requested return the normalized hash of      \n"
+"       * the closest feature point, otherwise return the closest              \n"
+"       * distance. */                                                         \n"
+"                                                                              \n"
+"      if(palettize)                                                           \n"
+"        {                                                                     \n"
+"          n += feature / 4294967295.0f / c;                                   \n"
+"        }                                                                     \n"
+"      else                                                                    \n"
+"        {                                                                     \n"
+"          n += pow(closest[rank - 1], 1 / shape) / c;                         \n"
+"        }                                                                     \n"
+"    }                                                                         \n"
+"                                                                              \n"
+"  out[gidy * get_global_size(0) + gidx] = n;                                  \n"
+"}                                                                             \n"
+;
diff --git a/operations/common/Makefile.am b/operations/common/Makefile.am
index 17fd937..df9b3ac 100644
--- a/operations/common/Makefile.am
+++ b/operations/common/Makefile.am
@@ -77,6 +77,7 @@ op_LTLIBRARIES = \
        noise-rgb.la \
        noise-slur.la \
        noise-spread.la \
+       noise-cell.la \
        noise.la \
        oilify.la \
        opacity.la \
@@ -117,4 +118,4 @@ op_LTLIBRARIES = \
        weighted-blend.la \
        whirl-pinch.la \
        wind.la \
-       write-buffer.la
\ No newline at end of file
+       write-buffer.la
diff --git a/operations/common/noise-cell.c b/operations/common/noise-cell.c
new file mode 100644
index 0000000..b241adf
--- /dev/null
+++ b/operations/common/noise-cell.c
@@ -0,0 +1,418 @@
+/* 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,
+ * 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2014 Dimitris Papavasiliou <dpapavas google com>
+ */
+
+/* This plug-in generates cellular noise textures based on the
+ * function described in the paper
+ *
+ *    Steven Worley. 1996. A cellular texture basis function.
+ *    In Proceedings of the 23rd annual conference on Computer
+ *    graphics and interactive techniques (SIGGRAPH '96).
+ *
+ * Comments and improvements for this code are welcome.
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#define MAX_RANK 3
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+gegl_chant_seed    (seed, rand, _("Random seed"),
+                    _("The random seed for the noise function"))
+gegl_chant_double  (scale, _("Scale"), 0, 20.0, 1.0,
+                    _("The scale of the noise function"))
+gegl_chant_double  (shape, _("Shape"), 1.0, 2.0, 2.0,
+                    _("Interpolate between Manhattan and Euclidean distance."))
+gegl_chant_int     (rank, _("Rank"), 1, MAX_RANK, 1,
+                    _("Select the n-th closest point"))
+gegl_chant_int     (iterations, _("Iterations"), 1, 20, 1,
+                    _("The number of noise octaves."))
+gegl_chant_boolean (palettize, _("Palettize"), FALSE,
+                    _("Fill each cell with a random color"))
+
+#else
+
+#define GEGL_CHANT_TYPE_POINT_RENDER
+#define GEGL_CHANT_C_FILE       "noise-cell.c"
+
+#include "gegl-chant.h"
+#include <gegl-buffer-cl-iterator.h>
+#include <gegl-debug.h>
+#include <math.h>
+
+#include "opencl/noise-cell.cl.h"
+
+/* Random feature counts following the Poisson distribution with
+   lambda equal to 7. */
+
+static const gint poisson[256] = {
+  7, 9, 12, 12, 8, 7, 5, 5, 6, 7, 8, 6, 10, 7, 6, 2, 8, 3, 9, 5, 13, 10, 9,
+  8, 8, 9, 3, 8, 9, 6, 8, 7, 4, 9, 6, 3, 10, 7, 7, 7, 6, 7, 4, 14, 7, 6, 11,
+  7, 7, 7, 12, 7, 10, 6, 8, 11, 3, 5, 7, 7, 8, 7, 9, 8, 5, 8, 11, 3, 4, 5, 8,
+  8, 7, 8, 9, 2, 7, 8, 12, 4, 8, 2, 11, 8, 14, 7, 8, 2, 3, 10, 4, 6, 9, 5, 8,
+  7, 10, 10, 10, 14, 5, 7, 6, 4, 5, 6, 11, 8, 7, 3, 11, 5, 5, 2, 9, 7, 7, 7,
+  9, 2, 7, 6, 9, 7, 6, 5, 12, 5, 3, 11, 9, 12, 8, 6, 8, 6, 8, 5, 5, 7, 5, 2,
+  9, 5, 5, 8, 11, 8, 8, 10, 6, 4, 7, 14, 7, 3, 10, 7, 7, 4, 9, 10, 10, 9, 8,
+  8, 7, 6, 5, 10, 10, 5, 10, 7, 7, 10, 7, 4, 9, 9, 6, 8, 5, 10, 7, 3, 9, 9,
+  7, 8, 9, 7, 5, 7, 6, 5, 5, 12, 4, 7, 5, 5, 4, 5, 7, 10, 8, 7, 9, 4, 6, 11,
+  6, 3, 7, 8, 9, 5, 8, 6, 7, 8, 7, 7, 3, 7, 7, 9, 4, 5, 5, 6, 9, 7, 6, 12, 4,
+  9, 10, 8, 8, 6, 4, 9, 9, 8, 11, 6, 8, 13, 8, 9, 12, 6, 9, 8
+};
+
+typedef struct
+{
+  gdouble  shape;
+  gdouble  closest[MAX_RANK];
+  guint    feature, rank, seed;
+  gboolean palettize;
+} Context;
+
+static GeglClRunData *cl_data = NULL;
+
+static inline guint
+philox (guint s,
+        guint t,
+        guint k)
+{
+  guint64 p;
+  gint    i;
+
+  /* For details regarding this hash function consult:
+
+     Salmon, J.K.; Moraes, M.A.; Dror, R.O.; Shaw, D.E., "Parallel
+     random numbers: As easy as 1, 2, 3," High Performance Computing,
+     Networking, Storage and Analysis (SC), 2011 International
+     Conference for , vol., no., pp.1,12, 12-18 Nov. 2011 */\
+
+  for (i = 0 ; i < 3 ; i += 1)
+    {
+      p = s * (guint64)0xcd9e8d57;
+
+      s = ((guint)(p >> 32)) ^ t ^ k;
+      t = (guint)p;
+
+      k += 0x9e3779b9;
+    }
+
+  return s;
+}
+
+static inline gdouble
+lcg (guint *hash)
+{
+  return (*hash = *hash * (guint)1664525 + (guint)1013904223) / (gdouble)4294967296.0;
+}
+
+static void
+search_box (gint     s,
+            gint     t,
+            gdouble  x,
+            gdouble  y,
+            Context *context)
+{
+  guint hash;
+  gint i, n;
+
+  hash = philox ((guint)s, (guint)t, context->seed);
+  n = poisson[hash >> 24];
+
+  for (i = 0 ; i < n ; i += 1)
+    {
+      gdouble delta_x, delta_y, d;
+      gint    j, k;
+
+      /* Calculate the distance to each feature point. */
+
+      delta_x = s + lcg (&hash) - x;
+      delta_y = t + lcg (&hash) - y;
+
+      if (context->shape == 2)
+        d = delta_x * delta_x + delta_y * delta_y;
+      else if (context->shape == 1)
+        d = fabs (delta_x) + fabs (delta_y);
+      else
+        d = pow (fabs (delta_x), context->shape) +
+          pow (fabs (delta_y), context->shape);
+
+      /* Insert it into the list of n closest distances if needed. */
+
+      for (j = 0 ; j < context->rank && d > context->closest[j] ; j += 1);
+
+      if (j < context->rank)
+        {
+          for (k = context->rank - 1 ; k > j ; k -= 1)
+            {
+              context->closest[k] = context->closest[k - 1];
+            }
+
+          context->closest[j] = d;
+
+          if (j == context->rank - 1)
+            context->feature = hash;
+        }
+    }
+}
+
+static double
+noise2 (double x,
+        double y,
+        Context *context)
+{
+  gdouble d_l, d_r, d_t, d_b, *d_0;
+  gint s, t, i;
+
+  for (i = 0 ; i < context->rank ; context->closest[i] = INFINITY, i += 1);
+
+  s = (gint)floor(x);
+  t = (gint)floor(y);
+
+  /* Search the box the point is in. */
+
+  search_box (s, t, x, y, context);
+
+  d_0 = &context->closest[context->rank - 1];
+  d_l = x - s; d_l *= d_l;
+  d_r = 1.0 - x + s; d_r *= d_r;
+  d_b = y - t; d_b *= d_b;
+  d_t = 1.0 - y + t; d_t *= d_t;
+
+  /* Search adjacent boxes if it is possible for them to contain a
+   * nearby feature point. */
+
+  if (d_l < *d_0)
+    {
+      if (d_l + d_b < *d_0)
+        search_box (s - 1, t - 1, x, y, context);
+
+      search_box (s - 1, t, x, y, context);
+
+      if (d_l + d_t < *d_0)
+        search_box (s - 1, t + 1, x, y, context);
+    }
+
+  if (d_b < *d_0)
+    search_box (s, t - 1, x, y, context);
+
+  if (d_t < *d_0)
+    search_box (s, t + 1, x, y, context);
+
+  if (d_r < *d_0)
+    {
+      if (d_r + d_b < *d_0)
+        search_box (s + 1, t - 1, x, y, context);
+
+      search_box (s + 1, t, x, y, context);
+
+      if (d_r + d_t < *d_0)
+        search_box (s + 1, t + 1, x, y, context);
+    }
+
+  /* If palettized output is requested return the normalized hash of
+   * the closest feature point, otherwise return the closest
+   * distance. */
+
+  if (context->palettize)
+    return (gdouble)context->feature / 4294967295.0;
+  else
+    return pow (context->closest[context->rank - 1], 1 / context->shape);
+}
+
+static void
+prepare (GeglOperation *operation)
+{
+  gegl_operation_set_format (operation, "output", babl_format ("Y float"));
+}
+
+static GeglRectangle
+get_bounding_box (GeglOperation *operation)
+{
+  return gegl_rectangle_infinite_plane ();
+}
+
+static gboolean
+cl_process (GeglOperation       *operation,
+            cl_mem               out_tex,
+            const GeglRectangle *roi)
+{
+  GeglChantO   *o          = GEGL_CHANT_PROPERTIES (operation);
+  const size_t  gbl_size[] = {roi->width, roi->height};
+  size_t        work_group_size;
+  cl_uint       cl_iterations   = o->iterations;
+  cl_int        cl_err          = 0;
+  cl_int        cl_x_0          = roi->x;
+  cl_int        cl_y_0          = roi->y;
+  cl_float      cl_scale        = o->scale / 50.0;
+  cl_float      cl_shape        = o->shape;
+  cl_uint       cl_rank         = o->rank;
+  cl_uint       cl_seed         = o->seed;
+  cl_int        cl_palettize    = (cl_int)o->palettize;
+
+  if (!cl_data)
+  {
+    const char *kernel_name[] = {"kernel_noise", NULL};
+    cl_data = gegl_cl_compile_and_build (noise_cell_cl_source, kernel_name);
+
+    if (!cl_data)
+      return TRUE;
+  }
+
+  cl_err = gegl_cl_set_kernel_args (cl_data->kernel[0],
+                                    sizeof(cl_mem), &out_tex,
+                                    sizeof(cl_int), &cl_x_0,
+                                    sizeof(cl_int), &cl_y_0,
+                                    sizeof(cl_uint), &cl_iterations,
+                                    sizeof(cl_float), &cl_scale,
+                                    sizeof(cl_float), &cl_shape,
+                                    sizeof(cl_uint), &cl_rank,
+                                    sizeof(cl_uint), &cl_seed,
+                                    sizeof(cl_int), &cl_palettize,
+                                    NULL);
+  CL_CHECK;
+
+  cl_err = gegl_clGetKernelWorkGroupInfo (cl_data->kernel[0],
+                                          gegl_cl_get_device (),
+                                          CL_KERNEL_WORK_GROUP_SIZE,
+                                          sizeof (size_t), &work_group_size,
+                                          NULL);
+  CL_CHECK;
+
+  cl_err = gegl_clEnqueueNDRangeKernel (gegl_cl_get_command_queue (),
+                                        cl_data->kernel[0], 2,
+                                        NULL, gbl_size, NULL,
+                                        0, NULL, NULL);
+  CL_CHECK;
+
+  cl_err = gegl_clFinish (gegl_cl_get_command_queue ());
+  CL_CHECK;
+
+  return FALSE;
+
+error:
+  return TRUE;
+}
+
+static gboolean
+c_process (GeglOperation       *operation,
+           void                *out_buf,
+           glong                n_pixels,
+           const GeglRectangle *roi,
+           gint                 level)
+{
+  GeglChantO *o         = GEGL_CHANT_PROPERTIES (operation);
+  Context     context;
+  gfloat     *pixel;
+  gint        s, t;
+
+  context.seed = o->seed;
+  context.rank = o->rank;
+  context.shape = o->shape;
+  context.palettize = o->palettize;
+
+  for (t = 0, pixel = out_buf ; t < roi->height ; t += 1)
+    {
+      for (s = 0 ; s < roi->width ; s += 1, pixel += 1)
+        {
+          gint    i;
+          gdouble c, d;
+
+          /* Pile up noise octaves onto the output value. */
+
+          for (i = 0, c = 1, d = o->scale / 50.0, *pixel = 0;
+               i < o->iterations;
+               c *= 2, d *= 2, i += 1) {
+            *pixel += noise2 ((double) (s + roi->x) * d,
+                              (double) (t + roi->y) * d,
+                              &context) / c;
+          }
+        }
+    }
+
+  return  TRUE;
+}
+
+static gboolean
+process (GeglOperation       *operation,
+         GeglBuffer          *out_buf,
+         const GeglRectangle *roi,
+         gint                 level)
+{
+  GeglBufferIterator *iter;
+  const Babl         *out_format = gegl_operation_get_format (operation,
+                                                              "output");
+
+  g_assert(babl_format_get_n_components (out_format) == 1 &&
+           babl_format_get_type (out_format, 0) == babl_type ("float"));
+
+  if (gegl_operation_use_opencl (operation))
+    {
+      GeglBufferClIterator *cl_iter;
+      gboolean              err;
+
+      GEGL_NOTE (GEGL_DEBUG_OPENCL, "GEGL_OPERATION_POINT_RENDER: %s", GEGL_OPERATION_GET_CLASS 
(operation)->name);
+
+      cl_iter = gegl_buffer_cl_iterator_new (out_buf, roi, out_format, GEGL_CL_BUFFER_WRITE);
+
+      while (gegl_buffer_cl_iterator_next (cl_iter, &err) && !err)
+        {
+          err = cl_process (operation, cl_iter->tex[0], cl_iter->roi);
+
+          if (err)
+            {
+              gegl_buffer_cl_iterator_stop (cl_iter);
+              break;
+            }
+        }
+
+      if (err)
+        GEGL_NOTE (GEGL_DEBUG_OPENCL, "Error: %s", GEGL_OPERATION_GET_CLASS (operation)->name);
+      else
+        return TRUE;
+    }
+
+  iter = gegl_buffer_iterator_new (out_buf, roi, level, out_format,
+                                   GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
+
+  while (gegl_buffer_iterator_next (iter))
+    c_process (operation, iter->data[0], iter->length, &iter->roi[0], level);
+
+  return  TRUE;
+}
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+  GeglOperationClass       *operation_class;
+  GeglOperationSourceClass *source_class;
+
+  operation_class = GEGL_OPERATION_CLASS (klass);
+  source_class = GEGL_OPERATION_SOURCE_CLASS (klass);
+
+  source_class->process = process;
+  operation_class->get_bounding_box = get_bounding_box;
+  operation_class->prepare = prepare;
+  operation_class->opencl_support = TRUE;
+
+  gegl_operation_class_set_keys (operation_class,
+    "name"       , "gegl:cell-noise",
+    "categories" , "render",
+    "description", _("Generates a cellular texture."),
+    NULL);
+}
+
+#endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3cc207c..bb248f6 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -63,6 +63,7 @@ operations/common/motion-blur-circular.c
 operations/common/motion-blur-linear.c
 operations/common/motion-blur-zoom.c
 operations/common/noise.c
+operations/common/noise-cell.c
 operations/common/noise-cie-lch.c
 operations/common/noise-hsv.c
 operations/common/noise-hurl.c
diff --git a/tests/compositions/Makefile.am b/tests/compositions/Makefile.am
index eb1d481..d0488a1 100644
--- a/tests/compositions/Makefile.am
+++ b/tests/compositions/Makefile.am
@@ -34,6 +34,7 @@ TESTS = \
   image-compare.xml               \
   mantiuk06.xml                   \
   noise-hurl.xml                 \
+  noise-cell.xml                 \
   pixelize.xml                    \
   posterize.xml                   \
   red-eye-removal.xml             \
diff --git a/tests/compositions/noise-cell.xml b/tests/compositions/noise-cell.xml
new file mode 100644
index 0000000..e3c5d33
--- /dev/null
+++ b/tests/compositions/noise-cell.xml
@@ -0,0 +1,152 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<gegl>
+  <node operation='gegl:add'>
+      <params>
+        <param name='value'>0</param>
+      </params>
+      <node operation='gegl:translate'>
+          <params>
+            <param name='origin-x'>0</param>
+            <param name='origin-y'>0</param>
+            <param name='sampler'>linear</param>
+            <param name='x'>128</param>
+            <param name='y'>128</param>
+          </params>
+      </node>
+      <node operation='gegl:crop'>
+          <params>
+            <param name='x'>-64</param>
+            <param name='y'>-64</param>
+            <param name='width'>128</param>
+            <param name='height'>128</param>
+          </params>
+      </node>
+      <node operation='gegl:cell-noise'>
+          <params>
+            <param name='seed'>0</param>
+            <param name='scale'>1</param>
+            <param name='shape'>2</param>
+            <param name='rank'>3</param>
+            <param name='iterations'>3</param>
+            <param name='palettize'>false</param>
+          </params>
+      </node>
+  </node>
+  <node operation='gegl:add'>
+      <params>
+        <param name='value'>0</param>
+      </params>
+      <node operation='gegl:translate'>
+          <params>
+            <param name='origin-x'>0</param>
+            <param name='origin-y'>0</param>
+            <param name='sampler'>linear</param>
+            <param name='x'>0</param>
+            <param name='y'>128</param>
+          </params>
+      </node>
+      <node operation='gegl:crop'>
+          <params>
+            <param name='x'>-64</param>
+            <param name='y'>-64</param>
+            <param name='width'>128</param>
+            <param name='height'>128</param>
+          </params>
+      </node>
+      <node operation='gegl:cell-noise'>
+          <params>
+            <param name='seed'>0</param>
+            <param name='scale'>1</param>
+            <param name='shape'>2</param>
+            <param name='rank'>1</param>
+            <param name='iterations'>1</param>
+            <param name='palettize'>true</param>
+          </params>
+      </node>
+  </node>
+  <node operation='gegl:add'>
+      <params>
+        <param name='value'>0</param>
+      </params>
+      <node operation='gegl:translate'>
+          <params>
+            <param name='origin-x'>0</param>
+            <param name='origin-y'>0</param>
+            <param name='sampler'>linear</param>
+            <param name='x'>128</param>
+            <param name='y'>0</param>
+          </params>
+      </node>
+      <node operation='gegl:crop'>
+          <params>
+            <param name='x'>-64</param>
+            <param name='y'>-64</param>
+            <param name='width'>128</param>
+            <param name='height'>128</param>
+          </params>
+      </node>
+      <node operation='gegl:subtract'>
+          <params>
+            <param name='value'>0</param>
+          </params>
+          <node operation='gegl:cell-noise'>
+              <params>
+                <param name='seed'>0</param>
+                <param name='scale'>1</param>
+                <param name='shape'>2</param>
+                <param name='rank'>1</param>
+                <param name='iterations'>1</param>
+                <param name='palettize'>false</param>
+              </params>
+          </node>
+      </node>
+      <node operation='gegl:cell-noise'>
+          <params>
+            <param name='seed'>0</param>
+            <param name='scale'>1</param>
+            <param name='shape'>2</param>
+            <param name='rank'>2</param>
+            <param name='iterations'>1</param>
+            <param name='palettize'>false</param>
+          </params>
+      </node>
+  </node>
+  <node operation='gegl:add'>
+      <params>
+        <param name='value'>0</param>
+      </params>
+      <node operation='gegl:crop'>
+          <params>
+            <param name='x'>-64</param>
+            <param name='y'>-64</param>
+            <param name='width'>128</param>
+            <param name='height'>128</param>
+          </params>
+      </node>
+      <node operation='gegl:cell-noise'>
+          <params>
+            <param name='seed'>0</param>
+            <param name='scale'>1</param>
+            <param name='shape'>2</param>
+            <param name='rank'>1</param>
+            <param name='iterations'>1</param>
+            <param name='palettize'>false</param>
+          </params>
+      </node>
+  </node>
+  <node operation='gegl:crop'>
+      <params>
+        <param name='x'>-64</param>
+        <param name='y'>-64</param>
+        <param name='width'>256</param>
+        <param name='height'>256</param>
+      </params>
+  </node>
+  <node operation='gegl:color'>
+      <params>
+        <param name='value'>rgb(0, 0, 0)</param>
+        <param name='format'></param>
+      </params>
+  </node>
+</gegl>
+
diff --git a/tests/compositions/reference/noise-cell.png b/tests/compositions/reference/noise-cell.png
new file mode 100644
index 0000000..89667f4
Binary files /dev/null and b/tests/compositions/reference/noise-cell.png differ



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