commit 7cd24173d9d9752a56b08659b7a86cbada3e504a
Author: leszek <leszek@koltunski.pl>
Date:   Wed Jun 21 00:51:46 2017 +0100

    Move all the knowledge about Vertex and Fragment effects to their respective classes.

diff --git a/src/main/java/org/distorted/library/effect/FragmentEffect.java b/src/main/java/org/distorted/library/effect/FragmentEffect.java
index cb6201b..94cb37e 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffect.java
+++ b/src/main/java/org/distorted/library/effect/FragmentEffect.java
@@ -26,6 +26,8 @@ package org.distorted.library.effect;
 public abstract class FragmentEffect extends Effect
   {
   public static final int NUM_UNIFORMS = 8; // 4-per effect interpolated values, 4 dimensional Region.
+  private static String mGLSL = "";
+  private static int mNumEnabled = 0;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -33,4 +35,47 @@ public abstract class FragmentEffect extends Effect
     {
     super(name);
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static void addEffect(EffectName not_smooth, EffectName yes_smooth, String code)
+    {
+    mNumEnabled ++;
+
+    mGLSL +=
+
+         "if( fName[i]=="+not_smooth.ordinal()+")\n"
+        +  "{\n"
+        +  "degree = sign(degree); \n"
+        +   code +"\n"
+        +  "}\n"
+        +"else\n"
+        +"if( fName[i]=="+yes_smooth.ordinal()+")\n"
+        +  "{\n"
+        +   code +"\n"
+        +  "}\n"
+        +"else\n";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static String getGLSL()
+    {
+    return mGLSL + "{}";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static int getNumEnabled()
+    {
+    return mNumEnabled;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void onDestroy()
+    {
+    mNumEnabled = 0;
+    mGLSL = "";
+    }
   }
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffectAlpha.java b/src/main/java/org/distorted/library/effect/FragmentEffectAlpha.java
index e958a88..a70fb54 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffectAlpha.java
+++ b/src/main/java/org/distorted/library/effect/FragmentEffectAlpha.java
@@ -67,4 +67,12 @@ public class FragmentEffectAlpha extends FragmentEffect
     mRegion.get(uniforms, index+4, currentDuration, step);
     return mAlpha.get(uniforms,index, currentDuration, step);
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void enable()
+    {
+    addEffect( EffectName.ALPHA,EffectName.SMOOTH_ALPHA,
+               "color.a *= (degree*(fUniforms[effect].x-1.0)+1.0);" );
+    }
   }
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffectBrightness.java b/src/main/java/org/distorted/library/effect/FragmentEffectBrightness.java
index ce68759..a6cc405 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffectBrightness.java
+++ b/src/main/java/org/distorted/library/effect/FragmentEffectBrightness.java
@@ -65,4 +65,12 @@ public class FragmentEffectBrightness extends FragmentEffect
     mRegion.get(uniforms,index+4,currentDuration,step);
     return mBrightness.get(uniforms,index,currentDuration,step);
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void enable()
+    {
+    addEffect( EffectName.BRIGHTNESS,EffectName.SMOOTH_BRIGHTNESS,
+               "color.rgb = mix(vec3(0.0,0.0,0.0), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 );" );
+    }
   }
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffectChroma.java b/src/main/java/org/distorted/library/effect/FragmentEffectChroma.java
index cdf0c59..9fe9e3e 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffectChroma.java
+++ b/src/main/java/org/distorted/library/effect/FragmentEffectChroma.java
@@ -76,4 +76,12 @@ public class FragmentEffectChroma extends FragmentEffect
     mColor.get(uniforms,index+1,currentDuration,step);
     return mBlend.get(uniforms,index,currentDuration,step);
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void enable()
+    {
+    addEffect( EffectName.CHROMA,EffectName.SMOOTH_CHROMA,
+               "color.rgb = mix(color.rgb, fUniforms[effect].yzw, degree*fUniforms[effect].x);" );
+    }
   }
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffectContrast.java b/src/main/java/org/distorted/library/effect/FragmentEffectContrast.java
index f3e80cc..93ac461 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffectContrast.java
+++ b/src/main/java/org/distorted/library/effect/FragmentEffectContrast.java
@@ -65,4 +65,12 @@ public class FragmentEffectContrast extends FragmentEffect
     mRegion.get(uniforms,index+4,currentDuration,step);
     return mContrast.get(uniforms,index,currentDuration,step);
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void enable()
+    {
+    addEffect( EffectName.CONTRAST,EffectName.SMOOTH_CONTRAST,
+               "color.rgb = mix(vec3(0.5,0.5,0.5), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 );" );
+    }
   }
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffectSaturation.java b/src/main/java/org/distorted/library/effect/FragmentEffectSaturation.java
index f4da466..a183837 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffectSaturation.java
+++ b/src/main/java/org/distorted/library/effect/FragmentEffectSaturation.java
@@ -67,4 +67,13 @@ public class FragmentEffectSaturation extends FragmentEffect
     mRegion.get(uniforms,index+4,currentDuration,step);
     return mSaturation.get(uniforms,index,currentDuration,step);
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void enable()
+    {
+    addEffect( EffectName.SATURATION,EffectName.SMOOTH_SATURATION,
+               "float luminance = dot(vec3( 0.2125, 0.7154, 0.0721 ),color.rgb);\n" +
+               "color.rgb = mix(vec3(luminance,luminance,luminance), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 ); " );
+    }
   }
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java b/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java
index dfb18c0..7e06cbc 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java
@@ -86,6 +86,13 @@ public class PostprocessEffectBlur extends PostprocessEffect
     mBlurRadius = blurRadius;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void enable()
