[lasem] svg_turbulence: implementation from librsvg



commit 2d576564499cf821c2906fd501ea0bb5e296d3a2
Author: Emmanuel Pacaud <emmanuel gnome org>
Date:   Tue Aug 4 23:30:50 2015 +0200

    svg_turbulence: implementation from librsvg

 docs/reference/lasem/Makefile.am |    1 +
 src/Makefile.am                  |    2 +
 src/lsmsvgattributes.h           |   10 ++
 src/lsmsvgdocument.c             |   19 ++-
 src/lsmsvgenums.c                |   42 +++++
 src/lsmsvgenums.h                |   18 +++
 src/lsmsvgfiltersurface.c        |  311 ++++++++++++++++++++++++++++++++++++++
 src/lsmsvgfiltersurface.h        |    4 +
 src/lsmsvgfilterturbulence.c     |  142 +++++++++++++++++
 src/lsmsvgfilterturbulence.h     |   61 ++++++++
 src/lsmsvgtraits.c               |   48 ++++++
 src/lsmsvgtraits.h               |    2 +
 src/lsmsvgtypes.h                |    1 +
 src/lsmsvgview.c                 |   27 ++++
 src/lsmsvgview.h                 |    5 +
 15 files changed, 685 insertions(+), 8 deletions(-)
---
diff --git a/docs/reference/lasem/Makefile.am b/docs/reference/lasem/Makefile.am
index 2b272bf..5b3c4fe 100644
--- a/docs/reference/lasem/Makefile.am
+++ b/docs/reference/lasem/Makefile.am
@@ -164,6 +164,7 @@ IGNORE_HFILES=\
        lsmsvgfiltermorphology.h                \
        lsmsvgfilterspecularlighting.h          \
        lsmsvgfiltertile.h                      \
+       lsmsvgfilterturbulence.h                \
        lsmsvgfiltersurface.h
 
 # Images to copy into HTML directory.
diff --git a/src/Makefile.am b/src/Makefile.am
index 14139da..e7053a2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -146,6 +146,7 @@ LASEM_SVG_SRCS =                            \
        lsmsvgfiltermorphology.c                \
        lsmsvgfilterspecularlighting.c          \
        lsmsvgfiltertile.c                      \
+       lsmsvgfilterturbulence.c                \
        lsmsvgfiltersurface.c
 
 LASEM_DOM_HDRS =                               \
@@ -268,6 +269,7 @@ LASEM_SVG_HDRS =                            \
        lsmsvgfiltermorphology.h                \
        lsmsvgfilterspecularlighting.h          \
        lsmsvgfiltertile.h                      \
+       lsmsvgfilterturbulence.h                \
        lsmsvgfiltersurface.h
 
 
diff --git a/src/lsmsvgattributes.h b/src/lsmsvgattributes.h
index 280c6e8..2f90678 100644
--- a/src/lsmsvgattributes.h
+++ b/src/lsmsvgattributes.h
@@ -148,6 +148,16 @@ typedef struct {
        LsmSvgOneOrTwoInteger value;
 } LsmSvgOneOrTwoIntegerAttribute;
 
+typedef struct {
+       LsmAttribute base;
+       LsmSvgStitchTiles value;
+} LsmSvgStitchTilesAttribute;
+
+typedef struct {
+       LsmAttribute base;
+       LsmSvgTurbulenceType value;
+} LsmSvgTurbulenceTypeAttribute;
+
 G_END_DECLS
 
 #endif
diff --git a/src/lsmsvgdocument.c b/src/lsmsvgdocument.c
index bf7a6d2..f341360 100644
--- a/src/lsmsvgdocument.c
+++ b/src/lsmsvgdocument.c
@@ -41,6 +41,7 @@
 #include <lsmsvgfiltermergenode.h>
 #include <lsmsvgfiltermorphology.h>
 #include <lsmsvgfilterspecularlighting.h>
+#include <lsmsvgfilterturbulence.h>
 #include <lsmsvgfiltertile.h>
 #include <lsmsvggelement.h>
 #include <lsmsvgimageelement.h>
@@ -158,28 +159,30 @@ _create_element (LsmDomDocument *document, const char *tag_name)
                node = lsm_svg_filter_blend_new ();
        else if (strcmp (tag_name, "feComposite") == 0)
                node = lsm_svg_filter_composite_new ();
+       else if (strcmp (tag_name, "feColorMatrix") == 0)
+               node = lsm_svg_filter_color_matrix_new ();
+       else if (strcmp (tag_name, "feConvolveMatrix") == 0)
+               node = lsm_svg_filter_convolve_matrix_new ();
        else if (strcmp (tag_name, "feFlood") == 0)
                node = lsm_svg_filter_flood_new ();
        else if (strcmp (tag_name, "feGaussianBlur") == 0)
                node = lsm_svg_filter_gaussian_blur_new ();
+       else if (strcmp (tag_name, "feImage") == 0)
+               node = lsm_svg_filter_image_new ();
        else if (strcmp (tag_name, "feMerge") == 0)
                node = lsm_svg_filter_merge_new ();
        else if (strcmp (tag_name, "feMergeNode") == 0)
                node = lsm_svg_filter_merge_node_new ();
