[gegl] add gegl_random_ functions, for reproducable positional random



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]