commit 834b2618a59c7b30b7b38c77dd01061428d44cef
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Jun 3 13:40:33 2021 +0200

    Square-1: beginnings

diff --git a/src/main/java/org/distorted/control/RubikControlWhole.java b/src/main/java/org/distorted/control/RubikControlWhole.java
index 3baf4000..5e239cec 100644
--- a/src/main/java/org/distorted/control/RubikControlWhole.java
+++ b/src/main/java/org/distorted/control/RubikControlWhole.java
@@ -543,6 +543,7 @@ class RubikControlWhole
     mDyn1.add(point2);
     mDyn1.add(point3);
     mDyn1.add(point0);
+
     mDyn2.add(point2);
     mDyn2.add(point3);
     mDyn2.add(point0);
@@ -552,6 +553,9 @@ class RubikControlWhole
     mDyn1.setConvexity(1.0f);
     mDyn2.setConvexity(1.0f);
 
+    mDyn1.setSpeedMode(Dynamic.SPEED_MODE_SEGMENT_CONSTANT);
+    mDyn2.setSpeedMode(Dynamic.SPEED_MODE_SEGMENT_CONSTANT);
+
     mPosition1.set(point0);
     mPosition2.set(point2);
 
@@ -592,6 +596,9 @@ class RubikControlWhole
     mDyn1.setConvexity(0.0f);
     mDyn2.setConvexity(0.0f);
 
+    mDyn1.setSpeedMode(Dynamic.SPEED_MODE_SMOOTH);
+    mDyn2.setSpeedMode(Dynamic.SPEED_MODE_SMOOTH);
+
     mPosition1.set(point1f);
     mPosition2.set(point2f);
 
diff --git a/src/main/java/org/distorted/main/RubikSurfaceView.java b/src/main/java/org/distorted/main/RubikSurfaceView.java
index 66f0ae24..21d917db 100644
--- a/src/main/java/org/distorted/main/RubikSurfaceView.java
+++ b/src/main/java/org/distorted/main/RubikSurfaceView.java
@@ -373,6 +373,11 @@ public class RubikSurfaceView extends GLSurfaceView
         float distQuot = mInitDistance<0 ? 1.0f : distNow/ mInitDistance;
         mInitDistance = distNow;
 
+if( angleDiff< 0.00001f && angleDiff>-0.00001f)
+  android.util.Log.e("D", " distQuot="+distQuot);
+else
+ android.util.Log.e("D", "angelDiff "+angleDiff+" distQuot="+distQuot);
+
         TwistyObject object = mPreRender.getObject();
         if( object!=null ) object.setObjectRatio(distQuot);
         }
