commit 08f92d82e0755817e1351946d74a1deaa6a85092
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Wed Jun 22 16:42:46 2016 +0100

    Skeleton of the new App: Vertex3D. So far just a copy of Matrix3D.

diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 63eac2e..c5f8723 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -35,6 +35,7 @@
         <activity android:name=".cubes.CubesActivity" />       
         <activity android:name=".quaternion.QuaternionActivity" />          
         <activity android:name=".matrix3d.Matrix3DActivity" />
+        <activity android:name=".vertex3d.Vertex3DActivity" />
         <activity android:name=".plainmonalisa.PlainMonaLisaActivity" />
         <activity android:name=".save.SaveActivity"/>
     </application>
diff --git a/src/main/java/org/distorted/examples/TableOfContents.java b/src/main/java/org/distorted/examples/TableOfContents.java
index 3461bf4..5405ce5 100644
--- a/src/main/java/org/distorted/examples/TableOfContents.java
+++ b/src/main/java/org/distorted/examples/TableOfContents.java
@@ -54,6 +54,7 @@ import org.distorted.examples.starwars.StarWarsActivity;
 import org.distorted.examples.cubes.CubesActivity;
 import org.distorted.examples.quaternion.QuaternionActivity;
 import org.distorted.examples.matrix3d.Matrix3DActivity;
+import org.distorted.examples.vertex3d.Vertex3DActivity;
 import org.distorted.examples.plainmonalisa.PlainMonaLisaActivity;
 import org.distorted.examples.save.SaveActivity;
 
@@ -258,6 +259,15 @@ public class TableOfContents extends ListActivity
       activityMapping.put(i++, Matrix3DActivity.class);
    }
 
