commit d425545a887144b94be74ec4913509a0be983760
Author: Leszek Koltunski <leszek@distorted.org>
Date:   Fri Jun 17 00:49:00 2016 +0100

    Some more progress with porting apps to new VERTEX API.

diff --git a/src/main/java/org/distorted/library/DistortedObject.java b/src/main/java/org/distorted/library/DistortedObject.java
index bb83569..1d13f3e 100644
--- a/src/main/java/org/distorted/library/DistortedObject.java
+++ b/src/main/java/org/distorted/library/DistortedObject.java
@@ -28,232 +28,220 @@ import org.distorted.library.type.Data1D;
 import org.distorted.library.type.Data2D;
 import org.distorted.library.type.Data3D;
 import org.distorted.library.type.Data4D;
-import org.distorted.library.type.Dynamic;
-import org.distorted.library.type.Dynamic1D;
-import org.distorted.library.type.Dynamic2D;
-import org.distorted.library.type.Dynamic3D;
-import org.distorted.library.type.Dynamic4D;
-import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static2D;
 import org.distorted.library.type.Static3D;
-import org.distorted.library.type.Static4D;
-import org.distorted.library.type.DynamicQuat;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * All Objects to which Distorted Graphics effects can be applied need to be extended from here.
  */
 public abstract class DistortedObject 
-{
-    private static final Static2D mZero2D = new Static2D(0,0);
-    private static final Static3D mZero3D = new Static3D(0,0,0);
-
-    private static float[] mViewMatrix   = new float[16];
+  {
+  private static float[] mViewMatrix   = new float[16];
    
-    protected EffectQueueMatrix    mM;
-    protected EffectQueueFragment  mF;
-    protected EffectQueueVertex    mV;
+  protected EffectQueueMatrix    mM;
+  protected EffectQueueFragment  mF;
+  protected EffectQueueVertex    mV;
 
-    protected boolean matrixCloned, vertexCloned, fragmentCloned;
+  protected boolean matrixCloned, vertexCloned, fragmentCloned;
  
-    protected DistortedObjectGrid mGrid = null;
-    protected long mID;
-    protected int mSizeX, mSizeY, mSizeZ, mSize; // in screen space
+  protected DistortedObjectGrid mGrid = null;
+  protected long mID;
+  protected int mSizeX, mSizeY, mSizeZ, mSize; // in screen space
 
-    protected Bitmap[] mBmp= null; // 
-    int[] mTextureDataH;           // have to be shared among all the cloned Objects
-    boolean[] mBitmapSet;          // 
+  protected Bitmap[] mBmp= null; //
+  int[] mTextureDataH;           // have to be shared among all the cloned Objects
+  boolean[] mBitmapSet;          //
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    protected abstract DistortedObject deepCopy(int flags);
+  protected abstract DistortedObject deepCopy(int flags);
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    protected void initializeData(int size)
-      {
-      mID             = DistortedObjectList.add(this);
-      mSize           = size;
-      mTextureDataH   = new int[1];
-      mTextureDataH[0]= 0;
-      mBmp            = new Bitmap[1];
-      mBmp[0]         = null;
-      mBitmapSet      = new boolean[1];
-      mBitmapSet[0]   = false;
+  protected void initializeData(int size)
+    {
+    mID             = DistortedObjectList.add(this);
+    mSize           = size;
+    mTextureDataH   = new int[1];
+    mTextureDataH[0]= 0;
+    mBmp            = new Bitmap[1];
+    mBmp[0]         = null;
+    mBitmapSet      = new boolean[1];
+    mBitmapSet[0]   = false;
       
-      initializeEffectLists(this,0);
+    initializeEffectLists(this,0);
       
-      if( Distorted.isInitialized() ) resetTexture();    
-      }
+    if( Distorted.isInitialized() ) resetTexture();
+    }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
-    protected void initializeEffectLists(DistortedObject d, int flags)
+  protected void initializeEffectLists(DistortedObject d, int flags)
+    {
+    if( (flags & Distorted.CLONE_PRESHADER) != 0 )
       {
-      if( (flags & Distorted.CLONE_PRESHADER) != 0 )
-        {
-        mM = d.mM;
-        matrixCloned = true;
-        } 
-      else
-        {
-        mM = new EffectQueueMatrix(d);
-        matrixCloned = false;  
-        }
+      mM = d.mM;
+      matrixCloned = true;
+      }
+    else
+      {
+      mM = new EffectQueueMatrix(d);
+      matrixCloned = false;
+      }
     
-      if( (flags & Distorted.CLONE_VERTEX) != 0 )
-        {
-        mV = d.mV;
-        vertexCloned = true;
-        } 
-      else
-        {
-        mV = new EffectQueueVertex(d);
-        vertexCloned = false;  
-        }
+    if( (flags & Distorted.CLONE_VERTEX) != 0 )
+      {
+      mV = d.mV;
+      vertexCloned = true;
+      }
+    else
+      {
+      mV = new EffectQueueVertex(d);
+      vertexCloned = false;
+      }
     
-      if( (flags & Distorted.CLONE_FRAGMENT) != 0 )
-        {
-        mF = d.mF;
-        fragmentCloned = true;
-        } 
-      else
-        {
-        mF = new EffectQueueFragment(d);
-        fragmentCloned = false;   
-        }
+    if( (flags & Distorted.CLONE_FRAGMENT) != 0 )
+      {
+      mF = d.mF;
+      fragmentCloned = true;
       }
+    else
+      {
+      mF = new EffectQueueFragment(d);
+      fragmentCloned = false;
+      }
+    }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // this will be called on startup and every time OpenGL context has been lost
 // also call this from the constructor if the OpenGL context has been created already.
     
-    void resetTexture()
+  void resetTexture()
+    {
+    if( mTextureDataH!=null )
       {
-      if( mTextureDataH!=null ) 
-        {
-        if( mTextureDataH[0]==0 ) GLES20.glGenTextures(1, mTextureDataH, 0);
+      if( mTextureDataH[0]==0 ) GLES20.glGenTextures(1, mTextureDataH, 0);
 
-        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);       
-        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR );
-        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR );
-        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE );
-        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE );
+      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);
+      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR );
+      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR );
+      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE );
+      GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE );
        
-        if( mBmp!=null && mBmp[0]!=null)
-          {
-          GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBmp[0], 0);
-          mBmp[0] = null;
-          }
+      if( mBmp!=null && mBmp[0]!=null)
+        {
+        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBmp[0], 0);
+        mBmp[0] = null;
         }
       }