+    {
+
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public boolean compute(float[] uniforms, int index, long currentDuration, long step )
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java b/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java
index 9ba2654..c4b6f6a 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java
@@ -30,6 +30,13 @@ public class PostprocessEffectGlow extends PostprocessEffect
   private Data1D mGlowRadius;
   private Data4D mColor;
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void enable()
+    {
+
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Make the object glow with a specific color and a halo of specific radius.
diff --git a/src/main/java/org/distorted/library/effect/VertexEffect.java b/src/main/java/org/distorted/library/effect/VertexEffect.java
index 5240865..25c7d15 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffect.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffect.java
@@ -25,6 +25,8 @@ package org.distorted.library.effect;
 public abstract class VertexEffect extends Effect
   {
   public static final int NUM_UNIFORMS = 12; // 5 per-effect interpolated values, 3-dimensional center, 4-dimensional Region
+  private static String mGLSL = "";
+  private static int mNumEnabled = 0;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -32,4 +34,41 @@ public abstract class VertexEffect extends Effect
     {
     super(name);
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static void addEffect(EffectName name, String code)
+    {
+    mNumEnabled ++;
+
+    mGLSL +=
+
+        "if( vName[i]=="+name.ordinal()+")\n" +
+          "{\n" +
+           code +"\n" +
+          "}\n" +
+        "else\n";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static String getGLSL()
+    {
+    return mGLSL + "{}";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static int getNumEnabled()
+    {
+    return mNumEnabled;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public static void onDestroy()
+    {
+    mNumEnabled = 0;
+    mGLSL = "";
+    }
   }
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectDeform.java b/src/main/java/org/distorted/library/effect/VertexEffectDeform.java
index 100686d..f6ea79d 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectDeform.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectDeform.java
@@ -75,4 +75,98 @@ public class VertexEffectDeform extends VertexEffect
 
     return ret;
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Deform the whole shape of the Object by force V. Algorithm is as follows:
+//
+// Suppose we apply force (Vx,Vy) at point (Cx,Cy) (i.e. the center of the effect). Then, first of all,
+// divide the rectangle into 4 smaller rectangles along the 1 horizontal + 1 vertical lines that pass
+// through (Cx,Cy). Now suppose we have already understood the following case:
+//
+// A vertical (0,Vy) force applied to a rectangle (WxH) in size, at center which is the top-left corner
+// of the rectangle.  (*)
+//
+// If we understand (*), then we understand everything, because in order to compute the movement of the
+// whole rectangle we can apply (*) 8 times: for each one of the 4 sub-rectangles, apply (*) twice,
+// once for the vertical component of the force vector, the second time for the horizontal one.
+//
+// Let's then compute (*):
+// 1) the top-left point will move by exactly (0,Vy)
+// 2) we arbitrarily decide that the top-right point will move by (|Vy|/(|Vy|+A*W))*Vy, where A is some
+//    arbitrary constant (const float A below). The F(V,W) = (|Vy|/(|Vy|+A*W)) comes from the following:
+//    a) we want F(V,0) = 1
+//    b) we want lim V->inf (F) = 1
+//    c) we actually want F() to only depend on W/V, which we have here.
+// 3) then the top edge of the rectangle will move along the line Vy*G(x), where G(x) = (1 - (A*W/(|Vy|+A*W))*(x/W)^2)
+// 4) Now we decide that the left edge of the rectangle will move along Vy*H(y), where H(y) = (1 - |y|/(|Vy|+C*|y|))
+//    where C is again an arbitrary constant. Again, H(y) comes from the requirement that no matter how
+//    strong we push the left edge of the rectangle up or down, it can never 'go over itself', but its
+//    length will approach 0 if squeezed very hard.
+// 5) The last point we need to compute is the left-right motion of the top-right corner (i.e. if we push
+//    the top-left corner up very hard, we want to have the top-right corner not only move up, but also to
+//    the left at least a little bit).
+//    We arbitrarily decide that, in addition to moving up-down by Vy*F(V,W), the corner will also move
+//    left-right by I(V,W) = B*W*F(V,W), where B is again an arbitrary constant.
+// 6) combining 3), 4) and 5) together, we arrive at a movement of an arbitrary point (x,y) away from the
+//    top-left corner:
+//    X(x,y) = -B*x * (|Vy|/(|Vy|+A*W)) * (1-(y/H)^2)                               (**)
+//    Y(x,y) = Vy * (1 - |y|/(|Vy|+C*|y|)) * (1 - (A*W/(|Vy|+A*W))*(x/W)^2)         (**)
+//
+// We notice that formulas (**) have been construed so that it is possible to continously mirror them
+// left-right and up-down (i.e. apply not only to the 'bottom-right' rectangle of the 4 subrectangles
+// but to all 4 of them!).
+//
+// Constants:
+// a) A : valid values: (0,infinity). 'Bendiness' if the surface - the higher A is, the more the surface
+//        bends. A<=0 destroys the system.
+// b) B : valid values: <-1,1>. The amount side edges get 'sucked' inwards when we pull the middle of the
+//        top edge up. B=0 --> not at all, B=1: a looot. B=-0.5: the edges will actually be pushed outwards
+//        quite a bit. One can also set it to <-1 or >1, but it will look a bit ridiculous.
+// c) C : valid values: <1,infinity). The derivative of the H(y) function at 0, i.e. the rate of 'squeeze'
+//        surface gets along the force line. C=1: our point gets pulled very closely to points above it
+//        even when we apply only small vertical force to it. The higher C is, the more 'uniform' movement
+//        along the force line is.
+//        0<=C<1 looks completely ridiculous and C<0 destroys the system.
+
+  public static void enable()
+    {
+    addEffect( EffectName.DEFORM,
+
+        "const vec2 ONE = vec2(1.0,1.0);  \n"
+      + "const float A = 0.5; \n"
+      + "const float B = 0.2; \n"
+      + "const float C = 5.0; \n"
+
+      + "vec2 center = vUniforms[effect+1].yz; \n"
+      + "vec2 ps     = center-v.xy; \n"
+      + "vec2 aPS    = abs(ps); \n"
+      + "vec2 maxps  = u_objD.xy + abs(center); \n"
+      + "float d     = degree_region(vUniforms[effect+2],ps); \n"
+      + "vec3 force  = vUniforms[effect].xyz * d; \n"
+      + "vec2 aForce = abs(force.xy); \n"
+      + "float denom = dot(ps+(1.0-d)*force.xy,ps); \n"
+      + "float one_over_denom = 1.0/(denom-0.001*(sign(denom)-1.0)); \n"
+      + "vec2 Aw = A*maxps; \n"
+      + "vec2 quot = ps / maxps; \n"
+      + "quot = quot*quot; \n"                          // ( (x/W)^2 , (y/H)^2 ) where x,y are distances from V to center
+
+      + "float denomV = 1.0 / (aForce.y + Aw.x); \n"
+      + "float denomH = 1.0 / (aForce.x + Aw.y); \n"
+
+      + "vec2 vertCorr= ONE - aPS / ( aForce+C*aPS + (ONE-sign(aForce)) ); \n" // avoid division by 0 when force and PS both are 0
+
+      + "float mvXvert = -B * ps.x * aForce.y * (1.0-quot.y) * denomV; \n"     // impact the vertical   component of the force vector has on horizontal movement
+      + "float mvYhorz = -B * ps.y * aForce.x * (1.0-quot.x) * denomH; \n"     // impact the horizontal component of the force vector has on vertical   movement
+      + "float mvYvert =  force.y * (1.0-quot.x*Aw.x*denomV) * vertCorr.y; \n" // impact the vertical   component of the force vector has on vertical   movement
+      + "float mvXhorz = -force.x * (1.0-quot.y*Aw.y*denomH) * vertCorr.x; \n" // impact the horizontal component of the force vector has on horizontal movement
+
+      + "v.x -= (mvXvert+mvXhorz); \n"
+      + "v.y -= (mvYvert+mvYhorz); \n"
+
+      + "v.z += force.z*d*d*(3.0*d*d -8.0*d +6.0); \n"                         // thick bubble
+      + "float b = -(12.0*force.z*d*(1.0-d)*(1.0-d)*(1.0-d))*one_over_denom; \n"
+
+      + "n.xy += n.z*b*ps;"
+      );
+    }
   }
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectDistort.java b/src/main/java/org/distorted/library/effect/VertexEffectDistort.java
index a9c6a88..76cb047 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectDistort.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectDistort.java
@@ -74,6 +74,84 @@ public class VertexEffectDistort extends VertexEffect
 
     return ret;
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Point (Px,Py) gets moved by vector (Wx,Wy,Wz) where Wx/Wy = Vx/Vy i.e. Wx=aVx and Wy=aVy where
+// a=Py/Sy (N --> when (Px,Py) is above (Sx,Sy)) or a=Px/Sx (W) or a=(w-Px)/(w-Sx) (E) or a=(h-Py)/(h-Sy) (S)
+// It remains to be computed which of the N,W,E or S case we have: answer: a = min[ Px/Sx , Py/Sy , (w-Px)/(w-Sx) , (h-Py)/(h-Sy) ]
+// Computations above are valid for screen (0,0)x(w,h) but here we have (-w/2,-h/2)x(w/2,h/2)
+//
+// the vertical part
+// Let |(v.x,v.y),(ux,uy)| = |PS|, ux-v.x=dx,uy-v.y=dy, f(x) (0<=x<=|SX|) be the shape of the side of the bubble.
+// H(v.x,v.y) = |PS|>|SX| ? 0 : f(|PX|)
+// N(v.x,v.y) = |PS|>|SX| ? (0,0,1) : ( -(dx/|PS|)sin(beta), -(dy/|PS|)sin(beta), cos(beta) ) where tan(beta) is f'(|PX|)
+// ( i.e. normalize( dx, dy, -|PS|/f'(|PX|))
+//
+// Now we also have to take into account the effect horizontal move by V=(u_dVx[i],u_dVy[i]) will have on the normal vector.
+// Solution:
+// 1. Decompose the V into two subcomponents, one parallel to SX and another perpendicular.
+// 2. Convince yourself (draw!) that the perpendicular component has no effect on normals.
+// 3. The parallel component changes the length of |SX| by the factor of a=(|SX|-|Vpar|)/|SX| (where the length
+//    can be negative depending on the direction)
+// 4. that in turn leaves the x and y parts of the normal unchanged and multiplies the z component by a!
+//
+// |Vpar| = (u_dVx[i]*dx - u_dVy[i]*dy) / sqrt(ps_sq) = (Vx*dx-Vy*dy)/ sqrt(ps_sq)  (-Vy because y is inverted)
+// a =  (|SX| - |Vpar|)/|SX| = 1 - |Vpar|/((sqrt(ps_sq)/(1-d)) = 1 - (1-d)*|Vpar|/sqrt(ps_sq) = 1-(1-d)*(Vx*dx-Vy*dy)/ps_sq
+//
+// Side of the bubble
+//
+// choose from one of the three bubble shapes: the cone, the thin bubble and the thick bubble
+// Case 1:
+// f(t) = t, i.e. f(x) = uz * x/|SX|   (a cone)
+// -|PS|/f'(|PX|) = -|PS|*|SX|/uz but since ps_sq=|PS|^2 and d=|PX|/|SX| then |PS|*|SX| = ps_sq/(1-d)
+// so finally -|PS|/f'(|PX|) = -ps_sq/(uz*(1-d))
+//
+// Case 2:
+// f(t) = 3t^2 - 2t^3 --> f(0)=0, f'(0)=0, f'(1)=0, f(1)=1 (the bell curve)
+// here we have t = x/|SX| which makes f'(|PX|) = 6*uz*|PS|*|PX|/|SX|^3.
+// so -|PS|/f'(|PX|) = (-|SX|^3)/(6uz|PX|) =  (-|SX|^2) / (6*uz*d) but
+// d = |PX|/|SX| and ps_sq = |PS|^2 so |SX|^2 = ps_sq/(1-d)^2
+// so finally -|PS|/f'(|PX|) = -ps_sq/ (6uz*d*(1-d)^2)
+//
+// Case 3:
+// f(t) = 3t^4-8t^3+6t^2 would be better as this satisfies f(0)=0, f'(0)=0, f'(1)=0, f(1)=1,
+// f(0.5)=0.7 and f'(t)= t(t-1)^2 >=0 for t>=0 so this produces a fuller, thicker bubble!
+// then -|PS|/f'(|PX|) = (-|PS|*|SX)) / (12uz*d*(d-1)^2) but |PS|*|SX| = ps_sq/(1-d) (see above!)
+// so finally -|PS|/f'(|PX|) = -ps_sq/ (12uz*d*(1-d)^3)
+//
+// Now, new requirement: we have to be able to add up normal vectors, i.e. distort already distorted surfaces.
+// If a surface is given by z = f(x,y), then the normal vector at (x0,y0) is given by (-df/dx (x0,y0), -df/dy (x0,y0), 1 ).
+// so if we have two surfaces defined by f1(x,y) and f2(x,y) with their normals expressed as (f1x,f1y,1) and (f2x,f2y,1)
+// then the normal to g = f1+f2 is simply given by (f1x+f2x,f1y+f2y,1), i.e. if the third components are equal, then we
+// can simply add up the first and second components.
+//
+// Thus we actually want to compute N(v.x,v.y) = a*(-(dx/|PS|)*f'(|PX|), -(dy/|PS|)*f'(|PX|), 1) and keep adding
+// the first two components. (a is the horizontal part)
+
+  public static void enable()
+    {
+    addEffect(EffectName.DISTORT,
+
+        "vec2 center = vUniforms[effect+1].yz; \n"
+      + "vec2 ps = center-v.xy; \n"
+      + "vec3 force = vUniforms[effect].xyz; \n"
+      + "float d = degree(vUniforms[effect+2],center,ps); \n"
+      + "float denom = dot(ps+(1.0-d)*force.xy,ps); \n"
+      + "float one_over_denom = 1.0/(denom-0.001*(sign(denom)-1.0)); \n"          // = denom==0 ? 1000:1/denom;
+
+       //v.z += force.z*d;                                                        // cone
+       //b = -(force.z*(1.0-d))*one_over_denom;                                   //
+
+       //v.z += force.z*d*d*(3.0-2.0*d);                                          // thin bubble
+       //b = -(6.0*force.z*d*(1.0-d)*(1.0-d))*one_over_denom;                     //
+
+      + "v.z += force.z*d*d*(3.0*d*d -8.0*d +6.0); \n"                            // thick bubble
+      + "float b = -(12.0*force.z*d*(1.0-d)*(1.0-d)*(1.0-d))*one_over_denom; \n"  //
+
+      + "v.xy += d*force.xy; \n"
+      + "n.xy += n.z*b*ps;"
+      );
+    }
   }
 
 
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectPinch.java b/src/main/java/org/distorted/library/effect/VertexEffectPinch.java
index 2479e3f..424f554 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectPinch.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectPinch.java
@@ -78,4 +78,25 @@ public class VertexEffectPinch extends VertexEffect
 
     return ret;
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Pull P=(v.x,v.y) towards the line that
+// a) passes through the center of the effect
+// b) forms angle defined in the 2nd interpolated value with the X-axis
+// with P' = P + (1-h)*dist(line to P)
+// when h>1 we are pushing points away from S: P' = P + (1/h-1)*dist(line to P)
+
+  public static void enable()
+    {
+    addEffect(EffectName.PINCH,
+
+        "vec2 center = vUniforms[effect+1].yz; \n"
+      + "vec2 ps = center-v.xy; \n"
+      + "float h = vUniforms[effect].x; \n"
+      + "float t = degree(vUniforms[effect+2],center,ps) * (1.0-h)/max(1.0,h); \n"
+      + "float angle = vUniforms[effect].y; \n"
+      + "vec2 dir = vec2(sin(angle),-cos(angle)); \n"
+      + "v.xy += t*dot(ps,dir)*dir;"
+      );
+    }
   }
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectSink.java b/src/main/java/org/distorted/library/effect/VertexEffectSink.java
index 739734c..e7de40e 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectSink.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectSink.java
@@ -77,4 +77,21 @@ public class VertexEffectSink extends VertexEffect
 
     return ret;
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Pull P=(v.x,v.y) towards center of the effect with P' = P + (1-h)*dist(S-P)
+// when h>1 we are pushing points away from S: P' = P + (1/h-1)*dist(S-P)
+
+  public static void enable()
+    {
+    addEffect(EffectName.SINK,
+
+        "vec2 center = vUniforms[effect+1].yz; \n"
+      + "vec2 ps = center-v.xy; \n"
+      + "float h = vUniforms[effect].x; \n"
+      + "float t = degree(vUniforms[effect+2],center,ps) * (1.0-h)/max(1.0,h); \n"
+
+      + "v.xy += t*ps;"
+      );
+    }
   }
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectSwirl.java b/src/main/java/org/distorted/library/effect/VertexEffectSwirl.java
index 3ee109b..236a8e5 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectSwirl.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectSwirl.java
@@ -76,5 +76,32 @@ public class VertexEffectSwirl extends VertexEffect
 
     return ret;
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Let d be the degree of the current vertex V with respect to center of the effect S and Region vRegion.
+// This effect rotates the current vertex V by vInterpolated.x radians clockwise around the circle dilated
+// by (1-d) around the center of the effect S.
+
+  public static void enable()
+    {
+    addEffect(EffectName.SWIRL,
+
+        "vec2 center  = vUniforms[effect+1].yz; \n"
+      + "vec2 PS = center-v.xy; \n"
+      + "vec4 SO = vUniforms[effect+2]; \n"
+      + "float d1_circle = degree_region(SO,PS); \n"
+      + "float d1_bitmap = degree_bitmap(center,PS); \n"
+
+      + "float alpha = vUniforms[effect].x; \n"
+      + "float sinA = sin(alpha); \n"
+      + "float cosA = cos(alpha); \n"
+
+      + "vec2 PS2 = vec2( PS.x*cosA+PS.y*sinA,-PS.x*sinA+PS.y*cosA ); \n" // vector PS rotated by A radians clockwise around center.
+      + "vec4 SG = (1.0-d1_circle)*SO; \n"                                // coordinates of the dilated circle P is going to get rotated around
+      + "float d2 = max(0.0,degree(SG,center,PS2)); \n"                   // make it a max(0,deg) because otherwise when center=left edge of the
+                                                                          // bitmap some points end up with d2<0 and they disappear off view.
+      + "v.xy += min(d1_circle,d1_bitmap)*(PS - PS2/(1.0-d2)); \n"        // if d2=1 (i.e P=center) we should have P unchanged. How to do it?
+      );
+    }
   }
 
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectWave.java b/src/main/java/org/distorted/library/effect/VertexEffectWave.java
index a0ba00d..a53a89c 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectWave.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectWave.java
@@ -99,4 +99,131 @@ public class VertexEffectWave extends VertexEffect
 
     return ret;
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Directional sinusoidal wave effect.
+//
+// This is an effect from a (hopefully!) generic family of effects of the form (vec3 V: |V|=1 , f(x,y) )  (*)
+// i.e. effects defined by a unit vector and an arbitrary function. Those effects are defined to move each
+// point (x,y,0) of the XY plane to the point (x,y,0) + V*f(x,y).
+//
+// In this case V is defined by angles A and B (sines and cosines of which are precomputed in
+// EffectQueueVertex and passed in the uniforms).
+// Let's move V to start at the origin O, let point C be the endpoint of V, and let C' be C's projection
+// to the XY plane. Then A is defined to be the angle C0C' and angle B is the angle C'O(axisY).
+//
+// Also, in this case f(x,y) = amplitude*sin(x/length), with those 2 parameters passed in uniforms.
+//
+//////////////////////////////////////////////////////////////////////////////////////////////
+// How to compute any generic effect of type (*)
+//////////////////////////////////////////////////////////////////////////////////////////////
+//
+// By definition, the vertices move by f(x,y)*V.
+//
+// Normals are much more complicated.
+// Let angle X be the angle (0,Vy,Vz)(0,Vy,0)(Vx,Vy,Vz).
+// Let angle Y be the angle (Vx,0,Vz)(Vx,0,0)(Vx,Vy,Vz).
+//
+// Then it can be shown that the resulting surface, at point to which point (x0,y0,0) got moved to,
+// has 2 tangent vectors given by
+//
+// SX = (1.0+cosX*fx , cosY*sinX*fx , |sinY|*sinX*fx);  (**)
+// SY = (cosX*sinY*fy , 1.0+cosY*fy , |sinX|*sinY*fy);  (***)
+//
+// and then obviously the normal N is given by N= SX x SY .
+//
+// We still need to remember the note from the distort function about adding up normals:
+// we first need to 'normalize' the normals to make their third components equal, and then we
+// simply add up the first and the second component while leaving the third unchanged.
+//
+// How to see facts (**) and (***) ? Briefly:
+// a) compute the 2D analogon and conclude that in this case the tangent SX is given by
+//    SX = ( cosA*f'(x) +1, sinA*f'(x) )    (where A is the angle vector V makes with X axis )
+// b) cut the resulting surface with plane P which
+//    - includes vector V
+//    - crosses plane XY along line parallel to X axis
+// c) apply the 2D analogon and notice that the tangent vector to the curve that is the common part of P
+//    and our surface (I am talking about the tangent vector which belongs to P) is given by
+//    (1+cosX*fx,0,sinX*fx) rotated by angle (90-|Y|) (where angles X,Y are defined above) along vector (1,0,0).
+//
+//    Matrix of rotation:
+//
+//    |sinY|  cosY
+//    -cosY  |sinY|
+//
+// d) compute the above and see that this is equal precisely to SX from (**).
+// e) repeat points b,c,d in direction Y and come up with (***).
+//
+//////////////////////////////////////////////////////////////////////////////////////////////
+// Note: we should avoid passing certain combinations of parameters to this function. One such known
+// combination is ( A: small but positive, B: any, amplitude >= length ).
+// In this case, certain 'unlucky' points have their normals almost horizontal (they got moved by (almost!)
+// amplitude, and other point length (i.e. <=amplitude) away got moved by 0, so the slope in this point is
+// very steep). Visual effect is: vast majority of surface pretty much unchanged, but random 'unlucky'
+// points very dark)
+//
+// Generally speaking I'd keep to amplitude < length, as the opposite case has some other problems as well.
+
+  public static void enable()
+    {
+    addEffect(EffectName.WAVE,
+
+        "vec2 center     = vUniforms[effect+1].yz; \n"
+      + "float amplitude = vUniforms[effect  ].x; \n"
+      + "float length    = vUniforms[effect  ].y; \n"
+
+      + "vec2 ps = center - v.xy; \n"
+      + "float deg = amplitude*degree_region(vUniforms[effect+2],ps); \n"
+
+      + "if( deg != 0.0 && length != 0.0 ) \n"
+      +   "{ \n"
+      +   "float phase = vUniforms[effect  ].z; \n"
+      +   "float alpha = vUniforms[effect  ].w; \n"
+      +   "float beta  = vUniforms[effect+1].x; \n"
+
+      +   "float sinA = sin(alpha); \n"
+      +   "float cosA = cos(alpha); \n"
+      +   "float sinB = sin(beta); \n"
+      +   "float cosB = cos(beta); \n"
+
+      +   "float angle= 1.578*(ps.x*cosB-ps.y*sinB) / length + phase; \n"
+      +   "vec3 dir= vec3(sinB*cosA,cosB*cosA,sinA); \n"
+      +   "v += sin(angle)*deg*dir; \n"
+
+      +   "if( n.z != 0.0 ) \n"
+      +     "{ \n"
+      +     "float sqrtX = sqrt(dir.y*dir.y + dir.z*dir.z); \n"
+      +     "float sqrtY = sqrt(dir.x*dir.x + dir.z*dir.z); \n"
+
+      +     "float sinX = ( sqrtY==0.0 ? 0.0 : dir.z / sqrtY); \n"
+      +     "float cosX = ( sqrtY==0.0 ? 1.0 : dir.x / sqrtY); \n"
+      +     "float sinY = ( sqrtX==0.0 ? 0.0 : dir.z / sqrtX); \n"
+      +     "float cosY = ( sqrtX==0.0 ? 1.0 : dir.y / sqrtX); \n"
+
+      +     "float abs_z = dir.z <0.0 ? -(sinX*sinY) : (sinX*sinY); \n"
+      +     "float tmp = 1.578*cos(angle)*deg/length; \n"
+
+      +     "float fx =-cosB*tmp; \n"
+      +     "float fy = sinB*tmp; \n"
+
+      +     "vec3 sx = vec3 (1.0+cosX*fx,cosY*sinX*fx,abs_z*fx); \n"
+      +     "vec3 sy = vec3 (cosX*sinY*fy,1.0+cosY*fy,abs_z*fy); \n"
+
+      +     "vec3 normal = cross(sx,sy); \n"
+
+      +     "if( normal.z<=0.0 ) \n"                   // Why this bizarre shit rather than the straightforward
+      +       "{ \n"                                   //
+      +       "normal.x= 0.0; \n"                      // if( normal.z>0.0 )
+      +       "normal.y= 0.0; \n"                      //   {
+      +       "normal.z= 1.0; \n"                      //   n.x = (n.x*normal.z + n.z*normal.x);
+      +       "} \n"                                   //   n.y = (n.y*normal.z + n.z*normal.y);
+                                                       //   n.z = (n.z*normal.z);
+                                                       //   }
+      +     "n.x = (n.x*normal.z + n.z*normal.x); \n"  //
+      +     "n.y = (n.y*normal.z + n.z*normal.y); \n"  // ? Because if we do the above, my shitty Nexus4 crashes
+      +     "n.z = (n.z*normal.z); \n"                 // during shader compilation!
+      +     "} \n"
+      +   "}"
+      );
+    }
   }
