[lasem] svg_turbulence: implementation from librsvg
- From: Emmanuel Pacaud <emmanuel src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [lasem] svg_turbulence: implementation from librsvg
- Date: Tue, 4 Aug 2015 21:32:29 +0000 (UTC)
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]