+    }
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
    
-    void drawPriv(long currTime, DistortedProjection dp)
-      {
-      GLES20.glViewport(0, 0, dp.width, dp.height); 
+  void drawPriv(long currTime, DistortedProjection dp)
+    {
+    GLES20.glViewport(0, 0, dp.width, dp.height);
       
-      mM.compute(currTime);
-      mM.send(mViewMatrix, dp);
+    mM.compute(currTime);
+    mM.send(mViewMatrix, dp);
       
-      mV.compute(currTime);
-      mV.postprocess();
-      mV.send();
+    mV.compute(currTime);
+    mV.postprocess();
+    mV.send();
         
-      mF.compute(currTime);
-      mF.postprocess(mViewMatrix);
-      mF.send();
+    mF.compute(currTime);
+    mF.postprocess(mViewMatrix);
+    mF.send();
        
-      mGrid.draw();
-      }
+    mGrid.draw();
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
    
-    void drawNoEffectsPriv(DistortedProjection dp)
-      {
-      GLES20.glViewport(0, 0, dp.width, dp.height);
-      mM.sendNoEffects(dp);
-      mV.sendZero();
-      mF.sendZero();
-      mGrid.draw();
-      }
+  void drawNoEffectsPriv(DistortedProjection dp)
+    {
+    GLES20.glViewport(0, 0, dp.width, dp.height);
+    mM.sendNoEffects(dp);
+    mV.sendZero();
+    mF.sendZero();
+    mGrid.draw();
+    }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
    
-    void releasePriv()
-      {
-      if( matrixCloned  ==false) mM.abortAll();
-      if( vertexCloned  ==false) mV.abortAll();
-      if( fragmentCloned==false) mF.abortAll();
-
-      mBmp          = null;
-      mGrid         = null;
-      mM            = null;
-      mV            = null;
-      mF            = null;
-      mTextureDataH = null;
-      }
+  void releasePriv()
+    {
+    if( matrixCloned  ==false) mM.abortAll();
+    if( vertexCloned  ==false) mV.abortAll();
+    if( fragmentCloned==false) mF.abortAll();
+
+    mBmp          = null;
+    mGrid         = null;
+    mM            = null;
+    mV            = null;
+    mF            = null;
+    mTextureDataH = null;
+    }
  
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    long getBitmapID()
+  long getBitmapID()
       {
       return mBmp==null ? 0 : mBmp.hashCode();
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Default empty constructor so that derived classes can call it
+ */
+  public DistortedObject()
+    {
 
-  /**
-   * Default empty constructor so that derived classes can call it
-   */
-    public DistortedObject()
-      {
-
-      }
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-  /**
-   * Copy constructor used to create a DistortedObject based on various parts of another object.
-   * <p>
-   * Whatever we do not clone gets created just like in the default constructor.
-   * We only call this from the descendant's classes' constructors where we have to pay attention
-   * to give it the appropriate type of a DistortedObject!
-   *
-   * @param dc    Source object to create our object from
-   * @param flags A bitmask of values specifying what to copy.
-   *              For example, CLONE_BITMAP | CLONE_MATRIX.
-   */
-    public DistortedObject(DistortedObject dc, int flags)
-      {
-      initializeEffectLists(dc,flags);
+/**
+ * Copy constructor used to create a DistortedObject based on various parts of another object.
+ * <p>
+ * Whatever we do not clone gets created just like in the default constructor.
+ * We only call this from the descendant's classes' constructors where we have to pay attention
+ * to give it the appropriate type of a DistortedObject!
+ *
+ * @param dc    Source object to create our object from
+ * @param flags A bitmask of values specifying what to copy.
+ *              For example, CLONE_BITMAP | CLONE_MATRIX.
+ */
+  public DistortedObject(DistortedObject dc, int flags)
+    {
+    initializeEffectLists(dc,flags);
 
-      mID = DistortedObjectList.add(this);
+    mID = DistortedObjectList.add(this);
 
-      mSizeX = dc.mSizeX;
-      mSizeY = dc.mSizeY;
-      mSizeZ = dc.mSizeZ;
-      mSize  = dc.mSize;
-      mGrid  = dc.mGrid;
+    mSizeX = dc.mSizeX;
+    mSizeY = dc.mSizeY;
+    mSizeZ = dc.mSizeZ;
+    mSize  = dc.mSize;
+    mGrid  = dc.mGrid;
 
-      if( (flags & Distorted.CLONE_BITMAP) != 0 )
-        {
-        mTextureDataH = dc.mTextureDataH;
-        mBmp          = dc.mBmp;
-        mBitmapSet    = dc.mBitmapSet;
-        }
-      else
-        {
-        mTextureDataH   = new int[1];
-        mTextureDataH[0]= 0;
-        mBitmapSet      = new boolean[1];
-        mBitmapSet[0]   = false;
-        mBmp            = new Bitmap[1];
-        mBmp[0]         = null;
-
-        if( Distorted.isInitialized() ) resetTexture();
-        }
+    if( (flags & Distorted.CLONE_BITMAP) != 0 )
+      {
+      mTextureDataH = dc.mTextureDataH;
+      mBmp          = dc.mBmp;
+      mBitmapSet    = dc.mBitmapSet;
       }
+    else
+      {
+      mTextureDataH   = new int[1];
+      mTextureDataH[0]= 0;
+      mBitmapSet      = new boolean[1];
+      mBitmapSet[0]   = false;
+      mBmp            = new Bitmap[1];
+      mBmp[0]         = null;
+
+      if( Distorted.isInitialized() ) resetTexture();
+      }
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -263,25 +251,25 @@ public abstract class DistortedObject
  *        This gets passed on to Interpolators inside the Effects that are currently applied to the 
  *        Object.
  */
-   public void draw(long currTime)
-     {
-     GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
-     GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
-     GLES20.glUniform1i(Distorted.mTextureUniformH, 0);  
-     GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]); 
+  public void draw(long currTime)
+    {
+    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
+    GLES20.glUniform1i(Distorted.mTextureUniformH, 0);
+    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);
       
-     drawPriv(currTime, Distorted.mProjection);
-     }
+    drawPriv(currTime, Distorted.mProjection);
+    }
  
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Releases all resources.
  */
-   public synchronized void release()
-     {
-     releasePriv();  
-     DistortedObjectList.remove(this);
-     }
+  public synchronized void release()
+    {
+    releasePriv();
+    DistortedObjectList.remove(this);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -293,21 +281,21 @@ public abstract class DistortedObject
  * @param bmp The android.graphics.Bitmap object to apply effects to and display.
  */
    
-   public void setBitmap(Bitmap bmp)
-     {
-     mBitmapSet[0] = true; 
+  public void setBitmap(Bitmap bmp)
+    {
+    mBitmapSet[0] = true;
       
-     if( Distorted.isInitialized() )
-       {
-       GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
-       GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);        
-       GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
-       }
-     else
-       {
-       mBmp[0] = bmp;  
-       }
-     }
+    if( Distorted.isInitialized() )
+      {
+      GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);
+      GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);
+      }
+    else
+      {
+      mBmp[0] = bmp;
+      }
+    }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -316,12 +304,12 @@ public abstract class DistortedObject
  * 
  * @param el A class implementing the EffectListener interface that wants to get notifications.
  */
