commit 538ee7a6eac0c05e93c447f6217b61bf67bbf0a5
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Mar 16 23:44:03 2021 +0100

    Progress with bandaged cubes.

diff --git a/src/main/java/org/distorted/objects/ObjectList.java b/src/main/java/org/distorted/objects/ObjectList.java
index c31db07c..9ec8c528 100644
--- a/src/main/java/org/distorted/objects/ObjectList.java
+++ b/src/main/java/org/distorted/objects/ObjectList.java
@@ -170,6 +170,36 @@ public enum ObjectList
          5,
          60
        ),
+
+  BAN2 (
+         new int[][] {
+                       {3 , 16, R.raw.mega3, R.drawable.ui_small_mega3, R.drawable.ui_medium_mega3, R.drawable.ui_big_mega3, R.drawable.ui_huge_mega3} ,
+                     },
+         TwistyBandaged2Bar.class,
+         new MovementCube(),
+         5,
+         60
+       ),
+
+  BAN3 (
+         new int[][] {
+                       {3 , 16, R.raw.mega3, R.drawable.ui_small_mega3, R.drawable.ui_medium_mega3, R.drawable.ui_big_mega3, R.drawable.ui_huge_mega3} ,
+                     },
+         TwistyBandaged3Plate.class,
+         new MovementCube(),
+         5,
+         60
+       ),
+
+  BAN4 (
+         new int[][] {
+                       {3 , 16, R.raw.mega3, R.drawable.ui_small_mega3, R.drawable.ui_medium_mega3, R.drawable.ui_big_mega3, R.drawable.ui_huge_mega3} ,
+                     },
+         TwistyBandagedEvil.class,
+         new MovementCube(),
+         5,
+         60
+       ),
   ;
 
   public static final int NUM_OBJECTS = values().length;
