commit e2b9e87e1f4496e8c6067f6b0865c8caa6d71eef
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Jun 8 13:03:31 2021 +0200

    Introduce Square-2 (unfinished)

diff --git a/src/main/java/org/distorted/objects/ObjectList.java b/src/main/java/org/distorted/objects/ObjectList.java
index 72c9aceb..853bd929 100644
--- a/src/main/java/org/distorted/objects/ObjectList.java
+++ b/src/main/java/org/distorted/objects/ObjectList.java
@@ -222,6 +222,16 @@ public enum ObjectList
          6,
          60
        ),
+
+  SQU2 (
+         new int[][] {
+                       {3 , 18, 0, R.drawable.ui_small_diam2, R.drawable.ui_medium_diam2, R.drawable.ui_big_diam2, R.drawable.ui_huge_diam2} ,
+                     },
+         TwistySquare2.class,
+         new MovementSquare(),
+         6,
+         60
+       ),
   ;
 
   public static final int NUM_OBJECTS = values().length;
@@ -621,6 +631,7 @@ public enum ObjectList
       case 15: return new TwistyBandagedEvil  (size, quat, texture, mesh, effects, moves, res, scrWidth);
       case 16: return new TwistyDiamond       (size, quat, texture, mesh, effects, moves, res, scrWidth);
       case 17: return new TwistySquare1       (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case 18: return new TwistySquare2       (size, quat, texture, mesh, effects, moves, res, scrWidth);
       }
 
     return null;