+       else if (strcmp (tag_name, "feMorphology") == 0)
+               node = lsm_svg_filter_morphology_new ();
        else if (strcmp (tag_name, "feOffset") == 0)
                node = lsm_svg_filter_offset_new ();
        else if (strcmp (tag_name, "feSpecularLighting") == 0)
                node = lsm_svg_filter_specular_lighting_new ();
-       else if (strcmp (tag_name, "feColorMatrix") == 0)
-               node = lsm_svg_filter_color_matrix_new ();
-       else if (strcmp (tag_name, "feConvolveMatrix") == 0)
-               node = lsm_svg_filter_convolve_matrix_new ();
-       else if (strcmp (tag_name, "feImage") == 0)
-               node = lsm_svg_filter_image_new ();
-       else if (strcmp (tag_name, "feMorphology") == 0)
-               node = lsm_svg_filter_morphology_new ();
        else if (strcmp (tag_name, "feTile") == 0)
                node = lsm_svg_filter_tile_new ();
+       else if (strcmp (tag_name, "feTurbulence") == 0)
+               node = lsm_svg_filter_turbulence_new ();
 
        if (node != NULL)
                lsm_debug_dom ("[LsmSvgDocument::create_element] Create a %s element", tag_name);
diff --git a/src/lsmsvgenums.c b/src/lsmsvgenums.c
index c5d12c4..502687f 100644
--- a/src/lsmsvgenums.c
+++ b/src/lsmsvgenums.c
@@ -607,3 +607,45 @@ lsm_svg_edge_mode_from_string (const char *string)
        return lsm_enum_value_from_string (string, lsm_svg_edge_mode_strings,
                                           G_N_ELEMENTS (lsm_svg_edge_mode_strings));
 }