diff --git a/src/main/java/org/distorted/library/main/Distorted.java b/src/main/java/org/distorted/library/main/Distorted.java
index 761d732..45297bd 100644
--- a/src/main/java/org/distorted/library/main/Distorted.java
+++ b/src/main/java/org/distorted/library/main/Distorted.java
@@ -25,7 +25,9 @@ import android.content.pm.ConfigurationInfo;
 import android.content.res.Resources;
 
 import org.distorted.library.effect.Effect;
+import org.distorted.library.effect.FragmentEffect;
 import org.distorted.library.effect.PostprocessEffectBlur;
+import org.distorted.library.effect.VertexEffect;
 import org.distorted.library.program.*;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -152,6 +154,8 @@ public class Distorted
     DistortedMaster.onDestroy();
     EffectQueue.onDestroy();
     Effect.onDestroy();
+    VertexEffect.onDestroy();
+    FragmentEffect.onDestroy();
     EffectMessageSender.stopSending();
 
     mInitialized = false;
diff --git a/src/main/java/org/distorted/library/main/DistortedEffects.java b/src/main/java/org/distorted/library/main/DistortedEffects.java
index 2b8dbd5..47ea704 100644
--- a/src/main/java/org/distorted/library/main/DistortedEffects.java
+++ b/src/main/java/org/distorted/library/main/DistortedEffects.java
@@ -26,6 +26,8 @@ import org.distorted.library.R;
 import org.distorted.library.effect.Effect;
 import org.distorted.library.effect.EffectName;
 import org.distorted.library.effect.EffectType;
