[gegl] add gegl_random_ functions, for reproducable positional random
- From: Ãyvind KolÃs <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] add gegl_random_ functions, for reproducable positional random
- Date: Tue, 11 Dec 2012 04:40:36 +0000 (UTC)
commit fa59ada99a6a45a09a6a9376792b3659537021c0
Author: Ãyvind KolÃs <pippin gimp org>
Date: Tue Dec 11 13:38:11 2012 +1100
add gegl_random_ functions, for reproducable positional random
This is an implementation using a set of prime-sizes lookuptables that are
cyclicly iterated and combined in paralell.
This is an initial implementation that only caches values/setup needed for one
seed.
gegl/Makefile.am | 1 +
gegl/gegl-random.c | 152 ++++++++++++++++++++++++++++++++++++++++
gegl/gegl.h | 6 ++
operations/common/noise-slur.c | 69 ++++++++++--------
4 files changed, 197 insertions(+), 31 deletions(-)
---
diff --git a/gegl/Makefile.am b/gegl/Makefile.am
index 601cade..83aa1ce 100644
--- a/gegl/Makefile.am
+++ b/gegl/Makefile.am
@@ -76,6 +76,7 @@ GEGL_introspectable_sources = \
gegl-utils.c \
gegl-lookup.c \
gegl-xml.c \
+ gegl-random.c \
gegl-matrix.c \
\
gegl-lookup.h \
diff --git a/gegl/gegl-random.c b/gegl/gegl-random.c
new file mode 100644
index 0000000..b2d0436
--- /dev/null
+++ b/gegl/gegl-random.c
@@ -0,0 +1,152 @@
+/* This file is part of 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 2012 Ãyvind KolÃs
+ */
+
+#include <glib.h>
+
+/* a set of reasonably large primes to choose from for array sizes
+ */
+static long primes[]={
+ 99989, 99991,100003,100019,100043,100049,100057,100069,100103,100109,
+ 100129,100151,100153,100169,100183,100189,100193,100207,100213,100237,
+ 100267,100271,100279,100291,100297,100313,100333,100343,100357,100361,
+ 100363,100379,100391,100393,100403,100411,100417,100447,100459,100469,
+ 100483,100493,100501,100511,100517,100519,100523,100537,100547,100549,
+ 100559,100591,100609,100613,100621,100649,100669,100673,100693,100699,
+ 100703,100733,100741,100747,100769,100787,100799,100801,100811,100823,
+ 100829,100847,100853,100907,100913,100927,100931,100937,100943,100957,
+ 100981,100987,100999,101009,101021,101027,101051,101063,101081,101089,
+ 101107,101113,101117,101119,101141,101149,101159,101161,101173,101183,
+ 101197,101203,101207,101209,101221,101267,101273,101279,101281,101287,
+ 101293,101323,101333,101341,101347,101363,101377,101383,101399,101411,
+ 101419,101429,101449,101467,101477,101483,101489,101501,101503,101513,
+ 101527,101531,101533,101537,101561,101573,101581,101599,101603,101611,
+ 101627,101641,101653,101663,101681,101693,101701,101719,101723,101737,
+ 101741,101747,101749,101771,101789,101797,101807,101833,101837,101839,
+ 101863,101869,101873,101879,101891,101917,101921,101929,101939,101957,
+ 101963,101977,101987,101999,102001,102013,102019,102023
+};
+
+#define N_PRIMES (sizeof(primes)/sizeof(primes[0]))
+
+/* these primes should not exist in the above set */
+#define XPRIME 103423
+#define ZPRIME 101359
+#define NPRIME 101111
+#define MAX_TABLES 4
+
+typedef struct GeglRandomSet
+{
+ int last_use;
+ int seed;
+ int tables;
+ gint64 *table[MAX_TABLES];
+ long prime[MAX_TABLES];
+} GeglRandomSet;
+
+#define make_index(x,y,n) ((x) * XPRIME + (z) * ZPRIME + (n) * NPRIME)
+
+static GeglRandomSet *gegl_random_set_new (int seed)
+{
+ GRand *gr;
+ int i;
+ GeglRandomSet *set = g_malloc0 (sizeof (GeglRandomSet));
+ set->seed = seed;
+ set->tables = MAX_TABLES;
+
+ gr = g_rand_new_with_seed (set->seed);
+ for (i = 0; i < set->tables; i++)
+ {
+ int j;
+ set->prime[i] = primes[g_rand_int_range (gr, 0, N_PRIMES-1)];
+ /*
+ * it might be possible to share a set of random data between sets
+ * and rejuggle the prime sizes chosen and keep an additional offset
+ * for feeding randomness.
+ *
+ */
+ set->table[i] = g_malloc0 (sizeof (guint64) * set->prime[i]);
+ for (j = 0; j < set->prime[i]; j++)
+ set->table[i][j] = (((gint64)g_rand_int (gr)) << 32) + g_rand_int(gr);
+ }
+ g_rand_free (gr);
+ return set;
+}
+
+static void gegl_random_set_free (GeglRandomSet *set)
+{
+ int i;
+ for (i = 0; i < set->tables; i++)
+ g_free (set->table[i]);
+ g_free (set);
+}
+
+/* a better cache with more entries would be nice ;) */
+static GeglRandomSet *cached = NULL;
+static long cachetime = 0;
+static inline GeglRandomSet *gegl_random_get_set_for_seed (int seed)
+{
+ if (cached && cached->seed == seed)
+ {
+ return cached;
+ }
+ else
+ {
+ if (cached)
+ gegl_random_set_free (cached);
+ cached = gegl_random_set_new (seed);
+ }
+ cached->last_use = cachetime++;
+ return cached;
+}
+
+gint64
+gegl_random_int (int seed, int x, int y, int z, int n)
+{
+ GeglRandomSet *set = gegl_random_get_set_for_seed (seed);
+ /* XXX: z is unhandled, it should average like a mipmap - or even
+ * use mipmap versions of random set
+ */
+ long idx = make_index(x,y,n);
+ gint64 ret = 0;
+ int i;
+ for (i = 0; i < set->tables; i++)
+ ret ^= set->table[i][idx % set->prime[i]];
+ return ret;
+}
+
+gint64
+gegl_random_int_range (int seed, int x, int y, int z, int n, int min, int max)
+{
+ gint64 ret = gegl_random_int (seed, x, y, z, n);
+ return (ret % (max-min)) + min;
+}
+
+/* transform [0..2^32] -> [0..1] */
+#define G_RAND_DOUBLE_TRANSFORM 2.3283064365386962890625e-10
+
+double
+gegl_random_double (int seed, int x, int y, int z, int n)
+{
+ return (gegl_random_int (seed,x,y,z,n) & 0xffffffff) * G_RAND_DOUBLE_TRANSFORM;
+}
+
+double
+gegl_random_double_range (int seed, int x, int y, int z, int n, double min, double max)
+{
+ return gegl_random_double (seed, x, y, z, n) * (max-min) + min;
+}
diff --git a/gegl/gegl.h b/gegl/gegl.h
index c471972..3964ba9 100644
--- a/gegl/gegl.h
+++ b/gegl/gegl.h
@@ -900,6 +900,12 @@ GeglNode *gegl_node (const gchar *op_type,
*/
GeglNode *gegl_graph (GeglNode *node);
+
+double gegl_random_double_range (int seed, int x, int y, int z, int n, double min, double max);
+gint64 gegl_random_int_range (int seed, int x, int y, int z, int n, int min, int max);
+gint64 gegl_random_int (int seed, int x, int y, int z, int n);
+double gegl_random_double (int seed, int x, int y, int z, int n);
+
#define GEGL_ALIGNED __restrict__ __attribute__((__aligned__ (16)))
G_END_DECLS
diff --git a/operations/common/noise-slur.c b/operations/common/noise-slur.c
index fb3d783..e3047a7 100644
--- a/operations/common/noise-slur.c
+++ b/operations/common/noise-slur.c
@@ -47,19 +47,19 @@ gegl_chant_int (repeat, _("Repeat"), 1, 100, 1, _("Repeat"))
#include <math.h>
#include <stdlib.h>
+
static void prepare (GeglOperation *operation)
{
GeglOperationAreaFilter *op_area;
op_area = GEGL_OPERATION_AREA_FILTER (operation);
op_area->left =
- op_area->right =
- op_area->top =
- op_area->bottom = 1;
+ op_area->right =
+ op_area->top =
+ op_area->bottom = 1;
gegl_operation_set_format (operation, "input" , babl_format ("RGBA float"));
gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
-
}
static gboolean
@@ -80,12 +80,9 @@ process (GeglOperation *operation,
gint n_pixels = result->width * result->height;
gint width = result->width;
GeglRectangle src_rect;
- GRand *gr;
gint k, b, i;
gint total_pixels;
- gr = g_rand_new_with_seed (o->seed);
-
tmp = gegl_buffer_new(result, babl_format ("RGBA float"));
src_rect.x = result->x - op_area->left;
@@ -103,6 +100,7 @@ process (GeglOperation *operation,
for (i = 0; i < o->repeat; i++)
{
+ int x, y;
n_pixels = result->width * result->height;
gegl_buffer_get (tmp, &src_rect, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP);
@@ -110,41 +108,50 @@ process (GeglOperation *operation,
in_pixel = src_buf + (src_rect.width + 1) * 4;
out_pixel = dst_buf;
+ x = result->x;
+ y = result->y;
+
while (n_pixels--)
{
- if (g_rand_double_range (gr, 0.0, 100.0) <= o->pct_random)
- {
- k = g_rand_int_range (gr, 0, 10);
-
- for (b = 0; b < 4; b++)
+ if (gegl_random_double_range (o->seed, x,y,0,i*2,0.0, 100.0) <= o->pct_random)
{
- switch (k )
+ k = gegl_random_int_range (o->seed, x,y,0,i*2+1,0, 10);
+
+ for (b = 0; b < 4; b++)
{
- case 0:
- out_pixel[b] = in_pixel[b - src_rect.width*4 - 4];
- break;
- case 9:
+ switch (k )
+ {
+ case 0:
+ out_pixel[b] = in_pixel[b - src_rect.width*4 - 4];
+ break;
+ case 9:
out_pixel[b] = in_pixel[b - src_rect.width*4 + 4];
- break;
- default:
+ break;
+ default:
out_pixel[b] = in_pixel[b - src_rect.width*4];
- break;
+ break;
+ }
}
}
- }
- else
- {
- for (b = 0; b < 4; b++)
+ else
{
- out_pixel[b] = in_pixel[b];
+ for (b = 0; b < 4; b++)
+ {
+ out_pixel[b] = in_pixel[b];
+ }
}
- }
- if (n_pixels % width == 0)
- in_pixel += 12;
- else
- in_pixel += 4;
- out_pixel += 4;
+ if (n_pixels % width == 0)
+ in_pixel += 12;
+ else
+ in_pixel += 4;
+ out_pixel += 4;
+ x++;
+ if (x>=result->x + result->width)
+ {
+ x=result->x;
+ y++;
+ }
}
gegl_buffer_set (tmp, result, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]