commit 1e7603bb61a55d211771f48efc4ed49301f9aeb8
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Mar 21 15:30:44 2019 +0000

    Refactor the 'Generic' app.

diff --git a/src/main/java/org/distorted/examples/generic/GenericActivity2.java b/src/main/java/org/distorted/examples/generic/GenericActivity2.java
index 29b945e..be1fea8 100644
--- a/src/main/java/org/distorted/examples/generic/GenericActivity2.java
+++ b/src/main/java/org/distorted/examples/generic/GenericActivity2.java
@@ -26,7 +26,6 @@ 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.support.v7.app.AppCompatActivity;
 import android.view.View;
 import android.widget.CheckBox;
@@ -41,6 +40,7 @@ import org.distorted.library.mesh.MeshFlat;
 import org.distorted.library.mesh.MeshBase;
 import org.distorted.library.mesh.MeshQuad;
 import org.distorted.library.mesh.MeshSphere;
+import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import java.io.IOException;
@@ -50,24 +50,13 @@ import java.io.InputStream;
 
 public class GenericActivity2 extends AppCompatActivity
   {
-  public static final int NUM_TABS = 4;
-
   private DistortedTexture mTexture;
   private MeshBase mMesh;
   private Bitmap mBitmap;
-
-  private float mCenterX, mCenterY, mCenterZ;
-  private float mRegionX, mRegionY, mRegionZ, mRegionR;
   private DistortedEffects mEffects;
-  private ViewPager mViewPager;
+  private GenericViewPager mViewPager;
 
-  private boolean mShowCenter;
-  private boolean mShowRegion;
-  private boolean mShowNormal;
-  private boolean mUseOIT    ;
-  private EffectType mCurrentType;
-
-  private GenericTab[] mTab;
+  private boolean mShowCenter, mShowRegion, mShowNormal, mUseOIT;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -78,8 +67,6 @@ public class GenericActivity2 extends AppCompatActivity
 
     setTheme(R.style.CustomActivityThemeNoActionBar);
 
-    mTab = new GenericTab[NUM_TABS];
-
     Bundle b = getIntent().getExtras();
 
     int objectType = b.getInt("type");
@@ -94,8 +81,6 @@ public class GenericActivity2 extends AppCompatActivity
     mShowNormal = false;
     mUseOIT     = false;
 
-    mCurrentType = EffectType.MATRIX;
-
     int maxsize = numCols > numRows ? (numCols>numSlic ? numCols:numSlic) : (numRows>numSlic ? numRows:numSlic) ;
 
     createBitmap(maxsize, bitmapID);
@@ -131,14 +116,9 @@ public class GenericActivity2 extends AppCompatActivity
 
     setContentView(view);
 
-    mViewPager = findViewById(R.id.generic_viewpager);
-    mViewPager.setOffscreenPageLimit( NUM_TABS-1 );
-    GenericTabViewPager pager = new GenericTabViewPager(this, getSupportFragmentManager() );
-    mViewPager.setAdapter(pager);
+    mViewPager = new GenericViewPager(this,R.id.generic_viewpager);
     TabLayout tabLayout = findViewById(R.id.generic_sliding_tabs);
-    tabLayout.setupWithViewPager(mViewPager);
-
-    resetData();
+    tabLayout.setupWithViewPager(mViewPager.getPager());
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -207,87 +187,6 @@ public class GenericActivity2 extends AppCompatActivity
     return mBitmap;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void setRegion(float x, float y, float z, float r)
-    {
-    mRegionX = x;
-    mRegionY =-y;
-    mRegionZ = z;
-    mRegionR = r;
-
-    setRendererRegion();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void setRendererRegion()
-    {
-    GenericSurfaceView view = findViewById(R.id.genericSurfaceView);
-    view.getRenderer().setRegion(mRegionX, mRegionY, mRegionZ, mRegionR);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void setCenter(float x, float y, float z)
-    {
-    mCenterX = x;
-    mCenterY = y;
-    mCenterZ = z;
-
-    setRendererCenter();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void setRendererCenter()
-    {
-    GenericSurfaceView view = findViewById(R.id.genericSurfaceView);
-    view.getRenderer().setCenter( mCenterX, mCenterY, mCenterZ );
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float getCenterX()
-    {
-    return mCenterX;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float getCenterY()
-    {
-    return mCenterY;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float getRegionX()
-    {
-    return mRegionX;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float getRegionY()
-    {
-    return mRegionY;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float getRegionZ()
-    {
-    return mRegionZ;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public float getRegionR()
-    {
-    return mRegionR;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getWidth()
@@ -319,150 +218,84 @@ public class GenericActivity2 extends AppCompatActivity
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  void resetData()
+  void setCenter(Static3D center)
     {
-    mCenterX = 0.5f*getWidth();
-    mCenterY = 0.5f*getHeight();
-    mRegionX = 0;
-    mRegionY = 0;
-    mRegionZ = 0;
-    mRegionR = getWidth()/2;
-
     GenericSurfaceView view = findViewById(R.id.genericSurfaceView);
-    GenericRenderer renderer= view.getRenderer();
-
-    renderer.setCenter( mCenterX, mCenterY, mCenterZ );
-    renderer.setRegion( mRegionX, mRegionY, mRegionZ, mRegionR );
+    view.getRenderer().setCenter( center.get1(), center.get2(), center.get3() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  void resetMatrixEffects()
+  void setRegion(Static4D region)
     {
     GenericSurfaceView view = findViewById(R.id.genericSurfaceView);
-    GenericRenderer renderer= view.getRenderer();
-
-    renderer.resetMatrixEffects();
+    view.getRenderer().setRegion( region.get1(), region.get2(), region.get3(), region.get4() );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  void setCurrentEffectType(EffectType type)
+  void resetMatrixEffects()
     {
-    mCurrentType = type;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
+    GenericSurfaceView view = findViewById(R.id.genericSurfaceView);
+    GenericRenderer renderer= view.getRenderer();
 
-  public DistortedEffects getEffects()
-    {
-    return mEffects;
+    renderer.resetMatrixEffects();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void newEffect(View v)
+  void setCurrentTab(EffectType type)
     {
-    int pos = mViewPager.getCurrentItem();
-
-    if( pos>=0 && pos<NUM_TABS ) mTab[pos].newEffect();
+    mViewPager.setCurrentTab(type);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void removeAll(View v)
+  void setTab(GenericTab tab, int position)
     {
-    int pos = mViewPager.getCurrentItem();
-
-    if( pos>=0 && pos<NUM_TABS ) mTab[pos].removeAll();
+    mViewPager.setTab(tab,position);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void remove(View v)
-    {
-    int pos = mViewPager.getCurrentItem();
-
-    if( pos>=0 && pos<NUM_TABS ) mTab[pos].remove(v);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void setTab(int pos, GenericTab tab)
+  public DistortedEffects getEffects()
     {
-    if( pos>=0 && pos<NUM_TABS ) mTab[pos] = tab;
+    return mEffects;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  boolean getShowCenter()
+  public void newEffect(View v)
     {
-    return mShowCenter;
+    mViewPager.newEffect();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  boolean getShowRegion()
+  public void removeAll(View v)
     {
-    return mShowRegion;
+    mViewPager.removeAll();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void showCenter(View view)
+  public void remove(View v)
     {
-    CheckBox box = (CheckBox)view;
-    mShowCenter = box.isChecked();
-
-    boolean showR=supportsRegion(mCurrentType);
-    boolean showC=supportsCenter(mCurrentType);
-
-    GenericSurfaceView sv = findViewById(R.id.genericSurfaceView);
-    sv.getRenderer().showRegionAndCenter( (mShowRegion&&showR) , (mShowCenter&&showC) );
+    mViewPager.remove(v);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public void showRegion(View view)
+  public void showRegionAndCenter(View view)
     {
-    CheckBox box = (CheckBox)view;
-    mShowRegion = box.isChecked();
-
-    boolean showR=supportsRegion(mCurrentType);
-    boolean showC=supportsCenter(mCurrentType);
+    CheckBox center = findViewById(R.id.genericCheckBoxCenter);
+    mShowCenter = center.isChecked();
+    CheckBox region = findViewById(R.id.genericCheckBoxRegion);
+    mShowRegion = region.isChecked();
 
     GenericSurfaceView sv = findViewById(R.id.genericSurfaceView);
-    sv.getRenderer().showRegionAndCenter( (mShowRegion&&showR) , (mShowCenter&&showC) );
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean supportsCenter(EffectType type)
-    {
-    switch(type)
-      {
-      case MATRIX     : return true;
-      case VERTEX     : return true;
-      case FRAGMENT   : return true;
-      case POSTPROCESS: return false;
-      }
-
-    return false;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean supportsRegion(EffectType type)
-    {
-    switch(type)
-      {
-      case MATRIX     : return false;
-      case VERTEX     : return true;
-      case FRAGMENT   : return false;
-      case POSTPROCESS: return false;
-      }
 
-    return false;
+    mViewPager.showRegionAndCenter(mShowRegion, mShowCenter, sv);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/examples/generic/GenericEffect.java b/src/main/java/org/distorted/examples/generic/GenericEffect.java
index 1a3498b..1afd5a3 100644
--- a/src/main/java/org/distorted/examples/generic/GenericEffect.java
+++ b/src/main/java/org/distorted/examples/generic/GenericEffect.java
@@ -620,7 +620,7 @@ class GenericEffect implements SeekBar.OnSeekBarChangeListener
         seek[i].setProgress(mInterRegion[i]);
         }
 
-      act.setRegion(mRegion4Sta.get1(), mRegion4Sta.get2(), mRegion4Sta.get3(), mRegion4Sta.get4());
+      act.setRegion(mRegion4Sta);
       }
     else
       {
@@ -647,7 +647,7 @@ class GenericEffect implements SeekBar.OnSeekBarChangeListener
         seek[i].setProgress(mInterRegion[i]);
         }
 
-      act.setRegion(mRegion3Sta.get1(), mRegion3Sta.get2(), mRegion3Sta.get3(), 1.0f );
+      act.setRegion( new Static4D( mRegion3Sta.get1(), mRegion3Sta.get2(), mRegion3Sta.get3(), 1.0f) );
       }
 
     return mRegion;
@@ -682,7 +682,7 @@ class GenericEffect implements SeekBar.OnSeekBarChangeListener
       seek[i].setProgress( mInterCenter[i] );
       }
 
-    act.setCenter(mCenterSta.get1(),mCenterSta.get2(),mCenterSta.get3());
+    act.setCenter(mCenterSta);
 
     return mCenter;
     }
@@ -769,8 +769,8 @@ class GenericEffect implements SeekBar.OnSeekBarChangeListener
     if( fromUser )
       {
       GenericActivity2 act = mAct.get();
-      act.setCenter(mCenterSta.get1(),mCenterSta.get2(),mCenterSta.get3());
-      act.setRegion(mRegion4Sta.get1(),mRegion4Sta.get2(),mRegion4Sta.get3(), mRegion4Sta.get4());
+      act.setCenter(mCenterSta);
+      act.setRegion(mRegion4Sta);
       }
     }
 
diff --git a/src/main/java/org/distorted/examples/generic/GenericRenderer.java b/src/main/java/org/distorted/examples/generic/GenericRenderer.java
index 865438f..20fe242 100644
--- a/src/main/java/org/distorted/examples/generic/GenericRenderer.java
+++ b/src/main/java/org/distorted/examples/generic/GenericRenderer.java
@@ -62,7 +62,7 @@ class GenericRenderer implements GLSurfaceView.Renderer
     private Static3D mRotateCen, mMoveObject, mScaleObject, mMoveCenter, mScaleCenter, mMoveRegion, mMoveBackground, mScaleBackground;
     private boolean mShowingCenter=false;
     private boolean mShowingRegion=false;
-    private float mFactorObj, mFactorReg;
+    private float mFactorObj;
     private int mWidth;
     private float mFactor;
 
@@ -91,6 +91,8 @@ class GenericRenderer implements GLSurfaceView.Renderer
       mCenterTexture     = new DistortedTexture(100,100);
       mRegionTexture     = new DistortedTexture(100,100);
 
+      mFactorObj = 1.0f;
+
       DistortedEffects objectEffects     = act.getEffects();
       DistortedEffects backgroundEffects = new DistortedEffects();
       DistortedEffects centerEffects     = new DistortedEffects();
@@ -174,8 +176,16 @@ class GenericRenderer implements GLSurfaceView.Renderer
       {
       if( mShowingCenter!=showCenter  )
         {
-        if( showCenter ) mScreen.attach(mCenterNode);
-        else             mScreen.detach(mCenterNode);
+        if( showCenter )
+          {
+          if( mShowingRegion ) mScreen.detach(mRegionNode);
+          mScreen.attach(mCenterNode);
+          if( mShowingRegion ) mScreen.attach(mRegionNode);
+          }
+        else
+          {
+          mScreen.detach(mCenterNode);
+          }
 
         mShowingCenter = showCenter;
         }
@@ -207,9 +217,10 @@ class GenericRenderer implements GLSurfaceView.Renderer
 
     void setRegion(float x, float y, float z, float r)
       {
-      mFactorReg = 2*mFactorObj*r/mRegionTexture.getWidth();
-      mRegionPoint.set(mFactorObj*x,-mFactorObj*y, mFactorObj*z);
-      mRegionScalePoint.set(mFactorReg,mFactorReg,mFactorReg);
+      float factorReg = 2*mFactorObj*r/mRegionTexture.getWidth();
+
+      mRegionPoint.set(mFactorObj*x,mFactorObj*y, mFactorObj*z);
+      mRegionScalePoint.set(factorReg,factorReg,factorReg);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -235,7 +246,7 @@ class GenericRenderer implements GLSurfaceView.Renderer
 
       float factorCen;
       int centerSize = mCenterTexture.getWidth();
-      int regionSize = mRegionTexture.getWidth();
+      float oldFactorObj = mFactorObj;
 
       if( width*mObjHeight > height*mObjWidth ) // screen is more 'horizontal' than the Object
         {
@@ -248,13 +259,22 @@ class GenericRenderer implements GLSurfaceView.Renderer
         factorCen  = (0.08f  *width)/centerSize;
         }
 
-      GenericActivity2 act = (GenericActivity2)mView.getContext();
-      mCenterPoint.set(mFactorObj*act.getCenterX(),+mFactorObj*act.getCenterY(),0);
-      mRegionPoint.set(mFactorObj*act.getRegionX(),-mFactorObj*act.getRegionY(),0);
-      mFactorReg = 2*mFactorObj*act.getRegionR()/regionSize;
-      mRegionScalePoint.set(mFactorReg,mFactorReg,mFactorReg);
+      float adjustFactor = mFactorObj/oldFactorObj;
+
+      mCenterPoint.set1( mCenterPoint.get1()*adjustFactor );
+      mCenterPoint.set2( mCenterPoint.get2()*adjustFactor );
+      mCenterPoint.set3( mCenterPoint.get3()*adjustFactor );
+
+      mRegionPoint.set1( mRegionPoint.get1()*adjustFactor );
+      mRegionPoint.set2( mRegionPoint.get2()*adjustFactor );
+      mRegionPoint.set3( mRegionPoint.get3()*adjustFactor );
+
+      mRegionScalePoint.set1(mRegionScalePoint.get1()*adjustFactor);
+      mRegionScalePoint.set2(mRegionScalePoint.get2()*adjustFactor);
+      mRegionScalePoint.set3(mRegionScalePoint.get3()*adjustFactor);
+
       mMoveObject.set( (width-mFactorObj*mObjWidth)/2 , (height-mFactorObj*mObjHeight)/2 , -mFactorObj*mObjDepth );
-      mRotateCen.set(width/2,height/2, 0);
+      mRotateCen.set(width*0.5f,height*0.5f, 0);
       mScaleObject.set(mFactorObj,mFactorObj,mFactorObj);
       mMoveCenter.set( (width -factorCen*centerSize-mFactorObj*mObjWidth )/2 ,
                        (height-factorCen*centerSize-mFactorObj*mObjHeight)/2 , 15 );
@@ -266,7 +286,7 @@ class GenericRenderer implements GLSurfaceView.Renderer
       float factorBackY = ((float)height)/backgroundSize;
 
       // quite tricky: move the background exactly to the FAR plane! (see DistortedOutputSurface.setProjection() )
-      mMoveBackground.set( -width/2, -height/2, -0.9f*height*(1.0f-NEAR)/(2.0f*(float)Math.tan(FOV*Math.PI/360)) );
+      mMoveBackground.set( -width*0.5f, -height*0.5f, -0.9f*height*(1.0f-NEAR)/(2.0f*(float)Math.tan(FOV*Math.PI/360)) );
       mScaleBackground.set( 2*factorBackX, 2*factorBackY, 1.0f );
 
       mScreen.resize(width, height);
diff --git a/src/main/java/org/distorted/examples/generic/GenericTab.java b/src/main/java/org/distorted/examples/generic/GenericTab.java
index afa608f..eafb750 100644
--- a/src/main/java/org/distorted/examples/generic/GenericTab.java
+++ b/src/main/java/org/distorted/examples/generic/GenericTab.java
@@ -29,7 +29,6 @@ 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;
@@ -46,7 +45,7 @@ public class GenericTab extends Fragment implements AdapterView.OnItemSelectedLi
   private EffectName[] mEffectNames;
   private DistortedEffects mEffects;
   private String[] mEffectStrings;
-  private int mTab, mLayout, mSpinner;
+  private int mLayout, mSpinner;
   private int mChildren;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -67,35 +66,16 @@ public class GenericTab extends Fragment implements AdapterView.OnItemSelectedLi
 
     int position = args.getInt("position");
 
-    switch(position)
-      {
-      case 0: mTab     = R.layout.effects3dtab0;
-              mLayout  = R.id.effects3dlayout0;
-              mSpinner = R.id.effects3dspinner0;
-              mType    = EffectType.MATRIX;
-              break;
-      case 1: mTab     = R.layout.effects3dtab1;
-              mLayout  = R.id.effects3dlayout1;
-              mSpinner = R.id.effects3dspinner1;
-              mType    = EffectType.VERTEX;
-              break;
-      case 2: mTab     = R.layout.effects3dtab2;
-              mLayout  = R.id.effects3dlayout2;
-              mSpinner = R.id.effects3dspinner2;
-              mType    = EffectType.FRAGMENT;
-              break;
-      case 3: mTab     = R.layout.effects3dtab3;
-              mLayout  = R.id.effects3dlayout3;
-              mSpinner = R.id.effects3dspinner3;
-              mType    = EffectType.POSTPROCESS;
-              break;
-      }
+    int tab  = GenericViewPager.TABS[GenericViewPager.NUM*position    ];
+    mLayout  = GenericViewPager.TABS[GenericViewPager.NUM*position + 1];
+    mSpinner = GenericViewPager.TABS[GenericViewPager.NUM*position + 2];
+    mType    = EffectType.getType(GenericViewPager.TABS[GenericViewPager.NUM*position + 3]);
 
     GenericActivity2 act = (GenericActivity2)getActivity();
 
     if( act!=null )
       {
-      act.setTab(position, this);
+      act.setTab(this,position);
       mEffects = act.getEffects();
       }
 
@@ -107,7 +87,7 @@ public class GenericTab extends Fragment implements AdapterView.OnItemSelectedLi
       mEffectStrings[i] = mEffectNames[i].name();
       }
 
-    return inflater.inflate( mTab, container, false);
+    return inflater.inflate( tab, container, false);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -140,15 +120,12 @@ public class GenericTab extends Fragment implements AdapterView.OnItemSelectedLi
        if( mType!=null )
          {
          GenericActivity2 act = (GenericActivity2)getActivity();
-         boolean region = act.getShowRegion();
-         boolean center = act.getShowCenter();
-         boolean showR  = act.supportsRegion(mType);
-         boolean showC  = act.supportsCenter(mType);
-
-         GenericSurfaceView sv = act.findViewById(R.id.genericSurfaceView);
-         sv.getRenderer().showRegionAndCenter( (showR && region) , (showC && center) );
 
-         act.setCurrentEffectType(mType);
+         if( act!=null )
+           {
+           act.setCurrentTab(mType);
+           act.showRegionAndCenter(null);
+           }
          }
        }
      }
@@ -233,8 +210,6 @@ public class GenericTab extends Fragment implements AdapterView.OnItemSelectedLi
     layout.removeAllViews();
     mEffects.abortByType(mType);
 
-    act.resetData();
-
     if( mType==EffectType.MATRIX )
       {
       act.resetMatrixEffects();
@@ -277,5 +252,4 @@ public class GenericTab extends Fragment implements AdapterView.OnItemSelectedLi
         }
       }
     }
-
   }
diff --git a/src/main/java/org/distorted/examples/generic/GenericTabViewPager.java b/src/main/java/org/distorted/examples/generic/GenericTabViewPager.java
deleted file mode 100644
index 69fb0d1..0000000
--- a/src/main/java/org/distorted/examples/generic/GenericTabViewPager.java
+++ /dev/null
@@ -1,86 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// 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.generic;
-
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentPagerAdapter;
-import android.os.Bundle;
-
-import org.distorted.examples.R;
-
-import java.lang.ref.WeakReference;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-public class GenericTabViewPager extends FragmentPagerAdapter
-  {
-  private WeakReference<GenericActivity2> mAct;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  GenericTabViewPager(GenericActivity2 act, FragmentManager fm)
-    {
-    super(fm);
-    mAct = new WeakReference<>(act);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public Fragment getItem(int position)
-    {
-    if( position>=0 && position< GenericActivity2.NUM_TABS )
-      {
-      GenericTab tab = new GenericTab();
-
-      Bundle bundle = new Bundle();
-      bundle.putInt("position", position);
-      tab.setArguments(bundle);
-
-      return tab;
-      }
-
-    return null;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public int getCount()
-    {
-    return GenericActivity2.NUM_TABS;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  @Override
-  public CharSequence getPageTitle(int position)
-    {
-    switch (position)
-      {
-      case 0 : return mAct.get().getString(R.string.type_matrix);
-      case 1 : return mAct.get().getString(R.string.type_vertex);
-      case 2 : return mAct.get().getString(R.string.type_fragment);
-      case 3 : return mAct.get().getString(R.string.type_postprocess);
-      default: return null;
-      }
-    }
-  }
diff --git a/src/main/java/org/distorted/examples/generic/GenericViewPager.java b/src/main/java/org/distorted/examples/generic/GenericViewPager.java
new file mode 100644
index 0000000..d29d204
--- /dev/null
+++ b/src/main/java/org/distorted/examples/generic/GenericViewPager.java
@@ -0,0 +1,185 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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.generic;
+
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentPagerAdapter;
+import android.support.v4.view.ViewPager;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+
+import org.distorted.examples.R;
+import org.distorted.library.effect.EffectType;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class GenericViewPager
+  {
+  // Add here a new row to create another tab serving effects of a given type (you would also need to create
+  // the three layouts to fill the first 3 values of the row )
+  // Comment out a row to remove the tab.
+  //
+  static final int[] TABS =
+
+      // LAYOUT ////////////  INNER LAYOUT ////////  SPINNER //////////////  EffectType /////////////////////  SHOW CENTER // SHOW REGION
+    { R.layout.effects3dtab0, R.id.effects3dlayout0, R.id.effects3dspinner0, EffectType.MATRIX     .ordinal() ,             1,          0 ,
+      R.layout.effects3dtab1, R.id.effects3dlayout1, R.id.effects3dspinner1, EffectType.VERTEX     .ordinal() ,             1,          1 ,
+      R.layout.effects3dtab2, R.id.effects3dlayout2, R.id.effects3dspinner2, EffectType.FRAGMENT   .ordinal() ,             1,          0 ,
+      R.layout.effects3dtab3, R.id.effects3dlayout3, R.id.effects3dspinner3, EffectType.POSTPROCESS.ordinal() ,             0,          0 };
+
+  static final int NUM = 6;  // 6 ints required to describe 1 tab
+  private static final int NUM_TABS = TABS.length/NUM;
+
+  private ViewPager mViewPager;
+  private GenericTab[] mTab;
+  private int mCurrentTab;
+
+  private class GenericTabViewPager extends FragmentPagerAdapter
+    {
+    GenericTabViewPager(FragmentManager fm)
+      {
+      super(fm);
+      }
+
+    @Override
+    public Fragment getItem(int position)
+      {
+      if( position>=0 && position<NUM_TABS )
+        {
+        GenericTab tab = new GenericTab();  // no we cannot make tab equal to mTab[position]
+                                            // tabs have to be set through the setTab() method
+        Bundle bundle = new Bundle();       // otherwise it doesn't work on recreation (rotate!)
+        bundle.putInt("position", position);
+        tab.setArguments(bundle);
+
+        return tab;
+        }
+
+      return null;
+      }
+
+    @Override
+    public int getCount()
+      {
+      return NUM_TABS;
+      }
+
+    @Override
+    public CharSequence getPageTitle(int position)
+      {
+      int ordinal = TABS[position*NUM + 3];
+      return EffectType.getType(ordinal).name();
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  GenericViewPager(AppCompatActivity act, int resourceID)
+    {
+    mViewPager = act.findViewById(resourceID);
+    mViewPager.setOffscreenPageLimit( NUM_TABS-1 );
+    GenericTabViewPager pager = new GenericTabViewPager( act.getSupportFragmentManager() );
+    mViewPager.setAdapter(pager);
+
+    mTab = new GenericTab[NUM_TABS];
+    mCurrentTab = 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void showRegionAndCenter(boolean showR, boolean showC, GenericSurfaceView sv)
+    {
+    boolean localShowC = showCenter(mCurrentTab);
+    boolean localShowR = showRegion(mCurrentTab);
+
+    sv.getRenderer().showRegionAndCenter( (showR&&localShowR) , (showC&&localShowC) );
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void newEffect()
+    {
+    int pos = mViewPager.getCurrentItem();
+
+    if( pos>=0 && pos<NUM_TABS ) mTab[pos].newEffect();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void removeAll()
+    {
+    int pos = mViewPager.getCurrentItem();
+
+    if( pos>=0 && pos<NUM_TABS ) mTab[pos].removeAll();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void remove(View v)
+    {
+    int pos = mViewPager.getCurrentItem();
+
+    if( pos>=0 && pos<NUM_TABS ) mTab[pos].remove(v);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  ViewPager getPager()
+    {
+    return mViewPager;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void setCurrentTab(EffectType type)
+    {
+    for(int i=0; i<NUM_TABS; i++)
+      {
+      if( TABS[i*NUM + 3] == type.ordinal() )
+        {
+        mCurrentTab = i;
+        break;
+        }
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void setTab(GenericTab tab, int position)
+    {
+    if( position>=0 && position<NUM_TABS ) mTab[position] = tab;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private static boolean showCenter(int position)
+    {
+    return TABS[NUM*position + 4] == 1;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private static boolean showRegion(int position)
+    {
+    return TABS[NUM*position + 5] == 1;
+    }
+  }
diff --git a/src/main/res/layout/genericlayout.xml b/src/main/res/layout/genericlayout.xml
index 75ade70..b9d781a 100644
--- a/src/main/res/layout/genericlayout.xml
+++ b/src/main/res/layout/genericlayout.xml
@@ -22,7 +22,7 @@
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:checked="false"
-            android:onClick="showCenter"
+            android:onClick="showRegionAndCenter"
             android:text="@string/show_center"
             android:textSize="12sp"/>
 
@@ -32,7 +32,7 @@
             android:layout_height="wrap_content"
             android:layout_weight="1"
             android:checked="false"
-            android:onClick="showRegion"
+            android:onClick="showRegionAndCenter"
             android:text="@string/show_region"
             android:textSize="12sp"/>
 