+import org.distorted.library.effect.FragmentEffect;
+import org.distorted.library.effect.VertexEffect;
 import org.distorted.library.message.EffectListener;
 import org.distorted.library.program.DistortedProgram;
 import org.distorted.library.program.FragmentCompilationException;
@@ -54,16 +56,6 @@ public class DistortedEffects implements DistortedSlave
   /// MAIN PROGRAM ///
   private static DistortedProgram mMainProgram;
   private static int mMainTextureH;
-  private static boolean[] mEffectEnabled = new boolean[EffectName.LENGTH];
-
-  static
-    {
-    int len = EffectName.LENGTH;
-    for(int i=0; i<len; i++)
-      {
-      mEffectEnabled[i] = false;
-      }
-    }
 
   /// BLIT PROGRAM ///
   private static DistortedProgram mBlitProgram;
@@ -122,43 +114,23 @@ public class DistortedEffects implements DistortedSlave
     final InputStream mainVertStream = resources.openRawResource(R.raw.main_vertex_shader);
     final InputStream mainFragStream = resources.openRawResource(R.raw.main_fragment_shader);
 
-    String mainVertHeader= Distorted.GLSL_VERSION;
-    String mainFragHeader= Distorted.GLSL_VERSION;
-
-    EffectName name;
-    EffectType type;
-    boolean foundF = false;
-    boolean foundV = false;
-
-    for(int i=0; i<mEffectEnabled.length; i++)
-      {
-      if( mEffectEnabled[i] )
-        {
-        name = EffectName.getName(i);
-        type = name.getType();
-
-        if( type == EffectType.VERTEX )
-          {
-          mainVertHeader += ("#define "+name.name()+" "+name.ordinal()+"\n");
-          foundV = true;
-          }
-        else if( type == EffectType.FRAGMENT )
-          {
-          mainFragHeader += ("#define "+name.name()+" "+name.ordinal()+"\n");
-          foundF = true;
-          }
-        }
-      }
+    int numF = FragmentEffect.getNumEnabled();
+    int numV = VertexEffect.getNumEnabled();
 