+   {
+      final Map<String, Object> item = new HashMap<>();
+      item.put(ITEM_IMAGE, R.drawable.icon_example_vertex3d);
+      item.put(ITEM_TITLE, (i+1)+". "+getText(R.string.example_vertex3d));
+      item.put(ITEM_SUBTITLE, getText(R.string.example_vertex3d_subtitle));
+      data.add(item);
+      activityMapping.put(i++, Vertex3DActivity.class);
+   }
+
    {
       final Map<String, Object> item = new HashMap<>();
       item.put(ITEM_IMAGE, R.drawable.icon_example_monalisa);
diff --git a/src/main/java/org/distorted/examples/matrix3d/Matrix3DActivity.java b/src/main/java/org/distorted/examples/matrix3d/Matrix3DActivity.java
index e647e86..e2eb06a 100644
--- a/src/main/java/org/distorted/examples/matrix3d/Matrix3DActivity.java
+++ b/src/main/java/org/distorted/examples/matrix3d/Matrix3DActivity.java
@@ -21,6 +21,7 @@ package org.distorted.examples.matrix3d;
 
 import org.distorted.library.Distorted;
 import org.distorted.examples.R;
+import org.distorted.library.EffectNames;
 
 import android.app.Activity;
 import android.os.Bundle;
@@ -35,11 +36,6 @@ import android.widget.SeekBar.OnSeekBarChangeListener;
 
 public class Matrix3DActivity extends Activity implements OnSeekBarChangeListener
 {
-    public static final int MOVE   =0;
-    public static final int SCALE  =1;
-    public static final int ROTATE =2;
-    public static final int SHEAR  =3;
-	
     private SeekBar bar;
     private TextView textMove, textScale, textRotate, textShear;
     private int moveX, moveY, moveZ;
@@ -54,7 +50,7 @@ public class Matrix3DActivity extends Activity implements OnSeekBarChangeListene
     private float frotateX, frotateY, frotateZ, frotateA;
     private float fshearX, fshearY, fshearZ;
     
-    private int[] effects = new int[4];
+    private EffectNames[] effects = new EffectNames[4];
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
@@ -70,10 +66,10 @@ public class Matrix3DActivity extends Activity implements OnSeekBarChangeListene
 
     public void Default(View view)
       {
-      effects[0] = MOVE;
-      effects[1] = SCALE;
-      effects[2] = ROTATE;
-      effects[3] = SHEAR;
+      effects[0] = EffectNames.MOVE;
+      effects[1] = EffectNames.SCALE;
+      effects[2] = EffectNames.ROTATE;
+      effects[3] = EffectNames.SHEAR;
     
       moveX = 50;
       moveY = 50;
@@ -151,14 +147,14 @@ public class Matrix3DActivity extends Activity implements OnSeekBarChangeListene
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void moveUp(int effect)
+    private void moveUp(EffectNames name)
       {
       int len = effects.length-1;	
       int index = -1;
       
       for(int i=0; i<=len; i++)	
         {
-        if( effects[i]==effect ) 
+        if( effects[i]==name )
           {
           index=i;
           break;
@@ -170,12 +166,12 @@ public class Matrix3DActivity extends Activity implements OnSeekBarChangeListene
         for(int i=0; i<len; i++)
           effects[i] = effects[i+1];
     	
-        effects[len] = effect;
+        effects[len] = name;
         }
       else if( index>0 )
         {
         effects[index]   = effects[index-1];
-        effects[index-1] = effect;
+        effects[index-1] = name;
         }
       
       addViews();
@@ -185,28 +181,28 @@ public class Matrix3DActivity extends Activity implements OnSeekBarChangeListene
 
     public void ButtonMove(View v)
       {
-      moveUp(MOVE); 	
+      moveUp(EffectNames.MOVE);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void ButtonScale(View v)
       {
-      moveUp(SCALE); 	
+      moveUp(EffectNames.SCALE);
       }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void ButtonRotate(View v)
       {
-      moveUp(ROTATE); 	
+      moveUp(EffectNames.ROTATE);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     public void ButtonShear(View v)
       {
-      moveUp(SHEAR); 	
+      moveUp(EffectNames.SHEAR);
       }
  
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/examples/matrix3d/Matrix3DRenderer.java b/src/main/java/org/distorted/examples/matrix3d/Matrix3DRenderer.java
index d070da6..b082ce4 100644
--- a/src/main/java/org/distorted/examples/matrix3d/Matrix3DRenderer.java
+++ b/src/main/java/org/distorted/examples/matrix3d/Matrix3DRenderer.java
@@ -28,6 +28,7 @@ import javax.microedition.khronos.opengles.GL10;
 import org.distorted.examples.R;
 
 import org.distorted.library.DistortedCubes;
+import org.distorted.library.EffectNames;
 import org.distorted.library.EffectTypes;
 import org.distorted.library.type.Dynamic3D;
 import org.distorted.library.type.Static3D;
@@ -49,7 +50,7 @@ class Matrix3DRenderer implements GLSurfaceView.Renderer
     private GLSurfaceView mView;
     private static DistortedCubes mCube;
 
-    private static int[] order;
+    private static EffectNames[] order;
     
     private static Dynamic3D mMoveInter, mScaleInter, mShearInter;
     private static Dynamic4D mDynamicRotate;
@@ -87,7 +88,7 @@ class Matrix3DRenderer implements GLSurfaceView.Renderer
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public static void setOrder(int[] effects)
+    public static void setOrder(EffectNames[] effects)
       {
       order = effects;
       setMatrixEffects();
@@ -103,10 +104,10 @@ class Matrix3DRenderer implements GLSurfaceView.Renderer
         {
         switch(order[i])
           {
-          case Matrix3DActivity.MOVE  : mCube.move(mMoveInter)                 ; break;
-          case Matrix3DActivity.SCALE : mCube.scale(mScaleInter)               ; break;
-          case Matrix3DActivity.ROTATE: mCube.rotate(mDynamicRotate,mZeroPoint); break;
-          case Matrix3DActivity.SHEAR : mCube.shear(mShearInter, mZeroPoint)   ; break;
+          case MOVE  : mCube.move(mMoveInter)                 ; break;
+          case SCALE : mCube.scale(mScaleInter)               ; break;
+          case ROTATE: mCube.rotate(mDynamicRotate,mZeroPoint); break;
+          case SHEAR : mCube.shear(mShearInter, mZeroPoint)   ; break;
           }
         }
       }
@@ -182,7 +183,7 @@ class Matrix3DRenderer implements GLSurfaceView.Renderer
         }
       catch(Exception ex)
         {
-        android.util.Log.e("Quaternion", ex.getMessage() );
+        android.util.Log.e("Matrix3D", ex.getMessage() );
         }
       }
 }
diff --git a/src/main/java/org/distorted/examples/vertex3d/Vertex3DActivity.java b/src/main/java/org/distorted/examples/vertex3d/Vertex3DActivity.java
new file mode 100644
index 0000000..c27276e
--- /dev/null
+++ b/src/main/java/org/distorted/examples/vertex3d/Vertex3DActivity.java
@@ -0,0 +1,381 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.vertex3d;
+
+import android.app.Activity;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.TextView;
+
+import org.distorted.examples.R;
+import org.distorted.library.Distorted;
+import org.distorted.library.EffectNames;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class Vertex3DActivity extends Activity implements OnSeekBarChangeListener
+{
+    private SeekBar bar;
+    private TextView textDeform, textDistort, textSink, textSwirl;
+    private int moveX, moveY, moveZ;
+    private int scaleX, scaleY, scaleZ;
+    private int rotateX, rotateY, rotateZ, rotateA;
+    private int shearX, shearY, shearZ;
+    
+    private int maxX, maxY, maxZ;
+    
+    private float fmoveX, fmoveY, fmoveZ;
+    private float fscaleX, fscaleY, fscaleZ;
+    private float frotateX, frotateY, frotateZ, frotateA;
+    private float fshearX, fshearY, fshearZ;
+    
+    private EffectNames[] effects = new EffectNames[4];
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onCreate(Bundle icicle) 
+      {
+      super.onCreate(icicle);
+      setContentView(R.layout.vertex3dlayout);
+      Default(null);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Default(View view)
+      {
+      effects[0] = EffectNames.DEFORM;
+      effects[1] = EffectNames.DISTORT;
+      effects[2] = EffectNames.SINK;
+      effects[3] = EffectNames.SWIRL;
+    
+      moveX = 50;
+      moveY = 50;
+      moveZ = 50;
+      
+      scaleX = 50;
+      scaleY = 50;
+      scaleZ = 50;
+      
+      rotateX = 100;
+      rotateY =  50;
+      rotateZ =  50;
+      rotateA =  50;
+      
+      shearX = 50;
+      shearY = 50;
+      shearZ = 50;
+      
+      addViews();
+      }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    private void addViews()
+      {
+      LinearLayout layout = (LinearLayout)findViewById(R.id.vertex3dlayout);
+    
+      layout.removeAllViews();
+      
+      View deform = getLayoutInflater().inflate(R.layout.vertex3ddeform , null);
+      View distort= getLayoutInflater().inflate(R.layout.vertex3ddistort, null);
+      View sink   = getLayoutInflater().inflate(R.layout.vertex3dsink   , null);
+      View swirl  = getLayoutInflater().inflate(R.layout.vertex3dswirl  , null);
+     
+      for( int i=effects.length-1 ; i>=0 ; i-- )
+        {
+        switch(effects[i])
+          {
+          case DEFORM : layout.addView(deform , 0); break;
+          case DISTORT: layout.addView(distort, 0); break;
+          case SINK   : layout.addView(sink   , 0); break;
+          case SWIRL  : layout.addView(swirl  , 0); break;
+          }
+        }
+      
+      textDeform = (TextView)findViewById(R.id.vertex3ddeformText);
+      textDistort= (TextView)findViewById(R.id.vertex3ddistortText);
+      textSink   = (TextView)findViewById(R.id.vertex3dsinkText);
+      textSwirl  = (TextView)findViewById(R.id.vertex3dswirlText);
+     
+      setDeformText();
+      setDistortText();
+      setSinkText();
+      setSwirlText();
+      
+      setBar(R.id.vertex3ddeformBar1, moveX);
+      setBar(R.id.vertex3ddeformBar2, moveY);
+      setBar(R.id.vertex3ddeformBar3, moveZ);
+      
+      setBar(R.id.vertex3ddistortBar1, scaleX);
+      setBar(R.id.vertex3ddistortBar2, scaleY);
+      setBar(R.id.vertex3ddistortBar3, scaleZ);
+      
+      setBar(R.id.vertex3dsinkBar1, rotateX);
+      setBar(R.id.vertex3dsinkBar2, rotateY);
+      setBar(R.id.vertex3dsinkBar3, rotateZ);
+
+      setBar(R.id.vertex3dswirlBar1, shearX);
+      setBar(R.id.vertex3dswirlBar2, shearY);
+      setBar(R.id.vertex3dswirlBar3, shearZ);
+      
+      Vertex3DRenderer.setOrder(effects);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void moveUp(EffectNames name)
+      {
+      int len = effects.length-1;
+      int index = -1;
+
+      for(int i=0; i<=len; i++)
+        {
+        if( effects[i]==name )
+          {
+          index=i;
+          break;
+          }
+        }
+
+      if( index==0 )
+        {
+        for(int i=0; i<len; i++)
+          effects[i] = effects[i+1];
+
+        effects[len] = name;
+        }
+      else if( index>0 )
+        {
+        effects[index]   = effects[index-1];
+        effects[index-1] = name;
+        }
+
+      addViews();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void ButtonDeform(View v)
+      {
+      moveUp(EffectNames.DEFORM);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void ButtonDistort(View v)
+      {
+      moveUp(EffectNames.DISTORT);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void ButtonSink(View v)
+      {
+      moveUp(EffectNames.SINK);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void ButtonSwirl(View v)
+      {
+      moveUp(EffectNames.SWIRL);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void setBar(int id, int value)
+      {
+      bar = (SeekBar)findViewById(id);
+      bar.setOnSeekBarChangeListener(this);
+      bar.setProgress(value);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void computeDeform()
+      {
+      fmoveX = (moveX-50)*maxX/50.0f;
+      fmoveY = (moveY-50)*maxY/50.0f;
+      fmoveZ = (moveZ-50)*maxZ/50.0f;
+
+      Vertex3DRenderer.setDeform( fmoveX, fmoveY, fmoveZ);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void setDeformText()
+      {
+      fmoveX = ((int)(100*fmoveX))/100.0f;
+      fmoveY = ((int)(100*fmoveY))/100.0f;
+      fmoveZ = ((int)(100*fmoveZ))/100.0f;
+
+      textDeform.setText("deform("+fmoveX+" , "+fmoveY+" , "+fmoveZ+")");
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void computeDistort()
+      {
+      fscaleX = (scaleX>50 ? 0.18f : 0.018f)*(scaleX-50)+1;
+      fscaleY = (scaleY>50 ? 0.18f : 0.018f)*(scaleY-50)+1;
+      fscaleZ = (scaleZ>50 ? 0.18f : 0.018f)*(scaleZ-50)+1;
+
+      Vertex3DRenderer.setDistort(fscaleX, fscaleY, fscaleZ);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void setDistortText()
+      {
+      fscaleX = ((int)(100*fscaleX))/100.0f;
+      fscaleY = ((int)(100*fscaleY))/100.0f;
+      fscaleZ = ((int)(100*fscaleZ))/100.0f;
+
+      textDistort.setText("distort("+fscaleX+" , "+fscaleY+" , "+fscaleZ+")");
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void computeSink()
+      {
+      frotateX = (rotateX-50)/50.0f;
+      frotateY = (rotateY-50)/50.0f;
+      frotateZ = (rotateZ-50)/50.0f;
+
+      Vertex3DRenderer.setSink( frotateA, frotateX, frotateY, frotateZ );
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void setSinkText()
+      {
+      frotateX = ((int)(100*frotateX))/100.0f;
+      frotateY = ((int)(100*frotateY))/100.0f;
+      frotateZ = ((int)(100*frotateZ))/100.0f;
+
+      frotateA = ((rotateA-50)*180)/50;
+
+      textSink.setText("sink( "+frotateA+" ("+frotateX+","+frotateY+","+frotateZ+") )");
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void computeSwirl()
+      {
+      fshearX = (shearX-50)/25.0f;
+      fshearY = (shearY-50)/25.0f;
+      fshearZ = (shearZ-50)/25.0f;
+
+      Vertex3DRenderer.setSwirl( fshearX, fshearY, fshearZ );
+      }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void setSwirlText()
+      {
+      fshearX = ((int)(100*fshearX))/100.0f;
+      fshearY = ((int)(100*fshearY))/100.0f;
+      fshearZ = ((int)(100*fshearZ))/100.0f;
+      
+      textSwirl.setText("swirl("+fshearX+" , "+fshearY+" , "+fshearZ+")");
+      }
+   
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onPause() 
+      {
+      GLSurfaceView mView = (GLSurfaceView) this.findViewById(R.id.vertex3dSurfaceView);
+      mView.onPause(); 
+      super.onPause();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onResume() 
+      {
+      super.onResume();
+      GLSurfaceView mView = (GLSurfaceView) this.findViewById(R.id.vertex3dSurfaceView);
+      mView.onResume();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) 
+      {
+      super.onWindowFocusChanged(hasFocus);
+  
+      GLSurfaceView mView = (GLSurfaceView) this.findViewById(R.id.vertex3dSurfaceView);
+      
+      maxX = mView.getWidth();
+      maxY = mView.getHeight();
+      maxZ = (maxX+maxY)/2;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onDestroy() 
+      {
+      Distorted.onDestroy();  
+      super.onDestroy();
+      }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    public void onProgressChanged(SeekBar bar, int progress, boolean fromUser) 
+      {
+      switch (bar.getId()) 
+        {
+        case R.id.vertex3ddeformBar1  : moveX = progress; computeDeform()  ; setDeformText()  ; break;
+        case R.id.vertex3ddeformBar2  : moveY = progress; computeDeform()  ; setDeformText()  ; break;
+        case R.id.vertex3ddeformBar3  : moveZ = progress; computeDeform()  ; setDeformText()  ; break;
+        
+        case R.id.vertex3ddistortBar1 : scaleX= progress; computeDistort() ; setDistortText() ; break;
+        case R.id.vertex3ddistortBar2 : scaleY= progress; computeDistort() ; setDistortText() ; break;
+        case R.id.vertex3ddistortBar3 : scaleZ= progress; computeDistort() ; setDistortText() ; break;
+        
+        case R.id.vertex3dsinkBar1    : rotateX=progress; computeSink()    ; setSinkText()    ; break;
+        case R.id.vertex3dsinkBar2    : rotateY=progress; computeSink()    ; setSinkText()    ; break;
+        case R.id.vertex3dsinkBar3    : rotateZ=progress; computeSink()    ; setSinkText()    ; break;
+
+        case R.id.vertex3dswirlBar1   : shearX= progress; computeSwirl()   ; setSwirlText()   ; break;
+        case R.id.vertex3dswirlBar2   : shearY= progress; computeSwirl()   ; setSwirlText()   ; break;
+        case R.id.vertex3dswirlBar3   : shearZ= progress; computeSwirl()   ; setSwirlText()   ; break;
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void onStartTrackingTouch(SeekBar bar) { }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void onStopTrackingTouch(SeekBar bar)  { }
+    
+}
diff --git a/src/main/java/org/distorted/examples/vertex3d/Vertex3DRenderer.java b/src/main/java/org/distorted/examples/vertex3d/Vertex3DRenderer.java
new file mode 100644
index 0000000..0dca6e1
--- /dev/null
+++ b/src/main/java/org/distorted/examples/vertex3d/Vertex3DRenderer.java
@@ -0,0 +1,188 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.vertex3d;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+
+import org.distorted.examples.R;
+import org.distorted.library.Distorted;
+import org.distorted.library.DistortedCubes;
+import org.distorted.library.EffectNames;
+import org.distorted.library.EffectTypes;
+import org.distorted.library.type.Dynamic3D;
+import org.distorted.library.type.Dynamic4D;
+import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Static4D;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class Vertex3DRenderer implements GLSurfaceView.Renderer
+{
+    private static final int SIZE = 100;
+	
+    private GLSurfaceView mView;
+    private static DistortedCubes mCube;
+
+    private static EffectNames[] order;
+    
+    private static Dynamic3D mMoveInter, mScaleInter, mShearInter;
+    private static Dynamic4D mDynamicRotate;
+
+    private static Static3D mZeroPoint, mMovePoint, mScalePoint, mShearPoint;
+    private static Static4D mRotatePoint;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public static void setDeform(float x, float y, float z)
+      {
+      mMovePoint.set(x, y, z);
+      }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public static void setDistort(float x, float y, float z)
+      {
+      mScalePoint.set(x, y, z);
+      }
+     
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public static void setSink(float a, float x, float y, float z)
+      {
+      mRotatePoint.set(a,x,y,z);
+      }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public static void setSwirl(float x, float y, float z)
+      {
+      mShearPoint.set(x, y, z);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public static void setOrder(EffectNames[] effects)
+      {
+      order = effects;
+      setMatrixEffects();
+      }
+      
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public static void setMatrixEffects()
+      {
+      mCube.abortEffects(EffectTypes.MATRIX);
+	
+      for( int i=0; i<=order.length-1 ; i++ )
+        {
+        switch(order[i])
+          {
+          case MOVE  : mCube.move(mMoveInter)                 ; break;
+          case SCALE : mCube.scale(mScaleInter)               ; break;
+          case ROTATE: mCube.rotate(mDynamicRotate,mZeroPoint); break;
+          case SHEAR : mCube.shear(mShearInter, mZeroPoint)   ; break;
+          }
+        }
+      }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public Vertex3DRenderer(GLSurfaceView v)
+      {
+      mView = v;
+      mCube = new DistortedCubes( 1, "1", SIZE);
+      
+      mZeroPoint   = new Static3D(0,0,0);
+      mMovePoint   = new Static3D(0,0,0);
+      mScalePoint  = new Static3D(1,1,1);
+      mShearPoint  = new Static3D(0,0,0);
+      mRotatePoint = new Static4D(0,1,0,0);
+
+      mMoveInter    = new Dynamic3D();
+      mScaleInter   = new Dynamic3D();
+      mShearInter   = new Dynamic3D();
+      mDynamicRotate= new Dynamic4D();
+
+      mMoveInter.add(mMovePoint);
+      mScaleInter.add(mScalePoint);
+      mShearInter.add(mShearPoint);
+      mDynamicRotate.add(mRotatePoint);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+   
+    public void onDrawFrame(GL10 glUnused) 
+      {
+      GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+      GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+      
+      mCube.draw(System.currentTimeMillis());
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    public void onSurfaceChanged(GL10 glUnused, int width, int height) 
+      {
+      setMatrixEffects();
+
+      Distorted.onSurfaceChanged(width, height); 
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) 
+      {
+      InputStream is = mView.getContext().getResources().openRawResource(R.raw.grid);
+      Bitmap bitmap;
+        
+      try 
+        {
+        bitmap = BitmapFactory.decodeStream(is);
+        } 
+      finally 
+        {
+        try 
+          {
+          is.close();
+          } 
+        catch(IOException e) { }
+        }  
+      
+      mCube.setBitmap(bitmap);
+      
+      try
+        {
+        Distorted.onSurfaceCreated(mView.getContext());
+        }
+      catch(Exception ex)
+        {
+        android.util.Log.e("Vertex3D", ex.getMessage() );
+        }
+      }
+}
diff --git a/src/main/java/org/distorted/examples/vertex3d/Vertex3DSurfaceView.java b/src/main/java/org/distorted/examples/vertex3d/Vertex3DSurfaceView.java
new file mode 100644
index 0000000..71b88f3
--- /dev/null
+++ b/src/main/java/org/distorted/examples/vertex3d/Vertex3DSurfaceView.java
@@ -0,0 +1,50 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.vertex3d;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.os.Build;
+import android.util.AttributeSet;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class Vertex3DSurfaceView extends GLSurfaceView
+{
+///////////////////////////////////////////////////////////////////////////////////////////////////
+   
+    public Vertex3DSurfaceView(Context c, AttributeSet attrs)
+      {
+      super(c, attrs);
+      
+      if(!isInEditMode())
+        {
+        setEGLContextClientVersion(2);
+        
+        if( Build.FINGERPRINT.startsWith("generic") )
+          { 
+          setEGLConfigChooser(8, 8, 8, 8, 16, 0);   
+          }
+        
+        setRenderer(new Vertex3DRenderer(this));
+        }
+      }
+}
+
diff --git a/src/main/res/drawable-hdpi/icon_example_vertex3d.png b/src/main/res/drawable-hdpi/icon_example_vertex3d.png
new file mode 100644
index 0000000..8074c9b
Binary files /dev/null and b/src/main/res/drawable-hdpi/icon_example_vertex3d.png differ
diff --git a/src/main/res/layout/vertex3ddeform.xml b/src/main/res/layout/vertex3ddeform.xml
new file mode 100644
index 0000000..f672056
--- /dev/null
+++ b/src/main/res/layout/vertex3ddeform.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:id="@+id/vertex3dRowDeform"
+                android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" >
+
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="0.70"
+                    android:orientation="vertical" >
+
+                    <TextView
+                        android:id="@+id/vertex3ddeformText"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginStart="5dp"
+                        android:layout_marginTop="3dp"
+                        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3ddeformBar4"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3ddeformBar1"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="end"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3ddeformBar2"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="end"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3ddeformBar3"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="end"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                </LinearLayout>
+
+                <Button
+                    android:id="@+id/vertex3dUpDeform"
+                    android:layout_width="60dp"
+                    android:layout_height="fill_parent"
+                    android:onClick="ButtonDeform"
+                    android:text="@string/Up" />
+
+            </LinearLayout>
\ No newline at end of file
diff --git a/src/main/res/layout/vertex3ddistort.xml b/src/main/res/layout/vertex3ddistort.xml
new file mode 100644
index 0000000..d181093
--- /dev/null
+++ b/src/main/res/layout/vertex3ddistort.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:id="@+id/vertex3dRowDistort"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal" >
+
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="0.8"
+                    android:orientation="vertical" >
+
+                    <TextView
+                        android:id="@+id/vertex3ddistortText"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginStart="5dp"
+                        android:layout_marginTop="3dp"
+                        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3ddistortBar1"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3ddistortBar2"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3ddistortBar3"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                </LinearLayout>
+
+                <Button
+                    android:id="@+id/vertex3dUpDistort"
+                    android:layout_width="60dp"
+                    android:layout_height="fill_parent"
+                    android:onClick="ButtonDistort"
+                    android:text="@string/Up" />
+
+            </LinearLayout>
diff --git a/src/main/res/layout/vertex3dlayout.xml b/src/main/res/layout/vertex3dlayout.xml
new file mode 100644
index 0000000..431b252
--- /dev/null
+++ b/src/main/res/layout/vertex3dlayout.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <org.distorted.examples.vertex3d.Vertex3DSurfaceView
+        android:id="@+id/vertex3dSurfaceView"
+        android:layout_width="fill_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <Button
+        android:id="@+id/button1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:onClick="Default"
+        android:text="@string/Default" />
+
+    <ScrollView
+        android:id="@+id/vertex3dscrollView"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="0.82" >
+
+        <LinearLayout
+            android:id="@+id/vertex3dlayout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical" >
+        </LinearLayout>
+
+    </ScrollView>
+
+</LinearLayout>
diff --git a/src/main/res/layout/vertex3dsink.xml b/src/main/res/layout/vertex3dsink.xml
new file mode 100644
index 0000000..02210ea
--- /dev/null
+++ b/src/main/res/layout/vertex3dsink.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:id="@+id/vertex3dRowSink"
+                android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" >
+
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="0.70"
+                    android:orientation="vertical" >
+
+                    <TextView
+                        android:id="@+id/vertex3dsinkText"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginStart="5dp"
+                        android:layout_marginTop="3dp"
+                        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3dsinkBar1"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="end"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3dsinkBar2"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="end"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3dsinkBar3"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="end"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                </LinearLayout>
+
+                <Button
+                    android:id="@+id/vertex3dUpSink"
+                    android:layout_width="60dp"
+                    android:layout_height="fill_parent"
+                    android:onClick="ButtonSink"
+                    android:text="@string/Up" />
+
+            </LinearLayout>
+           
\ No newline at end of file
diff --git a/src/main/res/layout/vertex3dswirl.xml b/src/main/res/layout/vertex3dswirl.xml
new file mode 100644
index 0000000..6fecb82
--- /dev/null
+++ b/src/main/res/layout/vertex3dswirl.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+                android:id="@+id/vertex3dRowSwirl"
+                android:orientation="horizontal"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content" >
+
+                <LinearLayout
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="0.70"
+                    android:orientation="vertical" >
+
+                    <TextView
+                        android:id="@+id/vertex3dswirlText"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginStart="5dp"
+                        android:layout_marginTop="3dp"
+                        android:textAppearance="?android:attr/textAppearanceLarge" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3dswirlBar1"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="end"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3dswirlBar2"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="end"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                    <SeekBar
+                        android:id="@+id/vertex3dswirlBar3"
+                        android:layout_width="fill_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_gravity="end"
+                        android:layout_marginEnd="5dp"
+                        android:layout_marginLeft="5dp"
+                        android:layout_marginRight="5dp" />
+
+                </LinearLayout>
+
+                <Button
+                    android:id="@+id/vertex3dUpSwirl"
+                    android:layout_width="60dp"
+                    android:layout_height="fill_parent"
+                    android:onClick="ButtonSwirl"
+                    android:text="@string/Up" />
+
+            </LinearLayout>
\ No newline at end of file
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 35e455c..a4ab762 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -86,7 +86,9 @@
     <string name="example_quaternion_subtitle">Random rotations using quaternions.</string>
     <string name="example_matrix3d">3D Matrix Effects</string>
     <string name="example_matrix3d_subtitle">Test results of Matrix effects on a 3D object.</string>
-    <string name="example_plainmonalisa">PlainMonaLisa</string>  
+    <string name="example_vertex3d">3D Vertex Effects</string>
+    <string name="example_vertex3d_subtitle">Test results of Vertex effects on a 3D object.</string>
+    <string name="example_plainmonalisa">PlainMonaLisa</string>
     <string name="example_plainmonalisa_subtitle">MonaLisa rendered on a plain SurfaceView</string>
     <string name="example_save">Save to PNG</string>
     <string name="example_save_subtitle">Saving the output to a PNG file.</string>