+
+static const char *lsm_svg_stitch_tiles_strings[] = {
+       "noStitch",
+       "stitch"
+};
+
+const char *
+lsm_svg_stitch_tiles_to_string (LsmSvgStitchTiles stitch_tiles)
+{
+       if (stitch_tiles < 0 || stitch_tiles > LSM_SVG_STITCH_TILES_STITCH)
+               return NULL;
+
+       return lsm_svg_stitch_tiles_strings[stitch_tiles];
+}
+
+LsmSvgStitchTiles
+lsm_svg_stitch_tiles_from_string (const char *string)
+{
+       return lsm_enum_value_from_string (string, lsm_svg_stitch_tiles_strings,
+                                          G_N_ELEMENTS (lsm_svg_stitch_tiles_strings));
+}
+
+static const char *lsm_svg_turbulence_type_strings[] = {
+       "turbulence",
+       "fractalNoise"
+};
+
+const char *
+lsm_svg_turbulence_type_to_string (LsmSvgTurbulenceType turbulence_type)
+{
+       if (turbulence_type < 0 || turbulence_type > LSM_SVG_TURBULENCE_TYPE_FRACTAL_NOISE)
+               return NULL;
+
+       return lsm_svg_turbulence_type_strings[turbulence_type];
+}
+
+LsmSvgTurbulenceType
+lsm_svg_turbulence_type_from_string (const char *string)
+{
+       return lsm_enum_value_from_string (string, lsm_svg_turbulence_type_strings,
+                                          G_N_ELEMENTS (lsm_svg_turbulence_type_strings));
+}
diff --git a/src/lsmsvgenums.h b/src/lsmsvgenums.h
index 13c7bcd..f96a7c9 100644
--- a/src/lsmsvgenums.h
+++ b/src/lsmsvgenums.h
@@ -382,6 +382,24 @@ typedef enum {
 const char *           lsm_svg_edge_mode_to_string     (LsmSvgEdgeMode edge_mode);
 LsmSvgEdgeMode         lsm_svg_edge_mode_from_string   (const char *string);
 
+typedef enum {
+       LSM_SVG_STITCH_TILES_ERROR = -1,
+       LSM_SVG_STITCH_TILES_NO_STITCH,
+       LSM_SVG_STITCH_TILES_STITCH
+} LsmSvgStitchTiles;
+
+const char *           lsm_svg_stitch_tiles_to_string          (LsmSvgStitchTiles stitch_tiles);
+LsmSvgStitchTiles      lsm_svg_stitch_tiles_from_string        (const char *string);
+
+typedef enum {
+       LSM_SVG_TURBULENCE_TYPE_ERROR = -1,
+       LSM_SVG_TURBULENCE_TYPE_TURBULENCE,
+       LSM_SVG_TURBULENCE_TYPE_FRACTAL_NOISE
+} LsmSvgTurbulenceType;
+
+const char *           lsm_svg_turbulence_type_to_string       (LsmSvgTurbulenceType turbulence_type);
+LsmSvgTurbulenceType   lsm_svg_turbulence_type_from_string     (const char *string);
+
 G_END_DECLS
 
 #endif
diff --git a/src/lsmsvgfiltersurface.c b/src/lsmsvgfiltersurface.c
index 9c77d59..22bd22a 100644
--- a/src/lsmsvgfiltersurface.c
+++ b/src/lsmsvgfiltersurface.c
@@ -886,3 +886,314 @@ lsm_svg_filter_surface_morphology (LsmSvgFilterSurface *input, LsmSvgFilterSurfa
        cairo_destroy (cairo);
 }
 
+/* Produces results in the range [1, 2**31 - 2].
+   Algorithm is: r = (a * r) mod m
+   where a = 16807 and m = 2**31 - 1 = 2147483647
+   See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
+   To test: the algorithm should produce the result 1043618065
+   as the 10,000th generated number if the original seed is 1.
+*/
+#define feTurbulence_RAND_m 2147483647  /* 2**31 - 1 */
+#define feTurbulence_RAND_a 16807       /* 7**5; primitive root of m */
+#define feTurbulence_RAND_q 127773      /* m / a */
+#define feTurbulence_RAND_r 2836        /* m % a */
+#define feTurbulence_BSize 0x100
+#define feTurbulence_BM 0xff
+#define feTurbulence_PerlinN 0x1000
+#define feTurbulence_NP 12      /* 2^PerlinN */
+#define feTurbulence_NM 0xfff
+
+typedef struct {
+       double base_frequency_x;
+       double base_frequency_y;
+       int n_octaves;
+       double seed;
+       LsmSvgStitchTiles stitch_tiles;
+       LsmSvgTurbulenceType type;
+
+       int uLatticeSelector[feTurbulence_BSize + feTurbulence_BSize + 2];
+       double fGradient[4][feTurbulence_BSize + feTurbulence_BSize + 2][2];
+} LsmSvgTurbulence;
+
+struct feTurbulence_StitchInfo {
+       int nWidth;                 /* How much to subtract to wrap for stitching. */
+       int nHeight;
+       int nWrapX;                 /* Minimum value to wrap. */
+       int nWrapY;
+};
+
+static long
+feTurbulence_setup_seed (int lSeed)
+{
+       if (lSeed <= 0)
+               lSeed = -(lSeed % (feTurbulence_RAND_m - 1)) + 1;
+       if (lSeed > feTurbulence_RAND_m - 1)
+               lSeed = feTurbulence_RAND_m - 1;
+       return lSeed;
+}
+
+static long
+feTurbulence_random (int lSeed)
+{
+       long result;
+
+       result =
+               feTurbulence_RAND_a * (lSeed % feTurbulence_RAND_q) -
+               feTurbulence_RAND_r * (lSeed / feTurbulence_RAND_q);
+       if (result <= 0)
+               result += feTurbulence_RAND_m;
+       return result;
+}
+
+static void
+feTurbulence_init (LsmSvgTurbulence *turbulence)
+{
+       double s;
+       int i, j, k, lSeed;
+
+       lSeed = feTurbulence_setup_seed (turbulence->seed);
+       for (k = 0; k < 4; k++) {
+               for (i = 0; i < feTurbulence_BSize; i++) {
+                       turbulence->uLatticeSelector[i] = i;
+                       for (j = 0; j < 2; j++)
+                               turbulence->fGradient[k][i][j] =
+                                       (double) (((lSeed =
+                                                   feTurbulence_random (lSeed)) % (feTurbulence_BSize +
+                                                                                   feTurbulence_BSize)) -
+                                                 feTurbulence_BSize) / feTurbulence_BSize;
+                       s = (double) (sqrt
+                                     (turbulence->fGradient[k][i][0] * turbulence->fGradient[k][i][0] +
+                                      turbulence->fGradient[k][i][1] * turbulence->fGradient[k][i][1]));
+                       turbulence->fGradient[k][i][0] /= s;
+                       turbulence->fGradient[k][i][1] /= s;
+               }
+       }
+
+       while (--i) {
+               k = turbulence->uLatticeSelector[i];
+               turbulence->uLatticeSelector[i] = turbulence->uLatticeSelector[j =
+                       (lSeed =
+                        feTurbulence_random (lSeed)) %
+                       feTurbulence_BSize];
+               turbulence->uLatticeSelector[j] = k;
+       }
+
+       for (i = 0; i < feTurbulence_BSize + 2; i++) {
+               turbulence->uLatticeSelector[feTurbulence_BSize + i] = turbulence->uLatticeSelector[i];
+               for (k = 0; k < 4; k++)
+                       for (j = 0; j < 2; j++)
+                               turbulence->fGradient[k][feTurbulence_BSize + i][j] = 
turbulence->fGradient[k][i][j];
+       }
+}
+
+#define feTurbulence_s_curve(t) ( t * t * (3. - 2. * t) )
+#define feTurbulence_lerp(t, a, b) ( a + t * (b - a) )
+
+static double
+feTurbulence_noise2 (LsmSvgTurbulence * turbulence,
+                     int nColorChannel, double vec[2], struct feTurbulence_StitchInfo *pStitchInfo)
+{
+       int bx0, bx1, by0, by1, b00, b10, b01, b11;
+       double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
+       register int i, j;
+
+       t = vec[0] + feTurbulence_PerlinN;
+       bx0 = (int) t;
+       bx1 = bx0 + 1;
+       rx0 = t - (int) t;
+       rx1 = rx0 - 1.0f;
+       t = vec[1] + feTurbulence_PerlinN;
+       by0 = (int) t;
+       by1 = by0 + 1;
+       ry0 = t - (int) t;
+       ry1 = ry0 - 1.0f;
+
+       /* If stitching, adjust lattice points accordingly. */
+       if (pStitchInfo != NULL) {
+               if (bx0 >= pStitchInfo->nWrapX)
+                       bx0 -= pStitchInfo->nWidth;
+               if (bx1 >= pStitchInfo->nWrapX)
+                       bx1 -= pStitchInfo->nWidth;
+               if (by0 >= pStitchInfo->nWrapY)
+                       by0 -= pStitchInfo->nHeight;
+               if (by1 >= pStitchInfo->nWrapY)
+                       by1 -= pStitchInfo->nHeight;
+       }
+
+       bx0 &= feTurbulence_BM;
+       bx1 &= feTurbulence_BM;
+       by0 &= feTurbulence_BM;
+       by1 &= feTurbulence_BM;
+       i = turbulence->uLatticeSelector[bx0];
+       j = turbulence->uLatticeSelector[bx1];
+       b00 = turbulence->uLatticeSelector[i + by0];
+       b10 = turbulence->uLatticeSelector[j + by0];
+       b01 = turbulence->uLatticeSelector[i + by1];
+       b11 = turbulence->uLatticeSelector[j + by1];
+       sx = (double) (feTurbulence_s_curve (rx0));
+       sy = (double) (feTurbulence_s_curve (ry0));
+       q = turbulence->fGradient[nColorChannel][b00];
+       u = rx0 * q[0] + ry0 * q[1];
+       q = turbulence->fGradient[nColorChannel][b10];
+       v = rx1 * q[0] + ry0 * q[1];
+       a = feTurbulence_lerp (sx, u, v);
+       q = turbulence->fGradient[nColorChannel][b01];
+       u = rx0 * q[0] + ry1 * q[1];
+       q = turbulence->fGradient[nColorChannel][b11];
+       v = rx1 * q[0] + ry1 * q[1];
+       b = feTurbulence_lerp (sx, u, v);
+
+       return feTurbulence_lerp (sy, a, b);
+}
+
+static double
+feTurbulence_turbulence (LsmSvgTurbulence * turbulence,
+                         int nColorChannel, double *point,
+                         double fTileX, double fTileY, double fTileWidth, double fTileHeight)
+{
+       struct feTurbulence_StitchInfo stitch;
+       struct feTurbulence_StitchInfo *pStitchInfo = NULL; /* Not stitching when NULL. */
+
+       double fSum = 0.0f, vec[2], ratio = 1.;
+       int nOctave;
+
+       /* Adjust the base frequencies if necessary for stitching. */
+       if (turbulence->stitch_tiles == LSM_SVG_STITCH_TILES_STITCH) {
+               /* When stitching tiled turbulence, the frequencies must be adjusted
+                  so that the tile borders will be continuous. */
+               if (turbulence->base_frequency_x != 0.0) {
+                       double fLoFreq = (double) (floor (fTileWidth * turbulence->base_frequency_x)) / 
fTileWidth;
+                       double fHiFreq = (double) (ceil (fTileWidth * turbulence->base_frequency_x)) / 
fTileWidth;
+                       if (turbulence->base_frequency_x / fLoFreq < fHiFreq / turbulence->base_frequency_x)
+                               turbulence->base_frequency_x = fLoFreq;
+                       else
+                               turbulence->base_frequency_x = fHiFreq;
+               }
+
+               if (turbulence->base_frequency_y != 0.0) {
+                       double fLoFreq = (double) (floor (fTileHeight * turbulence->base_frequency_y)) / 
fTileHeight;
+                       double fHiFreq = (double) (ceil (fTileHeight * turbulence->base_frequency_y)) / 
fTileHeight;
+                       if (turbulence->base_frequency_y / fLoFreq < fHiFreq / turbulence->base_frequency_y)
+                               turbulence->base_frequency_y = fLoFreq;
+                       else
+                               turbulence->base_frequency_y = fHiFreq;
+               }
+
+               /* Set up initial stitch values. */
+               pStitchInfo = &stitch;
+               stitch.nWidth = (int) (fTileWidth * turbulence->base_frequency_x + 0.5f);
+               stitch.nWrapX = fTileX * turbulence->base_frequency_x + feTurbulence_PerlinN + stitch.nWidth;
+               stitch.nHeight = (int) (fTileHeight * turbulence->base_frequency_y + 0.5f);
+               stitch.nWrapY = fTileY * turbulence->base_frequency_y + feTurbulence_PerlinN + stitch.nHeight;
+       }
+
+       vec[0] = point[0] * turbulence->base_frequency_x;
+       vec[1] = point[1] * turbulence->base_frequency_y;
+
+       for (nOctave = 0; nOctave < turbulence->n_octaves; nOctave++) {
+               if (turbulence->type == LSM_SVG_TURBULENCE_TYPE_FRACTAL_NOISE)
+                       fSum +=
+                               (double) (feTurbulence_noise2 (turbulence, nColorChannel, vec, pStitchInfo) / 
ratio);
+               else
+                       fSum +=
+                               (double) (fabs (feTurbulence_noise2 (turbulence, nColorChannel, vec, 
pStitchInfo)) /
+                                         ratio);
+
+               vec[0] *= 2;
+               vec[1] *= 2;
+               ratio *= 2;
+
+               if (pStitchInfo != NULL) {
+                       /* Update stitch values. Subtracting PerlinN before the multiplication and
+                          adding it afterward simplifies to subtracting it once. */
+                       stitch.nWidth *= 2;
+                       stitch.nWrapX = 2 * stitch.nWrapX - feTurbulence_PerlinN;
+                       stitch.nHeight *= 2;
+                       stitch.nWrapY = 2 * stitch.nWrapY - feTurbulence_PerlinN;
+               }
+       }
+
+       return fSum;
+}
+void
+lsm_svg_filter_surface_turbulence (LsmSvgFilterSurface *output,
+                                  double base_frequency_x, double base_frequency_y,
+                                  int n_octaves, double seed,
+                                  LsmSvgStitchTiles stitch_tiles, LsmSvgTurbulenceType type)
+{
+       LsmSvgTurbulence turbulence;
+       cairo_t *cairo;
+       gint x, y, x1, x2, y1, y2;
+       gint width, height, tileWidth, tileHeight;
+       gint rowstride;
+       guchar *output_pixels;
+       cairo_matrix_t affine;
+
+       g_return_if_fail (output != NULL);
+
+       width = cairo_image_surface_get_width (output->surface);
+       height = cairo_image_surface_get_height (output->surface);
+
+       if (height < 1 || width < 1)
+               return;
+
+       cairo = cairo_create (output->surface);
+
+       output_pixels = cairo_image_surface_get_data (output->surface);
+       rowstride = cairo_image_surface_get_stride (output->surface);
+
+       x1 = CLAMP (output->subregion.x, 0, width);
+       x2 = CLAMP (output->subregion.x + output->subregion.width, 0, width);
+       y1 = CLAMP (output->subregion.y, 0, height);
+       y2 = CLAMP (output->subregion.y + output->subregion.height, 0, height);
+
+       cairo_matrix_init_identity (&affine);
+
+       turbulence.base_frequency_x = base_frequency_x;
+       turbulence.base_frequency_y = base_frequency_y;
+       turbulence.n_octaves = n_octaves;
+       turbulence.seed = seed;
+       turbulence.stitch_tiles = stitch_tiles;
+       turbulence.type = type;
+
+       feTurbulence_init (&turbulence);
+
+       tileWidth = x2 - x1;
+       tileHeight = y2 - y1;
+
+       for (y = 0; y < tileHeight; y++) {
+               for (x = 0; x < tileWidth; x++) {
+                       gint i;
+                       double point[2];
+                       guchar *pixel;
+                       point[0] = affine.xx * (x + x1) + affine.xy * (y + y1) + affine.x0;
+                       point[1] = affine.yx * (x + x1) + affine.yy * (y + y1) + affine.y0;
+
+                       pixel = output_pixels + 4 * (x + x1) + (y + y1) * rowstride;
+
+                       for (i = 0; i < 4; i++) {
+                               double cr;
+
+                               cr = feTurbulence_turbulence (&turbulence, i, point, (double) x, (double) y,
+                                                             (double) tileWidth, (double) tileHeight);
+
+                               if (type == LSM_SVG_TURBULENCE_TYPE_FRACTAL_NOISE)
+                                       cr = ((cr * 255.) + 255.) / 2.;
+                               else
+                                       cr = (cr * 255.);
+
+                               cr = CLAMP (cr, 0., 255.);
+
+                               pixel[channelmap[i]] = (guchar) cr;
+                       }
+                       for (i = 0; i < 3; i++)
+                               pixel[channelmap[i]] =
+                                       pixel[channelmap[i]] * pixel[channelmap[3]] / 255;
+
+               }
+       }
+
+       cairo_surface_mark_dirty (output->surface);
+
+       cairo_destroy (cairo);
+}
diff --git a/src/lsmsvgfiltersurface.h b/src/lsmsvgfiltersurface.h
index 45ab6ed..42129ac 100644
--- a/src/lsmsvgfiltersurface.h
+++ b/src/lsmsvgfiltersurface.h
@@ -76,6 +76,10 @@ void                         lsm_svg_filter_surface_morphology       (LsmSvgFilterSurface 
*input_surface,
 void                   lsm_svg_filter_surface_specular_lighting(LsmSvgFilterSurface *output_surface,
                                                                 double surface_scale, double 
specular_constant, double specular_exponent,
                                                                 double dx, double dy);
+void                   lsm_svg_filter_surface_turbulence       (LsmSvgFilterSurface *output_surface,
+                                                                double base_frequency_x, double 
base_frequency_y,
+                                                                int n_octaves, double seed,
+                                                                LsmSvgStitchTiles stitch_tiles, 
LsmSvgTurbulenceType type);
 
 G_END_DECLS
 
diff --git a/src/lsmsvgfilterturbulence.c b/src/lsmsvgfilterturbulence.c
new file mode 100644
index 0000000..bf41b8d
--- /dev/null
+++ b/src/lsmsvgfilterturbulence.c
@@ -0,0 +1,142 @@
+/* Lasem
+ * 
+ * Copyright © 2012 Emmanuel Pacaud
+ *
+ * This library 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 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author:
+ *     Emmanuel Pacaud <emmanuel gnome org>
+ */
+
+#include <lsmsvgfilterturbulence.h>
+#include <lsmsvgview.h>
+
+static GObjectClass *parent_class;
+
+/* GdomNode implementation */
+
+static const char *
+lsm_svg_filter_turbulence_get_node_name (LsmDomNode *node)
+{
+       return "feTurbulence";
+}
+
+/* LsmSvgElement implementation */
+
+static void
+lsm_svg_filter_turbulence_apply  (LsmSvgFilterPrimitive *self, LsmSvgView *view,
+                            const char *input, const char *output, const LsmBox *subregion)
+{
+       LsmSvgFilterTurbulence *turbulence = LSM_SVG_FILTER_TURBULENCE (self);
+
+       lsm_svg_view_apply_turbulence (view, output, subregion,
+                                      turbulence->base_frequency.value.a,
+                                      turbulence->base_frequency.value.b,
+                                      turbulence->n_octaves.value,
+                                      turbulence->seed.value,
+                                      turbulence->stitch_tiles.value,
+                                      turbulence->type.value);
+}
+
+/* LsmSvgFilterTurbulence implementation */
+
+LsmDomNode *
+lsm_svg_filter_turbulence_new (void)
+{
+       return g_object_new (LSM_TYPE_SVG_FILTER_TURBULENCE, NULL);
+}
+
+static const LsmSvgOneOrTwoDouble base_frequency_default = {0.0, 0.0};
+static const int n_octaves_default = 1;
+static const double seed_default = 0.0;
+static const LsmSvgStitchTiles stitch_tiles_default = LSM_SVG_STITCH_TILES_NO_STITCH;
+static const LsmSvgTurbulenceType type_default = LSM_SVG_TURBULENCE_TYPE_TURBULENCE;
+
+static void
+lsm_svg_filter_turbulence_init (LsmSvgFilterTurbulence *self)
+{
+       self->base_frequency.value = base_frequency_default;
+       self->n_octaves.value = n_octaves_default;
+       self->seed.value = seed_default;
+       self->stitch_tiles.value = stitch_tiles_default;
+       self->type.value = type_default;
+}
+
+static void
+lsm_svg_filter_turbulence_finalize (GObject *object)
+{
+       parent_class->finalize (object);
+}
+
+/* LsmSvgFilterTurbulence class */
+
+static const LsmAttributeInfos lsm_svg_filter_turbulence_attribute_infos[] = {
+       {
+               .name = "baseFrequency",
+               .attribute_offset = offsetof (LsmSvgFilterTurbulence, base_frequency),
+               .trait_class = &lsm_svg_one_or_two_double_trait_class,
+               .trait_default = &base_frequency_default
+       },
+       {
+               .name = "numOctaves",
+               .attribute_offset = offsetof (LsmSvgFilterTurbulence, n_octaves),
+               .trait_class = &lsm_integer_trait_class,
+               .trait_default = &n_octaves_default
+       },
+       {
+               .name = "seed",
+               .attribute_offset = offsetof (LsmSvgFilterTurbulence, seed),
+               .trait_class = &lsm_double_trait_class,
+               .trait_default = &seed_default
+       },
+       {
+               .name = "stitchTiles",
+               .attribute_offset = offsetof (LsmSvgFilterTurbulence, stitch_tiles),
+               .trait_class = &lsm_svg_stitch_tiles_trait_class,
+               .trait_default = &stitch_tiles_default
+       },
+       {
+               .name = "type",
+               .attribute_offset = offsetof (LsmSvgFilterTurbulence, type),
+               .trait_class = &lsm_svg_turbulence_type_trait_class,
+               .trait_default = &type_default
+       }
+};
+
+static void
+lsm_svg_filter_turbulence_class_init (LsmSvgFilterTurbulenceClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       LsmDomNodeClass *d_node_class = LSM_DOM_NODE_CLASS (klass);
+       LsmSvgElementClass *s_element_class = LSM_SVG_ELEMENT_CLASS (klass);
+       LsmSvgFilterPrimitiveClass *f_primitive_class = LSM_SVG_FILTER_PRIMITIVE_CLASS (klass);
+
+       parent_class = g_type_class_peek_parent (klass);
+
+       object_class->finalize = lsm_svg_filter_turbulence_finalize;
+
+       d_node_class->get_node_name = lsm_svg_filter_turbulence_get_node_name;
+
+       s_element_class->attribute_manager = lsm_attribute_manager_duplicate 
(s_element_class->attribute_manager);
+
+       lsm_attribute_manager_add_attributes (s_element_class->attribute_manager,
+                                             G_N_ELEMENTS (lsm_svg_filter_turbulence_attribute_infos),
+                                             lsm_svg_filter_turbulence_attribute_infos);
+
+       f_primitive_class->apply = lsm_svg_filter_turbulence_apply;
+}
+
+G_DEFINE_TYPE (LsmSvgFilterTurbulence, lsm_svg_filter_turbulence, LSM_TYPE_SVG_FILTER_PRIMITIVE)
diff --git a/src/lsmsvgfilterturbulence.h b/src/lsmsvgfilterturbulence.h
new file mode 100644
index 0000000..b60c51c
--- /dev/null
+++ b/src/lsmsvgfilterturbulence.h
@@ -0,0 +1,61 @@
+/* Lasem
+ *
+ * Copyright © 2015 Emmanuel Pacaud
+ *
+ * This library 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 2 of the License, or (at your option) any later version.
+ *
+ * This library 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 this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author:
+ *     Emmanuel Pacaud <emmanuel gnome org>
+ */
+
+#ifndef LSM_SVG_FILTER_TURBULENCE_H
+#define LSM_SVG_FILTER_TURBULENCE_H
+
+#include <lsmsvgtypes.h>
+#include <lsmsvgfilterprimitive.h>
+
+G_BEGIN_DECLS
+
+#define LSM_TYPE_SVG_FILTER_TURBULENCE             (lsm_svg_filter_turbulence_get_type ())
+#define LSM_SVG_FILTER_TURBULENCE(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
LSM_TYPE_SVG_FILTER_TURBULENCE, LsmSvgFilterTurbulence))
+#define LSM_SVG_FILTER_TURBULENCE_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), 
LSM_TYPE_SVG_FILTER_TURBULENCE, LsmSvgFilterTurbulenceClass))
+#define LSM_IS_SVG_FILTER_TURBULENCE(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
LSM_TYPE_SVG_FILTER_TURBULENCE))
+#define LSM_IS_SVG_FILTER_TURBULENCE_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), 
LSM_TYPE_SVG_FILTER_TURBULENCE))
+#define LSM_SVG_FILTER_TURBULENCE_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS((obj), 
LSM_TYPE_SVG_FILTER_TURBULENCE, LsmSvgFilterTurbulenceClass))
+
+typedef struct _LsmSvgFilterTurbulenceClass LsmSvgFilterTurbulenceClass;
+
+struct _LsmSvgFilterTurbulence {
+       LsmSvgFilterPrimitive base;
+
+       LsmSvgOneOrTwoDoubleAttribute base_frequency;
+       LsmSvgIntegerAttribute n_octaves;
+       LsmSvgDoubleAttribute seed;
+       LsmSvgStitchTilesAttribute stitch_tiles;
+       LsmSvgTurbulenceTypeAttribute type;
+};
+
+struct _LsmSvgFilterTurbulenceClass {
+       LsmSvgFilterPrimitiveClass  element_class;
+};
+
+GType lsm_svg_filter_turbulence_get_type (void);
+
+LsmDomNode *   lsm_svg_filter_turbulence_new           (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/lsmsvgtraits.c b/src/lsmsvgtraits.c
index 5120049..25df16a 100644
--- a/src/lsmsvgtraits.c
+++ b/src/lsmsvgtraits.c
@@ -1407,3 +1407,51 @@ const LsmTraitClass lsm_svg_edge_mode_trait_class = {
        .from_string = lsm_svg_edge_mode_trait_from_string,
        .to_string = lsm_svg_edge_mode_trait_to_string
 };
+
+static gboolean
+lsm_svg_stitch_tiles_trait_from_string (LsmTrait *abstract_trait, char *string)
+{
+       LsmSvgStitchTiles *trait = (LsmSvgStitchTiles *) abstract_trait;
+
+       *trait = lsm_svg_stitch_tiles_from_string (string);
+
+       return *trait >= 0;
+}
+
+static char *
+lsm_svg_stitch_tiles_trait_to_string (LsmTrait *abstract_trait)
+{
+       LsmSvgStitchTiles *trait = (LsmSvgStitchTiles *) abstract_trait;
+
+       return g_strdup (lsm_svg_stitch_tiles_to_string (*trait));
+}
+
+const LsmTraitClass lsm_svg_stitch_tiles_trait_class = {
+       .size = sizeof (LsmSvgStitchTiles),
+       .from_string = lsm_svg_stitch_tiles_trait_from_string,
+       .to_string = lsm_svg_stitch_tiles_trait_to_string
+};
+
+static gboolean
+lsm_svg_turbulence_type_trait_from_string (LsmTrait *abstract_trait, char *string)
+{
+       LsmSvgTurbulenceType *trait = (LsmSvgTurbulenceType *) abstract_trait;
+
+       *trait = lsm_svg_turbulence_type_from_string (string);
+
+       return *trait >= 0;
+}
+
+static char *
+lsm_svg_turbulence_type_trait_to_string (LsmTrait *abstract_trait)
+{
+       LsmSvgTurbulenceType *trait = (LsmSvgTurbulenceType *) abstract_trait;
+
+       return g_strdup (lsm_svg_turbulence_type_to_string (*trait));
+}
+
+const LsmTraitClass lsm_svg_turbulence_type_trait_class = {
+       .size = sizeof (LsmSvgTurbulenceType),
+       .from_string = lsm_svg_turbulence_type_trait_from_string,
+       .to_string = lsm_svg_turbulence_type_trait_to_string
+};
diff --git a/src/lsmsvgtraits.h b/src/lsmsvgtraits.h
index a802494..22dd9ce 100644
--- a/src/lsmsvgtraits.h
+++ b/src/lsmsvgtraits.h
@@ -109,7 +109,9 @@ extern const LsmTraitClass lsm_svg_paint_trait_class;
 extern const LsmTraitClass lsm_svg_pattern_units_trait_class;
 extern const LsmTraitClass lsm_svg_preserve_aspect_ratio_trait_class;
 extern const LsmTraitClass lsm_svg_spread_method_trait_class;
+extern const LsmTraitClass lsm_svg_stitch_tiles_trait_class;
 extern const LsmTraitClass lsm_svg_text_anchor_trait_class;
+extern const LsmTraitClass lsm_svg_turbulence_type_trait_class;
 extern const LsmTraitClass lsm_svg_vector_trait_class;
 extern const LsmTraitClass lsm_svg_visibility_trait_class;
 extern const LsmTraitClass lsm_svg_writing_mode_trait_class;
diff --git a/src/lsmsvgtypes.h b/src/lsmsvgtypes.h
index 3675138..cf14d62 100644
--- a/src/lsmsvgtypes.h
+++ b/src/lsmsvgtypes.h
@@ -58,6 +58,7 @@ typedef struct _LsmSvgFilterMergeNode LsmSvgFilterMergeNode;
 typedef struct _LsmSvgFilterMorphology LsmSvgFilterMorphology;
 typedef struct _LsmSvgFilterOffset LsmSvgFilterOffset;
 typedef struct _LsmSvgFilterSpecularLighting LsmSvgFilterSpecularLighting;
+typedef struct _LsmSvgFilterTurbulence LsmSvgFilterTurbulence;
 typedef struct _LsmSvgFilterTile LsmSvgFilterTile;
 typedef struct _LsmSvgLineElement LsmSvgLineElement;
 typedef struct _LsmSvgPolylineElement LsmSvgPolylineElement;
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index 6b34f09..214b574 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -2302,6 +2302,33 @@ lsm_svg_view_apply_specular_lighting (LsmSvgView *view, const char *output, cons
 }
 
 void
+lsm_svg_view_apply_turbulence (LsmSvgView *view, const char *output, const LsmBox *subregion,
+                              double base_frequency_x, double base_frequency_y,
+                              int n_octaves, double seed,
+                              LsmSvgStitchTiles stitch_tiles,
+                              LsmSvgTurbulenceType type)
+{
+       LsmSvgFilterSurface *output_surface;
+       LsmSvgFilterSurface *input_surface;
+       LsmBox subregion_px;
+
+       g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+       input_surface = _get_filter_surface (view, NULL);
+
+       lsm_cairo_box_user_to_device (view->dom_view.cairo, &subregion_px, subregion);
+       output_surface = _create_filter_surface (view, output, input_surface, &subregion_px);
+
+       lsm_log_render ("[SvgView::apply_turbulence] subregion %gx%g px at %g,%g px",
+                       subregion_px.width, subregion_px.height,
+                       subregion_px.x, subregion_px.y);
+
+       cairo_user_to_device_distance (view->dom_view.cairo, &base_frequency_x, &base_frequency_y);
+
+       lsm_svg_filter_surface_turbulence (output_surface, base_frequency_x, base_frequency_y, n_octaves, 
seed, stitch_tiles, type);
+}
+
+void
 lsm_svg_view_apply_merge (LsmSvgView *view, const char *input, const char *output, const LsmBox *subregion)
 {
        LsmSvgFilterSurface *input_surface;
diff --git a/src/lsmsvgview.h b/src/lsmsvgview.h
index bc6c780..a505f5f 100644
--- a/src/lsmsvgview.h
+++ b/src/lsmsvgview.h
@@ -188,6 +188,11 @@ void               lsm_svg_view_apply_convolve_matrix      (LsmSvgView *view, const char 
*input,
 void           lsm_svg_view_apply_specular_lighting    (LsmSvgView *view, const char *output, const LsmBox 
*subregion,
                                                         double surface_scale, double specular_constant, 
double specular_exponent,
                                                         double dx, double dy);
+void           lsm_svg_view_apply_turbulence           (LsmSvgView *view, const char *output, const LsmBox 
*subregion,
+                                                        double base_frequency_x, double base_frequency_y,
+                                                        int n_octaves, double seed,
+                                                        LsmSvgStitchTiles stitch_tiles,
+                                                        LsmSvgTurbulenceType type);
 
 G_END_DECLS
 



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