-    mainVertHeader += ("#define NUM_VERTEX "   + ( foundV ? getMax(EffectType.VERTEX  ) : 0 ) + "\n");
-    mainFragHeader += ("#define NUM_FRAGMENT " + ( foundF ? getMax(EffectType.FRAGMENT) : 0 ) + "\n");
+    String mainVertHeader= Distorted.GLSL_VERSION + ("#define NUM_VERTEX "   + ( numV>0 ? getMax(EffectType.VERTEX  ) : 0 ) + "\n");
+    String mainFragHeader= Distorted.GLSL_VERSION + ("#define NUM_FRAGMENT " + ( numF>0 ? getMax(EffectType.FRAGMENT) : 0 ) + "\n");
+    String enabledEffectV= VertexEffect.getGLSL();
+    String enabledEffectF= FragmentEffect.getGLSL();
 
     //android.util.Log.e("Effects", "vertHeader= "+mainVertHeader);
     //android.util.Log.e("Effects", "fragHeader= "+mainFragHeader);
+    //android.util.Log.e("Effects", "enabledV= "+enabledEffectV);
+    //android.util.Log.e("Effects", "enabledF= "+enabledEffectF);
 
     String[] feedback = { "v_Position", "v_endPosition" };
 
-    mMainProgram = new DistortedProgram(mainVertStream,mainFragStream, mainVertHeader, mainFragHeader, Distorted.GLSL, feedback);
+    mMainProgram = new DistortedProgram( mainVertStream, mainFragStream, mainVertHeader, mainFragHeader,
+                                         enabledEffectV, enabledEffectF, Distorted.GLSL, feedback);
 
     int mainProgramH = mMainProgram.getProgramHandle();
     EffectQueueFragment.getUniforms(mainProgramH);
