commit 626b239fd5cc2a10d33a45a57daaa251086e8d7c
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Fri Mar 24 00:07:32 2023 +0100

    Add Square-0

diff --git a/src/main/java/org/distorted/objectlib/main/ObjectSignatures.java b/src/main/java/org/distorted/objectlib/main/ObjectSignatures.java
index 6a338cac..7921bfe4 100644
--- a/src/main/java/org/distorted/objectlib/main/ObjectSignatures.java
+++ b/src/main/java/org/distorted/objectlib/main/ObjectSignatures.java
@@ -56,6 +56,7 @@ public class ObjectSignatures
   public static final int BAN4_3 = ObjectType.BAN4_3.ordinal();
   public static final int BAN5_4 = ObjectType.BAN5_4.ordinal();
   public static final int BAN6_4 = ObjectType.BAN6_4.ordinal();
+  public static final int SQU0_3 = ObjectType.SQU0_3.ordinal();
   public static final int SQU1_3 = ObjectType.SQU1_3.ordinal();
   public static final int SQU2_3 = ObjectType.SQU2_3.ordinal();
   public static final int WIND_3 = ObjectType.WIND_3.ordinal();
diff --git a/src/main/java/org/distorted/objectlib/objects/TwistySquare0.java b/src/main/java/org/distorted/objectlib/objects/TwistySquare0.java
new file mode 100644
index 00000000..9e2f1f3b
--- /dev/null
+++ b/src/main/java/org/distorted/objectlib/objects/TwistySquare0.java
@@ -0,0 +1,273 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2023 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.objectlib.objects;
+
+import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Static4D;
+import org.distorted.objectlib.helpers.FactoryCubit;
+import org.distorted.objectlib.helpers.ObjectFaceShape;
+import org.distorted.objectlib.helpers.ObjectShape;
+import org.distorted.objectlib.helpers.ObjectSignature;
+import org.distorted.objectlib.helpers.ObjectVertexEffects;
+import org.distorted.objectlib.main.InitAssets;
+import org.distorted.objectlib.main.InitData;
+import org.distorted.objectlib.main.ObjectSignatures;
+import org.distorted.objectlib.main.ObjectType;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class TwistySquare0 extends TwistySquare
+{
+  private int[][] mEdges;
+  private int[] mQuatIndex;
+  private float[][] mCenters;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public TwistySquare0(int meshState, int iconMode, Static4D quat, Static3D move, float scale, InitData data, InitAssets asset)
+    {
+    super(meshState, iconMode, quat, move, scale, data, asset);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int[][] getScrambleEdges()
+    {
+    if( mEdges==null )
+      {
+      mEdges = new int[][]
+        {
+          { 0,2,1,2,2,2,   9,1,10,1,   11,3,12,3,13,3 },     // 0
+          { 0,2,1,2,2,2,               11,3,12,3,13,3 },     // 1 SL
+          {                9,1,10,1,   11,4,12,4,13,4 },     // 2 LO
+          { 0,4,1,4,2,4,   9,1,10,1,                  },     // 3 UP
+          {                9,1,10,1,                  }      // 4 UL
+        };
+      }
+
+    return mEdges;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[][] getCubitPositions(int[] numLayers)
+    {
+    if( mCenters ==null )
+      {
+      mCenters = new float[][]
+        {
+         { 1.5f, 0.0f, 0.0f },
+         {-1.5f, 0.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 },
+        };
+      }
+
+    return mCenters;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public Static4D getCubitQuats(int cubit, int[] numLayers)
+    {
+    if( mQuatIndex==null )
+      {
+      mQuatIndex = new int[]
+        {
+        0, 2,
+        0, 3, 1, 2,
+        0, 3, 1, 2,
+        };
+      }
+
+    return mObjectQuats[mQuatIndex[cubit]];
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float[][] getVertices(int variant)
+    {
+    if( variant==0 )
+      {
+      return new float[][]
+        {
+         { -1.5f-X, 0.5f, 1.5f },
+         {    0.0f, 0.5f, 1.5f },
+         {    0.0f, 0.5f,-1.5f },
+         { -1.5f+X, 0.5f,-1.5f },
+         { -1.5f-X,-0.5f, 1.5f },
+         {    0.0f,-0.5f, 1.5f },
+         {    0.0f,-0.5f,-1.5f },
+         { -1.5f+X,-0.5f,-1.5f }
+        };
+      }
+    else
+      {
+      return new float[][]
+        {
+         { -1.5f-X, 0.5f, 0.0f   },
+         {    0.0f, 0.5f, 0.0f   },
+         {    0.0f, 0.5f,-1.5F+X },
+         {   -1.5f, 0.5f,-1.5f   },
+         { -1.5f-X,-0.5f, 0.0f   },
+         {    0.0f,-0.5f, 0.0f   },
+         {    0.0f,-0.5f,-1.5F+X },
+         {   -1.5f,-0.5f,-1.5f   },
+        };
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public ObjectShape getObjectShape(int variant)
+    {
+    int[][] indices =
+      {
+        {4,5,1,0},
+        {5,6,2,1},
+        {6,7,3,2},
+        {7,4,0,3},
+        {0,1,2,3},
+        {7,6,5,4}
+      };
+
+    return new ObjectShape(getVertices(variant), indices);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public ObjectFaceShape getObjectFaceShape(int variant)
+    {
+    float h1 = isInIconMode() ? 0.001f : 0.04f;
+    float h2 = isInIconMode() ? 0.001f : 0.02f;
+    float[][] bands = { {h1,35,0.2f,0.8f,5,1,0}, {h2,35,0.5f,1.0f,5,1,0}, {0.001f,35,0.3f,0.8f,5,1,0} };
+    int[] indices;
+
+         if( variant==0 ) indices= new int[] { 0,0,1,2,2,2 };
+    else if( variant==1 ) indices= new int[] { 0,0,2,2,0,2 };
+    else                  indices= new int[] { 0,0,2,2,2,0 };
+
+    return new ObjectFaceShape(bands,indices,null);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public ObjectVertexEffects getVertexEffects(int variant)
+    {
+    float[][] corners = { {0.03f,0.05f} };
+    int[] indices     = { 0,0,0,0,0,0,0,0 };
+    float[][] centers = { { -0.75f, 0.0f, variant==0 ? 0.0f : -0.75f } };
+    return FactoryCubit.generateVertexEffect(getVertices(variant),corners,indices,centers,indices);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getNumCubitVariants(int[] numLayers)
+    {
+    return 3;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getCubitVariant(int cubit, int[] numLayers)
+    {
+    return cubit<2 ? 0 : (cubit<6 ? 1:2 );
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float getStickerRadius()
+    {
+    return 0.12f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float getStickerStroke()
+    {
+    return isInIconMode() ? 0.20f : 0.10f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public float[][] getStickerAngles()
+    {
+    return null;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
+
+  public int[][] getBasicAngles()
+    {
+    return new int[][] { {4,4,4},{2,2},{4,4,4} };
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public String getShortName()
+    {
+    return ObjectType.SQU0_3.name();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public ObjectSignature getSignature()
+    {
+    return new ObjectSignature(ObjectSignatures.SQU0_3);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public String getObjectName()
+    {
+    return "Square-0";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public String getInventor()
+    {
+    return "Aleksandra Franc";
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getYearOfInvention()
+    {
+    return 2008;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getComplexity()
+    {
+    return 2;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public String[][] getTutorials()
+    {
+    return new String[][] {
+                           {"gb","RqFhpWTApOo","Square-0 Cube Tutorial","Michele Regano"},
+                           {"es","A6mGEQC06mc","Tutorial Cómo hacer un Square-0","Pablo"},
+                           {"fr","zMIjj46inXg","Résoudre le Square-0","rubik'sIngrid"},
+                          };
+    }
+}
