commit f046b1592809af00c2eed71e3d1fdf20214362aa
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Sat May 16 20:54:56 2020 +0100

    First attempt at the MeshBase.apply(VertexEffect) API.

diff --git a/src/main/java/org/distorted/library/effect/Effect.java b/src/main/java/org/distorted/library/effect/Effect.java
index 57f13ed..b810e11 100644
--- a/src/main/java/org/distorted/library/effect/Effect.java
+++ b/src/main/java/org/distorted/library/effect/Effect.java
@@ -69,10 +69,7 @@ public abstract class Effect
     float[] u = name.getUnity();
     int l = u.length;
 
-    for(int i=0; i<l; i++)
-      {
-      mUnity[n*MAX_UNITY_DIM+i] = u[i];
-      }
+    System.arraycopy(u, 0, mUnity, MAX_UNITY_DIM*n, l);
 
     mUnityDim[n] = l;
 
diff --git a/src/main/java/org/distorted/library/effect/VertexEffect.java b/src/main/java/org/distorted/library/effect/VertexEffect.java
index 3e13d17..15575bd 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffect.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffect.java
@@ -21,6 +21,8 @@ package org.distorted.library.effect;
 
 import org.distorted.library.type.Static4D;
 
+import java.lang.reflect.Method;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Abstract class that represents an Effect that works by injecting certain code into the main Vertex shader.
@@ -37,6 +39,10 @@ public abstract class VertexEffect extends Effect
   private static String mGLSL = "";
   private static int mNumEnabled = 0;
 
+  private static String mFullGLSL = "";
+  private static int mFullEnabled = 0;
+  private static boolean mFullPrepared = false;
+
   final static Static4D MAX_REGION = new Static4D(0,0,0,1000000);
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -47,18 +53,10 @@ public abstract class VertexEffect extends Effect
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// prepare code to be injected into the 'main_vertex_shader' main() function.
 