@@ -449,11 +421,6 @@ public class DistortedEffects implements DistortedSlave
   static void onDestroy()
     {
     mNextID = 0;
-
-    for(int i=0; i<EffectName.LENGTH; i++)
-      {
-      mEffectEnabled[i] = false;
-      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -622,21 +589,6 @@ public class DistortedEffects implements DistortedSlave
       }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Enables a given Effect.
- * <p>
- * By default, all effects are disabled. One has to explicitly enable each effect one intends to use.
- * This needs to be called BEFORE shaders get compiled, i.e. before the call to Distorted.onCreate().
- * The point: by enabling only the effects we need, we can optimize the shaders.
- *
- * @param name one of the constants defined in {@link EffectName}
- */
-  public static void enableEffect(EffectName name)
-    {
-    mEffectEnabled[name.ordinal()] = true;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Returns the maximum number of effects of a given type.
diff --git a/src/main/java/org/distorted/library/program/DistortedProgram.java b/src/main/java/org/distorted/library/program/DistortedProgram.java
index 1d2af6f..25e2453 100644
--- a/src/main/java/org/distorted/library/program/DistortedProgram.java
+++ b/src/main/java/org/distorted/library/program/DistortedProgram.java
@@ -251,6 +251,36 @@ public class DistortedProgram
     return shaderHandle;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private static String insertEnabledEffects(String code, final String effects)
+    {
+    final String marker = "// ENABLED EFFECTS WILL BE INSERTED HERE";
+    int length = marker.length();
+
+    int place = code.indexOf(marker);
+
+    if( place>=0 )
+      {
+      String begin = code.substring(0,place-1);
+      String end   = code.substring(place+length);
+/*
+int len = begin.length();
+
+android.util.Log.d("Program", begin.substring(len-40));
+android.util.Log.d("Program", effects);
+android.util.Log.d("Program", end.substring(0,40));
+*/
+      return begin + effects + end;
+      }
+    else
+      {
+      android.util.Log.e("Program", "Error: marker string not found in SHADER!");
+      }
+
+    return null;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // feedback: List of 'out' variables (OpenGL ES >= 3.0 only!) that will be transferred back to CPU
 // using Transform Feedback.
@@ -281,6 +311,40 @@ public class DistortedProgram
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// feedback: List of 'out' variables (OpenGL ES >= 3.0 only!) that will be transferred back to CPU
+// using Transform Feedback.
+
+  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader,
+                          final String enabledVertex, final String enabledFragment, int glslVersion, final String[] feedback )
+  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
+    {
+    mAttributeStr = (glslVersion == 100 ? "attribute " : "in ");
+    mAttributeLen = mAttributeStr.length();
+
+    mNumAttributes = 0;
+
+    String vertexShader   = readTextFileFromRawResource(vertex  , true );
+    String fragmentShader = readTextFileFromRawResource(fragment, false);
+
+    vertexShader   = insertEnabledEffects(vertexShader  ,enabledVertex  );
+    fragmentShader = insertEnabledEffects(fragmentShader,enabledFragment);
+
+    sanitizeMaxValues();
+
+    final int vertexShaderHandle   = compileShader(GLES30.GL_VERTEX_SHADER  , vertexHeader   + vertexShader  );
+    final int fragmentShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragmentHeader + fragmentShader);
+
+    mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
+
+    mAttribute = new int[mNumAttributes];
+
+    for(int i=0; i<mNumAttributes; i++)
+      {
+      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/res/raw/main_fragment_shader.glsl b/src/main/res/raw/main_fragment_shader.glsl
index 6d1497d..a66fd41 100644
--- a/src/main/res/raw/main_fragment_shader.glsl
+++ b/src/main/res/raw/main_fragment_shader.glsl
@@ -41,115 +41,29 @@ uniform int fNumEffects;                // total number of fragment effects
 uniform int fName[NUM_FRAGMENT];        // their namess.
 uniform vec4 fUniforms[2*NUM_FRAGMENT]; // i-th effect is 2 consecutive vec4's: [2*i], [2*i+1]. First vec4 is the Interpolated values,
                                         // next describes the Region, i.e. area over which the effect is active.
-
-#if defined(SATURATION) || defined(SMOOTH_SATURATION)
-const vec3 LUMI = vec3( 0.2125, 0.7154, 0.0721 );                                        
-#endif
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-// CHROMA EFFECT
-
-#if defined(CHROMA) || defined(SMOOTH_CHROMA)
-void chroma(float degree, int effect, inout vec4 color)
-  {
-  color.rgb = mix(color.rgb, fUniforms[effect].yzw, degree*fUniforms[effect].x);
-  }
-#endif
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-// ALPHA EFFECT (change transparency level)
-
-#if defined(ALPHA) || defined(SMOOTH_ALPHA)
-void alpha(float degree, int effect, inout vec4 color)
-  {
-  color.a *= (degree*(fUniforms[effect].x-1.0)+1.0); 
-  }
-#endif
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-// BRIGHTNESS EFFECT
-
-#if defined(BRIGHTNESS) || defined(SMOOTH_BRIGHTNESS)
-void brightness(float degree, int effect, inout vec4 color)
-  {
-  color.rgb = mix(vec3(0.0,0.0,0.0), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 ); 
-  }
-#endif
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-// CONTRAST EFFECT
-
-#if defined(CONTRAST) || defined(SMOOTH_CONTRAST)
-void contrast(float degree, int effect, inout vec4 color)
-  {
-  color.rgb = mix(vec3(0.5,0.5,0.5), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 ); 
-  }
-#endif
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-// SATURATION EFFECT
-
-#if defined(SATURATION) || defined(SMOOTH_SATURATION)
-void saturation(float degree, int effect, inout vec4 color)
-  {
-  float luminance = dot(LUMI,color.rgb);
-  color.rgb = mix(vec3(luminance,luminance,luminance), color.rgb, degree*(fUniforms[effect].x-1.0)+1.0 ); 
-  }
-#endif
-
 #endif    // NUM_FRAGMENT>0
 
 //////////////////////////////////////////////////////////////////////////////////////////////
 
 void main()                    		
   {  
-  vec4 pixel = TEXTURE(u_Texture,v_TexCoordinate);
+  vec4 color = TEXTURE(u_Texture,v_TexCoordinate);
 
 #if NUM_FRAGMENT>0
   vec2 diff;
-  float pointDegree;
-  int j=0;
+  float degree;
+  int effect=0;
 
   for(int i=0; i<fNumEffects; i++)
     {
-    diff = (v_Position.xy - fUniforms[j+1].xy)/fUniforms[j+1].zw;
-    pointDegree = max(0.0,1.0-dot(diff,diff));
+    diff   = (v_Position.xy - fUniforms[effect+1].xy)/fUniforms[effect+1].zw;
+    degree = max(0.0,1.0-dot(diff,diff));
 
-#ifdef CHROMA
-    if( fName[i]==CHROMA            ) chroma    (sign(pointDegree),j,pixel); else
-#endif
-#ifdef SMOOTH_CHROMA
-    if( fName[i]==SMOOTH_CHROMA     ) chroma    (     pointDegree ,j,pixel); else
-#endif
-#ifdef ALPHA
-    if( fName[i]==ALPHA             ) alpha     (sign(pointDegree),j,pixel); else
-#endif
-#ifdef SMOOTH_ALPHA
-    if( fName[i]==SMOOTH_ALPHA      ) alpha     (     pointDegree ,j,pixel); else
-#endif
-#ifdef BRIGHTNESS
-    if( fName[i]==BRIGHTNESS        ) brightness(sign(pointDegree),j,pixel); else
-#endif
-#ifdef SMOOTH_BRIGHTNESS
-    if( fName[i]==SMOOTH_BRIGHTNESS ) brightness(     pointDegree ,j,pixel); else
-#endif
-#ifdef CONTRAST
-    if( fName[i]==CONTRAST          ) contrast  (sign(pointDegree),j,pixel); else
-#endif
-#ifdef SMOOTH_CONTRAST
-    if( fName[i]==SMOOTH_CONTRAST   ) contrast  (     pointDegree ,j,pixel); else
-#endif
-#ifdef SATURATION
-    if( fName[i]==SATURATION        ) saturation(sign(pointDegree),j,pixel); else
-#endif
-#ifdef SMOOTH_SATURATION
-    if( fName[i]==SMOOTH_SATURATION ) saturation(     pointDegree ,j,pixel); else
-#endif
-    {}
+    // ENABLED EFFECTS WILL BE INSERTED HERE
 
-    j+=2;
+    effect+=2;
     }
 #endif
 
-  FRAG_COLOR = vec4(pixel.rgb * (1.0 + 7.0*v_Normal.z) * 0.125, pixel.a);
+  FRAG_COLOR = vec4(color.rgb * (1.0 + 7.0*v_Normal.z) * 0.125, color.a);
   }
\ No newline at end of file
diff --git a/src/main/res/raw/main_vertex_shader.glsl b/src/main/res/raw/main_vertex_shader.glsl
index 570a3ef..3e92fda 100644
--- a/src/main/res/raw/main_vertex_shader.glsl
+++ b/src/main/res/raw/main_vertex_shader.glsl
@@ -144,381 +144,6 @@ float degree(in vec4 region, in vec2 S, in vec2 PS)
   return min(1.0/(1.0 + 1.0/(sqrt(DOT*DOT+D*one_over_ps_sq)-DOT)),E);
   }
 
-//////////////////////////////////////////////////////////////////////////////////////////////
-// DEFORM EFFECT
-//
-// Deform the whole shape of the Object by force V. Algorithm is as follows:
-//
-// Suppose we apply force (Vx,Vy) at point (Cx,Cy) (i.e. the center of the effect). Then, first of all,
-// divide the rectangle into 4 smaller rectangles along the 1 horizontal + 1 vertical lines that pass
-// through (Cx,Cy). Now suppose we have already understood the following case:
-//
-// A vertical (0,Vy) force applied to a rectangle (WxH) in size, at center which is the top-left corner
-// of the rectangle.  (*)
-//
-// If we understand (*), then we understand everything, because in order to compute the movement of the
-// whole rectangle we can apply (*) 8 times: for each one of the 4 sub-rectangles, apply (*) twice,
-// once for the vertical component of the force vector, the second time for the horizontal one.
-//
-// Let's then compute (*):
-// 1) the top-left point will move by exactly (0,Vy)
-// 2) we arbitrarily decide that the top-right point will move by (|Vy|/(|Vy|+A*W))*Vy, where A is some
-//    arbitrary constant (const float A below). The F(V,W) = (|Vy|/(|Vy|+A*W)) comes from the following:
-//    a) we want F(V,0) = 1
-//    b) we want lim V->inf (F) = 1
-//    c) we actually want F() to only depend on W/V, which we have here.
-// 3) then the top edge of the rectangle will move along the line Vy*G(x), where G(x) = (1 - (A*W/(|Vy|+A*W))*(x/W)^2)
-// 4) Now we decide that the left edge of the rectangle will move along Vy*H(y), where H(y) = (1 - |y|/(|Vy|+C*|y|))
-//    where C is again an arbitrary constant. Again, H(y) comes from the requirement that no matter how
-//    strong we push the left edge of the rectangle up or down, it can never 'go over itself', but its
-//    length will approach 0 if squeezed very hard.
-// 5) The last point we need to compute is the left-right motion of the top-right corner (i.e. if we push
-//    the top-left corner up very hard, we want to have the top-right corner not only move up, but also to
-//    the left at least a little bit).
-//    We arbitrarily decide that, in addition to moving up-down by Vy*F(V,W), the corner will also move
-//    left-right by I(V,W) = B*W*F(V,W), where B is again an arbitrary constant.
-// 6) combining 3), 4) and 5) together, we arrive at a movement of an arbitrary point (x,y) away from the
-//    top-left corner:
-//    X(x,y) = -B*x * (|Vy|/(|Vy|+A*W)) * (1-(y/H)^2)                               (**)
-//    Y(x,y) = Vy * (1 - |y|/(|Vy|+C*|y|)) * (1 - (A*W/(|Vy|+A*W))*(x/W)^2)         (**)
-//
-// We notice that formulas (**) have been construed so that it is possible to continously mirror them
-// left-right and up-down (i.e. apply not only to the 'bottom-right' rectangle of the 4 subrectangles
-// but to all 4 of them!).
-//
-// Constants:
-// a) A : valid values: (0,infinity). 'Bendiness' if the surface - the higher A is, the more the surface
-//        bends. A<=0 destroys the system.
-// b) B : valid values: <-1,1>. The amount side edges get 'sucked' inwards when we pull the middle of the
-//        top edge up. B=0 --> not at all, B=1: a looot. B=-0.5: the edges will actually be pushed outwards
-//        quite a bit. One can also set it to <-1 or >1, but it will look a bit ridiculous.
-// c) C : valid values: <1,infinity). The derivative of the H(y) function at 0, i.e. the rate of 'squeeze'
-//        surface gets along the force line. C=1: our point gets pulled very closely to points above it
-//        even when we apply only small vertical force to it. The higher C is, the more 'uniform' movement
-//        along the force line is.
-//        0<=C<1 looks completely ridiculous and C<0 destroys the system.
-
-#ifdef DEFORM
-void deform(in int effect, inout vec3 v, inout vec3 n)
-  {
-  const vec2 ONE = vec2(1.0,1.0);
-
-  const float A = 0.5;
-  const float B = 0.2;
-  const float C = 5.0;
-
-  vec2 center = vUniforms[effect+1].yz;
-  vec2 ps     = center-v.xy;
-  vec2 aPS    = abs(ps);
-  vec2 maxps  = u_objD.xy + abs(center);
-  float d     = degree_region(vUniforms[effect+2],ps);
-  vec3 force  = vUniforms[effect].xyz * d;
-  vec2 aForce = abs(force.xy);
-  float denom = dot(ps+(1.0-d)*force.xy,ps);
-  float one_over_denom = 1.0/(denom-0.001*(sign(denom)-1.0));
-  vec2 Aw = A*maxps;
-  vec2 quot = ps / maxps;
-  quot = quot*quot;                          // ( (x/W)^2 , (y/H)^2 ) where x,y are distances from V to center
-
-  float denomV = 1.0 / (aForce.y + Aw.x);
-  float denomH = 1.0 / (aForce.x + Aw.y);
-
-  vec2 vertCorr= ONE - aPS / ( aForce+C*aPS + (ONE-sign(aForce)) );  // avoid division by 0 when force and PS both are 0
-
-  float mvXvert = -B * ps.x * aForce.y * (1.0-quot.y) * denomV;      // impact the vertical   component of the force vector has on horizontal movement
-  float mvYhorz = -B * ps.y * aForce.x * (1.0-quot.x) * denomH;      // impact the horizontal component of the force vector has on vertical   movement
-  float mvYvert =  force.y * (1.0-quot.x*Aw.x*denomV) * vertCorr.y;  // impact the vertical   component of the force vector has on vertical   movement
-  float mvXhorz = -force.x * (1.0-quot.y*Aw.y*denomH) * vertCorr.x;  // impact the horizontal component of the force vector has on horizontal movement
-
-  v.x -= (mvXvert+mvXhorz);
-  v.y -= (mvYvert+mvYhorz);
-
-  v.z += force.z*d*d*(3.0*d*d -8.0*d +6.0);                          // thick bubble
-  float b = -(12.0*force.z*d*(1.0-d)*(1.0-d)*(1.0-d))*one_over_denom;//
-
-  n.xy += n.z*b*ps;
-  }
-#endif
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-// DISTORT EFFECT
-//
-// Point (Px,Py) gets moved by vector (Wx,Wy,Wz) where Wx/Wy = Vx/Vy i.e. Wx=aVx and Wy=aVy where
-// a=Py/Sy (N --> when (Px,Py) is above (Sx,Sy)) or a=Px/Sx (W) or a=(w-Px)/(w-Sx) (E) or a=(h-Py)/(h-Sy) (S)
-// It remains to be computed which of the N,W,E or S case we have: answer: a = min[ Px/Sx , Py/Sy , (w-Px)/(w-Sx) , (h-Py)/(h-Sy) ]
-// Computations above are valid for screen (0,0)x(w,h) but here we have (-w/2,-h/2)x(w/2,h/2)
-//
-// the vertical part
-// Let |(v.x,v.y),(ux,uy)| = |PS|, ux-v.x=dx,uy-v.y=dy, f(x) (0<=x<=|SX|) be the shape of the side of the bubble.
-// H(v.x,v.y) = |PS|>|SX| ? 0 : f(|PX|)
-// N(v.x,v.y) = |PS|>|SX| ? (0,0,1) : ( -(dx/|PS|)sin(beta), -(dy/|PS|)sin(beta), cos(beta) ) where tan(beta) is f'(|PX|)
-// ( i.e. normalize( dx, dy, -|PS|/f'(|PX|))
-//
-// Now we also have to take into account the effect horizontal move by V=(u_dVx[i],u_dVy[i]) will have on the normal vector.
-// Solution:
-// 1. Decompose the V into two subcomponents, one parallel to SX and another perpendicular.
-// 2. Convince yourself (draw!) that the perpendicular component has no effect on normals.
-// 3. The parallel component changes the length of |SX| by the factor of a=(|SX|-|Vpar|)/|SX| (where the length
-//    can be negative depending on the direction)
-// 4. that in turn leaves the x and y parts of the normal unchanged and multiplies the z component by a!
-//
-// |Vpar| = (u_dVx[i]*dx - u_dVy[i]*dy) / sqrt(ps_sq) = (Vx*dx-Vy*dy)/ sqrt(ps_sq)  (-Vy because y is inverted)
-// a =  (|SX| - |Vpar|)/|SX| = 1 - |Vpar|/((sqrt(ps_sq)/(1-d)) = 1 - (1-d)*|Vpar|/sqrt(ps_sq) = 1-(1-d)*(Vx*dx-Vy*dy)/ps_sq
-//
-// Side of the bubble
-//
-// choose from one of the three bubble shapes: the cone, the thin bubble and the thick bubble
-// Case 1:
-// f(t) = t, i.e. f(x) = uz * x/|SX|   (a cone)
-// -|PS|/f'(|PX|) = -|PS|*|SX|/uz but since ps_sq=|PS|^2 and d=|PX|/|SX| then |PS|*|SX| = ps_sq/(1-d)
-// so finally -|PS|/f'(|PX|) = -ps_sq/(uz*(1-d))
-//
-// Case 2:
-// f(t) = 3t^2 - 2t^3 --> f(0)=0, f'(0)=0, f'(1)=0, f(1)=1 (the bell curve)
-// here we have t = x/|SX| which makes f'(|PX|) = 6*uz*|PS|*|PX|/|SX|^3.
-// so -|PS|/f'(|PX|) = (-|SX|^3)/(6uz|PX|) =  (-|SX|^2) / (6*uz*d) but
-// d = |PX|/|SX| and ps_sq = |PS|^2 so |SX|^2 = ps_sq/(1-d)^2
-// so finally -|PS|/f'(|PX|) = -ps_sq/ (6uz*d*(1-d)^2)
-//
-// Case 3:
-// f(t) = 3t^4-8t^3+6t^2 would be better as this satisfies f(0)=0, f'(0)=0, f'(1)=0, f(1)=1,
-// f(0.5)=0.7 and f'(t)= t(t-1)^2 >=0 for t>=0 so this produces a fuller, thicker bubble!
-// then -|PS|/f'(|PX|) = (-|PS|*|SX)) / (12uz*d*(d-1)^2) but |PS|*|SX| = ps_sq/(1-d) (see above!)
-// so finally -|PS|/f'(|PX|) = -ps_sq/ (12uz*d*(1-d)^3)
-//
-// Now, new requirement: we have to be able to add up normal vectors, i.e. distort already distorted surfaces.
-// If a surface is given by z = f(x,y), then the normal vector at (x0,y0) is given by (-df/dx (x0,y0), -df/dy (x0,y0), 1 ).
-// so if we have two surfaces defined by f1(x,y) and f2(x,y) with their normals expressed as (f1x,f1y,1) and (f2x,f2y,1)
-// then the normal to g = f1+f2 is simply given by (f1x+f2x,f1y+f2y,1), i.e. if the third components are equal, then we
-// can simply add up the first and second components.
-//
-// Thus we actually want to compute N(v.x,v.y) = a*(-(dx/|PS|)*f'(|PX|), -(dy/|PS|)*f'(|PX|), 1) and keep adding
-// the first two components. (a is the horizontal part)
-
-#ifdef DISTORT
-void distort(in int effect, inout vec3 v, inout vec3 n)
-  {
-  vec2 center = vUniforms[effect+1].yz;
-  vec2 ps = center-v.xy;
-  vec3 force = vUniforms[effect].xyz;
-  float d = degree(vUniforms[effect+2],center,ps);
-  float denom = dot(ps+(1.0-d)*force.xy,ps);
-  float one_over_denom = 1.0/(denom-0.001*(sign(denom)-1.0));          // = denom==0 ? 1000:1/denom;
-
-  //v.z += force.z*d;                                                  // cone
-  //b = -(force.z*(1.0-d))*one_over_denom;                             //
-
-  //v.z += force.z*d*d*(3.0-2.0*d);                                    // thin bubble
-  //b = -(6.0*force.z*d*(1.0-d)*(1.0-d))*one_over_denom;               //
-
-  v.z += force.z*d*d*(3.0*d*d -8.0*d +6.0);                            // thick bubble
-  float b = -(12.0*force.z*d*(1.0-d)*(1.0-d)*(1.0-d))*one_over_denom;  //
-
-  v.xy += d*force.xy;
-  n.xy += n.z*b*ps;
-  }
-#endif
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-// SINK EFFECT
-//
-// Pull P=(v.x,v.y) towards center of the effect with P' = P + (1-h)*dist(S-P)
-// when h>1 we are pushing points away from S: P' = P + (1/h-1)*dist(S-P)
-
-#ifdef SINK
-void sink(in int effect,inout vec3 v)
-  {
-  vec2 center = vUniforms[effect+1].yz;
-  vec2 ps = center-v.xy;
-  float h = vUniforms[effect].x;
-  float t = degree(vUniforms[effect+2],center,ps) * (1.0-h)/max(1.0,h);
-
-  v.xy += t*ps;
-  }
-#endif
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-// PINCH EFFECT
-//
-// Pull P=(v.x,v.y) towards the line that
-// a) passes through the center of the effect
-// b) forms angle defined in the 2nd interpolated value with the X-axis
-// with P' = P + (1-h)*dist(line to P)
-// when h>1 we are pushing points away from S: P' = P + (1/h-1)*dist(line to P)
-
-#ifdef PINCH
-void pinch(in int effect,inout vec3 v)
-  {
-  vec2 center = vUniforms[effect+1].yz;
-  vec2 ps = center-v.xy;
-  float h = vUniforms[effect].x;
-  float t = degree(vUniforms[effect+2],center,ps) * (1.0-h)/max(1.0,h);
-  float angle = vUniforms[effect].y;
-  vec2 dir = vec2(sin(angle),-cos(angle));
-
-  v.xy += t*dot(ps,dir)*dir;
-  }
-#endif
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-// SWIRL EFFECT
-//
-// Let d be the degree of the current vertex V with respect to center of the effect S and Region vRegion.
-// This effect rotates the current vertex V by vInterpolated.x radians clockwise around the circle dilated
-// by (1-d) around the center of the effect S.
-
-#ifdef SWIRL
-void swirl(in int effect, inout vec3 v)
-  {
-  vec2 center  = vUniforms[effect+1].yz;
-  vec2 PS = center-v.xy;
-  vec4 SO = vUniforms[effect+2];
-  float d1_circle = degree_region(SO,PS);
-  float d1_bitmap = degree_bitmap(center,PS);
-
-  float alpha = vUniforms[effect].x;
-  float sinA = sin(alpha);
-  float cosA = cos(alpha);
-
-  vec2 PS2 = vec2( PS.x*cosA+PS.y*sinA,-PS.x*sinA+PS.y*cosA ); // vector PS rotated by A radians clockwise around center.
-  vec4 SG = (1.0-d1_circle)*SO;                                // coordinates of the dilated circle P is going to get rotated around
-  float d2 = max(0.0,degree(SG,center,PS2));                   // make it a max(0,deg) because otherwise when center=left edge of the
-                                                               // bitmap some points end up with d2<0 and they disappear off view.
-  v.xy += min(d1_circle,d1_bitmap)*(PS - PS2/(1.0-d2));        // if d2=1 (i.e P=center) we should have P unchanged. How to do it?
-  }
-#endif
-
-//////////////////////////////////////////////////////////////////////////////////////////////
-// WAVE EFFECT
-//
-// Directional sinusoidal wave effect.
-//
-// This is an effect from a (hopefully!) generic family of effects of the form (vec3 V: |V|=1 , f(x,y) )  (*)
-// i.e. effects defined by a unit vector and an arbitrary function. Those effects are defined to move each
-// point (x,y,0) of the XY plane to the point (x,y,0) + V*f(x,y).
-//
-// In this case V is defined by angles A and B (sines and cosines of which are precomputed in
-// EffectQueueVertex and passed in the uniforms).
-// Let's move V to start at the origin O, let point C be the endpoint of V, and let C' be C's projection
-// to the XY plane. Then A is defined to be the angle C0C' and angle B is the angle C'O(axisY).
-//
-// Also, in this case f(x,y) = amplitude*sin(x/length), with those 2 parameters passed in uniforms.
-//
-//////////////////////////////////////////////////////////////////////////////////////////////
-// How to compute any generic effect of type (*)
-//////////////////////////////////////////////////////////////////////////////////////////////
-//
-// By definition, the vertices move by f(x,y)*V.
-//
-// Normals are much more complicated.
-// Let angle X be the angle (0,Vy,Vz)(0,Vy,0)(Vx,Vy,Vz).
-// Let angle Y be the angle (Vx,0,Vz)(Vx,0,0)(Vx,Vy,Vz).
-//
-// Then it can be shown that the resulting surface, at point to which point (x0,y0,0) got moved to,
-// has 2 tangent vectors given by
-//
-// SX = (1.0+cosX*fx , cosY*sinX*fx , |sinY|*sinX*fx);  (**)
-// SY = (cosX*sinY*fy , 1.0+cosY*fy , |sinX|*sinY*fy);  (***)
-//
-// and then obviously the normal N is given by N= SX x SY .
-//
-// We still need to remember the note from the distort function about adding up normals:
-// we first need to 'normalize' the normals to make their third components equal, and then we
-// simply add up the first and the second component while leaving the third unchanged.
-//
-// How to see facts (**) and (***) ? Briefly:
-// a) compute the 2D analogon and conclude that in this case the tangent SX is given by
-//    SX = ( cosA*f'(x) +1, sinA*f'(x) )    (where A is the angle vector V makes with X axis )
-// b) cut the resulting surface with plane P which
-//    - includes vector V
-//    - crosses plane XY along line parallel to X axis
-// c) apply the 2D analogon and notice that the tangent vector to the curve that is the common part of P
-//    and our surface (I am talking about the tangent vector which belongs to P) is given by
-//    (1+cosX*fx,0,sinX*fx) rotated by angle (90-|Y|) (where angles X,Y are defined above) along vector (1,0,0).
-//
-//    Matrix of rotation:
-//
-//    |sinY|  cosY
-//    -cosY  |sinY|
-//
-// d) compute the above and see that this is equal precisely to SX from (**).
-// e) repeat points b,c,d in direction Y and come up with (***).
-//
-//////////////////////////////////////////////////////////////////////////////////////////////
-// Note: we should avoid passing certain combinations of parameters to this function. One such known
-// combination is ( A: small but positive, B: any, amplitude >= length ).
-// In this case, certain 'unlucky' points have their normals almost horizontal (they got moved by (almost!)
-// amplitude, and other point length (i.e. <=amplitude) away got moved by 0, so the slope in this point is
-// very steep). Visual effect is: vast majority of surface pretty much unchanged, but random 'unlucky'
-// points very dark)
-//
-// Generally speaking I'd keep to amplitude < length, as the opposite case has some other problems as well.
-
-#ifdef WAVE
-void wave(in int effect, inout vec3 v, inout vec3 n)
-  {
-  vec2 center     = vUniforms[effect+1].yz;
-  float amplitude = vUniforms[effect  ].x;
-  float length    = vUniforms[effect  ].y;
-
-  vec2 ps = center - v.xy;
-  float deg = amplitude*degree_region(vUniforms[effect+2],ps);
-
-  if( deg != 0.0 && length != 0.0 )
-    {
-    float phase = vUniforms[effect  ].z;
-    float alpha = vUniforms[effect  ].w;
-    float beta  = vUniforms[effect+1].x;
-
-    float sinA = sin(alpha);
-    float cosA = cos(alpha);
-    float sinB = sin(beta);
-    float cosB = cos(beta);
-
-    float angle= 1.578*(ps.x*cosB-ps.y*sinB) / length + phase;
-
-    vec3 dir= vec3(sinB*cosA,cosB*cosA,sinA);
-
-    v += sin(angle)*deg*dir;
-
-    if( n.z != 0.0 )
-      {
-      float sqrtX = sqrt(dir.y*dir.y + dir.z*dir.z);
-      float sqrtY = sqrt(dir.x*dir.x + dir.z*dir.z);
-
-      float sinX = ( sqrtY==0.0 ? 0.0 : dir.z / sqrtY);
-      float cosX = ( sqrtY==0.0 ? 1.0 : dir.x / sqrtY);
-      float sinY = ( sqrtX==0.0 ? 0.0 : dir.z / sqrtX);
-      float cosY = ( sqrtX==0.0 ? 1.0 : dir.y / sqrtX);
-
-      float abs_z = dir.z <0.0 ? -(sinX*sinY) : (sinX*sinY);
-
-      float tmp = 1.578*cos(angle)*deg/length;
-
-      float fx =-cosB*tmp;
-      float fy = sinB*tmp;
-
-      vec3 sx = vec3 (1.0+cosX*fx,cosY*sinX*fx,abs_z*fx);
-      vec3 sy = vec3 (cosX*sinY*fy,1.0+cosY*fy,abs_z*fy);
-
-      vec3 normal = cross(sx,sy);
-
-      if( normal.z<=0.0 )                   // Why this bizarre shit rather than the straightforward
-        {                                   //
-        normal.x= 0.0;                      // if( normal.z>0.0 )
-        normal.y= 0.0;                      //   {
-        normal.z= 1.0;                      //   n.x = (n.x*normal.z + n.z*normal.x);
-        }                                   //   n.y = (n.y*normal.z + n.z*normal.y);
-                                            //   n.z = (n.z*normal.z);
-                                            //   }
-      n.x = (n.x*normal.z + n.z*normal.x);  //
-      n.y = (n.y*normal.z + n.z*normal.y);  // ? Because if we do the above, my shitty Nexus4 crashes
-      n.z = (n.z*normal.z);                 // during shader compilation!
-      }
-    }
-  }
-#endif
-
 #endif  // NUM_VERTEX>0
 
 //////////////////////////////////////////////////////////////////////////////////////////////
@@ -529,31 +154,13 @@ void main()
   vec3 n = a_Normal;
 
 #if NUM_VERTEX>0
-  int j=0;
+  int effect=0;
 
   for(int i=0; i<vNumEffects; i++)
     {
-#ifdef DISTORT
-    if( vName[i]==DISTORT) distort(j,v,n); else
-#endif
-#ifdef DEFORM
-    if( vName[i]==DEFORM ) deform (j,v,n); else
-#endif
-#ifdef SINK
-    if( vName[i]==SINK   ) sink   (j,v);   else
-#endif
-#ifdef PINCH
-    if( vName[i]==PINCH  ) pinch  (j,v);   else
-#endif
-#ifdef SWIRL
-    if( vName[i]==SWIRL  ) swirl  (j,v);   else
-#endif
-#ifdef WAVE
-    if( vName[i]==WAVE   ) wave   (j,v,n); else
-#endif
-    {}
+    // ENABLED EFFECTS WILL BE INSERTED HERE
 
-    j+=3;
+    effect+=3;
     }
 #endif
    
