commit 4bfffdd51dd0335fa4f6a9b6f4b52658b58f4ba6
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Jun 8 17:41:48 2023 +0200

    build for API 34.

diff --git a/build.gradle b/build.gradle
index 22a18c6..3ab748b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,12 +1,12 @@
 apply plugin: 'com.android.application'
 
 android {
-    compileSdkVersion 32
+    compileSdkVersion 34
 
     defaultConfig {
         applicationId "org.distorted.examples"
         minSdkVersion 21
-        targetSdkVersion 32
+        targetSdkVersion 34
         versionCode 1
         versionName "1.0"
     }
@@ -24,7 +24,7 @@ dependencies {
     api project(':distorted-library-opengl')
     implementation 'androidx.legacy:legacy-support-v4:1.0.0'
     implementation 'androidx.legacy:legacy-support-v13:1.0.0'
-    implementation 'com.google.android.material:material:1.8.0'
+    implementation 'com.google.android.material:material:1.9.0'
     implementation project(path: ':distorted-library-object')
     implementation project(path: ':distorted-component-jsons')
 }
diff --git a/src/main/java/org/distorted/examples/TableOfContents.java b/src/main/java/org/distorted/examples/TableOfContents.java
index 3207f65..ff68db9 100644
--- a/src/main/java/org/distorted/examples/TableOfContents.java
+++ b/src/main/java/org/distorted/examples/TableOfContents.java
@@ -77,6 +77,7 @@ import org.distorted.examples.meshjoin.MeshJoinActivity;
 import org.distorted.examples.predeform.PredeformActivity;
 import org.distorted.examples.singlemesh.SingleMeshActivity;
 import org.distorted.examples.meshfile.MeshFileActivity;
+import org.distorted.examples.polymesh.PolymeshActivity;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -130,6 +131,7 @@ public class TableOfContents extends ListActivity
     SINGLEMESH        (R.drawable.icon_example_singlemesh      , R.string.example_singlemesh           , R.string.example_singlemesh_subtitle           ,            SingleMeshActivity.class),
     MESHFILE          (R.drawable.icon_example_meshfile        , R.string.example_meshfile           , R.string.example_meshfile_subtitle           ,            MeshFileActivity.class),
     FLATBLUR2         (R.drawable.icon_example_flatblur        , R.string.example_flatblur         , R.string.example_flatblur_subtitle         , FlatBlur2Activity.class ),
+    POLYMESH          (R.drawable.icon_example_wip             , R.string.example_polymesh         , R.string.example_polymesh_subtitle         , PolymeshActivity.class ),
     ;
 
     final int icon, title, subtitle;
diff --git a/src/main/java/org/distorted/examples/meshfile/MeshFileRenderer.java b/src/main/java/org/distorted/examples/meshfile/MeshFileRenderer.java
index 931eadd..a95ac03 100644
--- a/src/main/java/org/distorted/examples/meshfile/MeshFileRenderer.java
+++ b/src/main/java/org/distorted/examples/meshfile/MeshFileRenderer.java
@@ -19,9 +19,7 @@
 
 package org.distorted.examples.meshfile;
 
-import android.app.ActivityManager;
 import android.content.Context;
-import android.content.pm.ConfigurationInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -267,11 +265,11 @@ class MeshFileRenderer implements GLSurfaceView.Renderer, DistortedLibrary.Libra
     private void createPolygon()
       {
       float A = 0.5f;
-      float B = 0.1f;
+      float B = 0.5f;
 
-      int extraIndex    = 2;
-      int extraVertices = 2;
-      int numBands      = 2;
+      int extraIndex    = 0;
+      int extraVertices = 0;
+      int numBands      = 3;
 
       float[] vertices = new float[] { -A,-A, A,-A, A,A, -A,A };
       float[] bands = new float[2*numBands];
diff --git a/src/main/java/org/distorted/examples/polymesh/PolymeshActivity.java b/src/main/java/org/distorted/examples/polymesh/PolymeshActivity.java
new file mode 100644
index 0000000..c2c2c15
--- /dev/null
+++ b/src/main/java/org/distorted/examples/polymesh/PolymeshActivity.java
@@ -0,0 +1,206 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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.polymesh;
+
+import android.app.Activity;
+import android.opengl.GLSurfaceView;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Toast;
+
+import org.distorted.examples.R;
+import org.distorted.library.main.DistortedLibrary;
+
+///////////////////////////////////////////////////////////////////
+
+public class PolymeshActivity extends Activity
+    {
+    private static final int COLOR_PRESSED   = 0xff0000ff;
+    private static final int COLOR_UNPRESSED = 0x888888ff;
+    private static final String SHOWED_TOAST = "showed_toast";
+
+    private Button mAbort, mChroma, mTrans, mSink, mBubble, mSwirl;
+   
+///////////////////////////////////////////////////////////////////
+    @Override
+    protected void onCreate(Bundle savedState) 
+      {
+      super.onCreate(savedState);
+      DistortedLibrary.onCreate();
+      setContentView(R.layout.movingeffectslayout);
+      
+      mAbort = findViewById(R.id.movingeffectsAbort);
+      mChroma= findViewById(R.id.movingeffectsChroma);
+      mTrans = findViewById(R.id.movingeffectsTrans);
+      mSink  = findViewById(R.id.movingeffectsSink);
+      mBubble= findViewById(R.id.movingeffectsBubble);
+      mSwirl = findViewById(R.id.movingeffectsSwirl);
+      
+      mAbort.setBackgroundColor(COLOR_PRESSED);
+      mChroma.setBackgroundColor(COLOR_UNPRESSED);
+      mTrans.setBackgroundColor(COLOR_UNPRESSED);
+      mSink.setBackgroundColor(COLOR_UNPRESSED);
+      mBubble.setBackgroundColor(COLOR_UNPRESSED);
+      mSwirl.setBackgroundColor(COLOR_UNPRESSED);
+     
+      if ( savedState== null || !savedState.getBoolean(SHOWED_TOAST, false))
+         {
+         Toast.makeText(this, R.string.example_movingeffects_toast , Toast.LENGTH_LONG).show();
+         }   
+      }
+
+///////////////////////////////////////////////////////////////////
+
+    @Override
+    protected void onPause()
+      {
+      Abort(null);
+
+      super.onPause();
+      GLSurfaceView view = findViewById(R.id.movingeffectsSurfaceView);
+      view.onPause();
+      DistortedLibrary.onPause();
+      }
+
+///////////////////////////////////////////////////////////////////
+
+    @Override
+    protected void onResume() 
+      {
+      super.onResume();
+      GLSurfaceView view = findViewById(R.id.movingeffectsSurfaceView);
+      view.onResume();
+      }
+
+///////////////////////////////////////////////////////////////////
+
+    @Override
+    public void onStop()
+      {
+      super.onStop();
+      }
+
+///////////////////////////////////////////////////////////////////
+    @Override
+    public void onDestroy()
+      {
+      DistortedLibrary.onDestroy();
+      super.onDestroy();
+      }     
+   
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onSaveInstanceState (Bundle outState)
+      {
+      outState.putBoolean(SHOWED_TOAST, true);
+      }
+     
+///////////////////////////////////////////////////////////////////
+    
+    public void Bubble(View v)
+      {
+      PolymeshSurfaceView view = findViewById(R.id.movingeffectsSurfaceView);
+      view.Bubble();
+      
+      mAbort.setBackgroundColor(COLOR_UNPRESSED);
+      mChroma.setBackgroundColor(COLOR_UNPRESSED);
+      mTrans.setBackgroundColor(COLOR_UNPRESSED);
+      mSink.setBackgroundColor(COLOR_UNPRESSED);
+      mBubble.setBackgroundColor(COLOR_PRESSED);
+      mSwirl.setBackgroundColor(COLOR_UNPRESSED);
+      }     
+    
+///////////////////////////////////////////////////////////////////
+
+    public void Sink(View v)
+      {
+      PolymeshSurfaceView view = findViewById(R.id.movingeffectsSurfaceView);
+      view.Sink();
+      
+      mAbort.setBackgroundColor(COLOR_UNPRESSED);
+      mChroma.setBackgroundColor(COLOR_UNPRESSED);
+      mTrans.setBackgroundColor(COLOR_UNPRESSED);
+      mSink.setBackgroundColor(COLOR_PRESSED);
+      mBubble.setBackgroundColor(COLOR_UNPRESSED);
+      mSwirl.setBackgroundColor(COLOR_UNPRESSED);
+      }       
+
+///////////////////////////////////////////////////////////////////
+    
+    public void Transparency(View v)
+      {
+      PolymeshSurfaceView view = findViewById(R.id.movingeffectsSurfaceView);
+      view.Transparency();
+      
+      mAbort.setBackgroundColor(COLOR_UNPRESSED);
+      mChroma.setBackgroundColor(COLOR_UNPRESSED);
+      mTrans.setBackgroundColor(COLOR_PRESSED);
+      mSink.setBackgroundColor(COLOR_UNPRESSED);
+      mBubble.setBackgroundColor(COLOR_UNPRESSED);
+      mSwirl.setBackgroundColor(COLOR_UNPRESSED);
+      }     
+    
+///////////////////////////////////////////////////////////////////
+
+    public void Chroma(View v)
+      {
+      PolymeshSurfaceView view = findViewById(R.id.movingeffectsSurfaceView);
+      view.Chroma();
+      
+      mAbort.setBackgroundColor(COLOR_UNPRESSED);
+      mChroma.setBackgroundColor(COLOR_PRESSED);
+      mTrans.setBackgroundColor(COLOR_UNPRESSED);
+      mSink.setBackgroundColor(COLOR_UNPRESSED);
+      mBubble.setBackgroundColor(COLOR_UNPRESSED);
+      mSwirl.setBackgroundColor(COLOR_UNPRESSED);
+      }       
+
+///////////////////////////////////////////////////////////////////
+
+    public void Swirl(View v)
+      {
+      PolymeshSurfaceView view = findViewById(R.id.movingeffectsSurfaceView);
+      view.Swirl();
+      
+      mAbort.setBackgroundColor(COLOR_UNPRESSED);
+      mChroma.setBackgroundColor(COLOR_UNPRESSED);
+      mTrans.setBackgroundColor(COLOR_UNPRESSED);
+      mSink.setBackgroundColor(COLOR_UNPRESSED);
+      mBubble.setBackgroundColor(COLOR_UNPRESSED);
+      mSwirl.setBackgroundColor(COLOR_PRESSED);
+      }       
+    
+///////////////////////////////////////////////////////////////////
+
+    public void Abort(View v)
+      {
+      PolymeshSurfaceView view = findViewById(R.id.movingeffectsSurfaceView);
+      view.Abort();
+      
+      mAbort.setBackgroundColor(COLOR_PRESSED);
+      mChroma.setBackgroundColor(COLOR_UNPRESSED);
+      mTrans.setBackgroundColor(COLOR_UNPRESSED);
+      mSink.setBackgroundColor(COLOR_UNPRESSED);
+      mBubble.setBackgroundColor(COLOR_UNPRESSED);
+      mSwirl.setBackgroundColor(COLOR_UNPRESSED);
+      }
+}
diff --git a/src/main/java/org/distorted/examples/polymesh/PolymeshRenderer.java b/src/main/java/org/distorted/examples/polymesh/PolymeshRenderer.java
new file mode 100644
index 0000000..368691f
--- /dev/null
+++ b/src/main/java/org/distorted/examples/polymesh/PolymeshRenderer.java
@@ -0,0 +1,210 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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.polymesh;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.opengl.GLSurfaceView;
+
+import org.distorted.library.effect.Effect;
+import org.distorted.library.effect.EffectType;
+import org.distorted.library.effect.FragmentEffectAlpha;
+import org.distorted.library.effect.FragmentEffectChroma;
+import org.distorted.library.effect.MatrixEffectScale;
+import org.distorted.library.effect.VertexEffectDeform;
+import org.distorted.library.effect.VertexEffectScale;
+import org.distorted.library.effect.VertexEffectSink;
+import org.distorted.library.effect.VertexEffectSwirl;
+import org.distorted.library.main.DistortedEffects;
+import org.distorted.library.main.DistortedLibrary;
+import org.distorted.library.main.DistortedScreen;
+import org.distorted.library.main.DistortedTexture;
+import org.distorted.library.mesh.MeshSquare;
+import org.distorted.library.type.Static3D;
+
+import java.io.InputStream;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class PolymeshRenderer implements GLSurfaceView.Renderer, DistortedLibrary.LibraryUser
+   {  
+   private final PolymeshSurfaceView mView;
+   private final DistortedEffects mEffects;
+   private final DistortedTexture mTexture;
+   private final DistortedScreen mScreen;
+   private final Static3D mScaleMatrix, mScaleVertex;
+   private final Paint mPaint;
+   private final Resources mResources;
+
+   private MeshSquare mMesh;
+   private Canvas mCanvas;
+   private Bitmap mBitmap;
+   private int texW, texH;
+   private boolean mRefresh;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   PolymeshRenderer(PolymeshSurfaceView v)
+     {
+     mView = v;
+     mResources = v.getResources();
+
+     mPaint = new Paint();
+     mPaint.setAntiAlias(true);
+     mPaint.setFakeBoldText(true);
+     mPaint.setStyle(Style.FILL);
+
+     mEffects= new DistortedEffects();
+     mScreen = new DistortedScreen();
+     mTexture= new DistortedTexture();
+     mRefresh= true;
+
+     mScaleMatrix = new Static3D(1,1,1);
+     mScaleVertex = new Static3D(1,1,1);
+     mEffects.apply( new MatrixEffectScale(mScaleMatrix));
+     mEffects.apply( new VertexEffectScale(mScaleVertex));
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private void drawBackground()
+     {
+     int NW, NH;
+
+     if( texH<texW )
+       {
+       NH = 10;
+       NW = NH*texW/texH;
+       }
+     else
+       {
+       NW = 10;
+       NH = NW*texH/texW;
+       }
+
+     mPaint.setColor(0xff008800);
+     mCanvas.drawRect(0, 0, texW, texH, mPaint);
+     mPaint.setColor(0xffffffff);
+         
+     for(int i=0; i<=NH ; i++ ) mCanvas.drawRect( 0, texH*i/NH -2,  texW,  texH*i/NH + 2, mPaint);
+     for(int i=0; i<=NW ; i++ ) mCanvas.drawRect( texW*i/NW - 2, 0, texW*i/NW + 2,  texH, mPaint);
+     }
+   
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   void apply(Effect effect)
+     {
+     mEffects.abortByType(EffectType.VERTEX);
+     mEffects.abortByType(EffectType.FRAGMENT);
+
+     mEffects.apply( new VertexEffectScale(mScaleVertex));
+
+     if( effect!=null ) mEffects.apply(effect);
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   void setRefresh()
+     {
+     mRefresh = true;
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public void onDrawFrame(GL10 glUnused)
+     {
+     long time = System.currentTimeMillis();
+
+     if (mView.getCurrentEffect() == PolymeshSurfaceView.EFFECT_POINTS && mRefresh )
+       {
+       drawBackground();
+       mView.drawCurve(mCanvas,time);
+       mTexture.setTexture(mBitmap);
+       mRefresh = false;
+       }
+
+     mScreen.render(time);
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public void onSurfaceChanged(GL10 glUnused, int width, int height)
+     {
+     texW = width;
+     texH = height;
+
+     mScaleMatrix.set(width,width,width);
+     mScaleVertex.set(1.0f, (float)texH/texW, 1.0f);
+
+     mBitmap  = Bitmap.createBitmap(texW,texH, Bitmap.Config.ARGB_8888);
+     mCanvas  = new Canvas(mBitmap);
+
+     if( mMesh!=null ) mMesh.markForDeletion();
+     mMesh = new MeshSquare(80,80*texH/texW);
+
+     mScreen.detachAll();
+     mScreen.attach(mTexture,mEffects,mMesh);
+     mScreen.resize(texW, texH);
+     mView.onSurfaceChanged(texW,texH);
+
+     mRefresh = true;
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
+     {
+     VertexEffectScale.enable();
+     VertexEffectSwirl.enable();
+     VertexEffectDeform.enable();
+     VertexEffectSink.enable();
+     FragmentEffectChroma.enable();
+     FragmentEffectAlpha.enable();
+
+     DistortedLibrary.onSurfaceCreated(this);
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public void distortedException(Exception ex)
+     {
+     android.util.Log.e("MovingEffects", ex.getMessage() );
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public InputStream localFile(int fileID)
+      {
+      return mResources.openRawResource(fileID);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public void logMessage(String message)
+      {
+      android.util.Log.e("MovingEffects", message );
+      }
+}
diff --git a/src/main/java/org/distorted/examples/polymesh/PolymeshSurfaceView.java b/src/main/java/org/distorted/examples/polymesh/PolymeshSurfaceView.java
new file mode 100644
index 0000000..9e4aa8c
--- /dev/null
+++ b/src/main/java/org/distorted/examples/polymesh/PolymeshSurfaceView.java
@@ -0,0 +1,300 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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.polymesh;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import org.distorted.library.effect.FragmentEffectAlpha;
+import org.distorted.library.effect.FragmentEffectChroma;
+import org.distorted.library.effect.VertexEffectDeform;
+import org.distorted.library.effect.VertexEffectSink;
+import org.distorted.library.effect.VertexEffectSwirl;
+import org.distorted.library.type.Dynamic3D;
+import org.distorted.library.type.Static1D;
+import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Static4D;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class PolymeshSurfaceView extends GLSurfaceView
+    {
+    private static final int LOOP_TIME = 5000;
+    private static final int NUM_POINTS= 100;
+
+    public static final int EFFECT_POINTS=0;
+    public static final int EFFECT_BUBBLE=1;
+    public static final int EFFECT_SINK  =2;
+    public static final int EFFECT_TRANS =3;
+    public static final int EFFECT_CHROMA=4;
+    public static final int EFFECT_SWIRL =5;
+
+    private static final Object lock = new Object();
+
+    private Dynamic3D mCenter;
+    private Paint mPaint;
+    private int moving;
+    private int mScrWidth, mScrHeight;
+    private long mTime = 0;
+    
+    private int mCurrEffect;
+    private int mSize1, mSize2;
+    private Static3D mDeform;
+    private Static1D mRadius;
+
+    private PolymeshRenderer mRenderer;
+
+    private VertexEffectDeform mEffectDeform;
+    private VertexEffectSink mEffectSink;
+    private VertexEffectSwirl mEffectSwirl;
+    private FragmentEffectChroma mEffectChroma;
+    private FragmentEffectAlpha mEffectAlpha;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    public PolymeshSurfaceView(Context context, AttributeSet attrs)
+      {
+      super(context, attrs);
+
+      mCurrEffect=EFFECT_POINTS;
+      mPaint = new Paint();
+      mPaint.setStyle(Style.FILL);
+      moving = -1;
+      
+      mCenter = new Dynamic3D(LOOP_TIME,0.0f);
+      mDeform = new Static3D(0,0,0.15f);
+      mRadius = new Static1D(0);
+
+      if(!isInEditMode())
+        {
+        mRenderer = new PolymeshRenderer(this);
+
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+        final ActivityManager activityManager     = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
+        setEGLContextClientVersion( (configurationInfo.reqGlEsVersion>>16) >= 3 ? 3:2 );
+        setRenderer(mRenderer);
+
+        Static3D regionFrag = new Static3D(0.15f,0.15f,0.15f);
+        Static4D regionVert = new Static4D(0,0,0,0.15f);
+
+        mEffectDeform  = new VertexEffectDeform  ( mDeform          , mRadius, mCenter, regionVert);
+        mEffectSink    = new VertexEffectSink    (new Static1D(10)  , mCenter, regionVert);
+        mEffectSwirl   = new VertexEffectSwirl   (new Static1D(30)  , mCenter, regionVert);
+        mEffectAlpha   = new FragmentEffectAlpha (new Static1D(0.5f), mCenter, regionFrag, true);
+        mEffectChroma  = new FragmentEffectChroma(new Static1D(0.5f), new Static3D(1,0,0), mCenter, regionFrag, true);
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void onSurfaceChanged(int width,int height)
+      {
+      int max = Math.max(width, height);
+
+      mScrWidth  = width;
+      mScrHeight = height;
+
+      mRadius.set(max/2);
+
+      mSize1 = max/200;
+      mSize2 = max/80;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public int getCurrentEffect()
+      {
+      return mCurrEffect;
+      }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    public void Bubble()
+      {
+      if( mCurrEffect==EFFECT_BUBBLE ) return;     
+      
+      synchronized(lock)
+        {
+        mRenderer.apply(mEffectDeform);
+        mCurrEffect = EFFECT_BUBBLE;
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Sink()
+      {
+      if( mCurrEffect==EFFECT_SINK ) return; 
+         
+      synchronized(lock)
+        {
+        mRenderer.apply(mEffectSink);
+        mCurrEffect = EFFECT_SINK;
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Chroma()
+      {
+      if( mCurrEffect==EFFECT_CHROMA ) return;
+         
+      synchronized(lock)
+        {
+        mRenderer.apply(mEffectChroma);
+        mCurrEffect = EFFECT_CHROMA;
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Transparency()
+      {
+      if( mCurrEffect==EFFECT_TRANS ) return;   
+      
+      synchronized(lock)
+        {
+        mRenderer.apply(mEffectAlpha);
+        mCurrEffect = EFFECT_TRANS;
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Swirl()
+      {
+      if( mCurrEffect==EFFECT_SWIRL ) return;   
+      
+      synchronized(lock)
+        {
+        mRenderer.apply(mEffectSwirl);
+        mCurrEffect = EFFECT_SWIRL;
+        }
+      }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Abort()
+      {
+      synchronized(lock)
+        {
+        mRenderer.apply(null);
+        mCenter.removeAll();
+        mCenter.resetToBeginning();
+        mCurrEffect = EFFECT_POINTS;
+        mRenderer.setRefresh();
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+ 
+    public void drawCurve(Canvas c, long time)
+      {
+      synchronized(lock)
+        {  
+        int len = mCenter.getNumPoints();
+
+        float[] drawCoord = new float[3];
+        Static3D cu;
+
+        if( len>=2 )
+          {
+          final float step = (float)LOOP_TIME/(NUM_POINTS+1);
+
+          for(int i=0; i<NUM_POINTS; i++)
+            {
+            mPaint.setColor( 0xffffffff );
+            mCenter.get( drawCoord, 0, (long)(i*step), 0 );
+            c.drawCircle( (drawCoord[0]+0.5f)*mScrWidth, 0.5f*mScrHeight-drawCoord[1]*mScrWidth, mSize1, mPaint );
+            }
+          }
+
+        mPaint.setColor(0xffff0000);
+      
+        for(int curr=0; curr<len; curr++)
+          {       
+          cu = mCenter.getPoint(curr);
+          c.drawCircle( (cu.get0()+0.5f)*mScrWidth, 0.5f*mScrHeight-cu.get1()*mScrWidth, mSize2, mPaint);
+          }
+        
+        if( time-mTime > LOOP_TIME ) mTime = time;
+        }
+      }
+       
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    public boolean onTouchEvent(MotionEvent event)
+      {
+      if( mCurrEffect!=EFFECT_POINTS ) return true;   
+
+      float xDown = event.getX()/mScrWidth - 0.5f;
+      float yDown = (0.5f*mScrHeight - event.getY())/mScrWidth;
+
+      switch(event.getAction())
+        {
+        case MotionEvent.ACTION_DOWN: float gx, gy;
+                                      Static3D dv;
+                                      int len = mCenter.getNumPoints();
+                                 
+                                      for(int g=0; g<len; g++)
+                                        {
+                                        dv = mCenter.getPoint(g);
+                                        gx = dv.get0();
+                                        gy = dv.get1();
+
+                                        float Z = mDeform.get2()/7;
+
+                                        if( (xDown-gx)*(xDown-gx) + (yDown-gy)*(yDown-gy) < Z*Z )
+                                          {
+                                          moving = g;
+                                          break;
+                                          }
+                                        }
+                                      if( moving<0 )
+                                        {
+                                        synchronized(lock)
+                                          {
+                                          mCenter.add(new Static3D(xDown,yDown,0));
+                                          }
+                                        }
+                                      mRenderer.setRefresh();
+                                      break;
+        case MotionEvent.ACTION_MOVE: if( moving>=0 )
+                                        {
+                                        mCenter.setPoint(moving, xDown, yDown, 0);
+                                        }
+                                      mRenderer.setRefresh();
+                                      break;
+        case MotionEvent.ACTION_UP  : moving = -1;
+                                      break;
+        }
+      return true;
+      }
+  }
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index fc62ce7..634e6a0 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -217,6 +217,8 @@
     <string name="example_meshfile_subtitle">Explore Distorted\'s own Mesh format, dmesh. Open .dmesh files and explore their contents.</string>
     <string name="example_flatblur">Flat Blur</string>
     <string name="example_flatblur_subtitle">Unit test to see two partially obstructing flat objects, one of them blurred.</string>
+    <string name="example_polymesh">Polygon Mesh</string>
+    <string name="example_polymesh_subtitle">Test to be able to generate various polygon meshes with different parameters.</string>
 
     <string name="example_movingeffects_toast">Click on \'RESET\' and define your path by touching the screen. Then click on one of the effects and see it move along your path.</string>
     <string name="example_rotate_toast">Rotate the scene by swiping the screen</string>