diff --git a/src/main/java/org/distorted/objects/TwistySquare.java b/src/main/java/org/distorted/objects/TwistySquare.java
new file mode 100644
index 00000000..bb055e62
--- /dev/null
+++ b/src/main/java/org/distorted/objects/TwistySquare.java
@@ -0,0 +1,321 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2021 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube 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.                                                           //
+//                                                                                               //
+// Magic Cube 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 Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.objects;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
+import org.distorted.library.effect.MatrixEffectQuaternion;
+import org.distorted.library.main.DistortedEffects;
+import org.distorted.library.main.DistortedTexture;
+import org.distorted.library.mesh.MeshBase;
+import org.distorted.library.mesh.MeshSquare;
+import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Static4D;
+import org.distorted.main.R;
+
+import java.util.Random;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+abstract class TwistySquare extends TwistyObject
+{
+  static final int LAST_SL = 0; // automatic rotations: last rot was a 'slash' i.e. along ROT_AXIS[1]
+  static final int LAST_UP = 1; // last rot was along ROT_AXIS[0], upper layer and forelast was a slash
+  static final int LAST_LO = 2; // last rot was along ROT_AXIS[0], lower layer and forelast was a slash
+  static final int LAST_UL = 3; // two last rots were along ROT_AXIS[0] (so the next must be a slash)
+
+  static final float COS15 = (SQ6+SQ2)/4;
+  static final float SIN15 = (SQ6-SQ2)/4;
+  static final float     X = 3*(2-SQ3)/2;
+
+  static final Static3D[] ROT_AXIS = new Static3D[]
+    {
+      new Static3D(0,1,0),
+      new Static3D(COS15,0,SIN15)
+    };
+
+  static final int[] BASIC_ANGLE = new int[] { 12,2 };
+
+  static final int[] FACE_COLORS = new int[]
+    {
+      COLOR_YELLOW, COLOR_WHITE,
+      COLOR_BLUE  , COLOR_GREEN,
+      COLOR_RED   , COLOR_ORANGE
+    };
+
+  static final Static4D[] QUATS = new Static4D[]
+    {
+      new Static4D(  0.0f,  0.0f,  0.0f,  1.0f ),
+      new Static4D(  0.0f, SIN15,  0.0f, COS15 ),
+      new Static4D(  0.0f,  0.5f,  0.0f, SQ3/2 ),
+      new Static4D(  0.0f, SQ2/2,  0.0f, SQ2/2 ),
+      new Static4D(  0.0f, SQ3/2,  0.0f,  0.5f ),
+      new Static4D(  0.0f, COS15,  0.0f, SIN15 ),
+      new Static4D(  0.0f,  1.0f,  0.0f,  0.0f ),
+      new Static4D(  0.0f, COS15,  0.0f,-SIN15 ),
+      new Static4D(  0.0f, SQ3/2,  0.0f, -0.5f ),
+      new Static4D(  0.0f, SQ2/2,  0.0f,-SQ2/2 ),
+      new Static4D(  0.0f,  0.5f,  0.0f,-SQ3/2 ),
+      new Static4D(  0.0f, SIN15,  0.0f,-COS15 ),
+
+      new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
+      new Static4D( COS15,  0.0f, SIN15,  0.0f ),
+      new Static4D( SQ3/2,  0.0f,  0.5f,  0.0f ),
+      new Static4D( SQ2/2,  0.0f, SQ2/2,  0.0f ),
+      new Static4D(  0.5f,  0.0f, SQ3/2,  0.0f ),
+      new Static4D( SIN15,  0.0f, COS15,  0.0f ),
+      new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
+      new Static4D(-SIN15,  0.0f, COS15,  0.0f ),
+      new Static4D( -0.5f,  0.0f, SQ3/2,  0.0f ),
+      new Static4D(-SQ2/2,  0.0f, SQ2/2,  0.0f ),
+      new Static4D(-SQ3/2,  0.0f,  0.5f,  0.0f ),
+      new Static4D(-COS15,  0.0f, SIN15,  0.0f )
+    };
+
+  static final double[][] VERTICES_MIDDLE = new double[][]
+    {
+      { -1.5-X, 0.5, 1.5 },
+      {    0.0, 0.5, 1.5 },
+      {    0.0, 0.5,-1.5 },
+      { -1.5+X, 0.5,-1.5 },
+      { -1.5-X,-0.5, 1.5 },
+      {    0.0,-0.5, 1.5 },
+      {    0.0,-0.5,-1.5 },
+      { -1.5+X,-0.5,-1.5 }
+    };
+
+  static final int[][] VERT_INDEXES_MIDDLE = new int[][]
+    {
+      {0,1,2,3},   // counterclockwise!
+      {4,5,6,7},
+      {4,5,1,0},
+      {5,6,2,1},
+      {6,7,3,2},
+      {7,4,0,3}
+    };
+
+  static final double[][] VERTICES_EDGE = new double[][]
+    {
+      { -X, 0.5, 0.0 },
+      { +X, 0.5, 0.0 },
+      {0.0, 0.5,-1.5 },
+      { -X,-0.5, 0.0 },
+      { +X,-0.5, 0.0 },
+      {0.0,-0.5,-1.5 },
+    };
+
+  static final int[][] VERT_INDEXES_EDGE = new int[][]
+    {
+      {0,1,2},   // counterclockwise!
+      {3,4,5},
+      {3,4,1,0},
+      {4,5,2,1},
+      {5,3,0,2}
+    };
+
+  // QUATS[i]*QUATS[j] = QUATS[QUAT_MULT[i][j]]
+  static final int[][] QUAT_MULT = new int[][]
+    {
+      {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,},
+      {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12,},
+      {  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13,},
+      {  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14,},
+      {  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15,},
+      {  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16,},
+      {  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17,},
+      {  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18,},
+      {  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19,},
+      {  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20,},
+      { 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,},
+      { 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,},
+      { 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,},
+      { 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,},
+      { 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,},
+      { 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,},
+      { 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,},
+      { 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,},
+      { 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,},
+      { 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,},
+      { 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,},
+      { 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,},
+      { 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11,},
+      { 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,}
+    };
+
+  static MeshBase[] mMeshes;
+  int mLastRot;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  TwistySquare(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
+               DistortedEffects effects, int[][] moves, ObjectList obj, Resources res, int scrWidth)
+    {
+    super(size, size, quat, texture, mesh, effects, moves, obj, res, scrWidth);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createMiddleCubitMesh()
+    {
+    if( mMeshes[0]==null )
+      {
+      float[][] bands= new float[][]
+        {
+           {0.040f,35,0.8f,1.0f,5,2,1},
+           {0.020f,35,0.8f,1.0f,5,2,1},
+           {0.001f,35,0.8f,1.0f,5,2,1}
+        };
+      int[] bandIndexes   = new int[] { 2,2,1,1,0,2 };
+      float[][] corners   = new float[][] { {0.03f,0.05f} };
+      int[] cornerIndexes = new int[] { 0,0,0,0,0,0,0,0 };
+      float[][] centers   = new float[][] { { -0.75f, 0.0f, 0.0f} };
+      int[] centerIndexes = new int[] { 0,0,0,0,0,0,0,0 };
+
+      FactoryCubit factory = FactoryCubit.getInstance();
+      factory.createNewFaceTransform(VERTICES_MIDDLE,VERT_INDEXES_MIDDLE);
+      mMeshes[0] = factory.createRoundedSolid(VERTICES_MIDDLE, VERT_INDEXES_MIDDLE,
+                                              bands, bandIndexes,
+                                              corners, cornerIndexes,
+                                              centers, centerIndexes,
+                                              getNumCubitFaces() );
+      }
+
+    return mMeshes[0].copy(true);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createEdgeCubitMesh()
+    {
+    if( mMeshes[1]==null )
+       {
+       float[][] bands= new float[][]
+         {
+           {0.038f,35,0.5f,0.9f, 5,2,1},
+           {0.001f,35,0.5f,0.9f, 5,2,1}
+         };
+       int[] bandIndexes   = new int[] { 0,1,0,1,1 };
+       float[][] corners   = new float[][] { {0.04f,0.15f} };
+       int[] cornerIndexes = new int[] { 0,0,-1,0,0,-1 };
+       float[][] centers   = new float[][] { { 0.0f, 0.0f,-0.5f} };
+       int[] centerIndexes = new int[] { 0,0,-1,0,0,-1 };
+
+       FactoryCubit factory = FactoryCubit.getInstance();
+       factory.createNewFaceTransform(VERTICES_EDGE,VERT_INDEXES_EDGE);
+       mMeshes[1] = factory.createRoundedSolid(VERTICES_EDGE, VERT_INDEXES_EDGE,
+                                               bands, bandIndexes,
+                                               corners, cornerIndexes,
+                                               centers, centerIndexes,
+                                               getNumCubitFaces() );
+       }
+    return mMeshes[1].copy(true);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  Static4D[] getQuats()
+    {
+    return QUATS;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  boolean shouldResetTextureMaps()
+    {
+    return false;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumFaces()
+    {
+    return FACE_COLORS.length;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumCubitFaces()
+    {
+    return 6;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float getScreenRatio()
+    {
+    return 0.5f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float returnMultiplier()
+    {
+    return 1.0f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float[][] getCuts(int numLayers)
+    {
+    return new float[][] { {-0.5f,+0.5f}, {0.0f} };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+
+  public Static3D[] getRotationAxis()
+    {
+    return ROT_AXIS;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[] getBasicAngle()
+    {
+    return BASIC_ANGLE;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public boolean isSolved()
+    {
+    int index = CUBITS[0].mQuatIndex;
+
+    for(int i=1; i<NUM_CUBITS; i++)
+      {
+      if( CUBITS[i].mQuatIndex != index ) return false;
+      }
+
+    return true;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// only needed for solvers - there are no Square solvers ATM)
+
+  public String retObjectString()
+    {
+    return "";
+    }
+
+}
diff --git a/src/main/java/org/distorted/objects/TwistySquare1.java b/src/main/java/org/distorted/objects/TwistySquare1.java
index e74e36fd..e8b4f350 100644
--- a/src/main/java/org/distorted/objects/TwistySquare1.java
+++ b/src/main/java/org/distorted/objects/TwistySquare1.java
@@ -38,61 +38,8 @@ import java.util.Random;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class TwistySquare1 extends TwistyObject
+class TwistySquare1 extends TwistySquare
 {
-  private static final int LAST_SL = 0; // automatic rotations: last rot was a 'slash' i.e. along ROT_AXIS[1]
-  private static final int LAST_UP = 1; // last rot was along ROT_AXIS[0], upper layer and forelast was a slash
-  private static final int LAST_LO = 2; // last rot was along ROT_AXIS[0], lower layer and forelast was a slash
-  private static final int LAST_UL = 3; // two last rots were along ROT_AXIS[0] (so the next must be a slash)
-
-  private static final float COS15 = (SQ6+SQ2)/4;
-  private static final float SIN15 = (SQ6-SQ2)/4;
-  private static final float     X = 3*(2-SQ3)/2;
-
-  static final Static3D[] ROT_AXIS = new Static3D[]
-    {
-      new Static3D(0,1,0),
-      new Static3D(COS15,0,SIN15)
-    };
-
-  private static final int[] BASIC_ANGLE = new int[] { 12,2 };
-
-  private static final int[] FACE_COLORS = new int[]
-    {
-      COLOR_YELLOW, COLOR_WHITE,
-      COLOR_BLUE  , COLOR_GREEN,
-      COLOR_RED   , COLOR_ORANGE
-    };
-
-  private static final Static4D[] QUATS = new Static4D[]
-    {
-      new Static4D(  0.0f,  0.0f,  0.0f,  1.0f ),
-      new Static4D(  0.0f, SIN15,  0.0f, COS15 ),
-      new Static4D(  0.0f,  0.5f,  0.0f, SQ3/2 ),
-      new Static4D(  0.0f, SQ2/2,  0.0f, SQ2/2 ),
-      new Static4D(  0.0f, SQ3/2,  0.0f,  0.5f ),
-      new Static4D(  0.0f, COS15,  0.0f, SIN15 ),
-      new Static4D(  0.0f,  1.0f,  0.0f,  0.0f ),
-      new Static4D(  0.0f, COS15,  0.0f,-SIN15 ),
-      new Static4D(  0.0f, SQ3/2,  0.0f, -0.5f ),
-      new Static4D(  0.0f, SQ2/2,  0.0f,-SQ2/2 ),
-      new Static4D(  0.0f,  0.5f,  0.0f,-SQ3/2 ),
-      new Static4D(  0.0f, SIN15,  0.0f,-COS15 ),
-
-      new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
-      new Static4D( COS15,  0.0f, SIN15,  0.0f ),
-      new Static4D( SQ3/2,  0.0f,  0.5f,  0.0f ),
-      new Static4D( SQ2/2,  0.0f, SQ2/2,  0.0f ),
-      new Static4D(  0.5f,  0.0f, SQ3/2,  0.0f ),
-      new Static4D( SIN15,  0.0f, COS15,  0.0f ),
-      new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
-      new Static4D(-SIN15,  0.0f, COS15,  0.0f ),
-      new Static4D( -0.5f,  0.0f, SQ3/2,  0.0f ),
-      new Static4D(-SQ2/2,  0.0f, SQ2/2,  0.0f ),
-      new Static4D(-SQ3/2,  0.0f,  0.5f,  0.0f ),
-      new Static4D(-COS15,  0.0f, SIN15,  0.0f )
-    };
-
   private static final int[] QUAT_NUMBER = new int[]
     {
       0, 6,
@@ -125,47 +72,6 @@ class TwistySquare1 extends TwistyObject
       {-1.0f,-1.0f, 2.0f,-2.0f,-1.0f, 1.0f }
     };
 
-  private static final double[][] VERTICES_MIDDLE = new double[][]
-    {
-      { -1.5-X, 0.5, 1.5 },
-      {    0.0, 0.5, 1.5 },
-      {    0.0, 0.5,-1.5 },
-      { -1.5+X, 0.5,-1.5 },
-      { -1.5-X,-0.5, 1.5 },
-      {    0.0,-0.5, 1.5 },
-      {    0.0,-0.5,-1.5 },
-      { -1.5+X,-0.5,-1.5 }
-    };
-
-  private static final int[][] VERT_INDEXES_MIDDLE = new int[][]
-    {
-      {0,1,2,3},   // counterclockwise!
-      {4,5,6,7},
-      {4,5,1,0},
-      {5,6,2,1},
-      {6,7,3,2},
-      {7,4,0,3}
-    };
-
-  private static final double[][] VERTICES_EDGE = new double[][]
-    {
-      { -X, 0.5, 0.0 },
-      { +X, 0.5, 0.0 },
-      {0.0, 0.5,-1.5 },
-      { -X,-0.5, 0.0 },
-      { +X,-0.5, 0.0 },
-      {0.0,-0.5,-1.5 },
-    };
-
-  private static final int[][] VERT_INDEXES_EDGE = new int[][]
-    {
-      {0,1,2},   // counterclockwise!
-      {3,4,5},
-      {3,4,1,0},
-      {4,5,2,1},
-      {5,3,0,2}
-    };
-
   private static final double[][] VERTICES_CORNER = new double[][]
     {
       { X-1.5, 0.5,  0.0 },
@@ -239,47 +145,16 @@ class TwistySquare1 extends TwistyObject
       { 5,11,14,20},
     };
 
-  // QUATS[i]*QUATS[j] = QUATS[QUAT_MULT[i][j]]
-  private static final int[][] QUAT_MULT = new int[][]
-    {
-      {  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,},
-      {  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12,},
-      {  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13,},
-      {  3,  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2, 15, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14,},
-      {  4,  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3, 16, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15,},
-      {  5,  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4, 17, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16,},
-      {  6,  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5, 18, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17,},
-      {  7,  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6, 19, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18,},
-      {  8,  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7, 20, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19,},
-      {  9, 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8, 21, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20,},
-      { 10, 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 22, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,},
-      { 11,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 23, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,},
-      { 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,},
-      { 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,},
-      { 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16, 15,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,  3,},
-      { 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17, 16,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,  4,},
-      { 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18, 17,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,  5,},
-      { 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19, 18,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,  6,},
-      { 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20, 19,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,  7,},
-      { 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21, 20,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,  8,},
-      { 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22, 21,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,  9,},
-      { 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 22,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11, 10,},
-      { 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 23, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0, 11,},
-      { 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1,  0,}
-    };
-
-  private static MeshBase[] mMeshes;
-
   private final int[][] mPermittedAngles;
   private final int[] mCornerQuat;
-  private int mLastRot, mPermittedUp, mPermittedDo;
+  private int mPermittedUp, mPermittedDo;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   TwistySquare1(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
                 DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
     {
-    super(size, size, quat, texture, mesh, effects, moves, ObjectList.SQU1, res, scrWidth);
+    super(size, quat, texture, mesh, effects, moves, ObjectList.SQU1, res, scrWidth);
 
     mLastRot = LAST_SL;
     mPermittedAngles = new int[2][BASIC_ANGLE[0]];
@@ -293,6 +168,34 @@ class TwistySquare1 extends TwistyObject
     return QUATS[QUAT_NUMBER[cubit]];
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createCornerCubitMesh()
+    {
+    if( mMeshes[2]==null )
+      {
+      float[][] bands= new float[][]
+        {
+          {0.038f,35,0.9f,1.0f, 5,2,1},
+          {0.001f,35,0.9f,1.0f, 5,2,1}
+        };
+      int[] bandIndexes   = new int[] { 0,1,0,0,1,1 };
+      float[][] corners   = new float[][] { {0.05f,0.13f} };
+      int[] cornerIndexes = new int[] { 0,0,0,-1,0,0,0,-1 };
+      float[][] centers   = new float[][] { { -0.5f, 0.0f,-0.5f} };
+      int[] centerIndexes = new int[] { -1,0,-1,-1,-1,0,-1,-1 };
+
+      FactoryCubit factory = FactoryCubit.getInstance();
+      factory.createNewFaceTransform(VERTICES_CORNER,VERT_INDEXES_CORNER);
+      mMeshes[2] = factory.createRoundedSolid(VERTICES_CORNER, VERT_INDEXES_CORNER,
+                                              bands, bandIndexes,
+                                              corners, cornerIndexes,
+                                              centers, centerIndexes,
+                                              getNumCubitFaces() );
+      }
+    return mMeshes[2].copy(true);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   MeshBase createCubitMesh(int cubit, int numLayers)
@@ -301,87 +204,14 @@ class TwistySquare1 extends TwistyObject
       {
       FactoryCubit factory = FactoryCubit.getInstance();
       factory.clear();
-      mMeshes = new MeshBase[3];
+      mMeshes = new MeshBase[4];
       }
 
     MeshBase mesh;
 
-    if( cubit<2 )
-      {
-      if( mMeshes[0]==null )
-        {
-        float[][] bands= new float[][]
-          {
-             {0.040f,35,0.8f,1.0f,5,2,1},
-             {0.020f,35,0.8f,1.0f,5,2,1},
-             {0.001f,35,0.8f,1.0f,5,2,1}
-          };
-        int[] bandIndexes   = new int[] { 2,2,1,1,0,2 };
-        float[][] corners   = new float[][] { {0.04f,0.05f} };
-        int[] cornerIndexes = new int[] { 0,0,0,0,0,0,0,0 };
-        float[][] centers   = new float[][] { { -0.75f, 0.0f, 0.0f} };
-        int[] centerIndexes = new int[] { 0,0,0,0,0,0,0,0 };
-
-        FactoryCubit factory = FactoryCubit.getInstance();
-        factory.createNewFaceTransform(VERTICES_MIDDLE,VERT_INDEXES_MIDDLE);
-        mMeshes[0] = factory.createRoundedSolid(VERTICES_MIDDLE, VERT_INDEXES_MIDDLE,
-                                                bands, bandIndexes,
-                                                corners, cornerIndexes,
-                                                centers, centerIndexes,
-                                                getNumCubitFaces() );
-        }
-      mesh = mMeshes[0].copy(true);
-      }
-    else if( cubit<10 )
-      {
-      if( mMeshes[1]==null )
-        {
-        float[][] bands= new float[][]
-          {
-            {0.038f,35,0.5f,0.9f, 5,2,1},
-            {0.001f,35,0.5f,0.9f, 5,2,1}
-          };
-        int[] bandIndexes   = new int[] { 0,1,0,1,1 };
-        float[][] corners   = new float[][] { {0.05f,0.20f} };
-        int[] cornerIndexes = new int[] { 0,0,-1,0,0,-1 };
-        float[][] centers   = new float[][] { { 0.0f, 0.0f,-0.5f} };
-        int[] centerIndexes = new int[] { 0,0,-1,0,0,-1 };
-
-        FactoryCubit factory = FactoryCubit.getInstance();
-        factory.createNewFaceTransform(VERTICES_EDGE,VERT_INDEXES_EDGE);
-        mMeshes[1] = factory.createRoundedSolid(VERTICES_EDGE, VERT_INDEXES_EDGE,
-                                                bands, bandIndexes,
-                                                corners, cornerIndexes,
-                                                centers, centerIndexes,
-                                                getNumCubitFaces() );
-        }
-      mesh = mMeshes[1].copy(true);
-      }
-    else
-      {
-      if( mMeshes[2]==null )
-        {
-        float[][] bands= new float[][]
-          {
-            {0.038f,35,0.9f,1.0f, 5,2,1},
-            {0.001f,35,0.9f,1.0f, 5,2,1}
-          };
-        int[] bandIndexes   = new int[] { 0,1,0,0,1,1 };
-        float[][] corners   = new float[][] { {0.07f,0.20f} };
-        int[] cornerIndexes = new int[] { 0,0,0,-1,0,0,0,-1 };
-        float[][] centers   = new float[][] { { -0.5f, 0.0f,-0.5f} };
-        int[] centerIndexes = new int[] { -1,0,-1,-1,-1,0,-1,-1 };
-
-        FactoryCubit factory = FactoryCubit.getInstance();
-        factory.createNewFaceTransform(VERTICES_CORNER,VERT_INDEXES_CORNER);
-        mMeshes[2] = factory.createRoundedSolid(VERTICES_CORNER, VERT_INDEXES_CORNER,
-                                                bands, bandIndexes,
-                                                corners, cornerIndexes,
-                                                centers, centerIndexes,
-                                                getNumCubitFaces() );
-        }
-      mesh = mMeshes[2].copy(true);
-      }
+         if( cubit< 2 ) mesh = createMiddleCubitMesh();
+    else if( cubit<10 ) mesh = createEdgeCubitMesh();
+    else                mesh = createCornerCubitMesh();
 
     MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
     mesh.apply(quat,0xffffffff,0);
@@ -419,27 +249,6 @@ class TwistySquare1 extends TwistyObject
     return CENTERS;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  Static4D[] getQuats()
-    {
-    return QUATS;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean shouldResetTextureMaps()
-    {
-    return false;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  int getNumFaces()
-    {
-    return FACE_COLORS.length;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   int getNumStickerTypes(int numLayers)
@@ -447,20 +256,6 @@ class TwistySquare1 extends TwistyObject
     return STICKERS.length;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  int getNumCubitFaces()
-    {
-    return 6;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  float getScreenRatio()
-    {
-    return 0.5f;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   int getFaceColor(int cubit, int cubitface, int numLayers)
@@ -474,20 +269,6 @@ class TwistySquare1 extends TwistyObject
     return mStickerType[type][cubitface]*FACE_COLORS.length + mStickerColor[cubit][cubitface];
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  float returnMultiplier()
-    {
-    return 1.0f;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  float[][] getCuts(int numLayers)
-    {
-    return new float[][] { {-0.5f,+0.5f}, {0.0f} };
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // this implements the fact that corner cubits have multiple 'centers' and this means the cubit
 // might span more than one layer along a given axis - i.e. that this is a bandaged puzzle.
@@ -709,20 +490,6 @@ class TwistySquare1 extends TwistyObject
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
 
-  public Static3D[] getRotationAxis()
-    {
-    return ROT_AXIS;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public int[] getBasicAngle()
-    {
-    return BASIC_ANGLE;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
   public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
     {
     int layer, nextAngle;
@@ -791,28 +558,6 @@ class TwistySquare1 extends TwistyObject
       }
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public boolean isSolved()
-    {
-    int index = CUBITS[0].mQuatIndex;
-
-    for(int i=1; i<NUM_CUBITS; i++)
-      {
-      if( CUBITS[i].mQuatIndex != index ) return false;
-      }
-
-    return true;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// only needed for solvers - there are no Square solvers ATM)
-
-  public String retObjectString()
-    {
-    return "";
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public int getObjectName(int numLayers)
diff --git a/src/main/java/org/distorted/objects/TwistySquare2.java b/src/main/java/org/distorted/objects/TwistySquare2.java
new file mode 100644
index 00000000..45ea0461
--- /dev/null
+++ b/src/main/java/org/distorted/objects/TwistySquare2.java
@@ -0,0 +1,360 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2021 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube 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.                                                           //
+//                                                                                               //
+// Magic Cube 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 Magic Cube.  If not, see <http://www.gnu.org/licenses/>.                           //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.objects;
+
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+import org.distorted.helpers.FactoryCubit;
+import org.distorted.helpers.FactorySticker;
+import org.distorted.library.effect.MatrixEffectQuaternion;
+import org.distorted.library.main.DistortedEffects;
+import org.distorted.library.main.DistortedTexture;
+import org.distorted.library.mesh.MeshBase;
+import org.distorted.library.mesh.MeshSquare;
+import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Static4D;
+import org.distorted.main.R;
+
+import java.util.Random;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class TwistySquare2 extends TwistySquare
+{
+  private static final float Y = 0.75f + X/2;
+  private static final float Z = 0.75f - X/2;
+
+  private static final int[] QUAT_NUMBER = new int[]
+    {
+      0, 6,
+      0, 9, 6, 3, 18, 15, 12, 21,
+      0, 9, 6, 3, 15, 12, 21, 18,
+      0, 9, 6, 3, 15, 12, 21, 18
+    };
+
+  // centers of the 2 middles + 8 edges + 8 left corners + 8 right corners
+  private static final float[][] CENTERS = new float[][]
+    {
+      { 1.5f, 0.0f, 0.0f },
+      {-1.5f, 0.0f, 0.0f },
+
+      { 0.0f, 1.0f, 1.5f },
+      { 1.5f, 1.0f, 0.0f },
+      { 0.0f, 1.0f,-1.5f },
+      {-1.5f, 1.0f, 0.0f },
+      { 0.0f,-1.0f, 1.5f },
+      { 1.5f,-1.0f, 0.0f },
+      { 0.0f,-1.0f,-1.5f },
+      {-1.5f,-1.0f, 0.0f },
+
+      {    Y, 1.0f, 1.5f },
+      { 1.5f, 1.0f,   -Y },
+      {   -Y, 1.0f,-1.5f },
+      {-1.5f, 1.0f,    Y },
+      {    Y,-1.0f, 1.5f },
+      { 1.5f,-1.0f,   -Y },
+      {   -Y,-1.0f,-1.5f },
+      {-1.5f,-1.0f,    Y },
+
+      { 1.5f, 1.0f,    Y },
+      {    Y, 1.0f,-1.5f },
+      {-1.5f, 1.0f,   -Y },
+      {   -Y, 1.0f, 1.5f },
+      { 1.5f,-1.0f,    Y },
+      {    Y,-1.0f,-1.5f },
+      {-1.5f,-1.0f,   -Y },
+      {   -Y,-1.0f, 1.5f },
+    };
+
+  private static final double[][] VERTICES_CORNER = new double[][]
+    {
+      { X-1.5+Z, 0.5,  0.0 },
+      {       Z, 0.5,  0.0 },
+      {  -1.5+Z, 0.5, -1.5 },
+      { X-1.5+Z,-0.5,  0.0 },
+      {       Z,-0.5,  0.0 },
+      {  -1.5+Z,-0.5, -1.5 }
+    };
+
+  private static final int[][] VERT_INDEXES_CORNER = new int[][]
+    {
+      {0,1,2},   // counterclockwise!
+      {3,4,5},
+      {3,4,1,0},
+      {4,5,2,1},
+      {5,3,0,2}
+    };
+
+  private static final float[][] STICKERS = new float[][]
+    {
+      { -0.5f, -0.26289170f, 0.5f, -0.26289170f, 0.5f, 0.26289170f, -0.5f, 0.26289170f }, // middle front
+      { -0.5f, -0.16666667f, 0.5f, -0.16666667f, 0.5f, 0.16666667f, -0.5f, 0.16666667f }, // middle right
+      { -0.5f, -0.45534182f, 0.5f, -0.45534182f, 0.5f, 0.45534182f, -0.5f, 0.45534182f }, // middle back
+      { -0.20096192f, -0.25f, 0.20096192f, -0.25f, 0.0f, 0.5f },                          // edge top
+      { -0.40192384f, -0.5f, 0.40192384f, -0.5f, 0.40192384f, 0.5f, -0.40192384f, 0.5f }, // edge face
+      { -0.11602539f, -0.25f, 0.4330127f, -0.25f, -0.3169873f, 0.5f }                     // corner top
+    };
+
+  private static final int NUM_ST = STICKERS.length;
+
+  private static final int[][] mStickerType = new int[][]
+    {
+      {  NUM_ST,NUM_ST,0,     1,     2,NUM_ST },
+      {       3,NUM_ST,4,NUM_ST,NUM_ST,NUM_ST },
+      {       5,NUM_ST,2,NUM_ST,NUM_ST,NUM_ST },
+      {  NUM_ST,     5,2,NUM_ST,NUM_ST,NUM_ST }
+    };
+
+  // YELLOW 0 WHITE 1 BLUE 2 GREEN 3 RED 4 ORANGE 5
+  private static final int[][] mStickerColor = new int[][]
+    {
+      { 0, 0, 4, 0, 5, 0 }, // 0
+      { 0, 0, 5, 1, 4, 0 },
+
+      { 2, 0, 4, 0, 0, 0 }, // 2
+      { 2, 0, 0, 0, 0, 0 },
+      { 2, 0, 5, 0, 0, 0 },
+      { 2, 0, 1, 0, 0, 0 },
+      { 3, 0, 4, 0, 0, 0 },
+      { 3, 0, 0, 0, 0, 0 },
+      { 3, 0, 5, 0, 0, 0 },
+      { 3, 0, 1, 0, 0, 0 },
+
+      { 2, 0, 4, 0, 0, 0 }, // 10
+      { 2, 0, 0, 0, 0, 0 },
+      { 2, 0, 5, 0, 0, 0 },
+      { 2, 0, 1, 0, 0, 0 },
+      { 0, 3, 4, 0, 0, 0 },
+      { 0, 3, 0, 0, 0, 0 },
+      { 0, 3, 5, 0, 0, 0 },
+      { 0, 3, 1, 0, 0, 0 },
+
+      { 0, 2, 4, 0, 0, 0 }, // 18
+      { 0, 2, 0, 0, 0, 0 },
+      { 0, 2, 5, 0, 0, 0 },
+      { 0, 2, 1, 0, 0, 0 },
+      { 3, 0, 0, 0, 0, 0 },
+      { 3, 0, 5, 0, 0, 0 },
+      { 3, 0, 1, 0, 0, 0 },
+      { 3, 0, 4, 0, 0, 0 },
+    };
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  TwistySquare2(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
+                DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
+    {
+    super(size, quat, texture, mesh, effects, moves, ObjectList.SQU2, res, scrWidth);
+
+    FactoryCubit factory = FactoryCubit.getInstance();
+    factory.printStickerCoords();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private Static4D getQuat(int cubit)
+    {
+    if( (cubit>=0 && cubit<=13) || (cubit>=22))
+      {
+      return QUATS[QUAT_NUMBER[cubit]];
+      }
+    else
+      {
+      return QUATS[0];
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createCornerCubitMesh()
+    {
+    if( mMeshes[3]==null )
+      {
+      float[][] bands= new float[][]
+        {
+          {0.038f,35,0.9f,1.0f, 5,2,1},
+          {0.001f,35,0.9f,1.0f, 5,2,1}
+        };
+      int[] bandIndexes   = new int[] { 0,1,0,1,1 };
+      float[][] corners   = new float[][] { {0.05f,0.13f} };
+      int[] cornerIndexes = new int[] { 0,0,-1,0,0,-1 };
+      float[][] centers   = new float[][] { { 0.0f, 0.0f,-0.5f} };
+      int[] centerIndexes = new int[] { 0,0,-1,0,0,-1 };
+
+      FactoryCubit factory = FactoryCubit.getInstance();
+      factory.createNewFaceTransform(VERTICES_CORNER,VERT_INDEXES_CORNER);
+      mMeshes[3] = factory.createRoundedSolid(VERTICES_CORNER, VERT_INDEXES_CORNER,
+                                              bands, bandIndexes,
+                                              corners, cornerIndexes,
+                                              centers, centerIndexes,
+                                              getNumCubitFaces() );
+      }
+    return mMeshes[3].copy(true);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createCubitMesh(int cubit, int numLayers)
+    {
+    if( mMeshes==null )
+      {
+      FactoryCubit factory = FactoryCubit.getInstance();
+      factory.clear();
+      mMeshes = new MeshBase[4];
+      }
+
+    MeshBase mesh;
+
+         if( cubit< 2 ) mesh = createMiddleCubitMesh();
+    else if( cubit<10 ) mesh = createEdgeCubitMesh();
+    else                mesh = createCornerCubitMesh();
+
+    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
+    mesh.apply(quat,0xffffffff,0);
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
+    {
+    int COLORS = FACE_COLORS.length;
+    int stickerType = face/COLORS;
+    float R,S;
+
+    switch(stickerType)
+      {
+      case 0:  R = 0.060f; S = 0.05f; break;
+      case 1:  R = 0.040f; S = 0.04f; break;
+      case 2:  R = 0.110f; S = 0.09f; break;
+      case 3:  R = 0.030f; S = 0.05f; break;
+      case 4:  R = 0.110f; S = 0.08f; break;
+      case 5:  R = 0.025f; S = 0.06f; break;
+      default: R = 0.000f; S = 0.00f; break;
+      }
+
+    FactorySticker factory = FactorySticker.getInstance();
+    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[stickerType], S, FACE_COLORS[face%COLORS], R);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float[][] getCubitPositions(int numLayers)
+    {
+    return CENTERS;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumStickerTypes(int numLayers)
+    {
+    return STICKERS.length;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getFaceColor(int cubit, int cubitface, int numLayers)
+    {
+    int type;
+
+         if( cubit< 2             ) type = 0;
+    else if( cubit<10             ) type = 1;
+    else if( cubit>13 && cubit<22 ) type = 3;
+    else                            type = 2;
+
+    return mStickerType[type][cubitface]*FACE_COLORS.length + mStickerColor[cubit][cubitface];
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+
+  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
+    {
+    int layer, nextAngle;
+
+    if( num==0 ) mLastRot = rnd.nextInt(4);
+
+    switch(mLastRot)
+      {
+      case LAST_SL: layer = rnd.nextInt(2);
+                    nextAngle = rnd.nextInt(12)-6;
+
+                    if( nextAngle==0 )
+                      {
+                      layer = 1-layer;
+                      nextAngle = (2*rnd.nextInt(2)-1)*(rnd.nextInt(5)+1);
+                      }
+
+                    scramble[num][0] = 0;
+                    scramble[num][1] = 2*layer;
+                    scramble[num][2] = nextAngle;
+                    mLastRot = layer==0 ? LAST_LO : LAST_UP;
+                    break;
+      case LAST_LO:
+      case LAST_UP: layer = mLastRot==LAST_LO ? 1:0;
+                    nextAngle = rnd.nextInt(12)-6;
+
+                    if( nextAngle!=0 )
+                      {
+                      scramble[num][0] = 0;
+                      scramble[num][1] = 2*layer;
+                      scramble[num][2] = nextAngle;
+                      mLastRot = LAST_UL;
+                      }
+                    else
+                      {
+                      scramble[num][0] = 1;
+                      scramble[num][1] = rnd.nextInt(2);
+                      scramble[num][2] = 1;
+                      mLastRot = LAST_SL;
+                      }
+                    break;
+      case LAST_UL: scramble[num][0] = 1;
+                    scramble[num][1] = rnd.nextInt(2);
+                    scramble[num][2] = 1;
+                    mLastRot = LAST_SL;
+                    break;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getObjectName(int numLayers)
+    {
+    return R.string.squa2;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getInventor(int numLayers)
+    {
+    return R.string.squa2_inventor;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getComplexity(int numLayers)
+    {
+    return 7;
+    }
+}
