commit d40cfeb2469d24b463b637c77e4b50af7bbbc479
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Thu Jun 23 11:36:19 2016 +0100

    Progress with Vertex3D

diff --git a/src/main/java/org/distorted/examples/vertex3d/Vertex3DActivity.java b/src/main/java/org/distorted/examples/vertex3d/Vertex3DActivity.java
index cbc6feb..a992bd0 100644
--- a/src/main/java/org/distorted/examples/vertex3d/Vertex3DActivity.java
+++ b/src/main/java/org/distorted/examples/vertex3d/Vertex3DActivity.java
@@ -22,10 +22,14 @@ package org.distorted.examples.vertex3d;
 import android.app.Activity;
 import android.opengl.GLSurfaceView;
 import android.os.Bundle;
+import android.view.Gravity;
 import android.view.View;
+import android.widget.Button;
 import android.widget.LinearLayout;
+import android.widget.NumberPicker;
 import android.widget.SeekBar;
 import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.TableRow;
 import android.widget.TextView;
 
 import org.distorted.examples.R;
@@ -34,324 +38,466 @@ import org.distorted.library.EffectNames;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-public class Vertex3DActivity extends Activity implements OnSeekBarChangeListener
-{
-    private SeekBar bar;
-    private TextView textDeform, textDistort, textSink, textSwirl;
-    private int deformX, deformY, deformZ;
-    private int distortX, distortY, distortZ;
-    private int sinkA;
-    private int swirlA;
+public class Vertex3DActivity extends Activity implements OnSeekBarChangeListener, View.OnClickListener
+  {
+  private boolean firstScreen;
+
+  // fields needed for the first 'pick-a-shape' screen
+  //
+  private static int mNumCols = 3;
+  private static int mNumRows = 3;
+
+  private static final int COLOR_OFF = 0xffffe81f;
+  private static final int COLOR_ON  = 0xff0000ff;
+
+  private NumberPicker mColsPicker, mRowsPicker;
+  private LinearLayout mLay;
+  private static boolean[] mShape;
+
+  // fields needed for the second 'apply vertex effects' screen
+  //
+  private SeekBar bar;
+  private TextView textDeform, textDistort, textSink, textSwirl;
+  private int deformX, deformY, deformZ;
+  private int distortX, distortY, distortZ;
+  private int sinkA;
+  private int swirlA;
     
-    private int maxX, maxY, maxZ;
-    
-    private float fdeformX, fdeformY, fdeformZ;
-    private float fdistortX, fdistortY, fdistortZ;
-    private float fsinkA;
-    private float fswirlA;
+  private int maxX, maxY, maxZ;
+
+  private float fdeformX, fdeformY, fdeformZ;
+  private float fdistortX, fdistortY, fdistortZ;
+  private float fsinkA;
+  private float fswirlA;
     
-    private EffectNames[] effects = new EffectNames[4];
+  private EffectNames[] effects = new EffectNames[4];
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
-    @Override
-    protected void onCreate(Bundle icicle) 
+  @Override
+  protected void onCreate(Bundle savedState)
+    {
+    super.onCreate(savedState);
+
+    setContentView(R.layout.cubes1layout);
+
+    mLay = (LinearLayout)findViewById(R.id.buttongrid);
+
+    mColsPicker = (NumberPicker)findViewById(R.id.colsPicker);
+    mRowsPicker = (NumberPicker)findViewById(R.id.rowsPicker);
+
+    mColsPicker.setMaxValue(10);
+    mColsPicker.setMinValue( 0);
+    mRowsPicker.setMaxValue(10);
+    mRowsPicker.setMinValue( 0);
+
+    mColsPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener()
       {
-      super.onCreate(icicle);
-      setContentView(R.layout.vertex3dlayout);
-      Default(null);
-      }
+      @Override
+      public void onValueChange(NumberPicker picker, int oldVal, int newVal)
+        {
+        setGrid();
+        }
+      });
+
+    mRowsPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener()
+      {
+      @Override
+      public void onValueChange(NumberPicker picker, int oldVal, int newVal)
+        {
+        setGrid();
+        }
+      });
+
+    firstScreen = true;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 'first screen' methods
+
+  public static int getCols()
+    {
+    return mNumCols;
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void Default(View view)
+  public static String getShape()
+    {
+    String str = "";
+
+    for(int i=0; i<mNumRows*mNumCols; i++)
+      str += mShape[i] ? "1" : "0";
+
+    //android.util.Log.d("CUBES", str);
+
+    return str;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void setGrid()
+    {
+    mNumCols = mColsPicker.getValue();
+    mNumRows = mRowsPicker.getValue();
+
+    int width = mLay.getWidth();
+    int height= mLay.getHeight();
+    int w = mNumCols>0 ? (width / mNumCols) -10 : 0;
+    int h = mNumRows>0 ? (height/ mNumRows) -10 : 0;
+    int size= w<h ? w:h;
+    int pad = size/20;
+
+    mLay.removeAllViews();
+
+    mShape = new boolean[mNumRows*mNumCols];
+
+    TableRow.LayoutParams p = new android.widget.TableRow.LayoutParams();
+
+    p.rightMargin  = pad;
+    p.leftMargin   = pad;
+    p.topMargin    = pad;
+    p.bottomMargin = pad;
+    p.height       = size;
+    p.width        = size;
+
+    for (int rows=0; rows<mNumRows; rows++)
       {
-      effects[0] = EffectNames.DEFORM;
-      effects[1] = EffectNames.DISTORT;
-      effects[2] = EffectNames.SINK;
-      effects[3] = EffectNames.SWIRL;
+      TableRow tr = new TableRow(this);
+      tr.setGravity(Gravity.CENTER);
+
+      for(int cols=0; cols<mNumCols; cols++)
+        {
+        Button b = new Button(this);
+        b.setOnClickListener(this);
+        b.setId(rows*mNumCols+cols);
+        b.setLayoutParams(p);
+        b.setBackgroundColor(COLOR_OFF);
+        tr.addView(b, p);
+        mShape[rows*mNumCols+cols] = false;
+        }
+
+      mLay.addView(tr);
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void onClick(View view)
+    {
+    Button tmp = (Button)view;
+    int id = tmp.getId();
+    mShape[id] = !mShape[id];
+    tmp.setBackgroundColor(mShape[id] ? COLOR_ON:COLOR_OFF);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void Continue(View v)
+    {
+    firstScreen = false;
+    setContentView(R.layout.vertex3dlayout);
+    Default(null);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 'second screen' methods
+
+  public void Default(View view)
+    {
+    effects[0] = EffectNames.DEFORM;
+    effects[1] = EffectNames.DISTORT;
+    effects[2] = EffectNames.SINK;
+    effects[3] = EffectNames.SWIRL;
     
-      deformX = 50;
-      deformY = 50;
-      deformZ = 50;
+    deformX = 50;
+    deformY = 50;
+    deformZ = 50;
 
-      distortX = 50;
-      distortY = 50;
-      distortZ = 50;
+    distortX = 50;
+    distortY = 50;
+    distortZ = 50;
 
-      sinkA =  50;
-      swirlA = 50;
+    sinkA =  50;
+    swirlA = 50;
 
-      addViews();
-      }
+    addViews();
+    }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
-    private void addViews()
-      {
-      LinearLayout layout = (LinearLayout)findViewById(R.id.vertex3dlayout);
+  private void addViews()
+    {
+    LinearLayout layout = (LinearLayout)findViewById(R.id.vertex3dlayout);
     
-      layout.removeAllViews();
+    layout.removeAllViews();
       
-      View deform = getLayoutInflater().inflate(R.layout.vertex3ddeform , null);
-      View distort= getLayoutInflater().inflate(R.layout.vertex3ddistort, null);
-      View sink   = getLayoutInflater().inflate(R.layout.vertex3dsink   , null);
-      View swirl  = getLayoutInflater().inflate(R.layout.vertex3dswirl  , null);
+    View deform = getLayoutInflater().inflate(R.layout.vertex3ddeform , null);
+    View distort= getLayoutInflater().inflate(R.layout.vertex3ddistort, null);
+    View sink   = getLayoutInflater().inflate(R.layout.vertex3dsink   , null);
+    View swirl  = getLayoutInflater().inflate(R.layout.vertex3dswirl  , null);
      
-      for( int i=effects.length-1 ; i>=0 ; i-- )
+    for( int i=effects.length-1 ; i>=0 ; i-- )
+      {
+      switch(effects[i])
         {
-        switch(effects[i])
-          {
-          case DEFORM : layout.addView(deform , 0); break;
-          case DISTORT: layout.addView(distort, 0); break;
-          case SINK   : layout.addView(sink   , 0); break;
-          case SWIRL  : layout.addView(swirl  , 0); break;
-          }
+        case DEFORM : layout.addView(deform , 0); break;
+        case DISTORT: layout.addView(distort, 0); break;
+        case SINK   : layout.addView(sink   , 0); break;
+        case SWIRL  : layout.addView(swirl  , 0); break;
         }
+      }
       
-      textDeform = (TextView)findViewById(R.id.vertex3ddeformText);
-      textDistort= (TextView)findViewById(R.id.vertex3ddistortText);
-      textSink   = (TextView)findViewById(R.id.vertex3dsinkText);
-      textSwirl  = (TextView)findViewById(R.id.vertex3dswirlText);
+    textDeform = (TextView)findViewById(R.id.vertex3ddeformText);
+    textDistort= (TextView)findViewById(R.id.vertex3ddistortText);
+    textSink   = (TextView)findViewById(R.id.vertex3dsinkText);
+    textSwirl  = (TextView)findViewById(R.id.vertex3dswirlText);
      
-      setDeformText();
-      setDistortText();
-      setSinkText();
-      setSwirlText();
+    setDeformText();
+    setDistortText();
+    setSinkText();
+    setSwirlText();
       
-      setBar(R.id.vertex3ddeformBar1, deformX);
-      setBar(R.id.vertex3ddeformBar2, deformY);
-      setBar(R.id.vertex3ddeformBar3, deformZ);
+    setBar(R.id.vertex3ddeformBar1, deformX);
+    setBar(R.id.vertex3ddeformBar2, deformY);
+    setBar(R.id.vertex3ddeformBar3, deformZ);
 
-      setBar(R.id.vertex3ddistortBar1, distortX);
-      setBar(R.id.vertex3ddistortBar2, distortY);
-      setBar(R.id.vertex3ddistortBar3, distortZ);
+    setBar(R.id.vertex3ddistortBar1, distortX);
+    setBar(R.id.vertex3ddistortBar2, distortY);
+    setBar(R.id.vertex3ddistortBar3, distortZ);
       
-      setBar(R.id.vertex3dsinkBar1, sinkA);
+    setBar(R.id.vertex3dsinkBar1, sinkA);
 
-      setBar(R.id.vertex3dswirlBar1, swirlA);
+    setBar(R.id.vertex3dswirlBar1, swirlA);
 
-      Vertex3DRenderer.setOrder(effects);
-      }
+    Vertex3DRenderer.setOrder(effects);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void moveUp(EffectNames name)
-      {
-      int len = effects.length-1;
-      int index = -1;
+  private void moveUp(EffectNames name)
+    {
+    int len = effects.length-1;
+    int index = -1;
 
-      for(int i=0; i<=len; i++)
+    for(int i=0; i<=len; i++)
+      {
+      if( effects[i]==name )
         {
-        if( effects[i]==name )
-          {
-          index=i;
-          break;
-          }
+        index=i;
+        break;
         }
+      }
 
-      if( index==0 )
-        {
-        for(int i=0; i<len; i++)
-          effects[i] = effects[i+1];
-
-        effects[len] = name;
-        }
-      else if( index>0 )
-        {
-        effects[index]   = effects[index-1];
-        effects[index-1] = name;
-        }
+    if( index==0 )
+      {
+      for(int i=0; i<len; i++)
+        effects[i] = effects[i+1];
 
-      addViews();
+      effects[len] = name;
       }
+    else if( index>0 )
+      {
+      effects[index]   = effects[index-1];
+      effects[index-1] = name;
+      }
+
+    addViews();
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void ButtonDeform(View v)
-      {
-      moveUp(EffectNames.DEFORM);
-      }
+  public void ButtonDeform(View v)
+    {
+    moveUp(EffectNames.DEFORM);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void ButtonDistort(View v)
-      {
-      moveUp(EffectNames.DISTORT);
-      }
+  public void ButtonDistort(View v)
+    {
+    moveUp(EffectNames.DISTORT);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void ButtonSink(View v)
-      {
-      moveUp(EffectNames.SINK);
-      }
+  public void ButtonSink(View v)
+    {
+    moveUp(EffectNames.SINK);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void ButtonSwirl(View v)
-      {
-      moveUp(EffectNames.SWIRL);
-      }
+  public void ButtonSwirl(View v)
+    {
+    moveUp(EffectNames.SWIRL);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void setBar(int id, int value)
-      {
-      bar = (SeekBar)findViewById(id);
-      bar.setOnSeekBarChangeListener(this);
-      bar.setProgress(value);
-      }
+  private void setBar(int id, int value)
+    {
+    bar = (SeekBar)findViewById(id);
+    bar.setOnSeekBarChangeListener(this);
+    bar.setProgress(value);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void computeDeform()
-      {
-      fdeformX = (deformX-50)*maxX/50.0f;
-      fdeformY = (deformY-50)*maxY/50.0f;
-      fdeformZ = (deformZ-50)*maxZ/50.0f;
+  private void computeDeform()
+    {
+    fdeformX = (deformX-50)*maxX/50.0f;
+    fdeformY = (deformY-50)*maxY/50.0f;
+    fdeformZ = (deformZ-50)*maxZ/50.0f;
 
-      Vertex3DRenderer.setDeform( fdeformX, fdeformY, fdeformZ );
-      }
+    Vertex3DRenderer.setDeform( fdeformX, fdeformY, fdeformZ );
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void setDeformText()
-      {
-      fdeformX = ((int)(100*fdeformX))/100.0f;
-      fdeformY = ((int)(100*fdeformY))/100.0f;
-      fdeformZ = ((int)(100*fdeformZ))/100.0f;
+  private void setDeformText()
+    {
+    fdeformX = ((int)(100*fdeformX))/100.0f;
+    fdeformY = ((int)(100*fdeformY))/100.0f;
+    fdeformZ = ((int)(100*fdeformZ))/100.0f;
 
-      textDeform.setText("deform("+fdeformX+" , "+fdeformY+" , "+fdeformZ+")");
-      }
+    textDeform.setText("deform("+fdeformX+" , "+fdeformY+" , "+fdeformZ+")");
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void computeDistort()
-      {
-      fdistortX = (distortX-50)*maxX/50.0f;
-      fdistortY = (distortY-50)*maxY/50.0f;
-      fdistortZ = (distortZ-50)*maxZ/50.0f;
+  private void computeDistort()
+    {
+    fdistortX = (distortX-50)*maxX/50.0f;
+    fdistortY = (distortY-50)*maxY/50.0f;
+    fdistortZ = (distortZ-50)*maxZ/50.0f;
 
-      Vertex3DRenderer.setDistort(fdistortX, fdistortY, fdistortZ);
-      }
+    Vertex3DRenderer.setDistort(fdistortX, fdistortY, fdistortZ);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void setDistortText()
-      {
-      fdistortX = ((int)(100*fdistortX))/100.0f;
-      fdistortY = ((int)(100*fdistortY))/100.0f;
-      fdistortZ = ((int)(100*fdistortZ))/100.0f;
+  private void setDistortText()
+    {
+    fdistortX = ((int)(100*fdistortX))/100.0f;
+    fdistortY = ((int)(100*fdistortY))/100.0f;
+    fdistortZ = ((int)(100*fdistortZ))/100.0f;
 
-      textDistort.setText("distort("+fdistortX+" , "+fdistortY+" , "+fdistortZ+")");
-      }
+    textDistort.setText("distort("+fdistortX+" , "+fdistortY+" , "+fdistortZ+")");
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void computeSink()
-      {
-      fsinkA = (sinkA>= 50 ? sinkA-49 : 1/(51-sinkA));
+  private void computeSink()
+    {
+    fsinkA = (sinkA>= 50 ? sinkA-49 : 1/(51-sinkA));
 
-      Vertex3DRenderer.setSink( fsinkA );
-      }
+    Vertex3DRenderer.setSink( fsinkA );
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void setSinkText()
-      {
-      fsinkA = ((int)(100*fsinkA))/100.0f;
+  private void setSinkText()
+    {
+    fsinkA = ((int)(100*fsinkA))/100.0f;
 
-      textSink.setText("sink("+fsinkA+")");
-      }
+    textSink.setText("sink("+fsinkA+")");
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void computeSwirl()
-      {
-      fswirlA = (swirlA-50)*3.6f;
+  private void computeSwirl()
+    {
+    fswirlA = (swirlA-50)*3.6f;
 
-      Vertex3DRenderer.setSwirl( fswirlA );
-      }
+    Vertex3DRenderer.setSwirl( fswirlA );
+    }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private void setSwirlText()
-      {
-      fswirlA = ((int)(100*fswirlA))/100.0f;
+  private void setSwirlText()
+    {
+    fswirlA = ((int)(100*fswirlA))/100.0f;
 
-      textSwirl.setText("swirl("+fswirlA+")");
-      }
+    textSwirl.setText("swirl("+fswirlA+")");
+    }
    
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-    
-    @Override
-    protected void onPause() 
-      {
-      GLSurfaceView mView = (GLSurfaceView) this.findViewById(R.id.vertex3dSurfaceView);
-      mView.onPause(); 
-      super.onPause();
-      }
+// Overrides
+
+  @Override
+  protected void onPause()
+    {
+    GLSurfaceView mView = (GLSurfaceView)findViewById(R.id.vertex3dSurfaceView);
+    if( mView!=null ) mView.onPause();
+    super.onPause();
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
-    @Override
-    protected void onResume() 
-      {
-      super.onResume();
-      GLSurfaceView mView = (GLSurfaceView) this.findViewById(R.id.vertex3dSurfaceView);
-      mView.onResume();
-      }
+  @Override
+  protected void onResume()
+    {
+    super.onResume();
+    GLSurfaceView mView = (GLSurfaceView)findViewById(R.id.vertex3dSurfaceView);
+    if( mView!=null ) mView.onResume();
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus) 
+  @Override
+  public void onWindowFocusChanged(boolean hasFocus)
+    {
+    super.onWindowFocusChanged(hasFocus);
+
+    if( firstScreen )
+      {
+      mColsPicker.setValue(mNumCols);
+      mRowsPicker.setValue(mNumRows);
+
+      if( hasFocus ) setGrid();
+      }
+    else
       {
-      super.onWindowFocusChanged(hasFocus);
-  
       GLSurfaceView mView = (GLSurfaceView) this.findViewById(R.id.vertex3dSurfaceView);
       
       maxX = mView.getWidth();
       maxY = mView.getHeight();
       maxZ = (maxX+maxY)/2;
       }
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
-    @Override
-    protected void onDestroy() 
-      {
-      Distorted.onDestroy();  
-      super.onDestroy();
-      }
+  @Override
+  protected void onDestroy()
+    {
+    Distorted.onDestroy();
+    super.onDestroy();
+    }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
     
-    public void onProgressChanged(SeekBar bar, int progress, boolean fromUser) 
+  public void onProgressChanged(SeekBar bar, int progress, boolean fromUser)
+    {
+    switch (bar.getId())
       {
-      switch (bar.getId()) 
-        {
-        case R.id.vertex3ddeformBar1  : deformX= progress; computeDeform()  ; setDeformText()  ; break;
-        case R.id.vertex3ddeformBar2  : deformY= progress; computeDeform()  ; setDeformText()  ; break;
-        case R.id.vertex3ddeformBar3  : deformZ= progress; computeDeform()  ; setDeformText()  ; break;
-
-        case R.id.vertex3ddistortBar1 : distortX= progress; computeDistort(); setDistortText() ; break;
-        case R.id.vertex3ddistortBar2 : distortY= progress; computeDistort(); setDistortText() ; break;
-        case R.id.vertex3ddistortBar3 : distortZ= progress; computeDistort(); setDistortText() ; break;
-        
-        case R.id.vertex3dsinkBar1    : sinkA   = progress; computeSink()   ; setSinkText()    ; break;
-
-        case R.id.vertex3dswirlBar1   : swirlA  = progress; computeSwirl()  ; setSwirlText()   ; break;
-        }
+      case R.id.vertex3ddeformBar1  : deformX = progress; computeDeform() ; setDeformText()  ; break;
+      case R.id.vertex3ddeformBar2  : deformY = progress; computeDeform() ; setDeformText()  ; break;
+      case R.id.vertex3ddeformBar3  : deformZ = progress; computeDeform() ; setDeformText()  ; break;
+      case R.id.vertex3ddistortBar1 : distortX= progress; computeDistort(); setDistortText() ; break;
+      case R.id.vertex3ddistortBar2 : distortY= progress; computeDistort(); setDistortText() ; break;
+      case R.id.vertex3ddistortBar3 : distortZ= progress; computeDistort(); setDistortText() ; break;
+      case R.id.vertex3dsinkBar1    : sinkA   = progress; computeSink()   ; setSinkText()    ; break;
+      case R.id.vertex3dswirlBar1   : swirlA  = progress; computeSwirl()  ; setSwirlText()   ; break;
       }
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void onStartTrackingTouch(SeekBar bar) { }
+  public void onStartTrackingTouch(SeekBar bar) { }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void onStopTrackingTouch(SeekBar bar)  { }
-    
-}
+  public void onStopTrackingTouch(SeekBar bar)  { }
+  }
diff --git a/src/main/java/org/distorted/examples/vertex3d/Vertex3DRenderer.java b/src/main/java/org/distorted/examples/vertex3d/Vertex3DRenderer.java
index c4a66c9..0312f8f 100644
--- a/src/main/java/org/distorted/examples/vertex3d/Vertex3DRenderer.java
+++ b/src/main/java/org/distorted/examples/vertex3d/Vertex3DRenderer.java
@@ -48,10 +48,10 @@ import javax.microedition.khronos.opengles.GL10;
 class Vertex3DRenderer implements GLSurfaceView.Renderer
 {
     private static final int SIZE = 100;
-	  private static final int NUM  =   3;
 
     private GLSurfaceView mView;
     private static DistortedCubes mCube;
+    private int mCols, mRows;
 
     private static EffectNames[] order;
     
@@ -121,7 +121,13 @@ class Vertex3DRenderer implements GLSurfaceView.Renderer
     public Vertex3DRenderer(GLSurfaceView v)
       {
       mView = v;
-      mCube = new DistortedCubes( NUM, "111101111", SIZE);
+
+      String shape = Vertex3DActivity.getShape();
+
+      mCols = Vertex3DActivity.getCols();
+      mRows = shape.length() / mCols;
+
+      mCube = new DistortedCubes( mCols, shape, SIZE);
       
       mCenterPoint = new Static2D(0,0);
       mDeformPoint = new Static3D(0,0,0);
@@ -155,9 +161,19 @@ class Vertex3DRenderer implements GLSurfaceView.Renderer
     public void onSurfaceChanged(GL10 glUnused, int width, int height) 
       {
       mCube.abortEffects(EffectTypes.MATRIX);
-      float factor = (width>height ? height:width)/((NUM+2)*SIZE);
+      float factor;
+
+      if( width*mRows > height*mCols ) // screen is more 'horizontal' than the shape
+        {
+        factor = height/((mRows+2)*SIZE);
+        }
+      else
+        {
+        factor = width/((mCols+2)*SIZE);
+        }
+
       mCube.scale(factor);
-      mCube.move( new Static3D( (width-factor*NUM*SIZE)/2,(height-factor*NUM*SIZE)/2,0) );
+      mCube.move( new Static3D( (width-factor*mCols*SIZE)/2 , (height-factor*mRows*SIZE)/2 , 0) );
 
       setVertexEffects();
 
diff --git a/src/main/res/drawable/icon_example_vertex3d.png b/src/main/res/drawable/icon_example_vertex3d.png
new file mode 100644
index 0000000..8074c9b
Binary files /dev/null and b/src/main/res/drawable/icon_example_vertex3d.png differ