-  static void addEffect(EffectName name, String code)
+  private static String retSection(int effect, String code)
     {
-    int effect = name.ordinal();
-
-    if( mEnabled[effect] ) return;
-
-    mEnabled[effect] = true;
-    mNumEnabled ++;
-
-    mGLSL +=
+    return
 
         "if( vName[i]=="+effect+")\n" +
           "{\n" +
@@ -67,6 +65,62 @@ public abstract class VertexEffect extends Effect
         "else\n";
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// prepare the code to be injected into the Full program, i.e. code of ALL vertex effects.
+
+  private static void prepareFull()
+    {
+    Method method;
+
+    for(EffectName name: EffectName.values())
+      {
+      if( name.getType() == EffectType.VERTEX )
+        {
+        Class<? extends Effect> cls = name.getEffectClass();
+
+        try
+          {
+          method = cls.getDeclaredMethod("code");
+          }
+        catch(NoSuchMethodException ex)
+          {
+          android.util.Log.e("Effect", "exception getting method: "+ex.getMessage());
+          method = null;
+          }
+
+        try
+          {
+          if( method!=null )
+            {
+            Object value = method.invoke(null);
+            String code = (String)value;
+            mFullGLSL += retSection(name.ordinal(),code);
+            mFullEnabled++;
+            }
+          }
+        catch(Exception ex)
+          {
+          android.util.Log.e("Effect", "exception invoking method: "+ex.getMessage());
+          }
+        }
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// prepare code to be injected into the 'main_vertex_shader' main() function.
+
+  static void addEffect(EffectName name, String code)
+    {
+    int effect = name.ordinal();
+
+    if( !mEnabled[effect] )
+      {
+      mEnabled[effect] = true;
+      mNumEnabled ++;
+      mGLSL += retSection(effect,code);
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Only for use by the library itself.
@@ -78,12 +132,49 @@ public abstract class VertexEffect extends Effect
     return mGLSL + "{}";
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Only for use by the library itself.
+ *
+ * @y.exclude
+ */
+  public static String getAllGLSL()
+    {
+    if( !mFullPrepared )
+      {
+      prepareFull();
+      mFullPrepared = true;
+      }
+
+    return mFullGLSL + "{}";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Only for use by the library itself.
+ *
+ * @y.exclude
+ */
+  public static int getAllEnabled()
+    {
+    if( !mFullPrepared )
+      {
+      prepareFull();
+      mFullPrepared = true;
+      }
+
+    return mFullEnabled;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   static void destroyStatics()
     {
     mNumEnabled = 0;
     mGLSL = "";
+    mFullEnabled= 0;
+    mFullGLSL = "";
+    mFullPrepared = false;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectDeform.java b/src/main/java/org/distorted/library/effect/VertexEffectDeform.java
index dc35fdd..dcd871b 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectDeform.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectDeform.java
@@ -29,6 +29,8 @@ import org.distorted.library.type.Data4D;
  */
 public class VertexEffectDeform extends VertexEffect
   {
+  private static final EffectName NAME = EffectName.DEFORM;
+
   private Data3D mVector, mCenter;
   private Data1D mRadius;
   private Data4D mRegion;
@@ -41,10 +43,11 @@ public class VertexEffectDeform extends VertexEffect
  */
   public boolean compute(float[] uniforms, int index, long currentDuration, long step )
     {
-    mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    mRadius.get(uniforms,index+3,currentDuration,step);
-    return mVector.get(uniforms,index,currentDuration,step);
+    mCenter.get(uniforms,index+CENTER_OFFSET  ,currentDuration,step);
+    mRegion.get(uniforms,index+REGION_OFFSET  ,currentDuration,step);
+    mRadius.get(uniforms,index+VALUES_OFFSET+3,currentDuration,step);
+
+    return mVector.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -103,12 +106,10 @@ public class VertexEffectDeform extends VertexEffect
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // 2020-05-03: replaced vec3 'u_Bounding' with a uniform 'vUniforms[effect].w' (i.e. mRadius)
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+
+  static String code()
     {
-    addEffect( EffectName.DEFORM,
+    return
 
         "const vec3 ONE = vec3(1.0,1.0,1.0);                                 \n"
       + "const float A = 0.5;                                                \n"
@@ -144,8 +145,16 @@ public class VertexEffectDeform extends VertexEffect
       + "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.xy;"
-      );
+      + "n.xy += n.z*b*ps.xy;";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+ */
+  public static void enable()
+    {
+    addEffect( NAME, code() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -161,7 +170,7 @@ public class VertexEffectDeform extends VertexEffect
  */
   public VertexEffectDeform(Data3D vector, Data1D radius, Data3D center, Data4D region)
     {
-    super(EffectName.DEFORM);
+    super(NAME);
     mVector = vector;
     mRadius = radius;
     mCenter = center;
@@ -180,7 +189,7 @@ public class VertexEffectDeform extends VertexEffect
  */
   public VertexEffectDeform(Data3D vector, Data1D radius, Data3D center)
     {
-    super(EffectName.DEFORM);
+    super(NAME);
     mVector = vector;
     mRadius = radius;
     mCenter = center;
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectDistort.java b/src/main/java/org/distorted/library/effect/VertexEffectDistort.java
index b6488e8..d37fb69 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectDistort.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectDistort.java
@@ -28,6 +28,8 @@ import org.distorted.library.type.Data4D;
  */
 public class VertexEffectDistort extends VertexEffect
   {
+  private static final EffectName NAME = EffectName.DISTORT;
+
   private Data3D mVector, mCenter;
   private Data4D mRegion;
 
@@ -41,7 +43,8 @@ public class VertexEffectDistort extends VertexEffect
     {
     mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
     mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    return mVector.get(uniforms,index,currentDuration,step);
+
+    return mVector.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -118,12 +121,10 @@ public class VertexEffectDistort extends VertexEffect
 // which makes Vrot = (a+n.y*c , b-n.y*c , v*n) where
 // a = vx*nz-vz*nx , b = vy*nz-vz*ny , c = (vx*ny-vy*nx)/(1+nz)    (unless n=(0,0,-1))
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+
+  static String code()
     {
-    addEffect(EffectName.DISTORT,
+    return
 
         "vec3 ps = vUniforms[effect+1].yzw - v;                        \n"
       + "vec3 force = vUniforms[effect].xyz;                           \n"
@@ -152,8 +153,16 @@ public class VertexEffectDistort extends VertexEffect
       + "  n = vec3( an+n.y*cn , bn-n.x*cn , -N.x*n.x-N.y*n.y+N.z*n.z);\n"   // notice 4 signs change!
 
       + "  n = normalize(n);                                           \n"
-      + "  }                                                           \n"
-      );
+      + "  }                                                           \n";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+ */
+  public static void enable()
+    {
+    addEffect( NAME, code() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -166,7 +175,7 @@ public class VertexEffectDistort extends VertexEffect
  */
   public VertexEffectDistort(Data3D vector, Data3D center, Data4D region)
     {
-    super(EffectName.DISTORT);
+    super(NAME);
     mVector = vector;
     mCenter = center;
     mRegion = (region==null ? MAX_REGION : region);
@@ -181,7 +190,7 @@ public class VertexEffectDistort extends VertexEffect
  */
   public VertexEffectDistort(Data3D vector, Data3D center)
     {
-    super(EffectName.DISTORT);
+    super(NAME);
     mVector = vector;
     mCenter = center;
     mRegion = MAX_REGION;
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectMove.java b/src/main/java/org/distorted/library/effect/VertexEffectMove.java
index d4d5b17..9719c76 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectMove.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectMove.java
@@ -28,6 +28,8 @@ import org.distorted.library.type.Data3D;
  */
 public class VertexEffectMove extends VertexEffect
   {
+  private static final EffectName NAME = EffectName.VERTEX_MOVE;
+
   private Data3D mVector;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -38,7 +40,14 @@ public class VertexEffectMove extends VertexEffect
  */
   public boolean compute(float[] uniforms, int index, long currentDuration, long step )
     {
-    return mVector.get(uniforms,index,currentDuration,step);
+    return mVector.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static String code()
+    {
+    return "v += vUniforms[effect].xyz;";
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,7 +58,7 @@ public class VertexEffectMove extends VertexEffect
  */
   public static void enable()
     {
-    addEffect( EffectName.VERTEX_MOVE, "v += vUniforms[effect].xyz;" );
+    addEffect( NAME, code() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -60,7 +69,7 @@ public class VertexEffectMove extends VertexEffect
  */
   public VertexEffectMove(Data3D vector)
     {
-    super(EffectName.VERTEX_MOVE);
+    super(NAME);
     mVector = vector;
     }
   }
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectPinch.java b/src/main/java/org/distorted/library/effect/VertexEffectPinch.java
index c1fcf95..ac010c4 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectPinch.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectPinch.java
@@ -34,6 +34,8 @@ import org.distorted.library.type.Data4D;
  */
 public class VertexEffectPinch extends VertexEffect
   {
+  private static final EffectName NAME = EffectName.PINCH;
+
   private Data3D mPinch;
   private Data3D mCenter;
   private Data4D mRegion;
@@ -48,28 +50,24 @@ public class VertexEffectPinch extends VertexEffect
     {
     mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
     mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    boolean ret = mPinch.get(uniforms,index,currentDuration,step);
+    boolean ret = mPinch.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
 
-    uniforms[index+1] = (float)(Math.PI*uniforms[index+1]/180);
-    uniforms[index+2] = (float)(Math.PI*uniforms[index+2]/180);
+    uniforms[index+VALUES_OFFSET+1] = (float)(Math.PI*uniforms[index+1]/180);
+    uniforms[index+VALUES_OFFSET+2] = (float)(Math.PI*uniforms[index+2]/180);
 
     return ret;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Pull P=(v.x,v.y) along a vector from the center of region sphere to a point on it defined by
 // the (latitude,longitude) pair of angles 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)
 // (where 'line' above passes through the center point and goes along the vector)
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+
+  static String code()
     {
-    addEffect(EffectName.PINCH,
+    return
 
         "vec3 ps = vUniforms[effect+1].yzw -v;               \n"
       + "float h         = vUniforms[effect].x;              \n"
@@ -93,8 +91,18 @@ public class VertexEffectPinch extends VertexEffect
       + "n_ps = sign_ps*n_ps/(dot_ps-(sign_ps-1.0));         \n" // uff! now n_ps is the parallel to ps component of n, even if ps==0
       + "float move = deg*(h-1.0)/(h/B+1.0/A);               \n" // move(0)=-A*deg, move(1)=0, move(inf)=B*deg
       + "n += move * abs(dot(n,dir)) * n_ps;                 \n"
-      + "n = normalize(n);"
-      );
+      + "n = normalize(n);";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+ */
+  public static void enable()
+    {
+    addEffect( NAME, code() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -109,7 +117,7 @@ public class VertexEffectPinch extends VertexEffect
  */
   public VertexEffectPinch(Data3D pinch, Data3D center, Data4D region)
     {
-    super(EffectName.PINCH);
+    super(NAME);
     mPinch  = pinch;
     mCenter = center;
     mRegion = (region==null ? MAX_REGION : region);
@@ -126,7 +134,7 @@ public class VertexEffectPinch extends VertexEffect
  */
   public VertexEffectPinch(Data3D pinch, Data3D center)
     {
-    super(EffectName.PINCH);
+    super(NAME);
     mPinch  = pinch;
     mCenter = center;
     mRegion = MAX_REGION;
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectQuaternion.java b/src/main/java/org/distorted/library/effect/VertexEffectQuaternion.java
index def8dec..6b61893 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectQuaternion.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectQuaternion.java
@@ -29,6 +29,8 @@ import org.distorted.library.type.Data4D;
  */
 public class VertexEffectQuaternion extends VertexEffect
   {
+  private static final EffectName NAME = EffectName.VERTEX_QUATERNION;
+
   private Data4D mQuaternion;
   private Data3D mCenter;
 
@@ -41,7 +43,42 @@ public class VertexEffectQuaternion extends VertexEffect
   public boolean compute(float[] uniforms, int index, long currentDuration, long step )
     {
     mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    return mQuaternion.get(uniforms,index,currentDuration,step);
+    return mQuaternion.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static String code()
+    {
+    return
+
+       "float qx = vUniforms[effect].x;               \n"
+     + "float qy = vUniforms[effect].y;               \n"
+     + "float qz = vUniforms[effect].z;               \n"
+     + "float qw = vUniforms[effect].w;               \n"
+     + "vec3 center = vUniforms[effect+1].yzw;        \n"
+
+     + "v -= center;                                  \n"
+
+     + "float tx = qx - v.z*qy + v.y*qz + v.x*qw;     \n"
+     + "float ty = qy + v.z*qx + v.y*qw - v.x*qz;     \n"
+     + "float tz = qz + v.z*qw - v.y*qx + v.x*qy;     \n"
+     + "float tw = qw - v.z*qz - v.y*qy - v.x*qx;     \n"
+
+     + "v.x = qw*tx + qz*ty - qy*tz - qx*tw;          \n"
+     + "v.y = qw*ty - qz*tx - qy*tw + qx*tz;          \n"
+     + "v.z = qw*tz - qz*tw + qy*tx - qx*ty;          \n"
+
+     + "v += center;                                  \n"
+
+     + "float nx =  - n.z*qy + n.y*qz + n.x*qw;       \n"
+     + "float ny =  + n.z*qx + n.y*qw - n.x*qz;       \n"
+     + "float nz =  + n.z*qw - n.y*qx + n.x*qy;       \n"
+     + "float nw =  - n.z*qz - n.y*qy - n.x*qx;       \n"
+
+     + "n.x = qw*nx + qz*ny - qy*nz - qx*nw;          \n"
+     + "n.y = qw*ny - qz*nx - qy*nw + qx*nz;          \n"
+     + "n.z = qw*nz - qz*nw + qy*nx - qx*ny;          \n";
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -52,35 +89,7 @@ public class VertexEffectQuaternion extends VertexEffect
  */
   public static void enable()
     {
-    addEffect( EffectName.VERTEX_QUATERNION,
-               "float qx = vUniforms[effect].x;               \n"
-             + "float qy = vUniforms[effect].y;               \n"
-             + "float qz = vUniforms[effect].z;               \n"
-             + "float qw = vUniforms[effect].w;               \n"
-             + "vec3 center = vUniforms[effect+1].yzw;        \n"
-
-             + "v -= center;                                  \n"
-
-             + "float tx = qx - v.z*qy + v.y*qz + v.x*qw;     \n"
-             + "float ty = qy + v.z*qx + v.y*qw - v.x*qz;     \n"
-             + "float tz = qz + v.z*qw - v.y*qx + v.x*qy;     \n"
-             + "float tw = qw - v.z*qz - v.y*qy - v.x*qx;     \n"
-
-             + "v.x = qw*tx + qz*ty - qy*tz - qx*tw;          \n"
-             + "v.y = qw*ty - qz*tx - qy*tw + qx*tz;          \n"
-             + "v.z = qw*tz - qz*tw + qy*tx - qx*ty;          \n"
-
-             + "v += center;                                  \n"
-
-             + "float nx =  - n.z*qy + n.y*qz + n.x*qw;       \n"
-             + "float ny =  + n.z*qx + n.y*qw - n.x*qz;       \n"
-             + "float nz =  + n.z*qw - n.y*qx + n.x*qy;       \n"
-             + "float nw =  - n.z*qz - n.y*qy - n.x*qx;       \n"
-
-             + "n.x = qw*nx + qz*ny - qy*nz - qx*nw;          \n"
-             + "n.y = qw*ny - qz*nx - qy*nw + qx*nz;          \n"
-             + "n.z = qw*nz - qz*nw + qy*nx - qx*ny;          \n"
-             );
+    addEffect( NAME, code() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -92,7 +101,7 @@ public class VertexEffectQuaternion extends VertexEffect
  */
   public VertexEffectQuaternion(Data4D quaternion, Data3D center )
     {
-    super(EffectName.VERTEX_QUATERNION);
+    super(NAME);
     mQuaternion = quaternion;
     mCenter = center;
     }
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectRotate.java b/src/main/java/org/distorted/library/effect/VertexEffectRotate.java
index 1e98524..bd08c9b 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectRotate.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectRotate.java
@@ -30,6 +30,8 @@ import org.distorted.library.type.Data4D;
  */
 public class VertexEffectRotate extends VertexEffect
   {
+  private static final EffectName NAME = EffectName.VERTEX_ROTATE;
+
   private Data1D mAngle;
   private Data3D mAxis, mCenter;
 
@@ -42,63 +44,69 @@ public class VertexEffectRotate extends VertexEffect
   public boolean compute(float[] uniforms, int index, long currentDuration, long step )
     {
     mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    mAxis.get(uniforms,index+1,currentDuration,step);
+    mAxis.get(uniforms,index+VALUES_OFFSET+1,currentDuration,step);
 
     float len = uniforms[index+1]*uniforms[index+1] + uniforms[index+2]*uniforms[index+2] + uniforms[index+3]*uniforms[index+3];
     len = (float)Math.sqrt(len);
 
     if( len!=0 )
       {
-      uniforms[index+1] /= len;
-      uniforms[index+2] /= len;
-      uniforms[index+3] /= len;
+      uniforms[index+VALUES_OFFSET+1] /= len;
+      uniforms[index+VALUES_OFFSET+2] /= len;
+      uniforms[index+VALUES_OFFSET+3] /= len;
       }
 
-    return mAngle.get(uniforms,index,currentDuration,step);
+    return mAngle.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+
+  static String code()
     {
-    addEffect( EffectName.VERTEX_ROTATE,
+    return
+
+      "float angle = vUniforms[effect].x*3.1415/360.0;\n"
+    + "vec3 center = vUniforms[effect+1].yzw;         \n"
+    + "float sinHalf = sin(angle);                    \n"
+    + "float cosHalf = cos(angle);                    \n"
 
-               "float angle = vUniforms[effect].x*3.1415/360.0;\n"
-             + "vec3 center = vUniforms[effect+1].yzw;         \n"
-             + "float sinHalf = sin(angle);                    \n"
-             + "float cosHalf = cos(angle);                    \n"
+    + "float qx = vUniforms[effect].y * sinHalf;      \n"
+    + "float qy = vUniforms[effect].z * sinHalf;      \n"
+    + "float qz = vUniforms[effect].w * sinHalf;      \n"
+    + "float qw = cosHalf;                            \n"
 
-             + "float qx = vUniforms[effect].y * sinHalf;      \n"
-             + "float qy = vUniforms[effect].z * sinHalf;      \n"
-             + "float qz = vUniforms[effect].w * sinHalf;      \n"
-             + "float qw = cosHalf;                            \n"
+    + "v -= center;                                   \n"
 
-             + "v -= center;                                   \n"
+    + "float tx = qx - v.z*qy + v.y*qz + v.x*qw;      \n"
+    + "float ty = qy + v.z*qx + v.y*qw - v.x*qz;      \n"
+    + "float tz = qz + v.z*qw - v.y*qx + v.x*qy;      \n"
+    + "float tw = qw - v.z*qz - v.y*qy - v.x*qx;      \n"
 
-             + "float tx = qx - v.z*qy + v.y*qz + v.x*qw;      \n"
-             + "float ty = qy + v.z*qx + v.y*qw - v.x*qz;      \n"
-             + "float tz = qz + v.z*qw - v.y*qx + v.x*qy;      \n"
-             + "float tw = qw - v.z*qz - v.y*qy - v.x*qx;      \n"
+    + "v.x = qw*tx + qz*ty - qy*tz - qx*tw;           \n"
+    + "v.y = qw*ty - qz*tx - qy*tw + qx*tz;           \n"
+    + "v.z = qw*tz - qz*tw + qy*tx - qx*ty;           \n"
 
-             + "v.x = qw*tx + qz*ty - qy*tz - qx*tw;           \n"
-             + "v.y = qw*ty - qz*tx - qy*tw + qx*tz;           \n"
-             + "v.z = qw*tz - qz*tw + qy*tx - qx*ty;           \n"
+    + "v += center;                                   \n"
 
-             + "v += center;                                   \n"
+    + "float nx =  - n.z*qy + n.y*qz + n.x*qw;        \n"
+    + "float ny =  + n.z*qx + n.y*qw - n.x*qz;        \n"
+    + "float nz =  + n.z*qw - n.y*qx + n.x*qy;        \n"
+    + "float nw =  - n.z*qz - n.y*qy - n.x*qx;        \n"
 
-             + "float nx =  - n.z*qy + n.y*qz + n.x*qw;        \n"
-             + "float ny =  + n.z*qx + n.y*qw - n.x*qz;        \n"
-             + "float nz =  + n.z*qw - n.y*qx + n.x*qy;        \n"
-             + "float nw =  - n.z*qz - n.y*qy - n.x*qx;        \n"
+    + "n.x = qw*nx + qz*ny - qy*nz - qx*nw;           \n"
+    + "n.y = qw*ny - qz*nx - qy*nw + qx*nz;           \n"
+    + "n.z = qw*nz - qz*nw + qy*nx - qx*ny;           \n";
+    }
 
-             + "n.x = qw*nx + qz*ny - qy*nz - qx*nw;           \n"
-             + "n.y = qw*ny - qz*nx - qy*nw + qx*nz;           \n"
-             + "n.z = qw*nz - qz*nw + qy*nx - qx*ny;           \n"
-             );
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+ */
+  public static void enable()
+    {
+    addEffect( NAME, code() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -111,7 +119,7 @@ public class VertexEffectRotate extends VertexEffect
  */
   public VertexEffectRotate(Data1D angle, Data3D axis, Data3D center)
     {
-    super(EffectName.VERTEX_ROTATE);
+    super(NAME);
     mAngle = angle;
     mAxis = axis;
     mCenter = center;
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectScale.java b/src/main/java/org/distorted/library/effect/VertexEffectScale.java
index d85f26b..4f41413 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectScale.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectScale.java
@@ -28,6 +28,8 @@ import org.distorted.library.type.Static3D;
  */
 public class VertexEffectScale extends VertexEffect
   {
+  private static final EffectName NAME = EffectName.VERTEX_SCALE;
+
   private Data3D mScale;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -38,7 +40,14 @@ public class VertexEffectScale extends VertexEffect
  */
   public boolean compute(float[] uniforms, int index, long currentDuration, long step )
     {
-    return mScale.get(uniforms,index,currentDuration,step);
+    return mScale.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static String code()
+    {
+    return "v *= vUniforms[effect].xyz;";
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,7 +58,7 @@ public class VertexEffectScale extends VertexEffect
  */
   public static void enable()
     {
-    addEffect( EffectName.VERTEX_SCALE, "v *= vUniforms[effect].xyz;" );
+    addEffect( NAME, code() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -60,7 +69,7 @@ public class VertexEffectScale extends VertexEffect
  */
   public VertexEffectScale(Data3D scale)
     {
-    super(EffectName.VERTEX_SCALE);
+    super(NAME);
     mScale = scale;
     }
 
@@ -72,7 +81,7 @@ public class VertexEffectScale extends VertexEffect
  */
   public VertexEffectScale(float scale)
     {
-    super(EffectName.VERTEX_SCALE);
+    super(NAME);
     mScale = new Static3D(scale,scale,scale);
     }
   }
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectShear.java b/src/main/java/org/distorted/library/effect/VertexEffectShear.java
index f095bdd..4254a6b 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectShear.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectShear.java
@@ -27,7 +27,10 @@ import org.distorted.library.type.Data3D;
  */
 public class VertexEffectShear extends VertexEffect
   {
-  private Data3D mShear, mCenter;
+  private static final EffectName NAME = EffectName.VERTEX_SHEAR;
+
+  private Data3D mShear;
+  private Data3D mCenter;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -38,73 +41,50 @@ public class VertexEffectShear extends VertexEffect
   public boolean compute(float[] uniforms, int index, long currentDuration, long step )
     {
     mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
-    return mShear.get(uniforms,index,currentDuration,step);
+    return mShear.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/*
-  float sx = uniforms[NUM_UNIFORMS*index  ];
-    float sy = uniforms[NUM_UNIFORMS*index+1];
-    float sz = uniforms[NUM_UNIFORMS*index+2];
 
-    float x  = uniforms[NUM_UNIFORMS*index+CENTER_OFFSET  ];
-    float y  = uniforms[NUM_UNIFORMS*index+CENTER_OFFSET+1];
-    float z  = uniforms[NUM_UNIFORMS*index+CENTER_OFFSET+2];
+  static String code()
+    {
+    return
+
+      "float sx = vUniforms[effect].x;               \n"
+    + "float sy = vUniforms[effect].y;               \n"
+    + "float sz = vUniforms[effect].z;               \n"
+    + "vec3 center = vUniforms[effect+1].yzw;        \n"
 
-    Matrix.translateM(matrix, 0, x, y, z);
+    + "v -= center;                                  \n"
 
-    matrix[4] += sx*matrix[0]; // Multiply viewMatrix by 1 x 0 0 , i.e. X-shear.
-    matrix[5] += sx*matrix[1]; //                        0 1 0 0
-    matrix[6] += sx*matrix[2]; //                        0 0 1 0
-    matrix[7] += sx*matrix[3]; //                        0 0 0 1
+    + "float new_vx = (1.0+sx*sy)*v.x + sx*v.y;      \n"
+    + "float new_vy = sy*v.x + v.y;                  \n"
+    + "float new_vz = sz*v.y + v.z;                  \n"
 
-    matrix[0] += sy*matrix[4]; // Multiply viewMatrix by 1 0 0 0 , i.e. Y-shear.
-    matrix[1] += sy*matrix[5]; //                        y 1 0 0
-    matrix[2] += sy*matrix[6]; //                        0 0 1 0
-    matrix[3] += sy*matrix[7]; //                        0 0 0 1
+    + "v.x = new_vx;                                 \n"
+    + "v.y = new_vy;                                 \n"
+    + "v.z = new_vz;                                 \n"
 
-    matrix[4] += sz*matrix[8]; // Multiply viewMatrix by 1 0 0 0 , i.e. Z-shear.
-    matrix[5] += sz*matrix[9]; //                        0 1 0 0
-    matrix[6] += sz*matrix[10];//                        0 z 1 0
-    matrix[7] += sz*matrix[11];//                        0 0 0 1
+    + "v += center;                                  \n"
 
-    Matrix.translateM(matrix, 0,-x,-y,-z);
-*/
+    + "float new_nx = (1.0+sx*sy)*n.x + sx*n.y;      \n"
+    + "float new_ny = sy*n.x + n.y;                  \n"
+    + "float new_nz = sz*n.y + n.z;                  \n"
 
+    + "n.x = new_nx;                                 \n"
+    + "n.y = new_ny;                                 \n"
+    + "n.z = new_nz;                                 \n";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
  */
   public static void enable()
     {
-    addEffect( EffectName.VERTEX_SHEAR,
-
-               "float sx = vUniforms[effect].x;               \n"
-             + "float sy = vUniforms[effect].y;               \n"
-             + "float sz = vUniforms[effect].z;               \n"
-             + "vec3 center = vUniforms[effect+1].yzw;        \n"
-
-             + "v -= center;                                  \n"
-
-             + "float new_vx = (1.0+sx*sy)*v.x + sx*v.y;      \n"
-             + "float new_vy = sy*v.x + v.y;                  \n"
-             + "float new_vz = sz*v.y + v.z;                  \n"
-
-             + "v.x = new_vx;                                 \n"
-             + "v.y = new_vy;                                 \n"
-             + "v.z = new_vz;                                 \n"
-
-             + "v += center;                                  \n"
-
-             + "float new_nx = (1.0+sx*sy)*n.x + sx*n.y;      \n"
-             + "float new_ny = sy*n.x + n.y;                  \n"
-             + "float new_nz = sz*n.y + n.z;                  \n"
-
-             + "n.x = new_nx;                                 \n"
-             + "n.y = new_ny;                                 \n"
-             + "n.z = new_nz;                                 \n"
-             );
+    addEffect( NAME, code() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -119,7 +99,7 @@ public class VertexEffectShear extends VertexEffect
  */
   public VertexEffectShear(Data3D shear, Data3D center)
     {
-    super(EffectName.VERTEX_SHEAR);
+    super(NAME);
     mShear = shear;
     mCenter = center;
     }
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectSink.java b/src/main/java/org/distorted/library/effect/VertexEffectSink.java
index 42ea29b..dec5a61 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectSink.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectSink.java
@@ -30,6 +30,8 @@ import org.distorted.library.type.Data4D;
  */
 public class VertexEffectSink extends VertexEffect
   {
+  private static final EffectName NAME = EffectName.SINK;
+
   private Data1D mSink;
   private Data3D mCenter;
   private Data4D mRegion;
@@ -44,21 +46,14 @@ public class VertexEffectSink extends VertexEffect
     {
     mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
     mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    return mSink.get(uniforms,index,currentDuration,step);
+    return mSink.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// 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)
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+
+  static String code()
     {
-    addEffect(EffectName.SINK,
+    return
 
         "vec3 ps = vUniforms[effect+1].yzw - v;            \n"
       + "float h = vUniforms[effect].x;                    \n"
@@ -74,8 +69,21 @@ public class VertexEffectSink extends VertexEffect
       + "n_ps = (sign_ps*n_ps)/(dot_ps-(sign_ps-1.0));     \n" // uff! now n_ps is the parallel to ps component of n, even if ps==0
       + "float move = deg*(h-1.0)/(h/B+1.0/A);             \n" // move(0)=-A*deg, move(1)=0, move(inf)=B*deg
       + "n += move*n_ps;                                   \n"
-      + "n = normalize(n);"
-      );
+      + "n = normalize(n);";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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)
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+ */
+  public static void enable()
+    {
+    addEffect(NAME, code() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -89,7 +97,7 @@ public class VertexEffectSink extends VertexEffect
  */
   public VertexEffectSink(Data1D sink, Data3D center, Data4D region)
     {
-    super(EffectName.SINK);
+    super(NAME);
     mSink   = sink;
     mCenter = center;
     mRegion = (region==null ? MAX_REGION : region);
@@ -105,7 +113,7 @@ public class VertexEffectSink extends VertexEffect
  */
   public VertexEffectSink(Data1D sink, Data3D center)
     {
-    super(EffectName.SINK);
+    super(NAME);
     mSink   = sink;
     mCenter = center;
     mRegion = MAX_REGION;
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectSwirl.java b/src/main/java/org/distorted/library/effect/VertexEffectSwirl.java
index 6d441b9..4581eae 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectSwirl.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectSwirl.java
@@ -34,6 +34,8 @@ import org.distorted.library.type.Data4D;
  */
 public class VertexEffectSwirl extends VertexEffect
   {
+  private static final EffectName NAME = EffectName.SWIRL;
+
   private Data1D mSwirl;
   private Data3D mCenter;
   private Data4D mRegion;
@@ -48,26 +50,22 @@ public class VertexEffectSwirl extends VertexEffect
     {
     mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
     mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    boolean ret = mSwirl.get(uniforms,index,currentDuration,step);
+    boolean ret = mSwirl.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
 
-    uniforms[index] = (float)(Math.PI*uniforms[index]/180);
+    uniforms[index+VALUES_OFFSET] = (float)(Math.PI*uniforms[index]/180);
 
     return ret;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // 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.
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+
+  static String code()
     {
-    addEffect(EffectName.SWIRL,
+    return
 
         "vec3 center = vUniforms[effect+1].yzw;                             \n"
       + "vec3 PS = center-v.xyz;                                            \n"
@@ -81,8 +79,18 @@ public class VertexEffectSwirl extends VertexEffect
       + "vec4 SG = (1.0-deg1)*SO;                                           \n" // coordinates of the dilated circle P is going to get rotated around
       + "float d2 = max(0.0,degree(SG,PS2));                                \n" // make it a max(0,deg) because otherwise when center=left edge of the
                                                                                 // object some points end up with d2<0 and they disappear off view.
-      + "v.xy += deg1 * (PS.xy - PS2.xy/(1.0-d2));                          \n" // if d2=1 (i.e P=center) we should have P unchanged. How to do it?
-      );
+      + "v.xy += deg1 * (PS.xy - PS2.xy/(1.0-d2));                          \n";// if d2=1 (i.e P=center) we should have P unchanged. How to do it?
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+ */
+  public static void enable()
+    {
+    addEffect( NAME, code() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -95,7 +103,7 @@ public class VertexEffectSwirl extends VertexEffect
  */
   public VertexEffectSwirl(Data1D swirl, Data3D center, Data4D region)
     {
-    super(EffectName.SWIRL);
+    super(NAME);
     mSwirl  = swirl;
     mCenter = center;
     mRegion = (region==null ? MAX_REGION : region);
@@ -110,7 +118,7 @@ public class VertexEffectSwirl extends VertexEffect
  */
   public VertexEffectSwirl(Data1D swirl, Data3D center)
     {
-    super(EffectName.SWIRL);
+    super(NAME);
     mSwirl  = swirl;
     mCenter = center;
     mRegion = MAX_REGION;
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectWave.java b/src/main/java/org/distorted/library/effect/VertexEffectWave.java
index d545fad..a5a8f74 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectWave.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectWave.java
@@ -33,6 +33,8 @@ import org.distorted.library.type.Data5D;
  */
 public class VertexEffectWave extends VertexEffect
   {
+  private static final EffectName NAME = EffectName.WAVE;
+
   private Data5D mWave;
   private Data3D mCenter;
   private Data4D mRegion;
@@ -47,18 +49,16 @@ public class VertexEffectWave extends VertexEffect
     {
     mCenter.get(uniforms,index+CENTER_OFFSET,currentDuration,step);
     mRegion.get(uniforms,index+REGION_OFFSET,currentDuration,step);
-    boolean ret = mWave.get(uniforms,index,currentDuration,step);
+    boolean ret = mWave.get(uniforms,index+VALUES_OFFSET,currentDuration,step);
 
-    uniforms[index+2] = (float)(Math.PI*uniforms[index+2]/180);
-    uniforms[index+3] = (float)(Math.PI*uniforms[index+3]/180);
-    uniforms[index+4] = (float)(Math.PI*uniforms[index+4]/180);
+    uniforms[index+VALUES_OFFSET+2] = (float)(Math.PI*uniforms[index+2]/180);
+    uniforms[index+VALUES_OFFSET+3] = (float)(Math.PI*uniforms[index+3]/180);
+    uniforms[index+VALUES_OFFSET+4] = (float)(Math.PI*uniforms[index+4]/180);
 
     return ret;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////////////////
 // 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) )  (*)
@@ -122,12 +122,10 @@ public class VertexEffectWave extends VertexEffect
 //
 // Generally speaking I'd keep to amplitude < length, as the opposite case has some other problems as well.
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
- */
-  public static void enable()
+
+  static String code()
     {
-    addEffect(EffectName.WAVE,
+    return
 
         "vec3 center     = vUniforms[effect+1].yzw;                   \n"
       + "float amplitude = vUniforms[effect  ].x;                     \n"
@@ -184,8 +182,18 @@ public class VertexEffectWave extends VertexEffect
       +     "n.y = (n.y*normal.z + n.z*normal.y);                     \n"   // ? Because if we do the above, my Nexus4 crashes
       +     "n.z = (n.z*normal.z);                                    \n"   // during shader compilation!
       +     "}                                                        \n"
-      +   "}"
-      );
+      +   "}";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Have to call this before the shaders get compiled (i.e before DistortedLibrary.onCreate()) for the Effect to work.
+ */
+  public static void enable()
+    {
+    addEffect( NAME, code() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -219,7 +227,7 @@ public class VertexEffectWave extends VertexEffect
  */
   public VertexEffectWave(Data5D wave, Data3D center, Data4D region)
     {
-    super(EffectName.WAVE);
+    super(NAME);
     mWave   = wave;
     mCenter = center;
     mRegion = (region==null ? MAX_REGION : region);
@@ -229,12 +237,12 @@ public class VertexEffectWave extends VertexEffect
 /**
  * Directional, sinusoidal wave effect.
  *
- * @param wave   see {@link #VertexEffectWave(Data5D,Data3D)}
+ * @param wave   see {@link #VertexEffectWave(Data5D,Data3D,Data4D)}
  * @param center 3-dimensional Data that, at any given time, returns the Center of the Effect.
  */
   public VertexEffectWave(Data5D wave, Data3D center)
     {
-    super(EffectName.WAVE);
+    super(NAME);
     mWave   = wave;
     mCenter = center;
     mRegion = MAX_REGION;
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueue.java b/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
index a51d305..0f68dfc 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
@@ -37,7 +37,7 @@ import java.util.HashMap;
  */
 public abstract class EffectQueue implements InternalMaster.Slave
   {
-  static final int MAIN_VARIANTS = 3; // Number of Main program variants (ATM 3: MAIN, MAIN OIT, PREPROCESS)
+  static final int MAIN_VARIANTS = 4; // Number of Main program variants (ATM 4: MAIN, MAIN OIT, PREPROCESS, FULL)
 
   private static final int CREATE = 0;
   private static final int ATTACH = 1;
@@ -47,10 +47,11 @@ public abstract class EffectQueue implements InternalMaster.Slave
   int mNumEffects;              // 'ToBe' will be more than mNumEffects if doWork() hasn't
   private int mNumEffectsToBe;  // added them yet (or less if it hasn't removed some yet)
   float[] mUniforms;
+  private int mNumUniforms;
   long[] mCurrentDuration;
   Effect[] mEffects;
   int[] mName;
-  long mTime=0;
+  long mTime;
 
   private static int[] mMax = new int[EffectType.LENGTH];
   private static long mNextID;
@@ -60,7 +61,7 @@ public abstract class EffectQueue implements InternalMaster.Slave
   private int mIndex;
   private boolean mCreated;
 
-  private class Job
+  private static class Job
     {
     int type;
     int num;
@@ -88,15 +89,69 @@ public abstract class EffectQueue implements InternalMaster.Slave
   EffectQueue(int numUniforms, int index)
     {
     mCreated            = false;
+    mTime               = 0;
     mID                 = 0;
     mNumEffects         = 0;
     mNumEffectsToBe     = 0;
     mIndex              = index;
+    mNumUniforms        = numUniforms;
 
-    mJobs.add(new Job(CREATE,numUniforms,false,null));  // create the stuff that depends on max number
+    mJobs.add(new Job(CREATE,numUniforms,false,null)); // create the stuff that depends on max number
     InternalMaster.newSlave(this);                     // of uniforms later, on first render.
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  EffectQueue(EffectQueue source)
+    {
+    if( !source.mCreated )
+      {
+      mCreated            = false;
+      mTime               = 0;
+      mID                 = 0;
+      mNumEffects         = 0;
+      mNumEffectsToBe     = 0;
+      mIndex              = source.mIndex;
+      mNumUniforms        = source.mNumUniforms;
+
+      int numJobs = source.mJobs.size();
+
+      for(int i=0; i<numJobs; i++)
+        {
+        Job job = source.mJobs.get(i);
+        mJobs.add(job);
+        }
+
+      InternalMaster.newSlave(this);
+      }
+    else
+      {
+      mCreated            = true;
+      mTime               = source.mTime;
+      mID                 = source.mID;
+      mNumEffects         = source.mNumEffects;
+      mNumEffectsToBe     = source.mNumEffectsToBe;
+      mIndex              = source.mIndex;
+      mNumUniforms        = source.mNumUniforms;
+
+      int max = mMax[mIndex];
+      if( max>0 )
+        {
+        mUniforms        = new float[max*source.mNumUniforms];
+        mCurrentDuration = new long[max];
+        mEffects         = new Effect[max];
+        mName            = new int[max];
+        }
+
+      for(int i=0; i<mNumEffects; i++ )
+        {
+        mEffects[i]         = source.mEffects[i];
+        mCurrentDuration[i] = source.mCurrentDuration[i];
+        mName[i]            = source.mName[i];
+        }
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public static void allocateQueues(EffectQueue[] queues, EffectQueue[] from, int flags)
@@ -135,6 +190,7 @@ public abstract class EffectQueue implements InternalMaster.Slave
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+// variant: 0 --> MAIN  1 --> OIT  2 --> prePOST  3 --> FULL
 
   public static void getUniforms(int programH, int variant)
     {
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java b/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
index e0c16e8..f3c2f35 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
@@ -43,6 +43,13 @@ class EffectQueueFragment extends EffectQueue
     super(NUM_UNIFORMS,INDEX);
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  EffectQueueFragment(EffectQueueFragment source)
+    {
+    super(source);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   static void uniforms(int mProgramH, int variant)
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java b/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java
index 2582b84..5709e21 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java
@@ -47,6 +47,13 @@ class EffectQueueMatrix extends EffectQueue
     super(NUM_UNIFORMS,INDEX );
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  EffectQueueMatrix(EffectQueueMatrix source)
+    {
+    super(source);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   static void uniforms(int mProgramH, int variant)
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
index 25029e2..1233660 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
@@ -64,6 +64,13 @@ public class EffectQueuePostprocess extends EffectQueue
     super(NUM_UNIFORMS,INDEX );
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  EffectQueuePostprocess(EffectQueuePostprocess source)
+    {
+    super(source);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void compute(long currTime)
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java b/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java
index 6bde3df..19bfecf 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java
@@ -26,8 +26,12 @@ import org.distorted.library.effect.VertexEffect;
 import org.distorted.library.message.EffectMessageSender;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
-class EffectQueueVertex extends EffectQueue
+/**
+ * Not part of public API, do not document (public only because has to be used in Meshes)
+ *
+ * @y.exclude
+ */
+public class EffectQueueVertex extends EffectQueue
   { 
   private static final int NUM_UNIFORMS = VertexEffect.NUM_UNIFORMS;
   private static final int INDEX = EffectType.VERTEX.ordinal();
@@ -39,11 +43,18 @@ class EffectQueueVertex extends EffectQueue
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
    
-  EffectQueueVertex()
+  public EffectQueueVertex()
     { 
     super(NUM_UNIFORMS,INDEX);
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public EffectQueueVertex(EffectQueueVertex source)
+    {
+    super(source);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   static void uniforms(int mProgramH, int variant)
@@ -55,8 +66,12 @@ class EffectQueueVertex extends EffectQueue
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-  
-  void compute(long currTime)
+/**
+ * Not part of public API, do not document (public only because has to be used in Meshes)
+ *
+ * @y.exclude
+ */
+  public void compute(long currTime)
     {
     if( currTime==mTime ) return;
     if( mTime==0 ) mTime = currTime;
@@ -76,8 +91,12 @@ class EffectQueueVertex extends EffectQueue
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void send(float inflate, int variant)
+/**
+ * Not part of public API, do not document (public only because has to be used in Meshes)
+ *
+ * @y.exclude
+ */
+  public void send(float inflate, int variant)
     {
     GLES30.glUniform1i( mNumEffectsH[variant], mNumEffects);
     GLES30.glUniform1f( mInflateH[variant]   , inflate    );
diff --git a/src/main/java/org/distorted/library/main/DistortedLibrary.java b/src/main/java/org/distorted/library/main/DistortedLibrary.java
index b5f134e..77709e4 100644
--- a/src/main/java/org/distorted/library/main/DistortedLibrary.java
+++ b/src/main/java/org/distorted/library/main/DistortedLibrary.java
@@ -129,6 +129,9 @@ public class DistortedLibrary
   private static int mBlitDepthH;
   private static final FloatBuffer mQuadPositions;
 
+  /// FULL PROGRAM ///
+  private static DistortedProgram mFullProgram;
+
   static
     {
     float[] positionData= { -0.5f, -0.5f,  -0.5f, 0.5f,  0.5f,-0.5f,  0.5f, 0.5f };
@@ -288,6 +291,37 @@ public class DistortedLibrary
     mNormalMVPMatrixH  = GLES30.glGetUniformLocation( normalProgramH, "u_MVPMatrix");
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private static void createFullProgram(Resources resources)
+    {
+    final InputStream fullVertStream = resources.openRawResource(R.raw.main_vertex_shader);
+    final InputStream fullFragStream = resources.openRawResource(R.raw.main_fragment_shader);
+
+    int numV = VertexEffect.getAllEnabled();
+
+    String fullVertHeader= mGLSL_VERSION + ("#define NUM_VERTEX "   + ( numV>0 ? getMax(EffectType.VERTEX ) : 0 ) + "\n");
+    String fullFragHeader= mGLSL_VERSION + ("#define NUM_FRAGMENT " +                                         0   + "\n");
+    String enabledEffectV= VertexEffect.getAllGLSL();
+    String enabledEffectF= "{}";
+
+    String[] feedback = { "v_Position", "v_endPosition" };
+
+    try
+      {
+      mFullProgram = new DistortedProgram(fullVertStream, fullFragStream, fullVertHeader, fullFragHeader,
+                                          enabledEffectV, enabledEffectF, mGLSL, feedback);
+      }
+    catch(Exception e)
+      {
+      Log.e("EFFECTS", e.getClass().getSimpleName()+" trying to compile FULL program: "+e.getMessage());
+      throw new RuntimeException(e.getMessage());
+      }
+
+    int fullProgramH = mFullProgram.getProgramHandle();
+    EffectQueue.getUniforms(fullProgramH,3);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private static void createProgramsOIT(Resources resources)
@@ -418,13 +452,42 @@ public class DistortedLibrary
     GLES30.glEndTransformFeedback();
     GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
 
-    DistortedLibrary.mNormalProgram.useProgram();
-    GLES30.glUniformMatrix4fv(DistortedLibrary.mNormalMVPMatrixH, 1, false, EffectQueue.getMVP(queues) , 0);
-    mesh.bindTransformAttribs(DistortedLibrary.mNormalProgram);
+    mNormalProgram.useProgram();
+    GLES30.glUniformMatrix4fv(mNormalMVPMatrixH, 1, false, EffectQueue.getMVP(queues) , 0);
+    mesh.bindTransformAttribs(mNormalProgram);
     GLES30.glLineWidth(8.0f);
     GLES30.glDrawArrays(GLES30.GL_LINES, 0, 2*num);
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// execute all VertexEffects and adjust all vertices
+
+  public static void adjustVertices(MeshBase mesh)
+    {
+    if( mFullProgram!=null )
+      {
+      GLES30.glViewport(0, 0, 500, 500 ); // TODO ???
+
+      int num = mesh.getNumVertices();
+      int tfo = mesh.getTFO();
+
+      mFullProgram.useProgram();
+      mesh.bindVertexAttribs(mFullProgram);
+      mesh.computeQueue();
+      mesh.sendQueue();
+
+      GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfo );
+      GLES30.glBeginTransformFeedback( GLES30.GL_POINTS);
+      InternalRenderState.switchOffDrawing();
+      GLES30.glDrawArrays( GLES30.GL_POINTS, 0, num );
+      InternalRenderState.restoreDrawing();
+      GLES30.glEndTransformFeedback();
+      GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
+
+      mesh.copyTransformToVertex();
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   static void drawPrivOIT(DistortedEffects effects, MeshBase mesh, InternalOutputSurface surface, long currTime)
@@ -460,7 +523,7 @@ public class DistortedLibrary
 
   static void drawPriv(DistortedEffects effects, MeshBase mesh, InternalOutputSurface surface, long currTime)
     {
-    if( mMainOITProgram!=null )
+    if( mMainProgram!=null )
       {
       EffectQueue[] queues = effects.getQueues();
 
@@ -824,6 +887,15 @@ public class DistortedLibrary
       exception = ex;
       }
 
+    try
+      {
+      createFullProgram(resources);
+      }
+    catch(Exception ex)
+      {
+      exception = ex;
+      }
+
     if( mGLSL>=310)
       {
       try
diff --git a/src/main/java/org/distorted/library/main/InternalRenderState.java b/src/main/java/org/distorted/library/main/InternalRenderState.java
index 7e99f8d..4eb6a0e 100644
--- a/src/main/java/org/distorted/library/main/InternalRenderState.java
+++ b/src/main/java/org/distorted/library/main/InternalRenderState.java
@@ -250,7 +250,7 @@ public class InternalRenderState
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  static void switchOffDrawing()
+  public static void switchOffDrawing()
     {
     GLES30.glEnable(GLES30.GL_SCISSOR_TEST);
     GLES30.glScissor(0,0,0,0);
@@ -258,7 +258,7 @@ public class InternalRenderState
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  static void restoreDrawing()
+  public static void restoreDrawing()
     {
     GLES30.glDisable(GLES30.GL_SCISSOR_TEST);
     }
diff --git a/src/main/java/org/distorted/library/mesh/MeshBase.java b/src/main/java/org/distorted/library/mesh/MeshBase.java
index 0fc03f4..4389c04 100644
--- a/src/main/java/org/distorted/library/mesh/MeshBase.java
+++ b/src/main/java/org/distorted/library/mesh/MeshBase.java
@@ -20,13 +20,18 @@
 package org.distorted.library.mesh;
 
 import android.opengl.GLES30;
-import android.opengl.Matrix;
+import android.util.Log;
 
-import org.distorted.library.effect.MatrixEffect;
+import org.distorted.library.effect.VertexEffect;
+import org.distorted.library.effectqueue.EffectQueueVertex;
+import org.distorted.library.main.DistortedLibrary;
 import org.distorted.library.main.InternalBuffer;
 import org.distorted.library.program.DistortedProgram;
 import org.distorted.library.type.Static4D;
 
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
 import java.util.ArrayList;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -65,17 +70,19 @@ public abstract class MeshBase
    private int mNumVertices;
    private float[] mVertAttribs;      // packed: PosX,PosY,PosZ, NorX,NorY,NorZ, InfX,InfY,InfZ, TexS,TexT
    private float mInflate;
-   private float mStretchX, mStretchY, mStretchZ;
+   private boolean mNeedsAdjustment;
 
    private static class Component
      {
      private int mEndIndex;
      private Static4D mTextureMap;
+     private EffectQueueVertex mQueue;
 
      Component(int end)
        {
        mEndIndex  = end;
        mTextureMap= new Static4D(0,0,1,1);
+       mQueue     = new EffectQueueVertex();
        }
      Component(Component original)
        {
@@ -86,6 +93,7 @@ public abstract class MeshBase
        float z = original.mTextureMap.get2();
        float w = original.mTextureMap.get3();
        mTextureMap = new Static4D(x,y,z,w);
+       mQueue = new EffectQueueVertex(original.mQueue);
        }
 
      void setMap(Static4D map)
@@ -100,13 +108,10 @@ public abstract class MeshBase
 
    MeshBase()
      {
-     mStretchX = 1.0f;
-     mStretchY = 1.0f;
-     mStretchZ = 1.0f;
-
-     mShowNormals = false;
-     mInflate     = 0.0f;
-     mComponent   = new ArrayList<>();
+     mShowNormals     = false;
+     mInflate         = 0.0f;
+     mNeedsAdjustment = false;
+     mComponent       = new ArrayList<>();
 
      mVBO = new InternalBuffer(GLES30.GL_ARRAY_BUFFER             , GLES30.GL_STATIC_READ);
      mTFO = new InternalBuffer(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, GLES30.GL_STATIC_READ);
@@ -117,12 +122,9 @@ public abstract class MeshBase
 
    MeshBase(MeshBase original)
      {
-     mStretchX = original.mStretchX;
-     mStretchY = original.mStretchY;
-     mStretchZ = original.mStretchZ;
-
-     mShowNormals = original.mShowNormals;
-     mInflate     = original.mInflate;
+     mShowNormals     = original.mShowNormals;
+     mInflate         = original.mInflate;
+     mNeedsAdjustment = original.mNeedsAdjustment;
 
      int size = original.mComponent.size();
      mComponent = new ArrayList<>();
@@ -257,6 +259,81 @@ public abstract class MeshBase
      mVBO.invalidate();
      }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Not part of public API, do not document (public only because has to be used from the main package)
+ *
+ * @y.exclude
+ */
+   public void copyTransformToVertex()
+     {
+     float posX, posY, posZ, norX, norY, norZ;
+     FloatBuffer feedback=null;
+     ByteBuffer buffer = (ByteBuffer)GLES30.glMapBufferRange( GLES30.GL_TRANSFORM_FEEDBACK, 0, 6*4*mNumVertices,
+                                                                GLES30.GL_MAP_READ_BIT);
+     if( buffer!=null )
+       {
+       feedback = buffer.order(ByteOrder.nativeOrder()).asFloatBuffer();
+       }
+     else
+       {
+       Log.e("mesh", "print: failed to map tf buffer");
+       }
+
+     if( feedback!=null )
+       {
+       for(int vertex=0; vertex<mNumVertices; vertex++)
+         {
+         posX = feedback.get(6*vertex  );
+         posY = feedback.get(6*vertex+1);
+         posZ = feedback.get(6*vertex+2);
+         norX = feedback.get(6*vertex+3) - posX;
+         norY = feedback.get(6*vertex+4) - posY;
+         norZ = feedback.get(6*vertex+5) - posZ;
+
+         mVertAttribs[vertex*VERT_ATTRIBS + POS_ATTRIB     ] = posX;
+         mVertAttribs[vertex*VERT_ATTRIBS + POS_ATTRIB + 1 ] = posY;
+         mVertAttribs[vertex*VERT_ATTRIBS + POS_ATTRIB + 2 ] = posZ;
+
+         mVertAttribs[vertex*VERT_ATTRIBS + NOR_ATTRIB     ] = norX;
+         mVertAttribs[vertex*VERT_ATTRIBS + NOR_ATTRIB + 1 ] = norY;
+         mVertAttribs[vertex*VERT_ATTRIBS + NOR_ATTRIB + 2 ] = norZ;
+         }
+       }
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Not part of public API, do not document (public only because has to be used from the main package)
+ *
+ * @y.exclude
+ */
+   public void computeQueue()
+     {
+     int numComp = mComponent.size();
+
+     for(int i=0; i<numComp; i++)
+       {
+       mComponent.get(i).mQueue.compute(1);
+       }
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Not part of public API, do not document (public only because has to be used from the main package)
+ *
+ * @y.exclude
+ */
+   public void sendQueue()
+     {
+     int numComp = mComponent.size();
+
+     for(int i=0; i<numComp; i++)
+       {
+       mComponent.get(i).mQueue.send(0.0f,4);
+       }
+     }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Not part of public API, do not document (public only because has to be used from the main package)
@@ -287,6 +364,12 @@ public abstract class MeshBase
  */
    public void bindVertexAttribs(DistortedProgram program)
      {
+     if( mNeedsAdjustment )
+       {
+       mNeedsAdjustment = false;
+       DistortedLibrary.adjustVertices(this);
+       }
+
      int index = mVBO.createImmediately(mNumVertices*VERT_SIZE, mVertAttribs);
 
      GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index );
@@ -374,69 +457,26 @@ public abstract class MeshBase
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * Apply all Effects to the vertex mesh. Overwrite the mesh in place.
+ * Apply a Vertex Effect to the vertex mesh.
  * <p>
  * This is a static, permanent modification of the vertices contained in this Mesh. If the effects
- * contain any Dynamics, they will be evaluated at 0.
+ * contain any Dynamics, the Dynamics will be evaluated at 0.
  *
- * Please note that calling this once with the complete list of Effects will be much faster than
- * calling it repeatedly with one Effect at a time, as we have to reallocate the array of vertices
- * each time.
+ * We would call this several times building up a list of Effects to do. This list of effects gets
+ * lazily executed only when the Mesh is used for rendering for the first time.
  *
- * @param effects List of Matrix Effects to apply to the Mesh.
+ * @param effect Vertex Effect to apply to the Mesh.
  */
-   public void apply(MatrixEffect[] effects)
+   public void apply(VertexEffect effect)
      {
-     float[][] matrix = new float[effects.length][16];
-     float[] tmp;
-     float[] array = new float[7];
-     float x,y,z;
-     int numEffects = 0;
+     int numComp = mComponent.size();
 
-     for(MatrixEffect eff: effects)
+     for(int i=0; i<numComp; i++)
        {
-       if( eff!=null )
-         {
-         Matrix.setIdentityM(matrix[numEffects],0);
-         eff.compute(array,0,0,0);
-         eff.apply(matrix[numEffects], array, 0);
-         numEffects++;
-         }
+       mComponent.get(i).mQueue.add(effect);
        }
 
-     for(int index=0; index<mNumVertices*VERT_ATTRIBS; index+=VERT_ATTRIBS )
-       {
-       for(int mat=0; mat<numEffects; mat++)
-         {
-         tmp = matrix[mat];
-
-         x = mVertAttribs[index+POS_ATTRIB  ];
-         y = mVertAttribs[index+POS_ATTRIB+1];
-         z = mVertAttribs[index+POS_ATTRIB+2];
-
-         mVertAttribs[index+POS_ATTRIB  ] = tmp[0]*x + tmp[4]*y + tmp[ 8]*z + tmp[12];
-         mVertAttribs[index+POS_ATTRIB+1] = tmp[1]*x + tmp[5]*y + tmp[ 9]*z + tmp[13];
-         mVertAttribs[index+POS_ATTRIB+2] = tmp[2]*x + tmp[6]*y + tmp[10]*z + tmp[14];
-
-         x = mVertAttribs[index+NOR_ATTRIB  ];
-         y = mVertAttribs[index+NOR_ATTRIB+1];
-         z = mVertAttribs[index+NOR_ATTRIB+2];
-
-         mVertAttribs[index+NOR_ATTRIB  ] = tmp[0]*x + tmp[4]*y + tmp[ 8]*z;
-         mVertAttribs[index+NOR_ATTRIB+1] = tmp[1]*x + tmp[5]*y + tmp[ 9]*z;
-         mVertAttribs[index+NOR_ATTRIB+2] = tmp[2]*x + tmp[6]*y + tmp[10]*z;
-
-         x = mVertAttribs[index+INF_ATTRIB  ];
-         y = mVertAttribs[index+INF_ATTRIB+1];
-         z = mVertAttribs[index+INF_ATTRIB+2];
-
-         mVertAttribs[index+INF_ATTRIB  ] = tmp[0]*x + tmp[4]*y + tmp[ 8]*z;
-         mVertAttribs[index+INF_ATTRIB+1] = tmp[1]*x + tmp[5]*y + tmp[ 9]*z;
-         mVertAttribs[index+INF_ATTRIB+2] = tmp[2]*x + tmp[6]*y + tmp[10]*z;
-         }
-       }
-
-     mVBO.invalidate();
+     mNeedsAdjustment = true;
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/program/DistortedProgram.java b/src/main/java/org/distorted/library/program/DistortedProgram.java
index 0d4f1cd..5adcb78 100644
--- a/src/main/java/org/distorted/library/program/DistortedProgram.java
+++ b/src/main/java/org/distorted/library/program/DistortedProgram.java
@@ -430,7 +430,7 @@ android.util.Log.d("Program", end.substring(0,40));
  * @y.exclude
  */
   public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader, int glslVersion )
-  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
+  throws FragmentCompilationException,VertexCompilationException,LinkingException
     {
     this(vertex,fragment,vertexHeader,fragmentHeader,glslVersion,null);
     }
@@ -447,12 +447,10 @@ android.util.Log.d("Program", end.substring(0,40));
  * @param fragment Fragment shader code.
  * @throws FragmentCompilationException
  * @throws VertexCompilationException
- * @throws VertexUniformsException
- * @throws FragmentUniformsException
  * @throws LinkingException
  */
   public DistortedProgram(final String vertex, final String fragment)
-  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
+  throws FragmentCompilationException,VertexCompilationException,LinkingException
     {
     init(300);
 
diff --git a/src/main/res/raw/main_vertex_shader.glsl b/src/main/res/raw/main_vertex_shader.glsl
index 4054976..f461b5b 100644
--- a/src/main/res/raw/main_vertex_shader.glsl
+++ b/src/main/res/raw/main_vertex_shader.glsl
@@ -107,7 +107,7 @@ void main()
 #endif
    
   v_Position      = v;
-  v_endPosition   = v + 0.4*n;
+  v_endPosition   = v + n;
   v_TexCoordinate = a_TexCoordinate;
   v_Normal        = normalize(vec3(u_MVMatrix*vec4(n,0.0)));
   gl_Position     = u_MVPMatrix*vec4(v,1.0);