diff --git a/src/main/java/org/distorted/objects/MovementSquare.java b/src/main/java/org/distorted/objects/MovementSquare.java
new file mode 100644
index 00000000..63ad7cbd
--- /dev/null
+++ b/src/main/java/org/distorted/objects/MovementSquare.java
@@ -0,0 +1,82 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2020 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 org.distorted.library.type.Static3D;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class MovementSquare extends Movement
+{
+  static final float DIST3D = 0.5f;
+  static final float DIST2D = 0.5f;
+
+  static final Static3D[] FACE_AXIS = new Static3D[]
+         {
+           new Static3D(1,0,0), new Static3D(-1,0,0),
+           new Static3D(0,1,0), new Static3D(0,-1,0),
+           new Static3D(0,0,1), new Static3D(0,0,-1)
+         };
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MovementSquare()
+    {
+    super(TwistySquare1.ROT_AXIS, FACE_AXIS, DIST3D, DIST2D);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int computeRowFromOffset(int face, int size, float offset)
+    {
+    return (int)(size*offset);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float returnRotationFactor(int size, int row)
+    {
+    return 1.0f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  boolean isInsideFace(int face, float[] p)
+    {
+    return ( p[0]<=DIST2D && p[0]>=-DIST2D && p[1]<=DIST2D && p[1]>=-DIST2D );
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void computeEnabledAxis(int face, float[] touchPoint, int[] enabled)
+    {
+    enabled[0] = 2;
+
+    switch(face)
+      {
+      case 0:
+      case 1: enabled[1]=1; enabled[2]=2; break;
+      case 2:
+      case 3: enabled[1]=0; enabled[2]=2; break;
+      case 4:
+      case 5: enabled[1]=0; enabled[2]=1; break;
+      }
+    }
+}
diff --git a/src/main/java/org/distorted/objects/ObjectList.java b/src/main/java/org/distorted/objects/ObjectList.java
index addb2bc6..79c30059 100644
--- a/src/main/java/org/distorted/objects/ObjectList.java
+++ b/src/main/java/org/distorted/objects/ObjectList.java
@@ -212,6 +212,16 @@ public enum ObjectList
          6,
          60
        ),
+
+  SQU1 (
+         new int[][] {
+                       {2 , 18, 0, R.drawable.ui_small_diam2, R.drawable.ui_medium_diam2, R.drawable.ui_big_diam2, R.drawable.ui_huge_diam2} ,
+                     },
+         TwistySquare1.class,
+         new MovementSquare(),
+         6,
+         60
+       ),
   ;
 
   public static final int NUM_OBJECTS = values().length;
@@ -610,6 +620,7 @@ public enum ObjectList
       case 14: return new TwistyBandaged3Plate(size, quat, texture, mesh, effects, moves, res, scrWidth);
       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);
       }
 
     return null;
diff --git a/src/main/java/org/distorted/objects/TwistyRedi.java b/src/main/java/org/distorted/objects/TwistyRedi.java
index 45cb3d50..b6e07221 100644
--- a/src/main/java/org/distorted/objects/TwistyRedi.java
+++ b/src/main/java/org/distorted/objects/TwistyRedi.java
@@ -106,8 +106,8 @@ public class TwistyRedi extends TwistyObject
          };
 
   // Colors of the faces of cubits.