@@ -551,19 +581,22 @@ public enum ObjectList
 
     switch(ordinal())
       {
-      case  0: return new TwistyCube         (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case  1: return new TwistyPyraminx     (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case  2: return new TwistyDiamond      (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case  3: return new TwistyDino6        (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case  4: return new TwistyDino4        (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case  5: return new TwistyRedi         (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case  6: return new TwistyHelicopter   (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case  7: return new TwistySkewb        (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case  8: return new TwistyIvy          (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case  9: return new TwistyRex          (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case 10: return new TwistyKilominx     (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case 11: return new TwistyMegaminx     (size, quat, texture, mesh, effects, moves, res, scrWidth);
-      case 12: return new TwistyBandagedFused(size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case  0: return new TwistyCube          (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case  1: return new TwistyPyraminx      (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case  2: return new TwistyDiamond       (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case  3: return new TwistyDino6         (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case  4: return new TwistyDino4         (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case  5: return new TwistyRedi          (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case  6: return new TwistyHelicopter    (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case  7: return new TwistySkewb         (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case  8: return new TwistyIvy           (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case  9: return new TwistyRex           (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case 10: return new TwistyKilominx      (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case 11: return new TwistyMegaminx      (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case 12: return new TwistyBandagedFused (size, quat, texture, mesh, effects, moves, res, scrWidth);
+      case 13: return new TwistyBandaged2Bar(size, quat, texture, mesh, effects, moves, res, scrWidth);
+      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);
       }
 
     return null;
diff --git a/src/main/java/org/distorted/objects/TwistyBandaged2Bar.java b/src/main/java/org/distorted/objects/TwistyBandaged2Bar.java
new file mode 100644
index 00000000..e94cd40c
--- /dev/null
+++ b/src/main/java/org/distorted/objects/TwistyBandaged2Bar.java
@@ -0,0 +1,115 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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 org.distorted.library.main.DistortedEffects;
+import org.distorted.library.main.DistortedTexture;
+import org.distorted.library.mesh.MeshSquare;
+import org.distorted.library.type.Static4D;
+import org.distorted.main.R;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class TwistyBandaged2Bar extends TwistyBandagedAbstract
+{
+  TwistyBandaged2Bar(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
+                     DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
+    {
+    super(size, quat, texture, mesh, effects, moves, ObjectList.BAN2, res, scrWidth);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getCubitVariant(int cubit)
+    {
+    return cubit<=1 ? 2:0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumCubits()
+    {
+    return 22;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float[] getCubitPosition(int cubit)
+    {
+    switch(cubit)
+      {
+      case  0: return new float[] { 0.0f, +1.0f,  0.0f};
+      case  1: return new float[] { 0.0f, -1.0f,  0.0f};
+      case  2: return new float[] {-1.0f, +1.0f, +1.0f};
+      case  3: return new float[] {-1.0f, +1.0f,  0.0f};
+      case  4: return new float[] {-1.0f, +1.0f, -1.0f};
+      case  5: return new float[] {-1.0f,  0.0f, +1.0f};
+      case  6: return new float[] {-1.0f,  0.0f,  0.0f};
+      case  7: return new float[] {-1.0f,  0.0f, -1.0f};
+      case  8: return new float[] {-1.0f, -1.0f, +1.0f};
+      case  9: return new float[] {-1.0f, -1.0f, -1.0f};
+      case 10: return new float[] {+1.0f, +1.0f, +1.0f};
+      case 11: return new float[] {+1.0f, +1.0f,  0.0f};
+      case 12: return new float[] {+1.0f, +1.0f, -1.0f};
+      case 13: return new float[] {+1.0f,  0.0f, +1.0f};
+      case 14: return new float[] {+1.0f,  0.0f,  0.0f};
+      case 15: return new float[] {+1.0f,  0.0f, -1.0f};
+      case 16: return new float[] {+1.0f, -1.0f, +1.0f};
+      case 17: return new float[] {+1.0f, -1.0f, -1.0f};
+      case 18: return new float[] { 0.0f,  0.0f, +1.0f};
+      case 19: return new float[] { 0.0f, -1.0f, +1.0f};
+      case 20: return new float[] { 0.0f,  0.0f, -1.0f};
+      case 21: return new float[] { 0.0f, -1.0f, -1.0f};
+      }
+
+    return null;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getQuatIndex(int cubit)
+    {
+    return cubit==0 ? 2 : 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+
+  public int getObjectName(int numLayers)
+    {
+    return R.string.bandaged_2bar;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getInventor(int numLayers)
+    {
+    return R.string.bandaged_2bar_inventor;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getComplexity(int numLayers)
+    {
+    return 8;
+    }
+}
diff --git a/src/main/java/org/distorted/objects/TwistyBandaged3Plate.java b/src/main/java/org/distorted/objects/TwistyBandaged3Plate.java
new file mode 100644
index 00000000..35bd4741
--- /dev/null
+++ b/src/main/java/org/distorted/objects/TwistyBandaged3Plate.java
@@ -0,0 +1,118 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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 org.distorted.library.main.DistortedEffects;
+import org.distorted.library.main.DistortedTexture;
+import org.distorted.library.mesh.MeshSquare;
+import org.distorted.library.type.Static4D;
+import org.distorted.main.R;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class TwistyBandaged3Plate extends TwistyBandagedAbstract
+{
+  TwistyBandaged3Plate(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
+                       DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
+    {
+    super(size, quat, texture, mesh, effects, moves, ObjectList.BAN1, res, scrWidth);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getCubitVariant(int cubit)
+    {
+    return cubit<=2 ? 3:0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumCubits()
+    {
+    return 17;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float[] getCubitPosition(int cubit)
+    {
+    switch(cubit)
+      {
+      case  0: return new float[] {-0.5f,  0.5f,  1.0f};
+      case  1: return new float[] { 1.0f,  0.5f, -0.5f};
+      case  2: return new float[] {-0.5f, -1.0f, -0.5f};
+
+      case  3: return new float[] { 1.0f,  1.0f,  1.0f};
+      case  4: return new float[] { 1.0f,  0.0f,  1.0f};
+      case  5: return new float[] { 1.0f, -1.0f,  1.0f};
+      case  6: return new float[] {-1.0f, -1.0f,  1.0f};
+      case  7: return new float[] { 0.0f, -1.0f,  1.0f};
+      case  8: return new float[] { 1.0f, -1.0f,  0.0f};
+      case  9: return new float[] { 1.0f, -1.0f, -1.0f};
+
+      case 10: return new float[] {-1.0f,  1.0f, -1.0f};
+      case 11: return new float[] {-1.0f,  1.0f,  0.0f};
+      case 12: return new float[] { 0.0f,  1.0f, -1.0f};
+      case 13: return new float[] { 0.0f,  1.0f,  0.0f};
+      case 14: return new float[] {-1.0f,  0.0f, -1.0f};
+      case 15: return new float[] {-1.0f,  0.0f,  0.0f};
+      case 16: return new float[] { 0.0f,  0.0f, -1.0f};
+      }
+
+    return null;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getQuatIndex(int cubit)
+    {
+    switch(cubit)
+      {
+      case 0: return 1;
+      case 1: return 3;
+      }
+
+    return 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+
+  public int getObjectName(int numLayers)
+    {
+    return R.string.bandaged_3plate;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getInventor(int numLayers)
+    {
+    return R.string.bandaged_3plate_inventor;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getComplexity(int numLayers)
+    {
+    return 8;
+    }
+}
diff --git a/src/main/java/org/distorted/objects/TwistyBandagedAbstract.java b/src/main/java/org/distorted/objects/TwistyBandagedAbstract.java
new file mode 100644
index 00000000..136fd2dc
--- /dev/null
+++ b/src/main/java/org/distorted/objects/TwistyBandagedAbstract.java
@@ -0,0 +1,471 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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.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.RubikSurfaceView;
+
+import java.util.Random;
+
+import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+abstract class TwistyBandagedAbstract extends TwistyObject
+{
+  // the three rotation axis of a 3x3 Cube. Must be normalized.
+  static final Static3D[] ROT_AXIS = new Static3D[]
+         {
+           new Static3D(1,0,0),
+           new Static3D(0,1,0),
+           new Static3D(0,0,1)
+         };
+
+  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(  1.0f,   0.0f,   0.0f,   0.0f),
+         new Static4D(  0.0f,   1.0f,   0.0f,   0.0f),
+         new Static4D(  0.0f,   0.0f,   1.0f,   0.0f),
+
+         new Static4D( SQ2/2,  SQ2/2,  0.0f ,   0.0f),
+         new Static4D( SQ2/2, -SQ2/2,  0.0f ,   0.0f),
+         new Static4D( SQ2/2,   0.0f,  SQ2/2,   0.0f),
+         new Static4D(-SQ2/2,   0.0f,  SQ2/2,   0.0f),
+         new Static4D( SQ2/2,   0.0f,   0.0f,  SQ2/2),
+         new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),
+         new Static4D(  0.0f,  SQ2/2,  SQ2/2,   0.0f),
+         new Static4D(  0.0f,  SQ2/2, -SQ2/2,   0.0f),
+         new Static4D(  0.0f,  SQ2/2,   0.0f,  SQ2/2),
+         new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),
+         new Static4D(  0.0f,   0.0f,  SQ2/2,  SQ2/2),
+         new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),
+
+         new Static4D(  0.5f,   0.5f,   0.5f,   0.5f),
+         new Static4D(  0.5f,   0.5f,  -0.5f,   0.5f),
+         new Static4D(  0.5f,   0.5f,  -0.5f,  -0.5f),
+         new Static4D(  0.5f,  -0.5f,   0.5f,  -0.5f),
+         new Static4D( -0.5f,  -0.5f,  -0.5f,   0.5f),
+         new Static4D( -0.5f,   0.5f,  -0.5f,  -0.5f),
+         new Static4D( -0.5f,   0.5f,   0.5f,  -0.5f),
+         new Static4D( -0.5f,   0.5f,   0.5f,   0.5f)
+         };
+
+  private static final Static4D[] INIT_QUATS = new Static4D[]
+        {
+        new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),  // NULL
+        new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),  // X
+        new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),  // Y
+        new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),  // Z
+        new Static4D( -0.5f,  +0.5f,  -0.5f,  +0.5f),  // ZX
+        new Static4D( +0.5f,  +0.5f,  +0.5f,  -0.5f),  // YX
+        };
+
+  private static final int[][] mDimensions = new int[][]
+        {
+         {1,1,1},  // has to be X>=Z>=Y so that all
+         {2,1,1},  // the faces are horizontal
+         {3,1,1},
+         {2,1,2},
+         {2,2,2}
+        };
+
+  private static final int[][] mStickerDimensions = new int[][]
+        {
+         {1,1},  // dimensions of the faces of
+         {2,1},  // the cuboids defined above
+         {3,1},
+         {2,2}
+        };
+
+  private static final int[][] mFaceMap = new int[][] // cubitface=2 when rotated by
+    {                                                 // quatIndex=1 gets moved to
+        {0,0,5,2,4,2},                                // position mFaceMap[2][1]
+        {1,1,4,3,5,3},
+        {2,4,2,1,1,4},
+        {3,5,3,0,0,5},
+        {4,3,0,4,3,0},
+        {5,2,1,5,2,1}
+    };
+
+  private static final int[][] mAxisMap = new int[][] // axis=1 when rotated by
+    {                                                 // quatIndex=2 gets moved to
+        {0,0,2,1,2,1},                                // axis mAxisMap[1][2]
+        {1,2,1,0,0,2},
+        {2,1,0,2,1,0}
+    };
+
+  private static final int NUM_STICKERS = mStickerDimensions.length;
+
+  private static MeshBase[] mMeshes;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  TwistyBandagedAbstract(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
+                         DistortedEffects effects, int[][] moves, ObjectList list, Resources res, int scrWidth)
+    {
+    super(size, size, quat, texture, mesh, effects, moves, list, res, scrWidth);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  abstract int getCubitVariant(int cubit);
+  abstract int getNumCubits();
+  abstract int getQuatIndex(int cubit);
+  abstract float[] getCubitPosition(int cubit);
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  MeshBase createCubitMesh(int cubit, int numLayers)
+    {
+    if( mMeshes==null )
+      {
+      int LEN = mDimensions.length;
+      mMeshes = new MeshBase[LEN];
+
+      for(int i=0; i<LEN; i++)
+        {
+        mMeshes[i] = FactoryCubit.getInstance().createCuboidMesh(mDimensions[i]);
+        }
+      }
+
+    int variant = getCubitVariant(cubit);
+    MeshBase mesh = mMeshes[variant].copy(true);
+    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( INIT_QUATS[getQuatIndex(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 numFaces = FACE_COLORS.length;
+    int stickerType = face/numFaces;
+    int color = face%numFaces;
+    float X = mStickerDimensions[stickerType][0];
+    float Y = mStickerDimensions[stickerType][1];
+    float MAX = Math.max(X,Y);
+    float R = 0.10f / MAX;
+    float S = 0.08f / MAX;
+    X /= (2*MAX);
+    Y /= (2*MAX);
+
+    float[] vertices = { -X,-Y, +X,-Y, +X,+Y, -X,+Y};
+
+    FactorySticker factory = FactorySticker.getInstance();
+    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[color], R);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  Static3D[] getCubitPositions(int size)
+    {
+    int numCubits = getNumCubits();
+    Static3D[] tmp = new Static3D[numCubits];
+
+    for(int cubit=0; cubit<numCubits; cubit++)
+      {
+      float[] pos = getCubitPosition(cubit);
+      tmp[cubit] = new Static3D(pos[0],pos[1],pos[2]);
+      }
+
+    return tmp;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  Static4D[] getQuats()
+    {
+    return QUATS;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  boolean shouldResetTextureMaps()
+    {
+    return false;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumFaces()
+    {
+    return FACE_COLORS.length;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  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 NUM_STICKERS;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumCubitFaces()
+    {
+    return FACE_COLORS.length;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float getScreenRatio()
+    {
+    return 0.5f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int retStickerIndex(int horzSize, int vertSize)
+    {
+    switch(horzSize)
+      {
+      case 1: return 0;
+      case 2: return vertSize==1 ? 1:3;
+      case 3: return 2;
+      }
+
+    return 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int getStickerIndex(int cubitface, int[] dim)
+    {
+    switch(cubitface)
+      {
+      case 0: case 1: return retStickerIndex(dim[2],dim[1]);
+      case 2: case 3: return retStickerIndex(dim[0],dim[2]);
+      case 4: case 5: return retStickerIndex(dim[0],dim[1]);
+      }
+
+    return 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getFaceColor(int cubit, int cubitface, int numLayers)
+    {
+    int variant      = getCubitVariant(cubit);
+    int[] dim        = mDimensions[variant];
+    float[] pos      = getCubitPosition(cubit);
+    int stickerIndex = getStickerIndex(cubitface,dim);
+    int quatIndex    = getQuatIndex(cubit);
+    int face         = mFaceMap[cubitface][quatIndex];
+    int multiplier   = (face%2)==0 ? 1:-1;
+    int posIndex     = face/2;
+    int dimIndex     = mAxisMap[posIndex][quatIndex];
+    boolean reaches  = multiplier*pos[posIndex] + dim[dimIndex]*0.5f > (numLayers-1)*0.5f;
+
+    int ret=  reaches ? stickerIndex*NUM_FACES + face : NUM_STICKERS*NUM_FACES;
+
+if( cubit==0 )
+  {
+android.util.Log.e("DISTORTED", "cubit="+cubit+" cubitface="+cubitface+" ret="+ret+" stickerIndex="+stickerIndex+" face="+face);
+android.util.Log.e("DISTORTED", "reaches="+reaches+" border="+((numLayers-1)*0.5f)+" left="+(multiplier*pos[posIndex] + dim[dimIndex]*0.5f));
+android.util.Log.e("DISTORTED", "posIndex="+posIndex+" dimIndex="+dimIndex);
+
+  }
+    return ret;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float returnMultiplier()
+    {
+    return getNumLayers();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  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;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getBasicAngle()
+    {
+    return 4;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+
+  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
+    {
+    int numAxis = ROTATION_AXIS.length;
+
+    if( oldRotAxis == START_AXIS )
+      {
+      return rnd.nextInt(numAxis);
+      }
+    else
+      {
+      int newVector = rnd.nextInt(numAxis-1);
+      return (newVector>=oldRotAxis ? newVector+1 : newVector);
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+
+  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
+    {
+    float rowFloat = rnd.nextFloat();
+
+    for(int row=0; row<mRowChances.length; row++)
+      {
+      if( rowFloat<=mRowChances[row] ) return row;
+      }
+
+    return 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public boolean isSolved()
+    {
+    int index = CUBITS[0].mQuatIndex;
+
+    for(int i=1; i<NUM_CUBITS; i++)
+      {
+      if( !thereIsNoVisibleDifference(CUBITS[i], index) ) return false;
+      }
+
+    return true;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
+// then if it were rotated by quaternion 'quat'.
+// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
+// middle squares get interchanged. No visible difference!
+//
+// So: this is true iff the cubit
+// a) is a corner or edge and the quaternions are the same
+// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
+
+  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
+    {
+    if ( cubit.mQuatIndex == quatIndex ) return true;
+
+    int belongsToHowManyFaces = 0;
+    int lastLayer = getNumLayers()-1;
+    float row;
+    final float MAX_ERROR = 0.01f;
+
+    for(int i=0; i<NUM_AXIS; i++)
+      {
+      row = cubit.mRotationRow[i];
+      if( (row          <MAX_ERROR && row          >-MAX_ERROR) ||
+          (row-lastLayer<MAX_ERROR && row-lastLayer>-MAX_ERROR)  ) belongsToHowManyFaces++;
+      }
+
+    switch(belongsToHowManyFaces)
+      {
+      case 0 : return true ;  // 'inside' cubit that does not lie on any face
+      case 1 :                // cubit that lies inside one of the faces
+               Static3D orig = cubit.getOrigPosition();
+               Static4D quat1 = QUATS[quatIndex];
+               Static4D quat2 = QUATS[cubit.mQuatIndex];
+
+               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
+               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
+               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
+
+               float row1, row2;
+               float x1 = rotated1.get0();
+               float y1 = rotated1.get1();
+               float z1 = rotated1.get2();
+               float x2 = rotated2.get0();
+               float y2 = rotated2.get1();
+               float z2 = rotated2.get2();
+
+               for(int i=0; i<NUM_AXIS; i++)
+                 {
+                 row1 = computeRow(x1,y1,z1,i);
+                 row2 = computeRow(x2,y2,z2,i);
+
+                 if( (row1==0 && row2==0) || (row1==lastLayer && row2==lastLayer) ) return true;
+                 }
+               return false;
+
+      default: return false;  // edge or corner
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// only needed for solvers - there are no Bandaged solvers ATM)
+
+  public String retObjectString()
+    {
+    return "";
+    }
+}
diff --git a/src/main/java/org/distorted/objects/TwistyBandagedCube.java b/src/main/java/org/distorted/objects/TwistyBandagedCube.java
deleted file mode 100644
index 5b3f2858..00000000
--- a/src/main/java/org/distorted/objects/TwistyBandagedCube.java
+++ /dev/null
@@ -1,479 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// 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.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.RubikSurfaceView;
-
-import java.util.Random;
-
-import static org.distorted.effects.scramble.ScrambleEffect.START_AXIS;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-abstract class TwistyBandagedCube extends TwistyObject
-{
-  // the three rotation axis of a 3x3 Cube. Must be normalized.
-  static final Static3D[] ROT_AXIS = new Static3D[]
-         {
-           new Static3D(1,0,0),
-           new Static3D(0,1,0),
-           new Static3D(0,0,1)
-         };
-
-  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(  1.0f,   0.0f,   0.0f,   0.0f),
-         new Static4D(  0.0f,   1.0f,   0.0f,   0.0f),
-         new Static4D(  0.0f,   0.0f,   1.0f,   0.0f),
-
-         new Static4D( SQ2/2,  SQ2/2,  0.0f ,   0.0f),
-         new Static4D( SQ2/2, -SQ2/2,  0.0f ,   0.0f),
-         new Static4D( SQ2/2,   0.0f,  SQ2/2,   0.0f),
-         new Static4D(-SQ2/2,   0.0f,  SQ2/2,   0.0f),
-         new Static4D( SQ2/2,   0.0f,   0.0f,  SQ2/2),
-         new Static4D( SQ2/2,   0.0f,   0.0f, -SQ2/2),
-         new Static4D(  0.0f,  SQ2/2,  SQ2/2,   0.0f),
-         new Static4D(  0.0f,  SQ2/2, -SQ2/2,   0.0f),
-         new Static4D(  0.0f,  SQ2/2,   0.0f,  SQ2/2),
-         new Static4D(  0.0f,  SQ2/2,   0.0f, -SQ2/2),
-         new Static4D(  0.0f,   0.0f,  SQ2/2,  SQ2/2),
-         new Static4D(  0.0f,   0.0f,  SQ2/2, -SQ2/2),
-
-         new Static4D(  0.5f,   0.5f,   0.5f,   0.5f),
-         new Static4D(  0.5f,   0.5f,  -0.5f,   0.5f),
-         new Static4D(  0.5f,   0.5f,  -0.5f,  -0.5f),
-         new Static4D(  0.5f,  -0.5f,   0.5f,  -0.5f),
-         new Static4D( -0.5f,  -0.5f,  -0.5f,   0.5f),
-         new Static4D( -0.5f,   0.5f,  -0.5f,  -0.5f),
-         new Static4D( -0.5f,   0.5f,   0.5f,  -0.5f),
-         new Static4D( -0.5f,   0.5f,   0.5f,   0.5f)
-         };
-
-  // possible aspectRatios of cubit faces in case of a bandaged 3x3:
-  // 1/3, 1/2, 2/3, 1, 3/2, 2, 3. Numerator = (1/3)*3!, (1/2)*3!, ...
-  private static final int[] mAspectNumerator3 = new int[] {2,3,4,6,9,12,18};
-  private static final int[] mAspectRatio3     = new int[] {0,0,0,0,0,0,0};
-
-  static final Static4D[] INIT_QUATS = new Static4D[]
-        {
-        new Static4D(  0.0f,   0.0f,   0.0f,   1.0f),  // NULL
-        new Static4D( SQ2/2,   0.0f,   0.0f,  SQ2/2),  // X
-        new Static4D(  0.0f,  SQ2/2,   0.0f,  SQ2/2),  // Y
-        new Static4D(  0.0f,   0.0f,  SQ2/2,  SQ2/2),  // Z
-        new Static4D( -0.5f,  +0.5f,  -0.5f,  -0.5f),  // ZX
-        new Static4D( +0.5f,  +0.5f,  +0.5f,  +0.5f),  // YX
-        };
-
-  private static MeshBase[] mMeshes;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  TwistyBandagedCube(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
-                     DistortedEffects effects, int[][] moves, ObjectList list, Resources res, int scrWidth)
-    {
-    super(size, size, quat, texture, mesh, effects, moves, list, res, scrWidth);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  abstract int getNumCubitVariants();
-  abstract int getCubitVariant(int cubit);
-  abstract int getNumCubits();
-  abstract int[] getCubitDimensions(int variant);
-  abstract Static3D getCubitPosition(int cubit);
-  abstract int getQuatIndex(int cubit);
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  MeshBase createCubitMesh(int cubit, int numLayers)
-    {
-    if( mMeshes==null )
-      {
-      mMeshes = new MeshBase[getNumCubitVariants()];
-      }
-
-    int variant = getCubitVariant(cubit);
-
-    if( mMeshes[variant]==null )
-      {
-      int[] dimensions = getCubitDimensions(variant);
-      mMeshes[variant] = FactoryCubit.getInstance().createCuboidMesh(dimensions);
-      }
-
-    MeshBase mesh = mMeshes[variant].copy(true);
-    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( INIT_QUATS[getQuatIndex(cubit)], new Static3D(0,0,0) );
-    mesh.apply(quat,0xffffffff,0);
-
-    return mesh;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private int getAspectNumerator(int stickerType)
-    {
-    int type=-1;
-    int len = mAspectRatio3.length;
-
-    for(int i=0; i<len; i++)
-      {
-      if( mAspectRatio3[i] != 0 ) type++;
-      if( type==stickerType ) return mAspectNumerator3[i];
-      }
-
-    return 0;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
-    {
-    float R = 0.10f;
-    float S = 0.08f;
-    int numFaces = FACE_COLORS.length;
-    int stickerType = face/numFaces;
-    float ratio = getAspectNumerator(stickerType)/6.0f;
-    float X,Y;
-
-    if( ratio<1.0f )
-      {
-      X = ratio/2;
-      Y = 0.5f;
-      }
-    else
-      {
-      X = 0.5f;
-      Y = 0.5f/ratio;
-      }
-
-    float[] vertices = { -X,-Y, +X,-Y, +X,+Y, -X,+Y};
-
-    FactorySticker factory = FactorySticker.getInstance();
-    factory.drawRoundedPolygon(canvas, paint, left, top, vertices, S, FACE_COLORS[face%numFaces], R);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  Static3D[] getCubitPositions(int size)
-    {
-    int numCubits = getNumCubits();
-    Static3D[] tmp = new Static3D[numCubits];
-
-    for(int cubit=0; cubit<numCubits; cubit++)
-      {
-      tmp[cubit] = getCubitPosition(cubit);
-      }
-
-    return tmp;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  Static4D[] getQuats()
-    {
-    return QUATS;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  boolean shouldResetTextureMaps()
-    {
-    return false;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  int getNumFaces()
-    {
-    return FACE_COLORS.length;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  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)
-    {
-    if( numLayers==3 )
-      {
-      int numVariants = getNumCubitVariants();
-      int len = mAspectNumerator3.length;
-
-      for(int variant=0; variant<numVariants; variant++)
-        {
-        int[] dimensions = getCubitDimensions(variant);
-
-        int ratio0 = 6*dimensions[0]/dimensions[1];
-        int ratio1 = 6*dimensions[0]/dimensions[2];
-        int ratio2 = 6*dimensions[2]/dimensions[1];
-
-        for(int i=0; i<len; i++)
-          {
-          if( mAspectNumerator3[i]==ratio0 ||
-              mAspectNumerator3[i]==ratio1 ||
-              mAspectNumerator3[i]==ratio2  ) mAspectRatio3[i]++;
-          }
-        }
-
-      int result=0;
-
-      for(int i=0; i<len; i++)
-        {
-        if( mAspectRatio3[i]>0 ) result++;
-        }
-
-      return result;
-      }
-
-    return 1;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  int getNumCubitFaces()
-    {
-    return FACE_COLORS.length;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  float getScreenRatio()
-    {
-    return 0.5f;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  int getFaceColor(int cubit, int cubitface, int numLayers)
-    {
-    int X=0,Y=0,Z=0;
-    int variant = getCubitVariant(cubit);
-    int[] dim = getCubitDimensions(variant);
-    Static3D pos = getCubitPosition(cubit);
-
-    switch( getQuatIndex(cubit) )
-      {
-      case 0: X= dim[0]; Y=dim[1]; Z=dim[2]; break;
-      case 1: X= dim[0]; Y=dim[2]; Z=dim[1]; break;
-      case 2: X= dim[2]; Y=dim[1]; Z=dim[0]; break;
-      case 3: X= dim[1]; Y=dim[0]; Z=dim[2]; break;
-      case 4: X= dim[1]; Y=dim[2]; Z=dim[0]; break;
-      case 5: X= dim[2]; Y=dim[0]; Z=dim[1]; break;
-      }
-
-    float posX = pos.get0();
-    float posY = pos.get1();
-    float posZ = pos.get2();
-    float border = (numLayers-1)*0.5f;
-    int ret = NUM_FACES;
-
-    switch(cubitface)
-      {
-      case 0: ret = posX + X*0.5f > border ? cubitface : NUM_FACES; break;
-      case 1: ret = posX - X*0.5f <-border ? cubitface : NUM_FACES; break;
-      case 2: ret = posY + Y*0.5f > border ? cubitface : NUM_FACES; break;
-      case 3: ret = posY - Y*0.5f <-border ? cubitface : NUM_FACES; break;
-      case 4: ret = posZ + Z*0.5f > border ? cubitface : NUM_FACES; break;
-      case 5: ret = posZ - Z*0.5f <-border ? cubitface : NUM_FACES; break;
-      }
-
-    return ret;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  float returnMultiplier()
-    {
-    return getNumLayers();
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  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;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public int getBasicAngle()
-    {
-    return 4;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO
-
-  public int randomizeNewRotAxis(Random rnd, int oldRotAxis)
-    {
-    int numAxis = ROTATION_AXIS.length;
-
-    if( oldRotAxis == START_AXIS )
-      {
-      return rnd.nextInt(numAxis);
-      }
-    else
-      {
-      int newVector = rnd.nextInt(numAxis-1);
-      return (newVector>=oldRotAxis ? newVector+1 : newVector);
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO
-
-  public int randomizeNewRow(Random rnd, int oldRotAxis, int oldRow, int newRotAxis)
-    {
-    float rowFloat = rnd.nextFloat();
-
-    for(int row=0; row<mRowChances.length; row++)
-      {
-      if( rowFloat<=mRowChances[row] ) return row;
-      }
-
-    return 0;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public boolean isSolved()
-    {
-    int index = CUBITS[0].mQuatIndex;
-
-    for(int i=1; i<NUM_CUBITS; i++)
-      {
-      if( !thereIsNoVisibleDifference(CUBITS[i], index) ) return false;
-      }
-
-    return true;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// return if the Cubit, when rotated with its own mQuatScramble, would have looked any different
-// then if it were rotated by quaternion 'quat'.
-// No it is not so simple as the quats need to be the same - imagine a 4x4x4 cube where the two
-// middle squares get interchanged. No visible difference!
-//
-// So: this is true iff the cubit
-// a) is a corner or edge and the quaternions are the same
-// b) is inside one of the faces and after rotations by both quats it ends up on the same face.
-
-  private boolean thereIsNoVisibleDifference(Cubit cubit, int quatIndex)
-    {
-    if ( cubit.mQuatIndex == quatIndex ) return true;
-
-    int belongsToHowManyFaces = 0;
-    int lastLayer = getNumLayers()-1;
-    float row;
-    final float MAX_ERROR = 0.01f;
-
-    for(int i=0; i<NUM_AXIS; i++)
-      {
-      row = cubit.mRotationRow[i];
-      if( (row          <MAX_ERROR && row          >-MAX_ERROR) ||
-          (row-lastLayer<MAX_ERROR && row-lastLayer>-MAX_ERROR)  ) belongsToHowManyFaces++;
-      }
-
-    switch(belongsToHowManyFaces)
-      {
-      case 0 : return true ;  // 'inside' cubit that does not lie on any face
-      case 1 :                // cubit that lies inside one of the faces
-               Static3D orig = cubit.getOrigPosition();
-               Static4D quat1 = QUATS[quatIndex];
-               Static4D quat2 = QUATS[cubit.mQuatIndex];
-
-               Static4D cubitCenter = new Static4D( orig.get0(), orig.get1(), orig.get2(), 0);
-               Static4D rotated1 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat1 );
-               Static4D rotated2 = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat2 );
-
-               float row1, row2;
-               float x1 = rotated1.get0();
-               float y1 = rotated1.get1();
-               float z1 = rotated1.get2();
-               float x2 = rotated2.get0();
-               float y2 = rotated2.get1();
-               float z2 = rotated2.get2();
-
-               for(int i=0; i<NUM_AXIS; i++)
-                 {
-                 row1 = computeRow(x1,y1,z1,i);
-                 row2 = computeRow(x2,y2,z2,i);
-
-                 if( (row1==0 && row2==0) || (row1==lastLayer && row2==lastLayer) ) return true;
-                 }
-               return false;
-
-      default: return false;  // edge or corner
-      }
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// only needed for solvers - there are no Ivy solvers ATM)
-
-  public String retObjectString()
-    {
-    return "";
-    }
-}
diff --git a/src/main/java/org/distorted/objects/TwistyBandagedEvil.java b/src/main/java/org/distorted/objects/TwistyBandagedEvil.java
new file mode 100644
index 00000000..e6d48c59
--- /dev/null
+++ b/src/main/java/org/distorted/objects/TwistyBandagedEvil.java
@@ -0,0 +1,123 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// 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 org.distorted.library.main.DistortedEffects;
+import org.distorted.library.main.DistortedTexture;
+import org.distorted.library.mesh.MeshSquare;
+import org.distorted.library.type.Static4D;
+import org.distorted.main.R;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class TwistyBandagedEvil extends TwistyBandagedAbstract
+{
+  TwistyBandagedEvil(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
+                     DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
+    {
+    super(size, quat, texture, mesh, effects, moves, ObjectList.BAN1, res, scrWidth);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getCubitVariant(int cubit)
+    {
+    switch(cubit)
+      {
+      case 0: return 0;
+      case 1: return 3;
+      }
+
+    return 1;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumCubits()
+    {
+    return 13;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  float[] getCubitPosition(int cubit)
+    {
+    switch(cubit)
+      {
+      case  0: return new float[] { 1.0f,  1.0f, -1.0f};
+      case  1: return new float[] {-0.5f, -0.5f,  0.0f};
+      case  2: return new float[] {-0.5f,  1.0f, -1.0f};
+      case  3: return new float[] {-0.5f,  0.0f, -1.0f};
+      case  4: return new float[] {-0.5f, -1.0f, -1.0f};
+      case  5: return new float[] {-1.0f,  1.0f,  0.5f};
+      case  6: return new float[] { 0.0f,  1.0f,  0.5f};
+      case  7: return new float[] { 1.0f,  1.0f,  0.5f};
+      case  8: return new float[] {-1.0f, -0.5f,  1.0f};
+      case  9: return new float[] { 0.0f, -0.5f,  1.0f};
+      case 10: return new float[] { 1.0f, -0.5f,  1.0f};
+      case 11: return new float[] { 1.0f, -0.5f,  0.0f};
+      case 12: return new float[] { 1.0f, -0.5f, -1.0f};
+      }
+
+    return null;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getQuatIndex(int cubit)
+    {
+    switch(cubit)
+      {
+      case 1: return 1;
+      case 0:
+      case 2:
+      case 3:
+      case 4: return 0;
+      case 5:
+      case 6:
+      case 7: return 2;
+      default:return 3;
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+
+  public int getObjectName(int numLayers)
+    {
+    return R.string.bandaged_evil;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getInventor(int numLayers)
+    {
+    return R.string.bandaged_evil_inventor;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getComplexity(int numLayers)
+    {
+    return 8;
+    }
+}
diff --git a/src/main/java/org/distorted/objects/TwistyBandagedFused.java b/src/main/java/org/distorted/objects/TwistyBandagedFused.java
index d6e2746d..39a9b769 100644
--- a/src/main/java/org/distorted/objects/TwistyBandagedFused.java
+++ b/src/main/java/org/distorted/objects/TwistyBandagedFused.java
@@ -24,13 +24,12 @@ import android.content.res.Resources;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshSquare;
-import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 import org.distorted.main.R;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class TwistyBandagedFused extends TwistyBandagedCube
+class TwistyBandagedFused extends TwistyBandagedAbstract
 {
   TwistyBandagedFused(int size, Static4D quat, DistortedTexture texture, MeshSquare mesh,
                       DistortedEffects effects, int[][] moves, Resources res, int scrWidth)
@@ -38,18 +37,11 @@ class TwistyBandagedFused extends TwistyBandagedCube
     super(size, quat, texture, mesh, effects, moves, ObjectList.BAN1, res, scrWidth);
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  int getNumCubitVariants()
-    {
-    return 2;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   int getCubitVariant(int cubit)
     {
-    return cubit==0 ? 0:1;
+    return cubit==0 ? 4:0;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -61,37 +53,30 @@ class TwistyBandagedFused extends TwistyBandagedCube
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  int[] getCubitDimensions(int variant)
-    {
-    return variant==0 ? new int[] {2,2,2} : new int[] {1,1,1};
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  Static3D getCubitPosition(int cubit)
+  float[] getCubitPosition(int cubit)
     {
     switch(cubit)
       {
-      case  0: return new Static3D(-0.5f, -0.5f, +0.5f);
-      case  1: return new Static3D(-1.0f, +1.0f, +1.0f);
-      case  2: return new Static3D(-1.0f, +1.0f, +0.0f);
-      case  3: return new Static3D(-1.0f, +1.0f, -1.0f);
-      case  4: return new Static3D( 0.0f, +1.0f, +1.0f);
-      case  5: return new Static3D( 0.0f, +1.0f, +0.0f);
-      case  6: return new Static3D( 0.0f, +1.0f, -1.0f);
-      case  7: return new Static3D( 1.0f, +1.0f, +1.0f);
-      case  8: return new Static3D( 1.0f, +1.0f, +0.0f);
-      case  9: return new Static3D( 1.0f, +1.0f, -1.0f);
-      case 10: return new Static3D( 1.0f,  0.0f, +1.0f);
-      case 11: return new Static3D( 1.0f,  0.0f, +0.0f);
-      case 12: return new Static3D( 1.0f,  0.0f, -1.0f);
-      case 13: return new Static3D( 1.0f, -1.0f, +1.0f);
-      case 14: return new Static3D( 1.0f, -1.0f, +0.0f);
-      case 15: return new Static3D( 1.0f, -1.0f, -1.0f);
-      case 16: return new Static3D(-1.0f, -1.0f, -1.0f);
-      case 17: return new Static3D(-1.0f,  0.0f, -1.0f);
-      case 18: return new Static3D( 0.0f, -1.0f, -1.0f);
-      case 19: return new Static3D( 0.0f,  0.0f, -1.0f);
+      case  0: return new float[] {-0.5f, -0.5f, +0.5f};
+      case  1: return new float[] {-1.0f, +1.0f, +1.0f};
+      case  2: return new float[] {-1.0f, +1.0f, +0.0f};
+      case  3: return new float[] {-1.0f, +1.0f, -1.0f};
+      case  4: return new float[] { 0.0f, +1.0f, +1.0f};
+      case  5: return new float[] { 0.0f, +1.0f, +0.0f};
+      case  6: return new float[] { 0.0f, +1.0f, -1.0f};
+      case  7: return new float[] { 1.0f, +1.0f, +1.0f};
+      case  8: return new float[] { 1.0f, +1.0f, +0.0f};
+      case  9: return new float[] { 1.0f, +1.0f, -1.0f};
+      case 10: return new float[] { 1.0f,  0.0f, +1.0f};
+      case 11: return new float[] { 1.0f,  0.0f, +0.0f};
+      case 12: return new float[] { 1.0f,  0.0f, -1.0f};
+      case 13: return new float[] { 1.0f, -1.0f, +1.0f};
+      case 14: return new float[] { 1.0f, -1.0f, +0.0f};
+      case 15: return new float[] { 1.0f, -1.0f, -1.0f};
+      case 16: return new float[] {-1.0f, -1.0f, -1.0f};
+      case 17: return new float[] {-1.0f,  0.0f, -1.0f};
+      case 18: return new float[] { 0.0f, -1.0f, -1.0f};
+      case 19: return new float[] { 0.0f,  0.0f, -1.0f};
       }
 
     return null;
@@ -106,33 +91,17 @@ class TwistyBandagedFused extends TwistyBandagedCube
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
-// TODO
 
   public int getObjectName(int numLayers)
     {
-    switch(numLayers)
-      {
-      case 2: return R.string.cube2;
-      case 3: return R.string.cube3;
-      case 4: return R.string.cube4;
-      case 5: return R.string.cube5;
-      }
-    return R.string.cube3;
+    return R.string.bandaged_fused;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO
 
   public int getInventor(int numLayers)
     {
-    switch(numLayers)
-      {
-      case 2: return R.string.cube2_inventor;
-      case 3: return R.string.cube3_inventor;
-      case 4: return R.string.cube4_inventor;
-      case 5: return R.string.cube5_inventor;
-      }
-    return R.string.cube3_inventor;
+    return R.string.bandaged_fused_inventor;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 0e43b3bc..eece07cb 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -92,6 +92,11 @@
     <string name="minx3" translatable="false">Megaminx</string>
     <string name="minx4" translatable="false">Gigaminx</string>
 
+    <string name="bandaged_fused"  translatable="false">Fused Cube</string>
+    <string name="bandaged_2bar"   translatable="false">2Bar Cube</string>
+    <string name="bandaged_3plate" translatable="false">3Plate Cube</string>
+    <string name="bandaged_evil"   translatable="false">Evil Cube</string>
+
     <string name="cube2_inventor" translatable="false">Larry Nichols, 1970</string>
     <string name="cube3_inventor" translatable="false">Ernő Rubik, 1974</string>
     <string name="cube4_inventor" translatable="false">Péter Sebestény, 1981</string>
@@ -112,4 +117,9 @@
     <string name="minx3_inventor" translatable="false">Ferenc Szlivka, 1982</string>
     <string name="minx4_inventor" translatable="false">Tyler Fox, 2006</string>
 
+    <string name="bandaged_fused_inventor"  translatable="false">who knows</string>
+    <string name="bandaged_2bar_inventor"   translatable="false">who knows</string>
+    <string name="bandaged_3plate_inventor" translatable="false">who knows</string>
+    <string name="bandaged_evil_inventor"   translatable="false">who knows</string>
+
 </resources>
