[gegl] operations: add a cell noise operation
- From: Daniel Sabo <daniels src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] operations: add a cell noise operation
- Date: Wed, 16 Apr 2014 06:23:37 +0000 (UTC)
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]