-  // YELLOW 0 WHITE 1 BLUE 2 GREEN 3 RED 4  BROWN 5
-  // YELLOW 6 WHITE 7 BLUE 8 GREEN 9 RED 10 BROWN 11
+  // YELLOW 0 WHITE 1 BLUE 2 GREEN 3 RED 4  ORANGE 5
+  // YELLOW 6 WHITE 7 BLUE 8 GREEN 9 RED 10 ORANGE 11
   private static final int[][] mFaceMap = new int[][]
          {
            {  4, 2, 0,12,12,12 },
diff --git a/src/main/java/org/distorted/objects/TwistySquare1.java b/src/main/java/org/distorted/objects/TwistySquare1.java
new file mode 100644
index 00000000..59382ef1
--- /dev/null
+++ b/src/main/java/org/distorted/objects/TwistySquare1.java
@@ -0,0 +1,541 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2019 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 TwistySquare1 extends TwistyObject
+{
+  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[] 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,
+           0, 9, 6, 3, 18, 15, 12, 21,
+           0, 9, 6, 3, 15, 12, 21, 18
+         };
+
+  // centers of the 2 middles + 8 edges + 8 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 },
+
+             { 1.5f, 1.0f, 1.5f },
+             { 1.5f, 1.0f,-1.5f },
+             {-1.5f, 1.0f,-1.5f },
+             {-1.5f, 1.0f, 1.5f },
+             { 1.5f,-1.0f, 1.5f },
+             { 1.5f,-1.0f,-1.5f },
+             {-1.5f,-1.0f,-1.5f },
+             {-1.5f,-1.0f, 1.5f },
+         };
+
+  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 },
+              {   0.0, 0.5,  0.0 },
+              {   0.0, 0.5,X-1.5 },
+              {  -1.5, 0.5, -1.5 },
+              { X-1.5,-0.5,  0.0 },
+              {   0.0,-0.5,  0.0 },
+              {   0.0,-0.5,X-1.5 },
+              {  -1.5,-0.5, -1.5 }
+          };
+
+  private static final int[][] VERT_INDEXES_CORNER = new int[][]
+          {
+              {0,1,2,3},   // counterclockwise!
+              {4,5,6,7},
+              {4,5,1,0},
+              {5,6,2,1},
+              {7,4,0,3},
+              {6,7,3,2}
+          };
+
+  // TODO
+  private static final float[][] STICKERS = new float[][]
+          {
+              { -0.5f, -0.5f, 0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f }
+          };
+
+  private static final int NUM_ST = STICKERS.length;
+
+  private static final int[][] mStickerType = new int[][]
+         {
+           {  NUM_ST,NUM_ST,0,     1,     2,NUM_ST },
+           {       4,NUM_ST,3,NUM_ST,NUM_ST,NUM_ST },
+           {       5,NUM_ST,2,     2,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, 5, 0, 4, 0 },
+           { 0, 0, 4, 1, 5, 0 },
+
+           { 3, 0, 5, 0, 0, 0 },
+           { 3, 0, 0, 0, 0, 0 },
+           { 3, 0, 4, 0, 0, 0 },
+           { 3, 0, 1, 0, 0, 0 },
+           { 2, 0, 5, 0, 0, 0 },
+           { 2, 0, 0, 0, 0, 0 },
+           { 2, 0, 4, 0, 0, 0 },
+           { 2, 0, 1, 0, 0, 0 },
+
+           { 3, 0, 5, 0, 0, 0 },
+           { 3, 0, 0, 4, 0, 0 },
+           { 3, 0, 4, 1, 0, 0 },
+           { 3, 0, 1, 5, 0, 0 },
+           { 2, 0, 5, 0, 0, 0 },
+           { 2, 0, 0, 4, 0, 0 },
+           { 2, 0, 4, 1, 0, 0 },
+           { 2, 0, 1, 5, 0, 0 },
+         };
+
+  private static MeshBase[] mMeshes;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  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);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private Static4D getQuat(int cubit)
+    {
+    return QUATS[QUAT_NUMBER[cubit]];
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createCubitMesh(int cubit, int numLayers)
+    {
+    if( mMeshes==null )
+      {
+      FactoryCubit factory = FactoryCubit.getInstance();
+      factory.clear();
+      mMeshes = new MeshBase[3];
+      }
+
+    MeshBase mesh;
+
+    if( cubit<2 )
+      {
+      if( mMeshes[0]==null )
+        {
+        float[][] bands= new float[][]
+          {
+             {0.06f,35,0.5f,0.7f,6,2,2},
+             {0.03f,35,0.5f,0.7f,6,2,2},
+             {0.00f, 0,1.0f,0.0f,2,0,0}
+          };
+        int[] bandIndexes   = new int[] { 2,2,1,1,0,2 };
+        float[][] corners   = new float[][] { {0.06f,0.08f} };
+        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.250f,0.7f, 7,2,2},
+            {0.000f, 0,0.125f,0.2f, 3,1,1}
+          };
+        int[] bandIndexes   = new int[] { 1,1,0,1,1 };
+        float[][] corners   = new float[][] { {0.06f,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.250f,0.7f, 7,2,2},
+            {0.000f, 0,0.125f,0.2f, 3,1,1}
+          };
+        int[] bandIndexes   = new int[] { 1,1,0,0,1,1 };
+        float[][] corners   = new float[][] { {0.08f,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);
+      }
+
+    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( getQuat(cubit), new Static3D(0,0,0) );
+    mesh.apply(quat,0xffffffff,0);
+
+    return mesh;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+
+  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
+    {
+    float R = 0.10f;
+    float S = 0.08f;
+
+    FactorySticker factory = FactorySticker.getInstance();
+    factory.drawRoundedPolygon(canvas, paint, left, top, STICKERS[0], S, FACE_COLORS[face], R);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float[][] getCubitPositions(int size)
+    {
+    return CENTERS;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  Static4D[] getQuats()
+    {
+    return QUATS;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  boolean shouldResetTextureMaps()
+    {
+    return false;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumFaces()
+    {
+    return FACE_COLORS.length;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+
+  float[] getCuts(int numLayers)
+    {
+    float[] cuts = new float[numLayers-1];
+
+    for(int i=0; i<numLayers-1; i++)
+      {
+      cuts[i] = (2-numLayers)*0.5f + i;
+      }
+
+    return cuts;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumStickerTypes(int numLayers)
+    {
+    return STICKERS.length;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumCubitFaces()
+    {
+    return 6;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float getScreenRatio()
+    {
+    return 0.36f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getFaceColor(int cubit, int cubitface, int size)
+    {
+    int type;
+
+         if( cubit< 2 ) type = 0;
+    else if( cubit<10 ) type = 1;
+    else                type = 2;
+
+    return 0;//mStickerType[type][cubitface]*FACE_COLORS.length + mStickerColor[cubit][cubitface];
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float returnMultiplier()
+    {
+    return 1.0f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+
+  float[] getRowChances(int numLayers)
+    {
+    float[] chances = new float[numLayers];
+
+    for(int i=0; i<numLayers; i++)
+      {
+      chances[i] = (i+1.0f) / numLayers;
+      }
+
+    return chances;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+
+  public Static3D[] getRotationAxis()
+    {
+    return ROT_AXIS;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+
+  public int getBasicAngle()
+    {
+    return 4;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+
+  public void randomizeNewScramble(int[][] scramble, Random rnd, int num)
+    {
+    if( num==0 )
+      {
+      scramble[num][0] = rnd.nextInt(ROTATION_AXIS.length);
+      }
+    else
+      {
+      int newVector = rnd.nextInt(ROTATION_AXIS.length-1);
+      scramble[num][0] = (newVector>=scramble[num-1][0] ? newVector+1 : newVector);
+      }
+
+    float rowFloat = rnd.nextFloat();
+
+    for(int row=0; row<mRowChances.length; row++)
+      {
+      if( rowFloat<=mRowChances[row] )
+        {
+        scramble[num][1] = row;
+        break;
+        }
+      }
+
+    switch( rnd.nextInt(4) )
+      {
+      case 0: scramble[num][2] = -2; break;
+      case 1: scramble[num][2] = -1; break;
+      case 2: scramble[num][2] =  1; break;
+      case 3: scramble[num][2] =  2; break;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  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)
+    {
+    return R.string.squa1;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getInventor(int numLayers)
+    {
+    return R.string.squa1_inventor;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getComplexity(int numLayers)
+    {
+    return 9;
+    }
+}
diff --git a/src/main/java/org/distorted/screens/RubikScreenPlay.java b/src/main/java/org/distorted/screens/RubikScreenPlay.java
index 82f95c68..0d26310e 100644
--- a/src/main/java/org/distorted/screens/RubikScreenPlay.java
+++ b/src/main/java/org/distorted/screens/RubikScreenPlay.java
@@ -398,7 +398,7 @@ public class RubikScreenPlay extends RubikScreenBase
       case 2: RubikControl control = RubikControl.getInstance();
               control.animateAll(act);
               break;
-*/
+ */
       case 2: ScreenList.switchScreen(act, ScreenList.SVER);
               break;
       case 3: RubikDialogTutorial tDiag = new RubikDialogTutorial();
diff --git a/src/main/res/raw/compute_quats.c b/src/main/res/raw/compute_quats.c
index 56d91bd1..743e4f89 100644
--- a/src/main/res/raw/compute_quats.c
+++ b/src/main/res/raw/compute_quats.c
@@ -2,7 +2,7 @@
 #include <math.h>
 #include <stdlib.h>
 
-#define ULTI
+#define SQUARE
 
 #define SQ2 1.41421356237f
 #define SQ3 1.73205080757f
@@ -11,68 +11,71 @@
 #define NUM_QUATS  200
 
 #ifdef PYRA 
-#define NUM_AXIS    4
-#define BASIC_ANGLE 3
+int basic[] = { 3,3,3,3 };
 
-float axis[NUM_AXIS][3] = { { SQ2*SQ3/3,   SQ3/3,          0 } ,
-                            {-SQ2*SQ3/3,   SQ3/3,          0 } ,
-                            {         0,  -SQ3/3, -SQ2*SQ3/3 } ,
-                            {         0,  -SQ3/3,  SQ2*SQ3/3 } };
+float axis[][3] = { { SQ2*SQ3/3,   SQ3/3,          0 } ,
+                    {-SQ2*SQ3/3,   SQ3/3,          0 } ,
+                    {         0,  -SQ3/3, -SQ2*SQ3/3 } ,
+                    {         0,  -SQ3/3,  SQ2*SQ3/3 } };
 #endif
 
 #ifdef CUBE
-#define NUM_AXIS    3
-#define BASIC_ANGLE 4
+int basic[] = { 4,4,4 };
 
-float axis[NUM_AXIS][3] = { { 1,0,0 } , 
-                            { 0,1,0 } , 
-                            { 0,0,1 } };
+float axis[][3] = { { 1,0,0 } , 
+                    { 0,1,0 } , 
+                    { 0,0,1 } };
 #endif
 
 #ifdef DINO
-#define NUM_AXIS    4
-#define BASIC_ANGLE 3
+int basic[] = { 3,3,3,3 };
 
-float axis[NUM_AXIS][3] = { {+SQ3/3,+SQ3/3,+SQ3/3} , 
-                            {+SQ3/3,+SQ3/3,-SQ3/3} , 
-                            {+SQ3/3,-SQ3/3,+SQ3/3} , 
-                            {+SQ3/3,-SQ3/3,-SQ3/3} };
+float axis[][3] = { {+SQ3/3,+SQ3/3,+SQ3/3} , 
+                    {+SQ3/3,+SQ3/3,-SQ3/3} , 
+                    {+SQ3/3,-SQ3/3,+SQ3/3} , 
+                    {+SQ3/3,-SQ3/3,-SQ3/3} };
 #endif
 
 #ifdef DIAM
-#define NUM_AXIS    4
-#define BASIC_ANGLE 3
+int basic[] = { 3,3,3,3 };
 
-float axis[NUM_AXIS][3] = { {+SQ3*SQ2/3,+SQ3/3,         0} ,
-                            {-SQ3*SQ2/3,+SQ3/3,         0} ,
-                            {         0,+SQ3/3,+SQ3*SQ2/3} ,
-                            {         0,+SQ3/3,-SQ3*SQ2/3} };
+float axis[][3] = { {+SQ3*SQ2/3,+SQ3/3,         0} ,
+                    {-SQ3*SQ2/3,+SQ3/3,         0} ,
+                    {         0,+SQ3/3,+SQ3*SQ2/3} ,
+                    {         0,+SQ3/3,-SQ3*SQ2/3} };
 #endif
 
 #ifdef HELI
-#define NUM_AXIS 6
-#define BASIC_ANGLE 2
+int basic[] = { 2,2,2,2,2,2 };
 
-float axis[NUM_AXIS][3] = { {     0, +SQ2/2, -SQ2/2} ,
-                            {     0, -SQ2/2, -SQ2/2} ,
-                            {+SQ2/2,      0, -SQ2/2} ,
-                            {-SQ2/2,      0, -SQ2/2} ,
-                            {+SQ2/2, -SQ2/2,      0} ,
-                            {-SQ2/2, -SQ2/2,      0} };
+float axis[][3] = { {     0, +SQ2/2, -SQ2/2} ,
+                    {     0, -SQ2/2, -SQ2/2} ,
+                    {+SQ2/2,      0, -SQ2/2} ,
+                    {-SQ2/2,      0, -SQ2/2} ,
+                    {+SQ2/2, -SQ2/2,      0} ,
+                    {-SQ2/2, -SQ2/2,      0} };
 
 #endif
 
 #ifdef ULTI
-#define NUM_AXIS 4
-#define BASIC_ANGLE 3
+int basic[] = { 3,3,3,3 };
 
-float axis[NUM_AXIS][3] = {   { 5*SQ5/16 + 11.0f/16,              0.0f   ,    SQ5/8  + 1.0f/4 } ,
-                              {   SQ5/8  +  1.0f/4 ,  5*SQ5/16 + 11.0f/16,             0.0f   } ,
-                              {-3*SQ5/16 -  7.0f/16,  3*SQ5/16 +  7.0f/16,  3*SQ5/16 + 7.0f/16} ,
-                              {             0.0f   ,    SQ5/4  +  1.0f/2 , -5*SQ5/8  -11.0f/8 } };
+float axis[][3] = { { 5*SQ5/16 + 11.0f/16,              0.0f   ,    SQ5/8  + 1.0f/4 } ,
+                    {   SQ5/8  +  1.0f/4 ,  5*SQ5/16 + 11.0f/16,             0.0f   } ,
+                    {-3*SQ5/16 -  7.0f/16,  3*SQ5/16 +  7.0f/16,  3*SQ5/16 + 7.0f/16} ,
+                    {             0.0f   ,    SQ5/4  +  1.0f/2 , -5*SQ5/8  -11.0f/8 } };
 
 #endif
 
+#ifdef SQUARE
+#define COS15 (0.25f*SQ2*(SQ3+1))
+#define SIN15 (0.25f*SQ2*(SQ3-1))
+
+int basic[] = { 12, 2 };
+
+float axis[][3] = { {     0, 1,     0 } ,
+                    { COS15, 0, SIN15 } };
+#endif
 
 int inserted=0;
 
@@ -174,7 +177,7 @@ int main(int argc, char** argv)
   {
   float tmp[4];
   float table[4*NUM_QUATS];
-  int num;
+  int num,NUM_AXIS = sizeof(axis) / sizeof(axis[0]);
 
   tmp[0] = 0.0f; tmp[1] = 0.0f; tmp[2] = 0.0f; tmp[3] = 1.0f;
   insert(tmp,table);
@@ -184,10 +187,10 @@ int main(int argc, char** argv)
     normalize(ax);
     }
 
-  for(int angle=1; angle<BASIC_ANGLE; angle++)
-    for( int ax=0; ax<NUM_AXIS; ax++)
+  for( int ax=0; ax<NUM_AXIS; ax++)
+    for(int angle=1; angle<basic[ax]; angle++)
       {
-      create_quat(axis[ax], 2*PI*angle/BASIC_ANGLE, tmp);
+      create_quat(axis[ax], 2*PI*angle/basic[ax], tmp);
       insert(tmp,table); 
       }
 
@@ -204,11 +207,9 @@ int main(int argc, char** argv)
     }
   while( num < inserted );
 
-  printf("inserted: %d\n", inserted);
-
   for(int i=0; i<inserted; i++)
     {
-    printf( "%d %7.4f %7.4f %7.4f %7.4f\n", i, table[4*i], table[4*i+1], table[4*i+2], table[4*i+3] );
+    printf( "%2d %7.4f %7.4f %7.4f %7.4f\n", i, table[4*i], table[4*i+1], table[4*i+2], table[4*i+3] );
     }
 
 return 0;
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index be028100..02cc6c23 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -95,6 +95,8 @@
     <string name="minx4" translatable="false">Master Kilominx</string>
     <string name="minx5" translatable="false">Gigaminx</string>
     <string name="ulti2" translatable="false">Skewb Ultimate</string>
+    <string name="squa1" translatable="false">Square-1</string>
+    <string name="squa2" translatable="false">Square-2</string>
 
     <string name="bandaged_fused"  translatable="false">Fused Cube</string>
     <string name="bandaged_2bar"   translatable="false">2Bar Cube</string>
@@ -123,6 +125,8 @@
     <string name="minx4_inventor" translatable="false">David Gugl, 2010</string>
     <string name="minx5_inventor" translatable="false">Tyler Fox, 2006</string>
     <string name="ulti2_inventor" translatable="false">Tony Fisher, 2000</string>
+    <string name="squa1_inventor" translatable="false">Vojtech Kopsky, Harel Hrsel, 1999</string>
+    <string name="squa2_inventor" translatable="false">David Litwin, 1995</string>
 
     <string name="bandaged_fused_inventor"  translatable="false">who knows</string>
     <string name="bandaged_2bar_inventor"   translatable="false">who knows</string>
