/* Apophysis Plugin - Synth v2 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* The Thing That Should Not Be A much neater way of providing the kind of felixibility and control in Apophysis that I am aiming for with Synth would be to create a node-based system of connected functions that allowed advanced users to build their own routines for the Apophysis engine from simple components. Many other graphic and audio engines use this concept very successfully. Such a system could make FX, PX, xaos etc redundant too. I've made Synth, because I cannot forsee that kind of development happening with Apophysis. This is no sleight to the Apo developers - from Mark Townsend onwards the project has been an inspiration and joy to many people. It is more simply a recognition of how hard it would be to make such a change to Apophysis as it stands. */ // Must define this structure before we include apoplugin.h typedef struct { double synth_a; int synth_mode; double synth_power; double synth_mix; int synth_smooth; double synth_b; int synth_b_type; double synth_b_frq; double synth_b_skew; double synth_b_phs; int synth_b_layer; double synth_c; int synth_c_type; double synth_c_frq; double synth_c_skew; double synth_c_phs; int synth_c_layer; double synth_d; int synth_d_type; double synth_d_frq; double synth_d_skew; double synth_d_phs; int synth_d_layer; double synth_e; int synth_e_type; double synth_e_frq; double synth_e_skew; double synth_e_phs; int synth_e_layer; double synth_f; int synth_f_type; double synth_f_frq; double synth_f_skew; double synth_f_phs; int synth_f_layer; } Variables; #define _USE_MATH_DEFINES #include "apoplugin.h" // Set the name of this plugin APO_PLUGIN("synth"); // Define the Variables APO_VARIABLES( VAR_REAL(synth_a, 1.0), VAR_INTEGER(synth_mode, 3), VAR_REAL(synth_power, -2.0), VAR_REAL(synth_mix, 1.0), VAR_INTEGER(synth_smooth, 0), VAR_REAL(synth_b, 0.0), VAR_INTEGER(synth_b_type, 0), VAR_REAL(synth_b_skew, 0.0), VAR_REAL(synth_b_frq, 1.0), VAR_REAL(synth_b_phs, 0.0), VAR_INTEGER(synth_b_layer, 0), VAR_REAL(synth_c, 0.0), VAR_INTEGER(synth_c_type, 0), VAR_REAL(synth_c_skew, 0.0), VAR_REAL(synth_c_frq, 1.0), VAR_REAL(synth_c_phs, 0.0), VAR_INTEGER(synth_c_layer, 0), VAR_REAL(synth_d, 0.0), VAR_INTEGER(synth_d_type, 0), VAR_REAL(synth_d_skew, 0.0), VAR_REAL(synth_d_frq, 1.0), VAR_REAL(synth_d_phs, 0.0), VAR_INTEGER(synth_d_layer, 0), VAR_REAL(synth_e, 0.0), VAR_INTEGER(synth_e_type, 0), VAR_REAL(synth_e_skew, 0.0), VAR_REAL(synth_e_frq, 1.0), VAR_REAL(synth_e_phs, 0.0), VAR_INTEGER(synth_e_layer, 0), VAR_REAL(synth_f, 0.0), VAR_INTEGER(synth_f_type, 0), VAR_REAL(synth_f_skew, 0.0), VAR_REAL(synth_f_frq, 1.0), VAR_REAL(synth_f_phs, 0.0), VAR_INTEGER(synth_f_layer, 0) ); // You must call the argument "vp". int PluginVarPrepare(Variation* vp) { return TRUE; // Always return TRUE. } // ------------------------------------------------------------- // Modes // "Lagacy" modes from v1 #define MODE_SPHERICAL 0 #define MODE_BUBBLE 1 #define MODE_BLUR_LEGACY 2 // New modes in v2 #define MODE_BLUR_NEW 3 #define MODE_BLUR_ZIGZAG 4 #define MODE_RAWCIRCLE 5 #define MODE_RAWX 6 #define MODE_RAWY 7 #define MODE_RAWXY 8 #define MODE_SHIFTX 9 #define MODE_SHIFTY 10 #define MODE_SHIFTXY 11 #define MODE_SINUSOIDAL 12 #define MODE_SWIRL 13 #define MODE_HYPERBOLIC 14 #define MODE_JULIA 15 #define MODE_DISC 16 #define MODE_RINGS 17 #define MODE_CYLINDER 18 #define MODE_BLUR_RING 19 #define MODE_BLUR_RING2 20 #define MODE_SHIFTTHETA 21 // ------------------------------------------------------------- // Wave types #define WAVE_SIN 0 #define WAVE_COS 1 #define WAVE_SQUARE 2 #define WAVE_SAW 3 #define WAVE_TRIANGLE 4 #define WAVE_CONCAVE 5 #define WAVE_CONVEX 6 #define WAVE_NGON 7 // New wave types in v2 #define WAVE_INGON 8 // ------------------------------------------------------------- // Layer types #define LAYER_ADD 0 #define LAYER_MULT 1 #define LAYER_MAX 2 #define LAYER_MIN 3 // ------------------------------------------------------------- // Interpolation types #define LERP_LINEAR 0 #define LERP_BEZIER 1 // ------------------------------------------------------------- // Sine/Cosine interpretation types #define SINCOS_MULTIPLY 0 #define SINCOS_MIXIN 1 // ------------------------------------------------------------- // synth_value calculates the wave height y from theta, which is an abstract // angle that could come from any other calculation - for circular modes // it will be the angle between the positive y axis and the vector from // the origin to the pont i.e. atan2(x,y) // You must call the argument "vp". inline double synth_value(Variation* vp, double theta) { double theta_factor = VAR(synth_a); double x,y,z; if ( VAR(synth_b) != 0.0 ) { z = VAR(synth_b_phs) + theta * VAR(synth_b_frq); y = z / ( 2 * M_PI ); y -= floor( y ); // y is in range 0 - 1. Now skew according to synth_b_skew if ( VAR(synth_b_skew) != 0.0 ) { z = 0.5 + 0.5 * VAR(synth_b_skew); if ( y > z ) { // y is 0.5 if equals z, up to 1.0 y = 0.5 + 0.5 * (y - z)/(1.0 - z + EPS); } else { // y is 0.5 if equals z, down to 0.0 y = 0.5 - 0.5 * (z - y)/(z + EPS); } } switch ( VAR(synth_b_type) ) { case WAVE_SIN: x = sin( y * 2 * M_PI ); break; case WAVE_COS: x = cos( y * 2 * M_PI ); break; case WAVE_SQUARE: x = y > 0.5 ? 1.0 : -1.0; break; case WAVE_SAW: x = 1.0 - 2.0 * y; break; case WAVE_TRIANGLE: x = y > 0.5 ? 3.0 - 4.0 * y : 2.0 * y - 1.0; break; case WAVE_CONCAVE: x = 8.0 * ( y - 0.5 ) * ( y - 0.5 ) - 1.0; break; case WAVE_CONVEX: x = 2.0 * sqrt( y ) - 1.0; break; case WAVE_NGON: y -= 0.5; y *= (2.0 * M_PI / VAR(synth_b_frq) ); x = ( 1.0 / ( cos(y) + EPS ) - 1.0); break; case WAVE_INGON: y -= 0.5; y *= (2.0 * M_PI / VAR(synth_b_frq) ); z = cos(y); x = z / ( 1.0 + EPS - z ); break; } switch ( VAR(synth_b_layer) ) { case LAYER_ADD: theta_factor += VAR(synth_b) * x; break; case LAYER_MULT: theta_factor *= ( 1.0 + VAR(synth_b) * x ); break; case LAYER_MAX: z = VAR(synth_a) + VAR(synth_b) * x; theta_factor = ( theta_factor > z ? theta_factor : z ); break; case LAYER_MIN: z = VAR(synth_a) + VAR(synth_b) * x; theta_factor = ( theta_factor < z ? theta_factor : z ); break; } } if ( VAR(synth_c) != 0.0 ) { z = VAR(synth_c_phs) + theta * VAR(synth_c_frq); y = z / ( 2 * M_PI ); y -= floor( y ); // y is in range 0 - 1. Now skew according to synth_c_skew if ( VAR(synth_c_skew) != 0.0 ) { z = 0.5 + 0.5 * VAR(synth_c_skew); if ( y > z ) { // y is 0.5 if equals z, up to 1.0 y = 0.5 + 0.5 * (y - z)/(1.0 - z + EPS); } else { // y is 0.5 if equals z, down to 0.0 y = 0.5 - 0.5 * (z - y)/(z + EPS); } } switch ( VAR(synth_c_type) ) { case WAVE_SIN: x = sin( y * 2 * M_PI ); break; case WAVE_COS: x = cos( y * 2 * M_PI ); break; case WAVE_SQUARE: x = y > 0.5 ? 1.0 : -1.0; break; case WAVE_SAW: x = 1.0 - 2.0 * y; break; case WAVE_TRIANGLE: x = y > 0.5 ? 3.0 - 4.0 * y : 2.0 * y - 1.0; break; case WAVE_CONCAVE: x = 8.0 * ( y - 0.5 ) * ( y - 0.5 ) - 1.0; break; case WAVE_CONVEX: x = 2.0 * sqrt( y ) - 1.0; break; case WAVE_NGON: y -= 0.5; y *= (2.0 * M_PI / VAR(synth_c_frq) ); x = ( 1.0 / ( cos(y) + EPS ) - 1.0); break; case WAVE_INGON: y -= 0.5; y *= (2.0 * M_PI / VAR(synth_c_frq) ); z = cos(y); x = z / ( 1.0 + EPS - z ); break; } switch ( VAR(synth_c_layer) ) { case LAYER_ADD: theta_factor += VAR(synth_c) * x; break; case LAYER_MULT: theta_factor *= ( 1.0 + VAR(synth_c) * x ); break; case LAYER_MAX: z = VAR(synth_a) + VAR(synth_c) * x; theta_factor = ( theta_factor > z ? theta_factor : z ); break; case LAYER_MIN: z = VAR(synth_a) + VAR(synth_c) * x; theta_factor = ( theta_factor < z ? theta_factor : z ); break; } } if ( VAR(synth_d) != 0.0 ) { z = VAR(synth_d_phs) + theta * VAR(synth_d_frq); y = z / ( 2 * M_PI ); y -= floor( y ); // y is in range 0 - 1. Now skew according to synth_d_skew if ( VAR(synth_d_skew) != 0.0 ) { z = 0.5 + 0.5 * VAR(synth_d_skew); if ( y > z ) { // y is 0.5 if equals z, up to 1.0 y = 0.5 + 0.5 * (y - z)/(1.0 - z + EPS); } else { // y is 0.5 if equals z, down to 0.0 y = 0.5 - 0.5 * (z - y)/(z + EPS); } } switch ( VAR(synth_d_type) ) { case WAVE_SIN: x = sin( y * 2 * M_PI ); break; case WAVE_COS: x = cos( y * 2 * M_PI ); break; case WAVE_SQUARE: x = y > 0.5 ? 1.0 : -1.0; break; case WAVE_SAW: x = 1.0 - 2.0 * y; break; case WAVE_TRIANGLE: x = y > 0.5 ? 3.0 - 4.0 * y : 2.0 * y - 1.0; break; case WAVE_CONCAVE: x = 8.0 * ( y - 0.5 ) * ( y - 0.5 ) - 1.0; break; case WAVE_CONVEX: x = 2.0 * sqrt( y ) - 1.0; break; case WAVE_NGON: y -= 0.5; y *= (2.0 * M_PI / VAR(synth_d_frq) ); x = ( 1.0 / ( cos(y) + EPS ) - 1.0); break; case WAVE_INGON: y -= 0.5; y *= (2.0 * M_PI / VAR(synth_d_frq) ); z = cos(y); x = z / ( 1.0 + EPS - z ); break; } switch ( VAR(synth_d_layer) ) { case LAYER_ADD: theta_factor += VAR(synth_d) * x; break; case LAYER_MULT: theta_factor *= ( 1.0 + VAR(synth_d) * x ); break; case LAYER_MAX: z = VAR(synth_a) + VAR(synth_d) * x; theta_factor = ( theta_factor > z ? theta_factor : z ); break; case LAYER_MIN: z = VAR(synth_a) + VAR(synth_d) * x; theta_factor = ( theta_factor < z ? theta_factor : z ); break; } } if ( VAR(synth_e) != 0.0 ) { z = VAR(synth_e_phs) + theta * VAR(synth_e_frq); y = z / ( 2 * M_PI ); y -= floor( y ); // y is in range 0 - 1. Now skew according to synth_e_skew if ( VAR(synth_e_skew) != 0.0 ) { z = 0.5 + 0.5 * VAR(synth_e_skew); if ( y > z ) { // y is 0.5 if equals z, up to 1.0 y = 0.5 + 0.5 * (y - z)/(1.0 - z + EPS); } else { // y is 0.5 if equals z, down to 0.0 y = 0.5 - 0.5 * (z - y)/(z + EPS); } } switch ( VAR(synth_e_type) ) { case WAVE_SIN: x = sin( y * 2 * M_PI ); break; case WAVE_COS: x = cos( y * 2 * M_PI ); break; case WAVE_SQUARE: x = y > 0.5 ? 1.0 : -1.0; break; case WAVE_SAW: x = 1.0 - 2.0 * y; break; case WAVE_TRIANGLE: x = y > 0.5 ? 3.0 - 4.0 * y : 2.0 * y - 1.0; break; case WAVE_CONCAVE: x = 8.0 * ( y - 0.5 ) * ( y - 0.5 ) - 1.0; break; case WAVE_CONVEX: x = 2.0 * sqrt( y ) - 1.0; break; case WAVE_NGON: y -= 0.5; y *= (2.0 * M_PI / VAR(synth_e_frq) ); x = ( 1.0 / ( cos(y) + EPS ) - 1.0); break; case WAVE_INGON: y -= 0.5; y *= (2.0 * M_PI / VAR(synth_e_frq) ); z = cos(y); x = z / ( 1.0 + EPS - z ); break; } switch ( VAR(synth_e_layer) ) { case LAYER_ADD: theta_factor += VAR(synth_e) * x; break; case LAYER_MULT: theta_factor *= ( 1.0 + VAR(synth_e) * x ); break; case LAYER_MAX: z = VAR(synth_a) + VAR(synth_e) * x; theta_factor = ( theta_factor > z ? theta_factor : z ); break; case LAYER_MIN: z = VAR(synth_a) + VAR(synth_e) * x; theta_factor = ( theta_factor < z ? theta_factor : z ); break; } } if ( VAR(synth_f) != 0.0 ) { z = VAR(synth_f_phs) + theta * VAR(synth_f_frq); y = z / ( 2 * M_PI ); y -= floor( y ); // y is in range 0 - 1. Now skew according to synth_f_skew if ( VAR(synth_f_skew) != 0.0 ) { z = 0.5 + 0.5 * VAR(synth_f_skew); if ( y > z ) { // y is 0.5 if equals z, up to 1.0 y = 0.5 + 0.5 * (y - z)/(1.0 - z + EPS); } else { // y is 0.5 if equals z, down to 0.0 y = 0.5 - 0.5 * (z - y)/(z + EPS); } } switch ( VAR(synth_f_type) ) { case WAVE_SIN: x = sin( y * 2 * M_PI ); break; case WAVE_COS: x = cos( y * 2 * M_PI ); break; case WAVE_SQUARE: x = y > 0.5 ? 1.0 : -1.0; break; case WAVE_SAW: x = 1.0 - 2.0 * y; break; case WAVE_TRIANGLE: x = y > 0.5 ? 3.0 - 4.0 * y : 2.0 * y - 1.0; break; case WAVE_CONCAVE: x = 8.0 * ( y - 0.5 ) * ( y - 0.5 ) - 1.0; break; case WAVE_CONVEX: x = 2.0 * sqrt( y ) - 1.0; break; case WAVE_NGON: y -= 0.5; y *= (2.0 * M_PI / VAR(synth_f_frq) ); x = ( 1.0 / ( cos(y) + EPS ) - 1.0); break; case WAVE_INGON: y -= 0.5; y *= (2.0 * M_PI / VAR(synth_f_frq) ); z = cos(y); x = z / ( 1.0 + EPS - z ); break; } switch ( VAR(synth_f_layer) ) { case LAYER_ADD: theta_factor += VAR(synth_f) * x; break; case LAYER_MULT: theta_factor *= ( 1.0 + VAR(synth_f) * x ); break; case LAYER_MAX: z = VAR(synth_a) + VAR(synth_f) * x; theta_factor = ( theta_factor > z ? theta_factor : z ); break; case LAYER_MIN: z = VAR(synth_a) + VAR(synth_f) * x; theta_factor = ( theta_factor < z ? theta_factor : z ); break; } } // Mix is applied here, assuming 1.0 to be the "flat" line for legacy support return theta_factor * VAR(synth_mix) + ( 1.0 - VAR(synth_mix) ); } // ------------------------------------------------------------- // Mapping function y = fn(x) based on quadratic Bezier curves for smooth type 1 // Returns close to y = x for high/low values of x, y = m when x = 1.0, and // something in-between y = m*x and y = x lines when x is close-ish to 1.0 // Function always has slope of 0.0 or greater, so no x' values "overlap" inline double bezier_quad_map( double x, double m ) { double a = 1.0; // a is used to control sign of result double t = 0.0; // t is the Bezier curve parameter // Simply reflect in the y axis for negative values if ( m < 0.0 ) { m = -m; a = -1.0; } if ( x < 0.0 ) { x = -x; a = -a; } // iM is "inverse m" used in a few places below double iM = 1e10; if ( m > 1.0e-10 ) { iM = 1.0 / m; } // L is the upper bound on our curves, where we have rejoined the y = x line double L = iM < m * 2.0 ? m * 2.0 : iM; // "Non Curved" // Covers x >= L, or always true if m == 1.0 // y = x i.e. not distorted if ( ( x > L ) || ( m == 1.0 ) ) { return a * x; } if ( ( m < 1.0 ) && ( x <= 1.0 ) ) { // Bezier Curve #1 // Covers 0 <= $m <= 1.0, 0 <= $x <= 1.0 // Control points are (0,0), (m,m) and (1,m) t = x; // Special case when m == 0.5 if ( abs(m-0.5) > 1e-10 ) { t = ( -1.0 * m + sqrt( m * m + ( 1.0 - 2.0 * m) * x ) ) / ( 1.0 - 2.0 * m ); } return a * ( x + ( m - 1.0 ) * t * t ); } if ( ( 1.0 < m ) && ( x <= 1.0 ) ) { // Bezier Curve #2 // Covers m >= 1.0, 0 <= x <= 1.0 // Control points are (0,0), (iM,iM) and (1,m) t = x; // Special case when m == 2 if ( abs(m-2.0) > 1e-10 ) { t = ( -1.0 * iM + sqrt( iM * iM + ( 1.0 - 2.0 * iM ) * x ) ) / ( 1 - 2 * iM ); } return a * ( x + ( m - 1.0 ) * t * t ); } if ( m < 1.0 ) { // Bezier Curve #3 // Covers 0 <= m <= 1.0, 1 <= x <= L // Control points are (1,m), (1,1) and (L,L) // (L is x value (>1) where we re-join y = x line, and is maximum( iM, 2 * m ) t = sqrt( ( x - 1.0 ) / ( L - 1.0 ) ); return a * ( x + ( m - 1.0 ) * t * t + 2 * ( 1.0 - m ) * t + ( m - 1.0 ) ); } // Curve #4 // Covers 1.0 <= m, 1 <= x <= L // Control points are (1,m), (m,m) and (L,L) // (L is x value (>1) where we re-join y = x line, and is maximum( iM, 2 * m ) t = ( 1.0 - m ) + sqrt( ( m - 1.0 ) * ( m - 1.0 ) + ( x - 1.0 ) ); return a * ( x + ( m - 1.0 ) * t * t - 2.0 * ( m - 1.0 ) * t + ( m - 1.0 ) ); } // Handle potentially many types of interpolation routine in future . . . inline double interpolate( double x, double m, int lerp_type ) { switch ( lerp_type ) { case LERP_LINEAR: return x * m; case LERP_BEZIER: return bezier_quad_map( x, m ); } return x * m; } inline void synthsincos( Variation* vp, double theta, double* s, double* c, int sine_type ) { fsincos( theta, s, c ); switch ( sine_type ) { case SINCOS_MULTIPLY: *s = (*s) * synth_value( vp, theta ); *c = (*c) * synth_value( vp, theta + M_PI/2.0 ); break; case SINCOS_MIXIN: *s = ( 1.0 - VAR(synth_mix) ) * (*s) + ( synth_value( vp, theta ) - 1.0 ); *c = ( 1.0 - VAR(synth_mix) ) * (*c) + ( synth_value( vp, theta + M_PI/2.0 ) - 1.0 ); break; } return; } // You must call the argument "vp". int PluginVarCalc(Variation* vp) { double Vx, Vy, radius, theta; // Position vector in cartesian and polar co-ords double theta_factor; // Evaluation of synth() function for current point double s, c, mu; // Handy temp variables, s & c => sine & cosine, mu = generic temp param switch( VAR(synth_mode) ) { case MODE_RAWCIRCLE: // Power NO, Smooth YES // Get current radius and angle Vx = FTx; Vy = FTy; radius = sqrt(Vx * Vx + Vy * Vy); theta = atan2(Vx, Vy); // Calculate new radius theta_factor = synth_value( vp, theta ); radius = interpolate( radius, theta_factor, VAR(synth_smooth) ); fsincos(theta, &s, &c); // Write to running totals for transform FPx += VVAR * radius * s; FPy += VVAR * radius * c; break; case MODE_RAWY: // Power NO, Smooth YES // Use x and y values directly Vx = FTx; Vy = FTy; // y value will be mapped according to synth(x) value theta_factor = synth_value( vp, Vx ); // Write to running totals for transform FPx += VVAR * Vx; FPy += VVAR * interpolate( Vy, theta_factor, VAR(synth_smooth) );; break; case MODE_RAWX: // Power NO, Smooth YES // Use x and y values directly Vx = FTx; Vy = FTy; // x value will be mapped according to synth(y) value theta_factor = synth_value( vp, Vy ); // Write to running totals for transform FPx += VVAR * interpolate( Vx, theta_factor, VAR(synth_smooth) ); FPy += VVAR * Vy; break; case MODE_RAWXY: // Power NO, Smooth YES // Use x and y values directly Vx = FTx; Vy = FTy; // x value will be mapped according to synth(y) value theta_factor = synth_value( vp, Vy ); FPx += VVAR * interpolate( Vx, theta_factor, VAR(synth_smooth) ); // y value will be mapped according to synth(x) value theta_factor = synth_value( vp, Vx ); FPy += VVAR * interpolate( Vy, theta_factor, VAR(synth_smooth) ); break; case MODE_SPHERICAL: // Power YES, Smooth YES // Re-write of spherical with synth tweak Vx = FTx; Vy = FTy; radius = pow(Vx * Vx + Vy * Vy + EPS, ( VAR(synth_power) + 1.0 )/2.0); // Get angle and angular factor theta = atan2(Vx, Vy); theta_factor = synth_value( vp, theta ); radius = interpolate( radius, theta_factor, VAR(synth_smooth) ); fsincos(theta, &s, &c); // Write to running totals for transform FPx += VVAR * radius * s; FPy += VVAR * radius * c; break; case MODE_BUBBLE: // Power NO, Smooth YES // Re-write of bubble with synth tweak Vx = FTx; Vy = FTy; radius = sqrt(Vx * Vx + Vy * Vy) / ( (Vx * Vx + Vy * Vy)/4 + 1); // Get angle and angular factor theta = atan2(Vx, Vy); theta_factor = synth_value( vp, theta ); radius = interpolate( radius, theta_factor, VAR(synth_smooth) ); fsincos(theta, &s, &c); // Write to running totals for transform FPx += VVAR * radius * s; FPy += VVAR * radius * c; break; case MODE_BLUR_LEGACY: // Power YES, Smooth YES // "old" blur style, has some problems with moire-style artefacts radius = ( random01() + random01() + 0.002 * random01() ) / 2.002; theta = 2.0 * M_PI * random01() - M_PI; Vx = radius * sin(theta); Vy = radius * cos(theta); radius = pow( radius * radius + EPS, VAR(synth_power)/2.0); // Get angle and angular factor theta_factor = synth_value( vp, theta ); radius = VVAR * interpolate( radius, theta_factor, VAR(synth_smooth) ); // Write back to running totals for new vector FPx += Vx * radius; FPy += Vy * radius; break; case MODE_BLUR_NEW: // Power YES, Smooth YES // Blur style, with normal smoothing function // Choose radius randomly, then adjust distribution using pow radius = 0.5 * ( random01() + random01() ); theta = 2 * M_PI * random01() - M_PI; radius = pow( radius * radius + EPS, - VAR(synth_power)/2.0 ); // Get angular factor defining the shape theta_factor = synth_value( vp, theta ); // Get final radius after synth applied radius = interpolate( radius, theta_factor, VAR(synth_smooth) ); fsincos(theta, &s, &c); // Write to running totals for transform FPx += VVAR * radius * s; FPy += VVAR * radius * c; break; case MODE_BLUR_RING: // Power YES, Smooth YES // Blur style, with normal smoothing function radius = 1.0 + 0.1 * ( random01() + random01() - 1.0 ) * VAR(synth_power); theta = 2 * M_PI * random01() - M_PI; // Get angular factor defining the shape theta_factor = synth_value( vp, theta ); // Get final radius after synth applied radius = interpolate( radius, theta_factor, VAR(synth_smooth) ); fsincos(theta, &s, &c); // Write to running totals for transform FPx += VVAR * radius * s; FPy += VVAR * radius * c; break; case MODE_BLUR_RING2: // Power YES, Smooth NO // Simple, same-thickness ring // Choose radius randomly, then adjust distribution using pow theta = 2 * M_PI * random01() - M_PI; radius = pow( random01() + EPS, VAR(synth_power) ); // Get final radius after synth applied radius = synth_value( vp, theta ) + 0.1 * radius; fsincos(theta, &s, &c); // Write to running totals for transform FPx += VVAR * radius * s; FPy += VVAR * radius * c; break; case MODE_SHIFTTHETA: // Power YES, Smooth NO // Use (adjusted) radius to move point around circle Vx = FTx; Vy = FTy; radius = pow(Vx * Vx + Vy * Vy + EPS, VAR(synth_power)/2.0 ); theta = atan2( Vx, Vy ) - 1.0 + synth_value( vp, radius ); fsincos(theta, &s, &c); // Write to running totals for transform FPx += VVAR * radius * s; FPy += VVAR * radius * c; break; case MODE_BLUR_ZIGZAG: // Power YES, Smooth YES // Blur effect based on line segment // theta is used as x value // Vy is y value Vy = 1.0 + 0.1 * ( random01() + random01() - 1.0 ) * VAR(synth_power); theta = 2.0 * asin( (random01()- 0.5) * 2.0 ); // Get angular factor defining the shape theta_factor = synth_value( vp, theta ); // Get new location Vy = interpolate( Vy, theta_factor, VAR(synth_smooth) ); // Write to running totals for transform FPx += VVAR * ( theta / M_PI ); FPy += VVAR * ( Vy - 1.0 ); break; case MODE_SHIFTX: // Power NO, Smooth YES // Use x and y values directly Vx = FTx; Vy = FTy; // Write to running totals for transform FPx += VVAR * ( Vx + synth_value( vp, Vy ) - 1.0); FPy += VVAR * Vy; break; case MODE_SHIFTY: // Power NO, Smooth NO // Use x and y values directly Vx = FTx; Vy = FTy; // Write to running totals for transform FPx += VVAR * Vx; FPy += VVAR * ( Vy + synth_value( vp, Vx ) - 1.0); break; case MODE_SHIFTXY: // Power NO, Smooth NO // Use x and y values directly Vx = FTx; Vy = FTy; // Write to running totals for transform FPx += VVAR * ( Vx + synth_value( vp, Vy ) - 1.0); FPy += VVAR * ( Vy + synth_value( vp, Vx ) - 1.0); break; case MODE_SINUSOIDAL: // Power NO, Smooth NO Vx = FTx; Vy = FTy; // The default mix=0 is same as normal sin FPx += VVAR * ( synth_value( vp, Vx ) - 1.0 + (1.0-VAR(synth_mix)) * sin (Vx) ); FPy += VVAR * ( synth_value( vp, Vy ) - 1.0 + (1.0-VAR(synth_mix)) * sin (Vy) ); break; case MODE_SWIRL: // Power YES, Smooth WAVE Vx = FTx; Vy = FTy; radius = pow( Vx * Vx + Vy * Vy + EPS, VAR(synth_power)/2.0 ); // Synth-modified sine & cosine synthsincos( vp, radius, &s, &c, VAR(synth_smooth) ); FPx += VVAR * (s * Vx - c * Vy); FPy += VVAR * (c * Vx + s * Vy); break; case MODE_HYPERBOLIC: // Power YES, Smooth WAVE Vx = FTx; Vy = FTy; radius = pow(Vx * Vx + Vy * Vy + EPS, VAR(synth_power)/2.0 ); theta = atan2( Vx, Vy ); // Synth-modified sine & cosine synthsincos( vp, theta, &s, &c, VAR(synth_smooth) ); FPx += VVAR * s / radius; FPy += VVAR * c * radius; break; case MODE_JULIA: // Power YES, Smooth WAVE Vx = FTx; Vy = FTy; radius = pow(Vx * Vx + Vy * Vy + EPS, VAR(synth_power)/4.0 ); theta = atan2( Vx, Vy )/2.0; if ( random01() < 0.5 ) theta += M_PI; // Synth-modified sine & cosine synthsincos( vp, theta, &s, &c, VAR(synth_smooth) ); FPx += VVAR * radius * c; FPy += VVAR * radius * s; break; case MODE_DISC: // Power YES, Smooth WAVE Vx = FTx; Vy = FTy; theta = atan2( Vx, Vy ) / M_PI; radius = M_PI * pow(Vx * Vx + Vy * Vy + EPS, VAR(synth_power)/2.0 ); // Synth-modified sine & cosine synthsincos( vp, radius, &s, &c, VAR(synth_smooth) ); FPx = VVAR * s * theta; FPy = VVAR * c * theta; break; case MODE_RINGS: // Power PARAM, Smooth WAVE Vx = FTx; Vy = FTy; radius = sqrt( Vx * Vx + Vy * Vy ); theta = atan2( Vx, Vy ); mu = VAR(synth_power) * VAR(synth_power) + EPS; radius += -2.0 * mu * (int)((radius + mu)/( 2.0 * mu )) + radius * ( 1.0 - mu ); synthsincos( vp, radius, &s, &c, VAR(synth_smooth) ); FPx += VVAR * s * radius; FPy += VVAR * c * radius; break; case MODE_CYLINDER: // Power YES, Smooth WAVE Vx = FTx; Vy = FTy; radius = pow(Vx * Vx + Vy * Vy + EPS, VAR(synth_power)/2.0 ); // Modified sine only used here synthsincos( vp, Vx, &s, &c, VAR(synth_smooth) ); FPx += VVAR * radius * s; FPy += VVAR * radius * Vy; break; } return TRUE; }