commit fe7fe83ee8dba938d48e76f56057589f45f31ee4
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Mon Jul 30 00:00:20 2018 +0100

    Overhaul of the Effects3D generic test app.
    
    Still not perfect (the 'postprocess' tab does not work; things crash when we rotate)

diff --git a/build.gradle b/build.gradle
index 0047089..bc69275 100644
--- a/build.gradle
+++ b/build.gradle
@@ -20,4 +20,6 @@ android {
 dependencies {
     api project(':distorted-library')
     implementation 'com.android.support:support-v4:27.1.1'
+    implementation 'com.android.support:support-v13:27.1.1'
+    implementation 'com.android.support:design:27.1.1'
 }
diff --git a/src/main/java/org/distorted/examples/effects3d/Effects3DActivity.java b/src/main/java/org/distorted/examples/effects3d/Effects3DActivity.java
index c572466..9cfe0ac 100644
--- a/src/main/java/org/distorted/examples/effects3d/Effects3DActivity.java
+++ b/src/main/java/org/distorted/examples/effects3d/Effects3DActivity.java
@@ -26,6 +26,8 @@ import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.opengl.GLSurfaceView;
 import android.os.Bundle;
+import android.support.design.widget.TabLayout;
+import android.support.v4.view.ViewPager;
 import android.view.Gravity;
 import android.view.View;
 import android.widget.AdapterView;
@@ -38,7 +40,6 @@ import android.widget.Spinner;
 import android.widget.TableRow;
 
 import org.distorted.examples.R;
-import org.distorted.library.effect.EffectName;
 import org.distorted.library.effect.EffectType;
 import org.distorted.library.main.Distorted;
 import org.distorted.library.main.MeshCubes;
@@ -49,13 +50,11 @@ import org.distorted.library.main.DistortedEffects;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.ArrayList;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 public class Effects3DActivity extends Activity
-                               implements View.OnClickListener,
-                                          AdapterView.OnItemSelectedListener
+                               implements View.OnClickListener, AdapterView.OnItemSelectedListener
   {
   private static final int COLOR_OFF = 0xffffe81f;
   private static final int COLOR_ON  = 0xff0000ff;
@@ -68,22 +67,17 @@ public class Effects3DActivity extends Activity
   private NumberPicker mColsPicker, mRowsPicker, mSlicPicker;
   private boolean[] mShape;
   private DistortedTexture mTexture;
-  private DistortedEffects mEffects;
   private MeshObject mMesh;
   private int mObjectType;
   private int mBitmapID;
   private Bitmap mBitmap;
   private LinearLayout mLay;
 
-  private ArrayList<Effects3DEffect> mList;
-  private int mEffectAdd;
   private float mCenterX, mCenterY, mCenterZ;
   private float mRegionX, mRegionY, mRegionR;
-
-  private EffectName[] mEffectNames;
-
-  private static boolean mSupportsRegion;
-  private static boolean mSupportsCenter;
+  private DistortedEffects mEffects;
+  private ViewPager mViewPager;
+  private Effects3DTabViewPager mPager;
 
   private static boolean mShowCenter = true;
   private static boolean mShowRegion = true;
@@ -97,10 +91,6 @@ public class Effects3DActivity extends Activity
     {
     super.onCreate(savedState);
 
-    mList = new ArrayList<>();
-
-    createEffectNames();
-
     setContentView(R.layout.objectpickerlayout);
 
     mLay = findViewById(R.id.objectpicker_buttongrid);
@@ -166,31 +156,6 @@ public class Effects3DActivity extends Activity
     bitmapSpinner.setAdapter(adapterBitmap);
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void createEffectNames()
-    {
-    EffectType type1 = EffectType.FRAGMENT;
-    EffectType type2 = EffectType.VERTEX;
-
-    EffectName[] names = EffectName.values();
-
-    int numEffects=0;
-
-    for(int i=0; i<names.length; i++)
-      if( names[i].getType() == type1 || names[i].getType() == type2 ) numEffects++;
-
-    mEffectNames = new EffectName[numEffects];
-
-    numEffects=0;
-
-    for(int i=0; i<names.length; i++)
-      if( names[i].getType() == type1 || names[i].getType() == type2 )
-        {
-        mEffectNames[numEffects++] = names[i];
-        }
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private void setGrid()
@@ -247,13 +212,6 @@ public class Effects3DActivity extends Activity
     return mTexture;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public DistortedEffects getEffects()
-    {
-    return mEffects;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public MeshObject getMesh()
@@ -261,20 +219,6 @@ public class Effects3DActivity extends Activity
     return mMesh;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public void setSupportsRegion(boolean supports)
-    {
-    mSupportsRegion = supports;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public void setSupportsCenter(boolean supports)
-    {
-    mSupportsCenter = supports;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public Bitmap getBitmap()
@@ -443,28 +387,20 @@ public class Effects3DActivity extends Activity
       }
 
     mMesh.setShowNormals(mShowNormal);
-
-    mEffects= new DistortedEffects();
     mTexture= new DistortedTexture(mNumCols,mNumRows);
+    mEffects= new DistortedEffects();
 
     final View view = getLayoutInflater().inflate(R.layout.effects3dlayout, null);
 
     setContentView(view);
 
-    String[] effects = new String[mEffectNames.length];
-
-    for(int i=0; i<mEffectNames.length; i++) effects[i] = mEffectNames[i].name();
-
-    Spinner effectSpinner = findViewById(R.id.effects3dspinner );
-    effectSpinner.setOnItemSelectedListener(this);
-
-    ArrayAdapter<String> adapterEffect = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, effects);
-    adapterEffect.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
-    effectSpinner.setAdapter(adapterEffect);
+    mViewPager = findViewById(R.id.effects3d_viewpager);
+    mPager = new Effects3DTabViewPager(this, getFragmentManager() );
+    mViewPager.setAdapter(mPager);
+    TabLayout tabLayout = findViewById(R.id.effects3d_sliding_tabs);
+    tabLayout.setupWithViewPager(mViewPager);
 
     resetData();
-
-    mEffectAdd = 0;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -490,8 +426,6 @@ public class Effects3DActivity extends Activity
                                               case 6: mBitmapID = R.raw.monalisa; break;
                                               }
                                             break;
-      case R.id.effects3dspinner          : mEffectAdd = pos;
-                                            break;
       }
     }
 
@@ -531,7 +465,7 @@ public class Effects3DActivity extends Activity
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void resetData()
+  void resetData()
     {
     mCenterX = 0.5f*getWidth();
     mCenterY = 0.5f*getHeight();
@@ -539,155 +473,108 @@ public class Effects3DActivity extends Activity
     mRegionY = 0;
     mRegionR = getWidth()/2;
 
-    mSupportsRegion =false;
-    mSupportsCenter =false;
-
     Effects3DSurfaceView view = findViewById(R.id.effects3dSurfaceView);
-    view.getRenderer().showRegionAndCenter(false,false);
+    Effects3DRenderer renderer= view.getRenderer();
+
+    renderer.setCenter( mCenterX, mCenterY, mCenterZ );
+    renderer.setRegion( mRegionX, mRegionY, mRegionR );
+    renderer.mQuat1.set(0,0,0,1);
+    renderer.mQuat2.set(0,0,0,1);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // 'second screen' methods
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void newEffect(View v)
+  public DistortedEffects getEffects()
     {
-    Effects3DEffect eff = new Effects3DEffect(mEffectNames[mEffectAdd], this);
-    mList.add(eff);
-
-    LinearLayout layout = findViewById(R.id.effects3dlayout);
-    View view = eff.createView();
-    layout.addView(view);
-
-    if( mSupportsCenter )
-      {
-      View center = eff.createCenter();
-      layout.addView(center);
-      }
-
-    if( mSupportsRegion )
-      {
-      View region = eff.createRegion();
-      layout.addView(region);
-      }
+    return mEffects;
+    }
 
-    eff.apply(mEffects);
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    boolean show = (mEffectNames[mEffectAdd].getType()==EffectType.VERTEX);
-    Effects3DSurfaceView sv = findViewById(R.id.effects3dSurfaceView);
-    sv.getRenderer().showRegionAndCenter( (show && mShowRegion) , (show && mShowCenter) );
+  public void newEffect(View v)
+    {
+    mPager.newEffect(v,mViewPager.getCurrentItem());
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void removeAll(View v)
     {
-    mList.clear();
-    LinearLayout layout = findViewById(R.id.effects3dlayout);
-    layout.removeAllViews();
-    mEffects.abortByType(EffectType.VERTEX);
-    mEffects.abortByType(EffectType.FRAGMENT);
-
-    resetData();
-
-    Effects3DSurfaceView view = findViewById(R.id.effects3dSurfaceView);
-    Effects3DRenderer renderer= view.getRenderer();
-
-    renderer.setCenter( mCenterX, mCenterY, mCenterZ );
-    renderer.setRegion( mRegionX, mRegionY, mRegionR );
-    renderer.mQuat1.set(0,0,0,1);
-    renderer.mQuat2.set(0,0,0,1);
+    mPager.removeAll(v,mViewPager.getCurrentItem());
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void remove(View v)
     {
-    for(Effects3DEffect effect: mList)
-      {
-      if( effect.thisView(v) )
-        {
-        LinearLayout layout = findViewById(R.id.effects3dlayout);
-        View view;
-
-        view = effect.getEffect();
-        if( view!=null ) layout.removeView(view);
-        view = effect.getCenter();
-        if( view!=null ) layout.removeView(view);
-        view = effect.getRegion();
-        if( view!=null ) layout.removeView(view);
-
-        mEffects.abortById(effect.getId());
-        mList.remove(effect);
-
-        resetData();
-
-        break;
-        }
-      }
+    mPager.remove(v,mViewPager.getCurrentItem());
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    boolean getShowCenter()
-      {
-      return mShowCenter;
-      }
+  boolean getShowCenter()
+    {
+    return mShowCenter;
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    boolean getShowRegion()
-      {
-      return mShowRegion;
-      }
+  boolean getShowRegion()
+    {
+    return mShowRegion;
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void showCenter(View view)
-      {
-      CheckBox box = (CheckBox)view;
-      mShowCenter = box.isChecked();
+  public void showCenter(View view)
+    {
+    CheckBox box = (CheckBox)view;
+    mShowCenter = box.isChecked();
 
-      Effects3DSurfaceView sv = findViewById(R.id.effects3dSurfaceView);
-      sv.getRenderer().showRegionAndCenter(mShowRegion,mShowCenter);
-      }
+    Effects3DSurfaceView sv = findViewById(R.id.effects3dSurfaceView);
+    sv.getRenderer().showRegionAndCenter(mShowRegion,mShowCenter);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void showRegion(View view)
-      {
-      CheckBox box = (CheckBox)view;
-      mShowRegion = box.isChecked();
+  public void showRegion(View view)
+    {
+    CheckBox box = (CheckBox)view;
+    mShowRegion = box.isChecked();
 
-      Effects3DSurfaceView sv = findViewById(R.id.effects3dSurfaceView);
-      sv.getRenderer().showRegionAndCenter(mShowRegion,mShowCenter);
-      }
+    Effects3DSurfaceView sv = findViewById(R.id.effects3dSurfaceView);
+    sv.getRenderer().showRegionAndCenter(mShowRegion,mShowCenter);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void showNormal(View view)
-      {
-      CheckBox box = (CheckBox)view;
-      mShowNormal = box.isChecked();
+  public void showNormal(View view)
+    {
+    CheckBox box = (CheckBox)view;
+    mShowNormal = box.isChecked();
 
-      if ( mMesh!=null )
-        {
-        mMesh.setShowNormals(mShowNormal);
-        }
+    if ( mMesh!=null )
+      {
+      mMesh.setShowNormals(mShowNormal);
       }
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void triggerOIT(View view)
-      {
-      CheckBox box = (CheckBox)view;
-      mUseOIT = box.isChecked();
+  public void triggerOIT(View view)
+    {
+    CheckBox box = (CheckBox)view;
+    mUseOIT = box.isChecked();
 
-      Effects3DSurfaceView sv = findViewById(R.id.effects3dSurfaceView);
-      sv.getRenderer().useOIT(mUseOIT);
-      }
+    Effects3DSurfaceView sv = findViewById(R.id.effects3dSurfaceView);
+    sv.getRenderer().useOIT(mUseOIT);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Overrides
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
   @Override
   protected void onPause()
diff --git a/src/main/java/org/distorted/examples/effects3d/Effects3DEffect.java b/src/main/java/org/distorted/examples/effects3d/Effects3DEffect.java
index 2f24947..78d516e 100644
--- a/src/main/java/org/distorted/examples/effects3d/Effects3DEffect.java
+++ b/src/main/java/org/distorted/examples/effects3d/Effects3DEffect.java
@@ -444,35 +444,35 @@ class Effects3DEffect implements SeekBar.OnSeekBarChangeListener
     switch(mDimension)
       {
       case 1 : mEffect    = act.getLayoutInflater().inflate(R.layout.effect1d, null);
-               mText      = (TextView)mEffect.findViewById(R.id.effect1dText);
-               seek[0]    = (SeekBar)mEffect.findViewById(R.id.effect1dbar1);
+               mText      = mEffect.findViewById(R.id.effect1dText);
+               seek[0]    = mEffect.findViewById(R.id.effect1dbar1);
                mSeekID[0] = seek[0].getId();
                mButton    = mEffect.findViewById(R.id.button1dRemove);
                break;
       case 2 : mEffect    = act.getLayoutInflater().inflate(R.layout.effect2d, null);
-               mText      = (TextView)mEffect.findViewById(R.id.effect2dText);
-               seek[0]    = (SeekBar)mEffect.findViewById(R.id.effect2dbar1);
-               seek[1]    = (SeekBar)mEffect.findViewById(R.id.effect2dbar2);
+               mText      = mEffect.findViewById(R.id.effect2dText);
+               seek[0]    = mEffect.findViewById(R.id.effect2dbar1);
+               seek[1]    = mEffect.findViewById(R.id.effect2dbar2);
                mSeekID[0] = seek[0].getId();
                mSeekID[1] = seek[1].getId();
                mButton    = mEffect.findViewById(R.id.button2dRemove);
                break;
       case 3 : mEffect    = act.getLayoutInflater().inflate(R.layout.effect3d, null);
-               mText      = (TextView)mEffect.findViewById(R.id.effect3dText);
-               seek[0]    = (SeekBar)mEffect.findViewById(R.id.effect3dbar1);
-               seek[1]    = (SeekBar)mEffect.findViewById(R.id.effect3dbar2);
-               seek[2]    = (SeekBar)mEffect.findViewById(R.id.effect3dbar3);
+               mText      = mEffect.findViewById(R.id.effect3dText);
+               seek[0]    = mEffect.findViewById(R.id.effect3dbar1);
+               seek[1]    = mEffect.findViewById(R.id.effect3dbar2);
+               seek[2]    = mEffect.findViewById(R.id.effect3dbar3);
                mSeekID[0] = seek[0].getId();
                mSeekID[1] = seek[1].getId();
                mSeekID[2] = seek[2].getId();
                mButton    = mEffect.findViewById(R.id.button3dRemove);
                break;
       case 4 : mEffect    = act.getLayoutInflater().inflate(R.layout.effect4d, null);
-               mText      = (TextView)mEffect.findViewById(R.id.effect4dText);
-               seek[0]    = (SeekBar)mEffect.findViewById(R.id.effect4dbar1);
-               seek[1]    = (SeekBar)mEffect.findViewById(R.id.effect4dbar2);
-               seek[2]    = (SeekBar)mEffect.findViewById(R.id.effect4dbar3);
-               seek[3]    = (SeekBar)mEffect.findViewById(R.id.effect4dbar4);
+               mText      = mEffect.findViewById(R.id.effect4dText);
+               seek[0]    = mEffect.findViewById(R.id.effect4dbar1);
+               seek[1]    = mEffect.findViewById(R.id.effect4dbar2);
+               seek[2]    = mEffect.findViewById(R.id.effect4dbar3);
+               seek[3]    = mEffect.findViewById(R.id.effect4dbar4);
                mSeekID[0] = seek[0].getId();
                mSeekID[1] = seek[1].getId();
                mSeekID[2] = seek[2].getId();
@@ -480,12 +480,12 @@ class Effects3DEffect implements SeekBar.OnSeekBarChangeListener
                mButton    = mEffect.findViewById(R.id.button4dRemove);
                break;
       case 5 : mEffect    = act.getLayoutInflater().inflate(R.layout.effect5d, null);
-               mText      = (TextView)mEffect.findViewById(R.id.effect5dText);
-               seek[0]    = (SeekBar)mEffect.findViewById(R.id.effect5dbar1);
-               seek[1]    = (SeekBar)mEffect.findViewById(R.id.effect5dbar2);
-               seek[2]    = (SeekBar)mEffect.findViewById(R.id.effect5dbar3);
-               seek[3]    = (SeekBar)mEffect.findViewById(R.id.effect5dbar4);
-               seek[4]    = (SeekBar)mEffect.findViewById(R.id.effect5dbar5);
+               mText      = mEffect.findViewById(R.id.effect5dText);
+               seek[0]    = mEffect.findViewById(R.id.effect5dbar1);
+               seek[1]    = mEffect.findViewById(R.id.effect5dbar2);
+               seek[2]    = mEffect.findViewById(R.id.effect5dbar3);
+               seek[3]    = mEffect.findViewById(R.id.effect5dbar4);
+               seek[4]    = mEffect.findViewById(R.id.effect5dbar5);
                mSeekID[0] = seek[0].getId();
                mSeekID[1] = seek[1].getId();
                mSeekID[2] = seek[2].getId();
@@ -505,9 +505,6 @@ class Effects3DEffect implements SeekBar.OnSeekBarChangeListener
       seek[i].setProgress( mInter[i] );
       }
 
-    act.setSupportsCenter(mName.supportsCenter());
-    act.setSupportsRegion(mName.supportsRegion());
-
     return mEffect;
     }
 
@@ -521,17 +518,17 @@ class Effects3DEffect implements SeekBar.OnSeekBarChangeListener
 
     SeekBar[] seek = new SeekBar[4];
 
-    seek[0] = (SeekBar)mRegion.findViewById(R.id.effectRegionBarX );
-    seek[1] = (SeekBar)mRegion.findViewById(R.id.effectRegionBarY );
-    seek[2] = (SeekBar)mRegion.findViewById(R.id.effectRegionBarRX);
-    seek[3] = (SeekBar)mRegion.findViewById(R.id.effectRegionBarRY);
+    seek[0] = mRegion.findViewById(R.id.effectRegionBarX );
+    seek[1] = mRegion.findViewById(R.id.effectRegionBarY );
+    seek[2] = mRegion.findViewById(R.id.effectRegionBarRX);
+    seek[3] = mRegion.findViewById(R.id.effectRegionBarRY);
 
     mSeekRegionID[0] = seek[0].getId();
     mSeekRegionID[1] = seek[1].getId();
     mSeekRegionID[2] = seek[2].getId();
     mSeekRegionID[3] = seek[3].getId();
 
-    mTextRegion = (TextView)mRegion.findViewById(R.id.effectRegionText);
+    mTextRegion = mRegion.findViewById(R.id.effectRegionText);
 
     setDefaultRegionInter();
 
@@ -556,15 +553,15 @@ class Effects3DEffect implements SeekBar.OnSeekBarChangeListener
 
     SeekBar[] seek = new SeekBar[3];
 
-    seek[0] = (SeekBar)mCenter.findViewById(R.id.effectCenterBarX );
-    seek[1] = (SeekBar)mCenter.findViewById(R.id.effectCenterBarY );
-    seek[2] = (SeekBar)mCenter.findViewById(R.id.effectCenterBarZ );
+    seek[0] = mCenter.findViewById(R.id.effectCenterBarX );
+    seek[1] = mCenter.findViewById(R.id.effectCenterBarY );
+    seek[2] = mCenter.findViewById(R.id.effectCenterBarZ );
 
     mSeekCenterID[0] = seek[0].getId();
     mSeekCenterID[1] = seek[1].getId();
     mSeekCenterID[2] = seek[2].getId();
 
-    mTextCenter = (TextView)mCenter.findViewById(R.id.effectCenterText);
+    mTextCenter = mCenter.findViewById(R.id.effectCenterText);
 
     setDefaultCenterInter();
 
@@ -666,11 +663,9 @@ class Effects3DEffect implements SeekBar.OnSeekBarChangeListener
       boolean showR= (show && act.getShowRegion());
       boolean showC= (show && act.getShowCenter());
 
-      Effects3DSurfaceView view = (Effects3DSurfaceView)act.findViewById(R.id.effects3dSurfaceView);
+      Effects3DSurfaceView view = act.findViewById(R.id.effects3dSurfaceView);
       view.getRenderer().showRegionAndCenter( showR,showC );
 
-      act.setSupportsCenter(mName.supportsCenter());
-      act.setSupportsRegion(mName.supportsRegion());
       act.setCenter(mCenterSta.get1(),mCenterSta.get2(),mCenterSta.get3());
       act.setRegion(mRegionSta.get1(),mRegionSta.get2(),mRegionSta.get3());
       }
diff --git a/src/main/java/org/distorted/examples/effects3d/Effects3DTab.java b/src/main/java/org/distorted/examples/effects3d/Effects3DTab.java
new file mode 100644
index 0000000..6613e61
--- /dev/null
+++ b/src/main/java/org/distorted/examples/effects3d/Effects3DTab.java
@@ -0,0 +1,238 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2018 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.effects3d;
+
+import android.os.Bundle;
+import android.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.Spinner;
+
+import org.distorted.examples.R;
+import org.distorted.library.effect.EffectName;
+import org.distorted.library.effect.EffectType;
+import org.distorted.library.main.DistortedEffects;
+
+import java.util.ArrayList;
+import java.lang.ref.WeakReference;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class Effects3DTab extends Fragment implements AdapterView.OnItemSelectedListener
+  {
+  private WeakReference<Effects3DActivity> mAct;
+  private EffectType mType;
+  private ArrayList<Effects3DEffect> mList;
+  private int mEffectAdd;
+  private EffectName[] mEffectNames;
+  private DistortedEffects mEffects;
+  private String[] mEffectStrings;
+  private int mTab, mLayout, mSpinner;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public Effects3DTab()
+    {
+    mList = new ArrayList<>();
+    mEffectAdd = 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void setParams(EffectType type, WeakReference<Effects3DActivity> act, int tab, int layout, int spinner)
+    {
+    mTab     = tab;
+    mLayout  = layout;
+    mSpinner = spinner;
+    mType    = type;
+    mAct     = act;
+    mEffects = act.get().getEffects();
+
+    android.util.Log.e("tab", "setparams: "+type.name() );
+
+    createEffectNames(mType);
+    mEffectStrings = new String[mEffectNames.length];
+
+    for (int i = 0; i < mEffectNames.length; i++)
+      {
+      mEffectStrings[i] = mEffectNames[i].name();
+
+      android.util.Log.d("tab", "  effect: "+mEffectStrings[i]);
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
+    {
+    View rootView = inflater.inflate( mTab, container, false);
+    return rootView;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public void onStart()
+    {
+    super.onStart();
+
+    android.util.Log.e("tab", "onStart, type="+mType.name());
+
+    Effects3DActivity act = mAct.get();
+
+    ArrayAdapter<String> adapterEffect = new ArrayAdapter<>( act, android.R.layout.simple_spinner_item, mEffectStrings);
+    adapterEffect.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+
+    Spinner effectSpinner = act.findViewById(mSpinner);
+    effectSpinner.setOnItemSelectedListener(this);
+    effectSpinner.setAdapter(adapterEffect);
+
+    resetData();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void onItemSelected(AdapterView<?> parent, View view, int pos, long id)
+    {
+    if( parent.getId() == mSpinner )
+      {
+      mEffectAdd = pos;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void onNothingSelected(AdapterView<?> parent)
+    {
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void resetData()
+    {
+    Effects3DSurfaceView view = mAct.get().findViewById(R.id.effects3dSurfaceView);
+    view.getRenderer().showRegionAndCenter(false,false);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void newEffect()
+    {
+    Effects3DEffect eff = new Effects3DEffect(mEffectNames[mEffectAdd], mAct.get() );
+    mList.add(eff);
+
+    LinearLayout layout = mAct.get().findViewById(mLayout);
+    View view = eff.createView();
+    layout.addView(view);
+
+    if( mEffectNames[mEffectAdd].supportsCenter() )
+      {
+      View center = eff.createCenter();
+      layout.addView(center);
+      }
+
+    if( mEffectNames[mEffectAdd].supportsRegion() )
+      {
+      View region = eff.createRegion();
+      layout.addView(region);
+      }
+
+    eff.apply(mEffects);
+
+    Effects3DActivity act = mAct.get();
+    boolean region = act.getShowRegion();
+    boolean center = act.getShowCenter();
+
+    boolean show = (mEffectNames[mEffectAdd].getType()==EffectType.VERTEX);
+    Effects3DSurfaceView sv = act.findViewById(R.id.effects3dSurfaceView);
+    sv.getRenderer().showRegionAndCenter( (show && region) , (show && center) );
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void createEffectNames(EffectType type)
+    {
+    EffectName[] names = EffectName.values();
+
+    int numEffects=0;
+
+    for(int i=0; i<names.length; i++)
+      if( names[i].getType() == type ) numEffects++;
+
+    mEffectNames = new EffectName[numEffects];
+
+    numEffects=0;
+
+    for(int i=0; i<names.length; i++)
+      if( names[i].getType() == type )
+        {
+        mEffectNames[numEffects++] = names[i];
+        }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void removeAll()
+    {
+    Effects3DActivity act = mAct.get();
+
+    mList.clear();
+    LinearLayout layout = act.findViewById(mLayout);
+    layout.removeAllViews();
+    mEffects.abortByType(mType);
+
+    resetData();
+    act.resetData();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void remove(View v)
+    {
+    for(Effects3DEffect effect: mList)
+      {
+      if( effect.thisView(v) )
+        {
+        LinearLayout layout = mAct.get().findViewById(mLayout);
+        View view;
+
+        view = effect.getEffect();
+        if( view!=null ) layout.removeView(view);
+        view = effect.getCenter();
+        if( view!=null ) layout.removeView(view);
+        view = effect.getRegion();
+        if( view!=null ) layout.removeView(view);
+
+        mEffects.abortById(effect.getId());
+        mList.remove(effect);
+
+        resetData();
+
+        break;
+        }
+      }
+    }
+
+  }
diff --git a/src/main/java/org/distorted/examples/effects3d/Effects3DTabViewPager.java b/src/main/java/org/distorted/examples/effects3d/Effects3DTabViewPager.java
new file mode 100644
index 0000000..f300d80
--- /dev/null
+++ b/src/main/java/org/distorted/examples/effects3d/Effects3DTabViewPager.java
@@ -0,0 +1,114 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2018 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.effects3d;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.support.v13.app.FragmentPagerAdapter;
+import android.view.View;
+
+import org.distorted.examples.R;
+import org.distorted.library.effect.EffectType;
+
+import java.lang.ref.WeakReference;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class Effects3DTabViewPager extends FragmentPagerAdapter
+  {
+  private static final int NUM_TABS = 3;
+
+  private WeakReference<Effects3DActivity> mAct;
+  private Effects3DTab[] mTab;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public Effects3DTabViewPager(Effects3DActivity act, FragmentManager fm)
+    {
+    super(fm);
+    mAct = new WeakReference<>(act);
+    mTab = new Effects3DTab[NUM_TABS];
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void newEffect(View v, int pos)
+    {
+    if( pos>=0 && pos<NUM_TABS ) mTab[pos].newEffect();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void removeAll(View v, int pos)
+    {
+    if( pos>=0 && pos<NUM_TABS ) mTab[pos].removeAll();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void remove(View v, int pos)
+    {
+    if( pos>=0 && pos<NUM_TABS ) mTab[pos].remove(v);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public Fragment getItem(int position)
+    {
+    android.util.Log.e("viewPager","creating tab "+position);
+
+    switch(position)
+      {
+      case  0: mTab[0] = new Effects3DTab();
+               mTab[0].setParams(EffectType.VERTEX     , mAct, R.layout.effects3dtab1, R.id.effects3dlayout1, R.id.effects3dspinner1);
+               return mTab[0];
+      case  1: mTab[1] = new Effects3DTab();
+               mTab[1].setParams(EffectType.FRAGMENT   , mAct, R.layout.effects3dtab2, R.id.effects3dlayout2, R.id.effects3dspinner2);
+               return mTab[1];
+      case  2: mTab[2] = new Effects3DTab();
+               mTab[2].setParams(EffectType.POSTPROCESS, mAct, R.layout.effects3dtab3, R.id.effects3dlayout3, R.id.effects3dspinner3);
+               return mTab[2];
+      default: return null;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public int getCount()
+    {
+    return NUM_TABS;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @Override
+  public CharSequence getPageTitle(int position)
+    {
+    switch (position)
+      {
+      case 0 : return mAct.get().getString(R.string.type_vertex);
+      case 1 : return mAct.get().getString(R.string.type_fragment);
+      case 2 : return mAct.get().getString(R.string.type_postprocess);
+      default: return null;
+      }
+    }
+  }
diff --git a/src/main/res/drawable-hdpi/icon_example_movingglow.png b/src/main/res/drawable-hdpi/icon_example_movingglow.png
new file mode 100644
index 0000000..1019fbc
Binary files /dev/null and b/src/main/res/drawable-hdpi/icon_example_movingglow.png differ
diff --git a/src/main/res/layout/effects3dlayout.xml b/src/main/res/layout/effects3dlayout.xml
index cc068a9..8009bd4 100644
--- a/src/main/res/layout/effects3dlayout.xml
+++ b/src/main/res/layout/effects3dlayout.xml
@@ -2,6 +2,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
+    android:layout_weight="1"
     android:orientation="vertical" >
 
     <org.distorted.examples.effects3d.Effects3DSurfaceView
@@ -54,65 +55,21 @@
             android:onClick="triggerOIT"
             android:text="@string/oit"
             android:textSize="12sp"/>
-    </LinearLayout>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="42dp"
-        android:layout_gravity="center"
-        android:orientation="horizontal">
-
-        <Button
-            android:id="@+id/buttonAdd"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="newEffect"
-            android:text="@string/Add"
-            />
-
-        <TextView
-            android:id="@+id/textView10"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/New"
-            android:textAppearance="?android:attr/textAppearanceMedium"/>
-
-        <Spinner
-            android:id="@+id/effects3dspinner"
-            android:layout_width="0dp"
-            android:layout_height="wrap_content"
-            android:layout_weight="0.5"/>
-
-        <Button
-            android:id="@+id/buttonRemove"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:onClick="removeAll"
-            android:text="@string/reset"
-            />
 
     </LinearLayout>
 
-    <View
-        android:layout_height="4dip"
-        android:background="#777777"
+    <android.support.design.widget.TabLayout
+        android:id="@+id/effects3d_sliding_tabs"
         android:layout_width="match_parent"
-        />
+        android:layout_height="32dp"
+        android:theme="@style/Theme.AppCompat.NoActionBar">
+    </android.support.design.widget.TabLayout>
 
-    <ScrollView
-        android:id="@+id/effects3dscrollView"
+    <android.support.v4.view.ViewPager
+        android:id="@+id/effects3d_viewpager"
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:layout_weight="0.80"
-        >
-
-        <LinearLayout
-            android:id="@+id/effects3dlayout"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical" >
-        </LinearLayout>
-
-    </ScrollView>
+        android:layout_weight="1"
+        android:background="@android:color/black" />
 
 </LinearLayout>
diff --git a/src/main/res/layout/effects3dtab1.xml b/src/main/res/layout/effects3dtab1.xml
new file mode 100644
index 0000000..5ef4533
--- /dev/null
+++ b/src/main/res/layout/effects3dtab1.xml
@@ -0,0 +1,66 @@
+<?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" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="42dp"
+            android:layout_gravity="center"
+            android:orientation="horizontal">
+
+            <Button
+                android:id="@+id/buttonAdd"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="newEffect"
+                android:text="@string/Add"
+                />
+
+            <TextView
+                android:id="@+id/textViewFragment"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/New"
+                android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+            <Spinner
+                android:id="@+id/effects3dspinner1"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.5"/>
+
+            <Button
+                android:id="@+id/buttonRemove"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="removeAll"
+                android:text="@string/reset"
+                />
+
+        </LinearLayout>
+
+        <View
+            android:layout_height="4dip"
+            android:background="#777777"
+            android:layout_width="match_parent"
+            />
+
+        <ScrollView
+            android:id="@+id/effects3dscrollView"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="0.80"
+            >
+
+            <LinearLayout
+                android:id="@+id/effects3dlayout1"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical" >
+            </LinearLayout>
+
+        </ScrollView>
+
+</LinearLayout>
diff --git a/src/main/res/layout/effects3dtab2.xml b/src/main/res/layout/effects3dtab2.xml
new file mode 100644
index 0000000..6dc81b2
--- /dev/null
+++ b/src/main/res/layout/effects3dtab2.xml
@@ -0,0 +1,66 @@
+<?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" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="42dp"
+            android:layout_gravity="center"
+            android:orientation="horizontal">
+
+            <Button
+                android:id="@+id/buttonAdd"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="newEffect"
+                android:text="@string/Add"
+                />
+
+            <TextView
+                android:id="@+id/textViewFragment"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/New"
+                android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+            <Spinner
+                android:id="@+id/effects3dspinner2"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.5"/>
+
+            <Button
+                android:id="@+id/buttonRemove"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="removeAll"
+                android:text="@string/reset"
+                />
+
+        </LinearLayout>
+
+        <View
+            android:layout_height="4dip"
+            android:background="#777777"
+            android:layout_width="match_parent"
+            />
+
+        <ScrollView
+            android:id="@+id/effects3dscrollView"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="0.80"
+            >
+
+            <LinearLayout
+                android:id="@+id/effects3dlayout2"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical" >
+            </LinearLayout>
+
+        </ScrollView>
+
+</LinearLayout>
diff --git a/src/main/res/layout/effects3dtab3.xml b/src/main/res/layout/effects3dtab3.xml
new file mode 100644
index 0000000..ce79dc7
--- /dev/null
+++ b/src/main/res/layout/effects3dtab3.xml
@@ -0,0 +1,66 @@
+<?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" >
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="42dp"
+            android:layout_gravity="center"
+            android:orientation="horizontal">
+
+            <Button
+                android:id="@+id/buttonAdd"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="newEffect"
+                android:text="@string/Add"
+                />
+
+            <TextView
+                android:id="@+id/textViewFragment"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:text="@string/New"
+                android:textAppearance="?android:attr/textAppearanceMedium"/>
+
+            <Spinner
+                android:id="@+id/effects3dspinner3"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="0.5"/>
+
+            <Button
+                android:id="@+id/buttonRemove"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="removeAll"
+                android:text="@string/reset"
+                />
+
+        </LinearLayout>
+
+        <View
+            android:layout_height="4dip"
+            android:background="#777777"
+            android:layout_width="match_parent"
+            />
+
+        <ScrollView
+            android:id="@+id/effects3dscrollView"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="0.80"
+            >
+
+            <LinearLayout
+                android:id="@+id/effects3dlayout3"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical" >
+            </LinearLayout>
+
+        </ScrollView>
+
+</LinearLayout>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index d9cf2ea..5c3e2db 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
-<resources>    
+<resources>
     <string name="app_name">Distorted Examples</string>
     <string name="tocHeader">Welcome to the Distorted Examples!\nCode, Tutorials, Wiki: http://distorted.org/</string>
-    
+
     <string name="distort">Distort</string>
     <string name="deform">Deform</string>
     <string name="shear">Shear</string>
@@ -14,9 +14,14 @@
     <string name="contrast">Contrast</string>
     <string name="swirl">Swirl</string>
     <string name="blur">Blur</string>
+
+    <string name="type_matrix">Matrix</string>
+    <string name="type_vertex">Vertex</string>
+    <string name="type_fragment">Fragment</string>
+    <string name="type_postprocess">Postprocess</string>
+
     <string name="glow_radius">Radius</string>
     <string name="glow_alpha">Alpha</string>
-
     <string name="continu">Continue</string>
     <string name="rows">Rows</string>
     <string name="cols">Cols</string>
@@ -63,10 +68,6 @@
     <string name="DepthYes">Depth</string>
     <string name="DepthNo">No Depth</string>
     <string name="mesh">Mesh</string>
-    <string name="quality0">Highest</string>
-    <string name="quality1">High</string>
-    <string name="quality2">Medium</string>
-    <string name="quality3">Low</string>
     <string name="show_center">Center</string>
     <string name="show_region">Region</string>
     <string name="show_normal">Normals</string>
@@ -74,6 +75,11 @@
     <string name="screen">Screen</string>
     <string name="framebuffer">Framebuffer</string>
 
+    <string name="quality0">Highest</string>
+    <string name="quality1">High</string>
+    <string name="quality2">Medium</string>
+    <string name="quality3">Low</string>
+
     <string name="color_blue">Blue</string>
     <string name="color_black">Black</string>
     <string name="color_red">Red</string>
@@ -98,43 +104,43 @@
     <string name="glow_radius_placeholder">Radius: %1$d</string>
     <string name="glow_alpha_placeholder">Alpha: %1$.2f</string>
 
-    <string name="example_monalisa">Mona Lisa</string>  
+    <string name="example_monalisa">Mona Lisa</string>
     <string name="example_monalisa_subtitle">The basics of Distortions.</string>
     <string name="example_sink">Sink</string>
     <string name="example_sink_subtitle">Learn about sinks.</string>
-    <string name="example_bean">Mr. Bean</string>  
+    <string name="example_bean">Mr. Bean</string>
     <string name="example_bean_subtitle">Interpolation between more than two Points.</string>
     <string name="example_projection">Projection</string>
     <string name="example_projection_subtitle">Adjust the Projection Matrix.</string>
-    <string name="example_deform">Deformations and Distortions</string>  
+    <string name="example_deform">Deformations and Distortions</string>
     <string name="example_deform_subtitle">Deform the whole bitmap or Distort a part of it.</string>
-    <string name="example_listener">DistortedListener</string>  
+    <string name="example_listener">DistortedListener</string>
     <string name="example_listener_subtitle">Listen on effect events and react on them.</string>
     <string name="example_dynamic">Dynamics</string>
     <string name="example_dynamic_subtitle">Not an effect in itself, but rather a building block for other effects.</string>
-    <string name="example_girl">Girl</string>  
+    <string name="example_girl">Girl</string>
     <string name="example_girl_subtitle">Distort, Sink and Swirl effects all in one.</string>
-    <string name="example_macroblock">Cat and Dog</string>  
+    <string name="example_macroblock">Cat and Dog</string>
     <string name="example_macroblock_subtitle">Chroma, Transparency and Rotation effects.</string>
-    <string name="example_movingeffects">Moving Effects</string>  
+    <string name="example_movingeffects">Moving Effects</string>
     <string name="example_movingeffects_subtitle">Use the Interpolator to move effects around.</string>
-    <string name="example_differenteffects">Different Effects</string>  
+    <string name="example_differenteffects">Different Effects</string>
     <string name="example_differenteffects_subtitle">See how to draw the same bitmap multiple times, each time with different set of effects applied.</string>
-    <string name="example_differentbitmaps">Different Bitmaps</string>  
+    <string name="example_differentbitmaps">Different Bitmaps</string>
     <string name="example_differentbitmaps_subtitle">Draw 3 different bitmaps, apply the same set of effects to each one in one go.</string>
     <string name="example_effectqueue">Effect Queue</string>
     <string name="example_effectqueue_subtitle">Add, remove and list all effects currently acting on a Bitmap.</string>
-    <string name="example_check">Check</string>  
+    <string name="example_check">Check</string>
     <string name="example_check_subtitle">Check the maximum number of effects (separately for vertex and fragment shaders) we can apply to a single bitmap.</string>
     <string name="example_bitmaptree">Bitmap Tree</string>
     <string name="example_bitmaptree_subtitle">Render one bitmap on top of another.</string>
-    <string name="example_starwars">Star Wars</string>  
+    <string name="example_starwars">Star Wars</string>
     <string name="example_starwars_subtitle">Shows how to create the opening crawl from Star Wars Episode IV.</string>
-    <string name="example_olimpic">Olimpic Rings</string>  
+    <string name="example_olimpic">Olimpic Rings</string>
     <string name="example_olimpic_subtitle">Shows the Chroma effect and Node optimizations.</string>
-    <string name="example_cubes">Cubes</string>  
+    <string name="example_cubes">Cubes</string>
     <string name="example_cubes_subtitle">Tests the DistortedCubes render target.</string>
-    <string name="example_quaternion">Quaternion</string>  
+    <string name="example_quaternion">Quaternion</string>
     <string name="example_quaternion_subtitle">Random rotations using quaternions.</string>
     <string name="example_matrix3d">Matrix Effects</string>
     <string name="example_matrix3d_subtitle">Test results of Matrix effects on a 3D object.</string>