-   public void addEventListener(EffectListener el)
-     {
-     mV.addListener(el);
-     mF.addListener(el);
-     mM.addListener(el);
-     }
+  public void addEventListener(EffectListener el)
+    {
+    mV.addListener(el);
+    mF.addListener(el);
+    mM.addListener(el);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -329,12 +317,12 @@ public abstract class DistortedObject
  * 
  * @param el A class implementing the EffectListener interface that no longer wants to get notifications.
  */
-   public void removeEventListener(EffectListener el)
-     {
-     mV.removeListener(el);
-     mF.removeListener(el);
-     mM.removeListener(el);
-     }
+  public void removeEventListener(EffectListener el)
+    {
+    mV.removeListener(el);
+    mF.removeListener(el);
+    mM.removeListener(el);
+    }
    
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -342,7 +330,7 @@ public abstract class DistortedObject
  *    
  * @return height of the object, in pixels.
  */
-   public int getWidth()
+  public int getWidth()
      {
      return mSizeX;   
      }
@@ -353,7 +341,7 @@ public abstract class DistortedObject
  * 
  * @return width of the Object, in pixels.
  */
-    public int getHeight()
+  public int getHeight()
       {
       return mSizeY;  
       }
@@ -364,7 +352,7 @@ public abstract class DistortedObject
  * 
  * @return depth of the Object, in pixels.
  */
-    public int getDepth()
+  public int getDepth()
       {
       return mSizeZ;  
       }
@@ -375,7 +363,7 @@ public abstract class DistortedObject
  * 
  * @return ID of the object.
  */
-    public long getID()
+  public long getID()
       {
       return mID;  
       }
@@ -385,7 +373,7 @@ public abstract class DistortedObject
  * Aborts all Effects.
  * @return Number of effects aborted.
  */
-    public int abortAllEffects()
+  public int abortAllEffects()
       {
       return mM.abortAll() + mV.abortAll() + mF.abortAll();
       }
@@ -397,16 +385,16 @@ public abstract class DistortedObject
  * @param type one of the constants defined in {@link EffectTypes}
  * @return Number of effects aborted.
  */
-    public int abortEffects(EffectTypes type)
+  public int abortEffects(EffectTypes type)
+    {
+    switch(type)
       {
-      switch(type)
-        {
-        case MATRIX  : return mM.abortAll();
-        case VERTEX  : return mV.abortAll();
-        case FRAGMENT: return mF.abortAll();
-        default      : return 0;
-        }
+      case MATRIX  : return mM.abortAll();
+      case VERTEX  : return mV.abortAll();
+      case FRAGMENT: return mF.abortAll();
+      default      : return 0;
       }
+    }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -415,16 +403,16 @@ public abstract class DistortedObject
  * @param id ID of the Effect we want to abort.
  * @return number of Effects aborted. Always either 0 or 1.
  */
-    public int abortEffect(long id)
-      {
-      int type = (int)(id&EffectTypes.MASK);
+  public int abortEffect(long id)
+    {
+    int type = (int)(id&EffectTypes.MASK);
 
-      if( type==EffectTypes.MATRIX.type   ) return mM.removeByID(id>>EffectTypes.LENGTH);
-      if( type==EffectTypes.VERTEX.type   ) return mV.removeByID(id>>EffectTypes.LENGTH);
-      if( type==EffectTypes.FRAGMENT.type ) return mF.removeByID(id>>EffectTypes.LENGTH);
+    if( type==EffectTypes.MATRIX.type   ) return mM.removeByID(id>>EffectTypes.LENGTH);
+    if( type==EffectTypes.VERTEX.type   ) return mV.removeByID(id>>EffectTypes.LENGTH);
+    if( type==EffectTypes.FRAGMENT.type ) return mF.removeByID(id>>EffectTypes.LENGTH);
 
-      return 0;
-      }
+    return 0;
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -433,16 +421,16 @@ public abstract class DistortedObject
  * @param name one of the constants defined in {@link EffectNames}
  * @return number of Effects aborted.
  */
-    public int abortEffects(EffectNames name)
+  public int abortEffects(EffectNames name)
+    {
+    switch(name.getType())
       {
-      switch(name.getType())
-        {
-        case MATRIX  : return mM.removeByType(name);
-        case VERTEX  : return mV.removeByType(name);
-        case FRAGMENT: return mF.removeByType(name);
-        default      : return 0;
-        }
+      case MATRIX  : return mM.removeByType(name);
+      case VERTEX  : return mV.removeByType(name);
+      case FRAGMENT: return mF.removeByType(name);
+      default      : return 0;
       }
+    }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -452,16 +440,16 @@ public abstract class DistortedObject
  * @return <code>true</code> if a single Effect of type effectType has been found.
  */
     
-    public boolean printEffect(long id)
-      {
-      int type = (int)(id&EffectTypes.MASK);
+  public boolean printEffect(long id)
+    {
+    int type = (int)(id&EffectTypes.MASK);
 
-      if( type==EffectTypes.MATRIX.type   )  return mM.printByID(id>>EffectTypes.LENGTH);
-      if( type==EffectTypes.VERTEX.type   )  return mV.printByID(id>>EffectTypes.LENGTH);
-      if( type==EffectTypes.FRAGMENT.type )  return mF.printByID(id>>EffectTypes.LENGTH);
+    if( type==EffectTypes.MATRIX.type   )  return mM.printByID(id>>EffectTypes.LENGTH);
+    if( type==EffectTypes.VERTEX.type   )  return mV.printByID(id>>EffectTypes.LENGTH);
+    if( type==EffectTypes.FRAGMENT.type )  return mF.printByID(id>>EffectTypes.LENGTH);
 
-      return false;
-      }
+    return false;
+    }
    
 ///////////////////////////////////////////////////////////////////////////////////////////////////   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -501,10 +489,10 @@ public abstract class DistortedObject
  * @param scale The factor to scale all 3 dimensions with.
  * @return      ID of the effect added, or -1 if we failed to add one.
  */
-public long scale(float scale)
-  {
-  return mM.add(EffectNames.SCALE, new Static3D(scale,scale,scale));
-  }
+  public long scale(float scale)
+    {
+    return mM.add(EffectNames.SCALE, new Static3D(scale,scale,scale));
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -765,8 +753,6 @@ public long scale(float scale)
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Distort a (possibly changing in time) part of the Object by a (possibly changing in time) vector of force.
- * <p>
- * Only at most one of the 'center' and 'region' can be a Dynamic!
  *
  * @param vector 3-dimensional Vector which represents the force the Center of the Effect is
  *               currently being dragged with.
@@ -788,10 +774,10 @@ public long scale(float scale)
  * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one.
  */
-public long distort(Data3D vector, Data2D center)
-  {
-  return mV.add(EffectNames.DISTORT, vector, center);
-  }
+  public long distort(Data3D vector, Data2D center)
+    {
+    return mV.add(EffectNames.DISTORT, vector, center);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -811,8 +797,6 @@ public long distort(Data3D vector, Data2D center)
 /**
  * Pull all points around the center of the Effect towards the center (if degree>=1) or push them
  * away from the center (degree<=1)
- * <p>
- * Only at most one of the 'center' and 'region' can be a Dynamic!
  *
  * @param sink   The current degree of the Effect.
  * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
@@ -833,16 +817,14 @@ public long distort(Data3D vector, Data2D center)
  * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one.
  */
-public long sink(Data1D sink, Data2D center)
-  {
-  return mV.add(EffectNames.SINK, sink, center);
-  }
+  public long sink(Data1D sink, Data2D center)
+    {
+    return mV.add(EffectNames.SINK, sink, center);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////  
 /**
  * Rotate part of the Object around the Center of the Effect by a certain angle.
- * <p>
- * Only at most one of the 'center' and 'region' can be a Dynamic!
  *
  * @param swirl  The degree of Swirl. Positive values swirl clockwise.
  * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
@@ -862,8 +844,8 @@ public long sink(Data1D sink, Data2D center)
  * @param center 2-dimensional Data that, at any given time, returns the Center of the Effect.
  * @return       ID of the effect added, or -1 if we failed to add one.
  */
-public long swirl(Data1D swirl, Data2D center)
-  {
-  return mV.add(EffectNames.SWIRL, swirl, center);
+  public long swirl(Data1D swirl, Data2D center)
+    {
+    return mV.add(EffectNames.SWIRL, swirl, center);
+    }
   }
-}
diff --git a/src/main/java/org/distorted/library/EffectQueue.java b/src/main/java/org/distorted/library/EffectQueue.java
index 3aa5e76..08958bd 100644
--- a/src/main/java/org/distorted/library/EffectQueue.java
+++ b/src/main/java/org/distorted/library/EffectQueue.java
@@ -22,7 +22,6 @@ package org.distorted.library;
 import org.distorted.library.message.EffectListener;
 import org.distorted.library.message.EffectMessage;
 import org.distorted.library.type.Dynamic;
-import org.distorted.library.type.Dynamic2D;
 
 import java.util.Vector;
 
@@ -35,8 +34,7 @@ abstract class EffectQueue
   
   protected int[] mType;
   protected float[] mUniforms;
-  protected Dynamic[] mInterP;  // center of the effect
-  protected Dynamic[] mInterI;  // all other interpolated values
+  protected Dynamic[][] mInter;  // center of the effect
   protected long[] mCurrentDuration;
   protected byte[] mFreeIndexes;
   protected byte[] mIDIndex;
@@ -80,8 +78,7 @@ abstract class EffectQueue
       {
       mType            = new int[mMax[mMaxIndex]];
       mUniforms        = new float[numUniforms*mMax[mMaxIndex]];
-      mInterI          = new Dynamic[mMax[mMaxIndex]];
-      mInterP          = new Dynamic[mMax[mMaxIndex]];
+      mInter           = new Dynamic[3][mMax[mMaxIndex]];
       mCurrentDuration = new long[mMax[mMaxIndex]];
       mID              = new long[mMax[mMaxIndex]];
       mIDIndex         = new byte[mMax[mMaxIndex]];
@@ -205,8 +202,9 @@ abstract class EffectQueue
 
     for(int i=0; i<ret; i++ )
       {
-      mInterI[i] = null;
-      mInterP[i] = null;
+      mInter[0][i] = null;
+      mInter[1][i] = null;
+      mInter[2][i] = null;
       }
 
     mNumEffects= 0;
@@ -236,17 +234,19 @@ abstract class EffectQueue
     for(int j=effect; j<mNumEffects; j++ ) 
       {
       mType[j]            = mType[j+1];
-      mInterI[j]          = mInterI[j+1];
-      mInterP[j]          = mInterP[j+1];
+      mInter[0][j]          = mInter[0][j+1];
+      mInter[1][j]          = mInter[1][j+1];
+      mInter[2][j]          = mInter[2][j+1];
       mCurrentDuration[j] = mCurrentDuration[j+1];
       mID[j]              = mID[j+1];
     
       moveEffect(j);
       }
    
-    mInterI[mNumEffects] = null;
-    mInterP[mNumEffects] = null;
-   
+    mInter[0][mNumEffects] = null;
+    mInter[1][mNumEffects] = null;
+    mInter[2][mNumEffects] = null;
+
     for(int i=0; i<mNumListeners; i++) 
       EffectMessageSender.newMessage( mListeners.elementAt(i),
                                       EffectMessage.EFFECT_REMOVED,
@@ -314,20 +314,26 @@ abstract class EffectQueue
    
     if( index>=0 ) 
       {
-      boolean interI = mInterI[index]==null; 
-      boolean interP = mInterP[index]==null; 
-      
-      android.util.Log.e("EffectQueue", "numEffects="+mNumEffects+" effect id="+id+" index="+index+" duration="+mCurrentDuration[index]+" interI null="+interI+" interP null="+interP);
+      boolean inter0 = mInter[0][index]==null;
+      boolean inter1 = mInter[1][index]==null;
+      boolean inter2 = mInter[2][index]==null;
+
+      android.util.Log.e("EffectQueue", "numEffects="+mNumEffects+" effect id="+id+" index="+index+
+                         " duration="+mCurrentDuration[index]+" inter[0] null="+inter0+" inter[1] null="+inter1+" inter[2] null="+inter2);
       
-      if( interI==false )
+      if( inter0==false )
         {
-        android.util.Log.e("EffectQueue","interI: "+mInterI[index].print());
+        android.util.Log.e("EffectQueue","inter[0]: "+mInter[0][index].print());
         }
-      if( interP==false )
+      if( inter1==false )
         {
-        android.util.Log.e("EffectQueue","interP: "+mInterP[index].print());
+        android.util.Log.e("EffectQueue","inter[1]: "+mInter[1][index].print());
         }
-     
+      if( inter2==false )
+        {
+        android.util.Log.e("EffectQueue","inter[2]: "+mInter[2][index].print());
+        }
+
       return true;
       }
    
diff --git a/src/main/java/org/distorted/library/EffectQueueFragment.java b/src/main/java/org/distorted/library/EffectQueueFragment.java
index 9f43117..8c690cf 100644
--- a/src/main/java/org/distorted/library/EffectQueueFragment.java
+++ b/src/main/java/org/distorted/library/EffectQueueFragment.java
@@ -27,11 +27,8 @@ import org.distorted.library.type.Data4D;
 import org.distorted.library.type.Dynamic1D;
 import org.distorted.library.type.Dynamic4D;
 import org.distorted.library.type.Static1D;
-import org.distorted.library.type.Static2D;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
-import org.distorted.library.type.Dynamic;
-import org.distorted.library.type.Dynamic2D;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -75,11 +72,11 @@ class EffectQueueFragment extends EffectQueue
    
     for(int i=0; i<mNumEffects; i++)
       {
-      if( mInterI[i]==null ) continue;    
+      if( mInter[0][i]==null ) continue;
       
-      if( mInterP[i]!=null ) mInterP[i].interpolateMain(mBuf, 4*i, mCurrentDuration[i]);
+      if( mInter[1][i]!=null ) mInter[1][i].interpolateMain(mBuf, 4*i, mCurrentDuration[i]);
         
-      if( mInterI[i].interpolateMain(mUniforms ,NUM_UNIFORMS*i, mCurrentDuration[i], step) )      
+      if( mInter[0][i].interpolateMain(mUniforms ,NUM_UNIFORMS*i, mCurrentDuration[i], step) )
         {
         for(int j=0; j<mNumListeners; j++)   
           EffectMessageSender.newMessage( mListeners.elementAt(j),
@@ -180,15 +177,15 @@ class EffectQueueFragment extends EffectQueue
       EffectNames.fillWithUnities(eln.ordinal(), mUniforms, NUM_UNIFORMS*mNumEffects); 
 
       if( data instanceof Dynamic1D)
-        mInterI[mNumEffects] = (Dynamic1D)data;
+        mInter[0][mNumEffects] = (Dynamic1D)data;
       else if( data instanceof Static1D )
         {
-        mInterI[mNumEffects] = null;
+        mInter[0][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects] = ((Static1D)data).getX();
         }
       else return -1;
 
-      mInterP[mNumEffects] = null;
+      mInter[1][mNumEffects] = null;
       mBuf[4*mNumEffects+2] = 1000*mObjHalfX;
       mBuf[4*mNumEffects+3] = 1000*mObjHalfY;
 
@@ -208,19 +205,19 @@ class EffectQueueFragment extends EffectQueue
       EffectNames.fillWithUnities(eln.ordinal(), mUniforms, NUM_UNIFORMS*mNumEffects);
 
       if( data instanceof Dynamic1D)
-        mInterI[mNumEffects] = (Dynamic1D)data;
+        mInter[0][mNumEffects] = (Dynamic1D)data;
       else if( data instanceof Static1D )
         {
-        mInterI[mNumEffects] = null;
+        mInter[0][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects] = ((Static1D)data).getX();
         }
       else return -1;
 
       if( region instanceof Dynamic4D)
-        mInterP[mNumEffects] = (Dynamic4D)region;
+        mInter[1][mNumEffects] = (Dynamic4D)region;
       else if( region instanceof Static4D )
         {
-        mInterP[mNumEffects]  = null;
+        mInter[1][mNumEffects]  = null;
         mBuf[4*mNumEffects  ] = ((Static4D)region).getX();
         mBuf[4*mNumEffects+1] = ((Static4D)region).getY();
         mBuf[4*mNumEffects+2] = ((Static4D)region).getZ();
@@ -244,10 +241,10 @@ class EffectQueueFragment extends EffectQueue
       EffectNames.fillWithUnities(eln.ordinal(), mUniforms, NUM_UNIFORMS*mNumEffects);
 
       if( level instanceof Dynamic1D)
-        mInterI[mNumEffects] = (Dynamic1D)level;
+        mInter[0][mNumEffects] = (Dynamic1D)level;
       else if( level instanceof Static1D )
         {
-        mInterI[mNumEffects] = null;
+        mInter[0][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects] = ((Static1D)level).getX();
         }
       else return -1;
@@ -257,10 +254,10 @@ class EffectQueueFragment extends EffectQueue
       mUniforms[NUM_UNIFORMS*mNumEffects+3] = color.getZ();
 
       if( region instanceof Dynamic4D)
-        mInterP[mNumEffects] = (Dynamic4D)region;
+        mInter[1][mNumEffects] = (Dynamic4D)region;
       else if( region instanceof Static4D )
         {
-        mInterP[mNumEffects]  = null;
+        mInter[1][mNumEffects]  = null;
         mBuf[4*mNumEffects  ] = ((Static4D)region).getX();
         mBuf[4*mNumEffects+1] = ((Static4D)region).getY();
         mBuf[4*mNumEffects+2] = ((Static4D)region).getZ();
@@ -284,10 +281,10 @@ class EffectQueueFragment extends EffectQueue
       EffectNames.fillWithUnities(eln.ordinal(), mUniforms, NUM_UNIFORMS*mNumEffects);
 
       if( level instanceof Dynamic1D)
-        mInterI[mNumEffects] = (Dynamic1D)level;
+        mInter[0][mNumEffects] = (Dynamic1D)level;
       else if( level instanceof Static1D )
         {
-        mInterI[mNumEffects] = null;
+        mInter[0][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects] = ((Static1D)level).getX();
         }
       else return -1;
@@ -296,7 +293,7 @@ class EffectQueueFragment extends EffectQueue
       mUniforms[NUM_UNIFORMS*mNumEffects+2] = color.getY();
       mUniforms[NUM_UNIFORMS*mNumEffects+3] = color.getZ();
 
-      mInterP[mNumEffects]  = null;            //
+      mInter[1][mNumEffects]  = null;          //
       mBuf[4*mNumEffects+2] = 1000*mObjHalfX;  // i.e. null region
       mBuf[4*mNumEffects+3] = 1000*mObjHalfY;  //
 
@@ -316,10 +313,10 @@ class EffectQueueFragment extends EffectQueue
       EffectNames.fillWithUnities(eln.ordinal(), mUniforms, NUM_UNIFORMS*mNumEffects);
 
       if( chroma instanceof Dynamic4D)
-        mInterI[mNumEffects] = (Dynamic4D)chroma;
+        mInter[0][mNumEffects] = (Dynamic4D)chroma;
       else if( chroma instanceof Static4D )
         {
-        mInterI[mNumEffects] = null;
+        mInter[0][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects  ] = ((Static4D)chroma).getX();
         mUniforms[NUM_UNIFORMS*mNumEffects+1] = ((Static4D)chroma).getY();
         mUniforms[NUM_UNIFORMS*mNumEffects+2] = ((Static4D)chroma).getZ();
@@ -328,10 +325,10 @@ class EffectQueueFragment extends EffectQueue
       else return -1;
 
       if( region instanceof Dynamic4D)
-        mInterP[mNumEffects] = (Dynamic4D)region;
+        mInter[1][mNumEffects] = (Dynamic4D)region;
       else if( region instanceof Static4D )
         {
-        mInterP[mNumEffects]  = null;
+        mInter[1][mNumEffects]  = null;
         mBuf[4*mNumEffects  ] = ((Static4D)region).getX();
         mBuf[4*mNumEffects+1] = ((Static4D)region).getY();
         mBuf[4*mNumEffects+2] = ((Static4D)region).getZ();
@@ -355,10 +352,10 @@ class EffectQueueFragment extends EffectQueue
       EffectNames.fillWithUnities(eln.ordinal(), mUniforms, NUM_UNIFORMS*mNumEffects);
 
       if( chroma instanceof Dynamic4D)
-        mInterI[mNumEffects] = (Dynamic4D)chroma;
+        mInter[0][mNumEffects] = (Dynamic4D)chroma;
       else if( chroma instanceof Static4D )
         {
-        mInterI[mNumEffects] = null;
+        mInter[0][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects  ] = ((Static4D)chroma).getX();
         mUniforms[NUM_UNIFORMS*mNumEffects+1] = ((Static4D)chroma).getY();
         mUniforms[NUM_UNIFORMS*mNumEffects+2] = ((Static4D)chroma).getZ();
@@ -366,7 +363,7 @@ class EffectQueueFragment extends EffectQueue
         }
       else return -1;
 
-      mInterP[mNumEffects]  = null;            //
+      mInter[1][mNumEffects]  = null;          //
       mBuf[4*mNumEffects+2] = 1000*mObjHalfX;  // i.e. null region
       mBuf[4*mNumEffects+3] = 1000*mObjHalfY;  //
 
diff --git a/src/main/java/org/distorted/library/EffectQueueMatrix.java b/src/main/java/org/distorted/library/EffectQueueMatrix.java
index 3e4d5cf..665cd54 100644
--- a/src/main/java/org/distorted/library/EffectQueueMatrix.java
+++ b/src/main/java/org/distorted/library/EffectQueueMatrix.java
@@ -32,7 +32,6 @@ import org.distorted.library.type.Dynamic4D;
 import org.distorted.library.type.DynamicQuat;
 import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static3D;
-import org.distorted.library.type.Dynamic;
 import org.distorted.library.type.Static4D;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -106,14 +105,14 @@ class EffectQueueMatrix extends EffectQueue
    
     for(int i=0; i<mNumEffects; i++)
       {
-      if( mInterI[i]==null ) continue;    
+      if( mInter[0][i]==null ) continue;
            
-      if( mInterP[i]!=null ) 
+      if( mInter[1][i]!=null )
         {
-        mInterP[i].interpolateMain(mUniforms, NUM_UNIFORMS*i, mCurrentDuration[i]);
+        mInter[1][i].interpolateMain(mUniforms, NUM_UNIFORMS*i, mCurrentDuration[i]);
         }
         
-      if( mInterI[i].interpolateMain(mUniforms ,NUM_UNIFORMS*i+3, mCurrentDuration[i], step) )      
+      if( mInter[0][i].interpolateMain(mUniforms ,NUM_UNIFORMS*i+3, mCurrentDuration[i], step) )
         {   
         for(int j=0; j<mNumListeners; j++)   
           EffectMessageSender.newMessage( mListeners.elementAt(j),
@@ -257,12 +256,12 @@ class EffectQueueMatrix extends EffectQueue
     {
     if( mMax[INDEX]>mNumEffects )
       {
-      mInterP[mNumEffects] = null;
+      mInter[1][mNumEffects] = null;
 
-           if( vector instanceof Dynamic3D) mInterI[mNumEffects] = (Dynamic3D)vector;
+           if( vector instanceof Dynamic3D) mInter[0][mNumEffects] = (Dynamic3D)vector;
       else if( vector instanceof Static3D )
         {
-        mInterI[mNumEffects] = null;
+        mInter[0][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects+3] = ((Static3D)vector).getX();
         mUniforms[NUM_UNIFORMS*mNumEffects+4] = ((Static3D)vector).getY();
         mUniforms[NUM_UNIFORMS*mNumEffects+5] = ((Static3D)vector).getZ();
@@ -282,20 +281,20 @@ class EffectQueueMatrix extends EffectQueue
     {
     if( mMax[INDEX]>mNumEffects )
       {
-           if( center instanceof Dynamic3D) mInterP[mNumEffects] = (Dynamic3D)center;
+           if( center instanceof Dynamic3D) mInter[1][mNumEffects] = (Dynamic3D)center;
       else if( center instanceof Static3D )
         {
-        mInterP[mNumEffects] = null;
+        mInter[1][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects  ] = ((Static3D)center).getX();
         mUniforms[NUM_UNIFORMS*mNumEffects+1] = ((Static3D)center).getY();
         mUniforms[NUM_UNIFORMS*mNumEffects+2] = ((Static3D)center).getZ();
         }
       else return -1;
 
-           if( angle instanceof Dynamic1D) mInterI[mNumEffects] = (Dynamic1D)angle;
+           if( angle instanceof Dynamic1D) mInter[0][mNumEffects] = (Dynamic1D)angle;
       else if( angle instanceof Static1D)
         {
-        mInterI[mNumEffects] = null;
+        mInter[0][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects+3] = ((Static1D)angle).getX();
         }
       else return -1;
@@ -317,21 +316,21 @@ class EffectQueueMatrix extends EffectQueue
     {
     if( mMax[INDEX]>mNumEffects )
       {
-           if( center instanceof Dynamic3D) mInterP[mNumEffects] = (Dynamic3D)center;
+           if( center instanceof Dynamic3D) mInter[1][mNumEffects] = (Dynamic3D)center;
       else if( center instanceof Static3D )
         {
-        mInterP[mNumEffects] = null;
+        mInter[1][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects  ] = ((Static3D)center).getX();
         mUniforms[NUM_UNIFORMS*mNumEffects+1] = ((Static3D)center).getY();
         mUniforms[NUM_UNIFORMS*mNumEffects+2] = ((Static3D)center).getZ();
         }
       else return -1;
 
-           if( data instanceof Dynamic4D  ) mInterI[mNumEffects] = (Dynamic4D)data;
-      else if( data instanceof DynamicQuat) mInterI[mNumEffects] = (DynamicQuat)data;
+           if( data instanceof Dynamic4D  ) mInter[0][mNumEffects] = (Dynamic4D)data;
+      else if( data instanceof DynamicQuat) mInter[0][mNumEffects] = (DynamicQuat)data;
       else if( data instanceof Static4D   )
         {
-        mInterI[mNumEffects] = null;
+        mInter[0][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects+3] = ((Static4D)data).getX();
         mUniforms[NUM_UNIFORMS*mNumEffects+4] = ((Static4D)data).getY();
         mUniforms[NUM_UNIFORMS*mNumEffects+5] = ((Static4D)data).getZ();
@@ -352,20 +351,20 @@ class EffectQueueMatrix extends EffectQueue
     {
     if( mMax[INDEX]>mNumEffects )
       {
-           if( center instanceof Dynamic3D) mInterP[mNumEffects] = (Dynamic3D)center;
+           if( center instanceof Dynamic3D) mInter[1][mNumEffects] = (Dynamic3D)center;
       else if( center instanceof Static3D )
         {
-        mInterP[mNumEffects] = null;
+        mInter[1][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects  ] = ((Static3D)center).getX();
         mUniforms[NUM_UNIFORMS*mNumEffects+1] = ((Static3D)center).getY();
         mUniforms[NUM_UNIFORMS*mNumEffects+2] = ((Static3D)center).getZ();
         }
       else return -1;
 
-           if( shear instanceof Dynamic3D) mInterI[mNumEffects] = (Dynamic3D)shear;
+           if( shear instanceof Dynamic3D) mInter[0][mNumEffects] = (Dynamic3D)shear;
       else if( shear instanceof Static3D )
         {
-        mInterI[mNumEffects] = null;
+        mInter[0][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects+3] = ((Static3D)shear).getX();
         mUniforms[NUM_UNIFORMS*mNumEffects+4] = ((Static3D)shear).getY();
         mUniforms[NUM_UNIFORMS*mNumEffects+5] = ((Static3D)shear).getZ();
diff --git a/src/main/java/org/distorted/library/EffectQueueVertex.java b/src/main/java/org/distorted/library/EffectQueueVertex.java
index 35f482b..9c5311c 100644
--- a/src/main/java/org/distorted/library/EffectQueueVertex.java
+++ b/src/main/java/org/distorted/library/EffectQueueVertex.java
@@ -26,12 +26,13 @@ import org.distorted.library.type.Data1D;
 import org.distorted.library.type.Data2D;
 import org.distorted.library.type.Data3D;
 import org.distorted.library.type.Data4D;
-import org.distorted.library.type.Dynamic;
 import org.distorted.library.type.Dynamic1D;
 import org.distorted.library.type.Dynamic2D;
+import org.distorted.library.type.Dynamic3D;
 import org.distorted.library.type.Dynamic4D;
 import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static2D;
+import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -70,17 +71,22 @@ class EffectQueueVertex extends EffectQueue
    
     for(int i=0; i<mNumEffects; i++)
       {
-      if( mInterI[i]==null ) continue;    
+      if( mInter[0][i]==null ) continue;
       
-      if( mInterP[i]!=null ) 
+      if( mInter[1][i]!=null )
         {
-        mInterP[i].interpolateMain(mUniforms, NUM_UNIFORMS*i+7, mCurrentDuration[i]);
+        mInter[1][i].interpolateMain(mUniforms, NUM_UNIFORMS*i+7, mCurrentDuration[i]);
       
         mUniforms[NUM_UNIFORMS*i+7] = mUniforms[NUM_UNIFORMS*i+7]-mObjHalfX;
         mUniforms[NUM_UNIFORMS*i+8] =-mUniforms[NUM_UNIFORMS*i+8]+mObjHalfY;
         }
-        
-      if( mInterI[i].interpolateMain(mUniforms ,NUM_UNIFORMS*i, mCurrentDuration[i], step) )      
+
+      if( mInter[2][i]!=null )
+        {
+        mInter[2][i].interpolateMain(mUniforms, NUM_UNIFORMS*i+3, mCurrentDuration[i]);
+        }
+
+      if( mInter[0][i].interpolateMain(mUniforms ,NUM_UNIFORMS*i, mCurrentDuration[i], step) )
         {
         for(int j=0; j<mNumListeners; j++)   
           EffectMessageSender.newMessage( mListeners.elementAt(j),
@@ -160,58 +166,73 @@ class EffectQueueVertex extends EffectQueue
     }
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-  
+// distort
+
   synchronized long add(EffectNames eln, Data3D data, Data2D center, Data4D region)
     {
     if( mMax[INDEX]>mNumEffects )
       {
       EffectNames.fillWithUnities(eln.ordinal(), mUniforms, NUM_UNIFORMS*mNumEffects);    
-      
-      mInterI[mNumEffects] = inter;
-      mInterP[mNumEffects] = point;
 
-      return addPriv(eln,region);
+      if( data instanceof Dynamic3D)
+        mInter[0][mNumEffects] = (Dynamic3D)data;
+      else if( data instanceof Static3D)
+        {
+        mInter[0][mNumEffects] = null;
+        mUniforms[NUM_UNIFORMS*mNumEffects  ] = ((Static3D)data).getX();
+        mUniforms[NUM_UNIFORMS*mNumEffects+1] = ((Static3D)data).getY();
+        mUniforms[NUM_UNIFORMS*mNumEffects+2] = ((Static3D)data).getZ();
+        }
+
+      return addPriv(eln,center,region);
       }
       
     return -1;
     }
    
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-  
+// deform, distort
+
   synchronized long add(EffectNames eln, Data3D data, Data2D center)
     {
     if( mMax[INDEX]>mNumEffects )
       {
       EffectNames.fillWithUnities(eln.ordinal(), mUniforms, NUM_UNIFORMS*mNumEffects);    
-      
-      mInterI[mNumEffects] = inter;
-      mInterP[mNumEffects] = null;
-      mUniforms[NUM_UNIFORMS*mNumEffects+7] = point.getX()-mObjHalfX;
-      mUniforms[NUM_UNIFORMS*mNumEffects+8] =-point.getY()+mObjHalfY;
-     
-      return addPriv(eln,null);
+
+      if( data instanceof Dynamic3D)
+        mInter[0][mNumEffects] = (Dynamic3D)data;
+      else if( data instanceof Static3D)
+        {
+        mInter[0][mNumEffects] = null;
+        mUniforms[NUM_UNIFORMS*mNumEffects  ] = ((Static3D)data).getX();
+        mUniforms[NUM_UNIFORMS*mNumEffects+1] = ((Static3D)data).getY();
+        mUniforms[NUM_UNIFORMS*mNumEffects+2] = ((Static3D)data).getZ();
+        }
+
+      return addPriv(eln,center,null);
       }
       
     return -1;
     }
  
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-  
+// sink, swirl
+
   synchronized long add(EffectNames eln, Data1D data, Data2D center, Data4D region)
     {
     if( mMax[INDEX]>mNumEffects )
       {
-      EffectNames.fillWithUnities(eln.ordinal(), mUniforms, NUM_UNIFORMS*mNumEffects); 
-      mUniforms[NUM_UNIFORMS*mNumEffects  ] = v1;
-      mUniforms[NUM_UNIFORMS*mNumEffects+1] = v2;  
-      mUniforms[NUM_UNIFORMS*mNumEffects+2] = v3;  
-     
-      mInterI[mNumEffects] = null;
-      mInterP[mNumEffects] = null;
-      mUniforms[NUM_UNIFORMS*mNumEffects+7] = point.getX()-mObjHalfX;
-      mUniforms[NUM_UNIFORMS*mNumEffects+8] =-point.getY()+mObjHalfY;
-      
-      return addPriv(eln,region);    
+      EffectNames.fillWithUnities(eln.ordinal(), mUniforms, NUM_UNIFORMS*mNumEffects);
+
+      if( data instanceof Dynamic1D)
+        mInter[0][mNumEffects] = (Dynamic1D)data;
+      else if( data instanceof Static1D)
+        {
+        mInter[0][mNumEffects] = null;
+        mUniforms[NUM_UNIFORMS*mNumEffects] = ((Static1D)data).getX();
+        }
+
+      return addPriv(eln,center,region);
       }
       
     return -1;
@@ -227,17 +248,14 @@ class EffectQueueVertex extends EffectQueue
       EffectNames.fillWithUnities(eln.ordinal(), mUniforms, NUM_UNIFORMS*mNumEffects);
 
       if( data instanceof Dynamic1D)
-        mInterI[mNumEffects] = (Dynamic1D)data;
+        mInter[0][mNumEffects] = (Dynamic1D)data;
       else if( data instanceof Static1D)
         {
-        mInterI[mNumEffects] = null;
+        mInter[0][mNumEffects] = null;
         mUniforms[NUM_UNIFORMS*mNumEffects] = ((Static1D)data).getX();
         }
 
-      mUniforms[NUM_UNIFORMS*mNumEffects+7] = point.getX()-mObjHalfX;
-      mUniforms[NUM_UNIFORMS*mNumEffects+8] =-point.getY()+mObjHalfY;
-
-      return addPriv(eln,null);
+      return addPriv(eln,center,null);
       }
 
     return -1;
@@ -245,13 +263,22 @@ class EffectQueueVertex extends EffectQueue
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
   
-  private long addPriv(EffectNames eln, Data4D region)
-    {    
+  private long addPriv(EffectNames eln, Data2D center, Data4D region)
+    {
+    if( center instanceof Dynamic2D)
+      mInter[1][mNumEffects] = (Dynamic2D)center;
+    else if( center instanceof Static2D)
+      {
+      mInter[1][mNumEffects] = null;
+      mUniforms[NUM_UNIFORMS*mNumEffects+7] = ((Static2D)center).getX()-mObjHalfX;
+      mUniforms[NUM_UNIFORMS*mNumEffects+8] =-((Static2D)center).getY()+mObjHalfY;
+      }
+
     if( region!=null )
       {
       if( region instanceof Dynamic4D)
         {
-        mInterP[mNumEffects] = (Dynamic4D)region;
+        mInter[2][mNumEffects] = (Dynamic4D)region;
         }
       else if ( region instanceof Static4D)
         {
@@ -263,6 +290,7 @@ class EffectQueueVertex extends EffectQueue
         mUniforms[NUM_UNIFORMS*mNumEffects+4] =-tmp.getY();   // invert y already
         mUniforms[NUM_UNIFORMS*mNumEffects+5] = z<=0.0f ? 1000*mObjHalfX : z;
         mUniforms[NUM_UNIFORMS*mNumEffects+6] = tmp.getW();
+        mInter[2][mNumEffects] = null;
         }
       else return -1;
       }
@@ -272,6 +300,7 @@ class EffectQueueVertex extends EffectQueue
       mUniforms[NUM_UNIFORMS*mNumEffects+4] = 0.0f;
       mUniforms[NUM_UNIFORMS*mNumEffects+5] = 1000*mObjHalfX;
       mUniforms[NUM_UNIFORMS*mNumEffects+6] = 0.0f;
+      mInter[2][mNumEffects] = null;
       }
     
     return addBase(eln);
