32class TurbulenceGenerator
48 , _fractalnoise(false) {}
58 _stitchTiles = stitch;
59 _fractalnoise = fractalnoise;
63 for (
int k = 0; k < 4; ++k) {
64 for (i = 0; i < BSize; ++i) {
65 _latticeSelector[i] = i;
68 _gradient[i][k][0] =
static_cast<double>(_random() % (BSize * 2) - BSize) / BSize;
69 _gradient[i][k][1] =
static_cast<double>(_random() % (BSize * 2) - BSize) / BSize;
70 }
while (_gradient[i][k][0] == 0 && _gradient[i][k][1] == 0);
73 double s = hypot(_gradient[i][k][0], _gradient[i][k][1]);
74 _gradient[i][k][0] /= s;
75 _gradient[i][k][1] /= s;
80 int j = _random() % BSize;
81 std::swap(_latticeSelector[i], _latticeSelector[j]);
85 for (i = 0; i < BSize + 2; ++i)
87 _latticeSelector[BSize + i] = _latticeSelector[i];
89 for (
int k = 0; k < 4; ++k) {
90 _gradient[BSize + i][k][0] = _gradient[i][k][0];
91 _gradient[BSize + i][k][1] = _gradient[i][k][1];
98 if (_baseFreq[
Geom::X] != 0.0) {
99 double freq = _baseFreq[
Geom::X];
100 double lo = std::floor(_tile.width() * freq) / _tile.width();
101 double hi = std::ceil(_tile.width() * freq) / _tile.width();
102 _baseFreq[
Geom::X] = freq / lo < hi / freq ? lo : hi;
104 if (_baseFreq[
Geom::Y] != 0.0) {
105 double freq = _baseFreq[
Geom::Y];
106 double lo = std::floor(_tile.height() * freq) / _tile.height();
107 double hi = std::ceil(_tile.height() * freq) / _tile.height();
108 _baseFreq[
Geom::Y] = freq / lo < hi / freq ? lo : hi;
111 _wrapw = _tile.width() * _baseFreq[
Geom::X] + 0.5;
112 _wraph = _tile.height() * _baseFreq[
Geom::Y] + 0.5;
113 _wrapx = _tile.left() * _baseFreq[
Geom::X] + PerlinOffset + _wrapw;
114 _wrapy = _tile.top() * _baseFreq[
Geom::Y] + PerlinOffset + _wraph;
122 int wrapx = _wrapx, wrapy = _wrapy, wrapw = _wrapw, wraph = _wraph;
129 for (
double & k : pixel)
132 for (
int octave = 0; octave < _octaves; ++octave)
134 double tx = x + PerlinOffset;
135 double bx =
floor(tx);
136 double rx0 = tx - bx, rx1 = rx0 - 1.0;
137 int bx0 = bx, bx1 = bx0 + 1;
139 double ty = y + PerlinOffset;
140 double by =
floor(ty);
141 double ry0 = ty - by, ry1 = ry0 - 1.0;
142 int by0 = by, by1 = by0 + 1;
145 if (bx0 >= wrapx) bx0 -= wrapw;
146 if (bx1 >= wrapx) bx1 -= wrapw;
147 if (by0 >= wrapy) by0 -= wraph;
148 if (by1 >= wrapy) by1 -= wraph;
155 int i = _latticeSelector[bx0];
156 int j = _latticeSelector[bx1];
157 int b00 = _latticeSelector[i + by0];
158 int b01 = _latticeSelector[i + by1];
159 int b10 = _latticeSelector[j + by0];
160 int b11 = _latticeSelector[j + by1];
162 double sx = _scurve(rx0);
163 double sy = _scurve(ry0);
167 for (
int k = 0; k < 4; ++k) {
168 double const *qxa = _gradient[b00][k];
169 double const *qxb = _gradient[b10][k];
170 double a = _lerp(sx, rx0 * qxa[0] + ry0 * qxa[1],
171 rx1 * qxb[0] + ry0 * qxb[1]);
172 double const *qya = _gradient[b01][k];
173 double const *qyb = _gradient[b11][k];
174 double b = _lerp(sx, rx0 * qya[0] + ry1 * qya[1],
175 rx1 * qyb[0] + ry1 * qyb[1]);
176 result[k] = _lerp(sy, a, b);
180 for (
int k = 0; k < 4; ++k)
181 pixel[k] +=
result[k] / ratio;
183 for (
int k = 0; k < 4; ++k)
184 pixel[k] += fabs(
result[k]) / ratio;
197 wrapx = wrapx*2 - PerlinOffset;
198 wrapy = wrapy*2 - PerlinOffset;
203 guint32 r = CLAMP_D_TO_U8((pixel[0]*255.0 + 255.0) / 2);
204 guint32 g = CLAMP_D_TO_U8((pixel[1]*255.0 + 255.0) / 2);
205 guint32 b = CLAMP_D_TO_U8((pixel[2]*255.0 + 255.0) / 2);
206 guint32 a = CLAMP_D_TO_U8((pixel[3]*255.0 + 255.0) / 2);
210 ASSEMBLE_ARGB32(pxout, a,r,g,b);
213 guint32 r = CLAMP_D_TO_U8(pixel[0]*255.0);
214 guint32 g = CLAMP_D_TO_U8(pixel[1]*255.0);
215 guint32 b = CLAMP_D_TO_U8(pixel[2]*255.0);
216 guint32 a = CLAMP_D_TO_U8(pixel[3]*255.0);
220 ASSEMBLE_ARGB32(pxout, a,r,g,b);
250 bool ready()
const {
return _inited; }
251 void dirty() { _inited =
false; }
254 void _setupSeed(
long seed)
257 if (_seed <= 0) _seed = -(_seed % (RAND_m - 1)) + 1;
258 if (_seed > RAND_m - 1) _seed = RAND_m - 1;
269 _seed = RAND_a * (_seed % RAND_q) - RAND_r * (_seed / RAND_q);
270 if (_seed <= 0) _seed += RAND_m;
274 static inline double _scurve(
double t)
276 return t * t * (3.0 - 2.0 * t);
279 static inline double _lerp(
double t,
double a,
double b)
281 return a + t * (b - a);
285 static long constexpr
292 static int constexpr BSize = 0x100;
293 static int constexpr BMask = 0xff;
295 static double constexpr PerlinOffset = 4096.0;
299 int _latticeSelector[2 * BSize + 2];
300 double _gradient[2 * BSize + 2][4][2];
313 : gen(
std::make_unique<TurbulenceGenerator>())
365 Turbulence(TurbulenceGenerator
const &gen,
Geom::Affine const &trans,
int x0,
int y0)
368 , _x0(x0), _y0(y0) {}
370 guint32 operator()(
int x,
int y)
374 return _gen.turbulencePixel(point);
378 TurbulenceGenerator
const &_gen;
395 cairo_surface_get_device_scale(input, &x_scale, &y_scale);
396 int width = ceil(cairo_image_surface_get_width( input)/x_scale/x_scale);
397 int height = ceil(cairo_image_surface_get_height(input)/y_scale/y_scale);
399 cairo_surface_set_device_scale( temp, 1, 1 );
420 cairo_t *ct = cairo_create(out);
421 cairo_set_source_surface(ct, temp, 0, 0);
425 cairo_surface_destroy(temp);
427 cairo_surface_mark_dirty(out);
430 cairo_surface_destroy(out);
Cairo software blending templates.
void ink_cairo_surface_synthesize(cairo_surface_t *out, cairo_rectangle_t const &out_area, Synth &&synth)
Synthesize surface pixels based on their position.
cairo_surface_t * ink_cairo_surface_create_same_size(cairo_surface_t *s, cairo_content_t c)
void set_cairo_surface_ci(cairo_surface_t *surface, SPColorInterpolation ci)
Set the color_interpolation_value for a Cairo surface.
Cairo integration helpers.
G_GNUC_CONST guint32 premul_alpha(const guint32 color, const guint32 alpha)
3x3 matrix representing an affine transformation.
Affine inverse() const
Compute the inverse matrix.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
Two-dimensional point that doubles as a vector.
Axis aligned, non-empty rectangle.
SPColorInterpolation color_interpolation
cairo_surface_t * getcairo(int slot)
Returns the pixblock in specified slot.
void set(int slot, cairo_surface_t *s)
Sets or re-sets the pixblock associated with given slot.
Geom::Rect get_slot_area() const
FilterUnits const & get_units() const
void set_type(FilterTurbulenceType t)
void set_stitchTiles(bool st)
void set_numOctaves(int num)
void set_baseFrequency(int axis, double freq)
void render_cairo(FilterSlot &slot) const override
~FilterTurbulence() override
double complexity(Geom::Affine const &ctm) const override
FilterTurbulenceType type
std::unique_ptr< TurbulenceGenerator > gen
Geom::Affine get_matrix_primitiveunits2pb() const
Gets the primitiveUnits to pixblock coordinates transformation matrix.
struct _cairo_surface cairo_surface_t
auto floor(Geom::Rect const &rect)
@ TURBULENCE_FRACTALNOISE
Helper class to stream background task notifications as a series of messages.
Definition of functions needed by several filters.
void init(int argc, char **argv, Toy *t, int width=600, int height=600)