commit d38f1397569bd66a56a16c5c9849aa6eae280332
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Mon Jan 25 00:59:15 2021 +0100

    Progress with Megaminx.

diff --git a/src/main/java/org/distorted/objects/FactoryCubit.java b/src/main/java/org/distorted/objects/FactoryCubit.java
index 3927cd14..3062307a 100644
--- a/src/main/java/org/distorted/objects/FactoryCubit.java
+++ b/src/main/java/org/distorted/objects/FactoryCubit.java
@@ -1760,4 +1760,14 @@ class FactoryCubit
 
     return mesh;
     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// numLayers==3 --> index=0; numLayers=5 --> index=1 ...
+// type: 0,1,... 0 --> edge, 1 --> 1 layer deeper, etc
+
+  MeshBase createMegaminxEdgeMesh(int index, int type)
+    {
+
+    return createTetraMesh();
+    }
   }
diff --git a/src/main/java/org/distorted/objects/TwistyKilominx.java b/src/main/java/org/distorted/objects/TwistyKilominx.java
index f7188986..bed80076 100644
--- a/src/main/java/org/distorted/objects/TwistyKilominx.java
+++ b/src/main/java/org/distorted/objects/TwistyKilominx.java
@@ -71,7 +71,7 @@ public class TwistyKilominx extends TwistyMinx
 
   private int getQuat(int cubit)
     {
-    return ( cubit>=0 && cubit<20 ) ? QUAT_INDICES[cubit] : 0;
+    return ( cubit>=0 && cubit<20 ) ? QUAT_CORNER_INDICES[cubit] : 0;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objects/TwistyMegaminx.java b/src/main/java/org/distorted/objects/TwistyMegaminx.java
index 78308c9a..74dbae38 100644
--- a/src/main/java/org/distorted/objects/TwistyMegaminx.java
+++ b/src/main/java/org/distorted/objects/TwistyMegaminx.java
@@ -43,34 +43,107 @@ public class TwistyMegaminx extends TwistyMinx
   private static final int NUM_CENTERS = 12;
   private static final int NUM_EDGES   = 30;
 
-  private static final int[][] mFaceVertexMap =
+  // the five vertices that form a given face. Order: the same as colors
+  // of the faces in TwistyMinx.
+  private static final int[][] mCenterMap =
          {
-           { 0, 12,  8, 10, 16},
            { 0, 12,  4, 14,  2},
-           { 2, 14,  9, 11, 18},
            { 0,  2, 18,  6, 16},
-           { 8, 13,  5,  4, 12},
-           { 4,  5, 15,  9, 14},
            { 6, 18, 11, 19,  7},
-           {10, 16,  6,  7, 17},
-           { 1, 13,  8, 10, 17},
-           { 1, 13,  5, 15,  3},
            { 3, 15,  9, 11, 19},
+           { 4,  5, 15,  9, 14},
+           { 1, 13,  5, 15,  3},
            { 1,  3, 19,  7, 17},
+           {10, 16,  6,  7, 17},
+           { 0, 12,  8, 10, 16},
+           { 8, 13,  5,  4, 12},
+           { 1, 13,  8, 10, 17},
+           { 2, 14,  9, 11, 18},
          };
 
-  private static MeshBase[] mCenterMeshes, mCornerMeshes, mEdgeMeshes;
+  // the quadruple ( vertex1, vertex2, face1, face2 ) defining an edge.
+  // In fact the 2 vertices already define it, the faces only provide easy
+  // way to get to know the colors. Order: arbitrary. Face1 arbitrarily on
+  // the 'left' or right of vector vertex1 --> vertex2, according to Quat.
+  private static final int[][] mEdgeMap =
+         {
+           {  0, 12,  0,  8},
+           { 12,  4,  0,  9},
+           {  4, 14,  0,  4},
+           { 14,  2,  0, 11},
+           {  2,  0,  0,  1},
+           { 14,  9,  4, 11},
+           {  9, 11,  3, 11},
+           { 11, 18,  2, 11},
+           { 18,  2,  1, 11},
+           { 18,  6,  2,  1},
+           {  6, 16,  7,  1},
+           { 16,  0,  8,  1},
+           { 16, 10,  8,  7},
+           { 10,  8,  8, 10},
+           {  8, 12,  8,  9},
+           {  8, 13,  9, 10},
+           { 13,  5,  9,  5},
+           {  5,  4,  9,  4},
+           {  5, 15,  4,  5},
+           { 15,  9,  4,  3},
+           { 11, 19,  2,  3},
+           { 19,  7,  2,  6},
+           {  7,  6,  2,  7},
+           {  7, 17,  7,  6},
+           { 17, 10,  7, 10},
+           { 17,  1,  6, 10},
+           {  1,  3,  6,  4},
+           {  3, 19,  6,  3},
+           {  1, 13, 10,  5},
+           {  3, 15,  5,  3},
+         };
 
-  private static final Static4D[] mBasicV, mCurrV;
+  private static final float[][] mCenterCoords = new float[NUM_CENTERS][3];
 
   static
     {
-    mBasicV = new Static4D[3];
-    mCurrV  = new Static4D[3];
+    for(int center=0; center<NUM_CENTERS; center++)
+      {
+      int[] map = mCenterMap[center];
+
+      float x = CORNERS[map[0]].get0() +
+                CORNERS[map[1]].get0() +
+                CORNERS[map[2]].get0() +
+                CORNERS[map[3]].get0() +
+                CORNERS[map[4]].get0() ;
+
+      float y = CORNERS[map[0]].get1() +
+                CORNERS[map[1]].get1() +
+                CORNERS[map[2]].get1() +
+                CORNERS[map[3]].get1() +
+                CORNERS[map[4]].get1() ;
+
+      float z = CORNERS[map[0]].get2() +
+                CORNERS[map[1]].get2() +
+                CORNERS[map[2]].get2() +
+                CORNERS[map[3]].get2() +
+                CORNERS[map[4]].get2() ;
+
+      mCenterCoords[center][0] = x/5;
+      mCenterCoords[center][1] = y/5;
+      mCenterCoords[center][2] = z/5;
+      }
+    }
+
+  private static MeshBase[] mCenterMeshes, mCornerMeshes;
+  private static MeshBase[][] mEdgeMeshes;
+
+  private static final Static4D[] mBasicCornerV, mCurrCornerV;
 
-    mBasicV[0] = new Static4D( (SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
-    mBasicV[1] = new Static4D(-(SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
-    mBasicV[2] = new Static4D(              0,        -0.500f,    0.0f, 0.0f );
+  static
+    {
+    mBasicCornerV = new Static4D[3];
+    mCurrCornerV  = new Static4D[3];
+
+    mBasicCornerV[0] = new Static4D( (SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
+    mBasicCornerV[1] = new Static4D(-(SQ5+1)*0.125f, (SQ5-1)*0.125f, -0.250f, 0.0f );
+    mBasicCornerV[2] = new Static4D(              0,        -0.500f,    0.0f, 0.0f );
     };
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -99,7 +172,7 @@ public class TwistyMegaminx extends TwistyMinx
 
   int getNumStickerTypes(int numLayers)
     {
-    return 1; //numLayers;
+    return numLayers-1; //numLayers;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -129,40 +202,21 @@ public class TwistyMegaminx extends TwistyMinx
 
   private void computeCenter(Static3D[] array, int center)
     {
-    int[] map = mFaceVertexMap[center];
-
-    float x = CORNERS[map[0]].get0() +
-              CORNERS[map[1]].get0() +
-              CORNERS[map[2]].get0() +
-              CORNERS[map[3]].get0() +
-              CORNERS[map[4]].get0() ;
-
-    float y = CORNERS[map[0]].get1() +
-              CORNERS[map[1]].get1() +
-              CORNERS[map[2]].get1() +
-              CORNERS[map[3]].get1() +
-              CORNERS[map[4]].get1() ;
-
-    float z = CORNERS[map[0]].get2() +
-              CORNERS[map[1]].get2() +
-              CORNERS[map[2]].get2() +
-              CORNERS[map[3]].get2() +
-              CORNERS[map[4]].get2() ;
-
-    array[center].set(x/5,y/5,z/5);
+    float[] coords = mCenterCoords[center];
+    array[center].set( coords[0], coords[1], coords[2]);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// Fill out mCurr{X,Y,Z} by applying appropriate Quat to mBasic{X,Y,Z}
+// Fill out mCurrCorner{X,Y,Z} by applying appropriate Quat to mBasicCorner{X,Y,Z}
 // Appropriate one: QUATS[QUAT_INDICES[corner]].
 
-  private void computeBasicVectors(int corner)
+  private void computeBasicCornerVectors(int corner)
     {
-    Static4D quat = QUATS[QUAT_INDICES[corner]];
+    Static4D quat = QUATS[QUAT_CORNER_INDICES[corner]];
 
-    mCurrV[0] = RubikSurfaceView.rotateVectorByQuat(mBasicV[0],quat);
-    mCurrV[1] = RubikSurfaceView.rotateVectorByQuat(mBasicV[1],quat);
-    mCurrV[2] = RubikSurfaceView.rotateVectorByQuat(mBasicV[2],quat);
+    mCurrCornerV[0] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[0],quat);
+    mCurrCornerV[1] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[1],quat);
+    mCurrCornerV[2] = RubikSurfaceView.rotateVectorByQuat(mBasicCornerV[2],quat);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -182,8 +236,8 @@ public class TwistyMegaminx extends TwistyMinx
       int N = (numCubitsPerCorner-1)/3;
       int block = (part-1) % N;
       int index = (part-1) / N;
-      Static4D pri = mCurrV[index];
-      Static4D sec = mCurrV[(index+2)%3];
+      Static4D pri = mCurrCornerV[index];
+      Static4D sec = mCurrCornerV[(index+2)%3];
 
       int multP = (block % ((numLayers-3)/2)) + 1;
       int multS = (block / ((numLayers-3)/2));
@@ -195,11 +249,41 @@ public class TwistyMegaminx extends TwistyMinx
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO
 
-  private void computeEdge(Static3D pos, int edge, int part)
+  private int computeEdgeType(int cubit, int numCubitsPerCorner, int numCubitsPerEdge)
     {
+    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
+    return (part+1)/2;
+    }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void computeEdge(Static3D pos, int numLayers, int edge, int part)
+    {
+    Static3D c1 = CORNERS[ mEdgeMap[edge][0] ];
+    Static3D c2 = CORNERS[ mEdgeMap[edge][1] ];
+    float x = (c1.get0() + c2.get0())/2;
+    float y = (c1.get1() + c2.get1())/2;
+    float z = (c1.get2() + c2.get2())/2;
+
+    if( part==0 )
+      {
+      pos.set(x,y,z);
+      }
+    else
+      {
+      int mult = (part+1)/2;
+      int dir  = (part+1)%2;
+      float[] center = mCenterCoords[ mEdgeMap[edge][dir+2] ];
+
+      float vX = center[0]-x;
+      float vY = center[1]-y;
+      float vZ = center[2]-z;
+
+      float A = mult*(0.5f-MEGA_D)/((1+SQ5/5)*(numLayers-1));
+
+      pos.set( x+A*vX, y+A*vY, z+A*vZ );
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -207,15 +291,15 @@ public class TwistyMegaminx extends TwistyMinx
   Static3D[] getCubitPositions(int numLayers)
     {
     int numCubitsPerCorner = numCubitsPerCorner(numLayers);
-  //  int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
-    int numCubits = NUM_CORNERS*numCubitsPerCorner ;//+ NUM_EDGES*numCubitsPerEdge + NUM_CENTERS;
+    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
+    int numCubits = NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge;// + NUM_CENTERS;
     int index=0;
 
     final Static3D[] CENTERS = new Static3D[numCubits];
 
     for(int corner=0; corner<NUM_CORNERS; corner++)
       {
-      computeBasicVectors(corner);
+      computeBasicCornerVectors(corner);
 
       for(int part=0; part<numCubitsPerCorner; part++, index++)
         {
@@ -223,15 +307,16 @@ public class TwistyMegaminx extends TwistyMinx
         computeCorner(CENTERS[index],numCubitsPerCorner,numLayers,corner,part);
         }
       }
-/*
+
     for(int edge=0; edge<NUM_EDGES; edge++)
       {
       for(int part=0; part<numCubitsPerEdge; part++, index++)
         {
-        computeEdge(CENTERS,index, edge, part );
+        CENTERS[index] = new Static3D(0,0,0);
+        computeEdge(CENTERS[index], numLayers, edge, part );
         }
       }
-
+/*
     for(int center=0; center<NUM_CENTERS; center++, index++)
       {
       computeCenter(CENTERS,index);
@@ -249,32 +334,24 @@ public class TwistyMegaminx extends TwistyMinx
     if( cubit < NUM_CORNERS*numCubitsPerCorner )
       {
       int corner = cubit/numCubitsPerCorner;
-      return QUAT_INDICES[corner];
-      }
-/*
-    if( cubit < NUM_CENTERS + NUM_CORNERS*numCubitsPerCorner )
-      {
-      switch(cubit-NUM_CORNERS*numCubitsPerCorner)
-        {
-        case  0: return  0;
-        case  1: return 52;
-        case  2: return  3;
-        case  3: return 53;
-        case  4: return 59;
-        case  5: return 20;
-        case  6: return 22;
-        case  7: return 58;
-        case  8: return 55;
-        case  9: return 13;
-        case 10: return  1;
-        case 11: return 14;
-        }
+      return QUAT_CORNER_INDICES[corner];
       }
 
     int numCubitsPerEdge = numCubitsPerEdge(numLayers);
 
-    // TODO: edges
+    if( cubit < NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
+      {
+      int edge = (cubit-NUM_CORNERS*numCubitsPerCorner)/numCubitsPerEdge;
+      return QUAT_EDGE_INDICES[edge];
+      }
+
+/*
+    else
+      {
+      // TODO: centers
+      }
 */
+
     return 0;
     }
 
@@ -285,26 +362,35 @@ public class TwistyMegaminx extends TwistyMinx
     int numCubitsPerCorner = numCubitsPerCorner(numLayers);
     int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
     int index = (numLayers-3)/2;
+    int variants = ObjectList.MEGA.getNumVariants();
     MeshBase mesh;
 
-    if( mCornerMeshes==null ) mCornerMeshes = new MeshBase[ObjectList.MEGA.getNumVariants()];
+    if( mCornerMeshes==null ) mCornerMeshes = new MeshBase[variants];
+    if( mEdgeMeshes  ==null ) mEdgeMeshes   = new MeshBase[variants][index+1];
 
-//    if( cubit < NUM_CORNERS*numCubitsPerCorner )
+    if( cubit < NUM_CORNERS*numCubitsPerCorner )
       {
-      if( mCornerMeshes[index]==null ) mCornerMeshes[index] = FactoryCubit.getInstance().createMegaminxCornerMesh(numLayers);
+      if( mCornerMeshes[index]==null )
+        {
+        mCornerMeshes[index] = FactoryCubit.getInstance().createMegaminxCornerMesh(numLayers);
+        }
       mesh = mCornerMeshes[index].copy(true);
       }
-/*
-    else if( cubit<NUM_CENTERS + NUM_CORNERS*numCubitsPerCorner )
+    else //if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
       {
-      if( mCornerMesh==null ) mCornerMesh = FactoryCubit.getInstance().createMegaminxCenterMesh();
-      mesh = mCornerMesh.copy(true);
+      int type = computeEdgeType(cubit,numCubitsPerCorner,numCubitsPerEdge);
+
+      if( mEdgeMeshes[index][type]==null )
+        {
+        mEdgeMeshes[index][type] = FactoryCubit.getInstance().createMegaminxEdgeMesh(index,type);
+        }
+
+      mesh = mEdgeMeshes[index][type].copy(true);
       }
+/*
     else
       {
-      if( mEdgeMesh==null ) mEdgeMesh = new MeshBase[(numLayers-1)/2];
-
-      // TODO
+      // TODO: centers
       }
 */
     MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[getQuat(cubit,numLayers)], new Static3D(0,0,0) );
@@ -314,13 +400,11 @@ public class TwistyMegaminx extends TwistyMinx
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO
 
-  int getFaceColor(int cubit, int cubitface, int numLayers)
+  int getCornerColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner)
     {
     if( cubitface<0 || cubitface>2 ) return NUM_TEXTURES*NUM_FACES;
 
-    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
     int part  = cubit % numCubitsPerCorner;
     int corner= cubit / numCubitsPerCorner;
 
@@ -357,12 +441,58 @@ public class TwistyMegaminx extends TwistyMinx
     return NUM_TEXTURES*NUM_FACES;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getEdgeColor(int cubit, int cubitface, int numLayers, int numCubitsPerCorner, int numCubitsPerEdge)
+    {
+    if( cubitface<0 || cubitface>1 ) return NUM_TEXTURES*NUM_FACES;
+
+    int part = (cubit - NUM_CORNERS*numCubitsPerCorner) % numCubitsPerEdge;
+    int edge = (cubit - NUM_CORNERS*numCubitsPerCorner) / numCubitsPerEdge;
+
+    if( part==0 )
+      {
+      return mEdgeMap[edge][cubitface+2];
+      }
+
+    return cubitface==((part+1)%2) ? mEdgeMap[edge][cubitface+2] : NUM_TEXTURES*NUM_FACES;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
+
+  int getCenterColor(int cubit, int cubitface, int numLayers)
+    {
+    return 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getFaceColor(int cubit, int cubitface, int numLayers)
+    {
+    int numCubitsPerCorner = numCubitsPerCorner(numLayers);
+    int numCubitsPerEdge   = numCubitsPerEdge(numLayers);
+
+    if( cubit < NUM_CORNERS*numCubitsPerCorner )
+      {
+      return getCornerColor(cubit,cubitface,numLayers,numCubitsPerCorner);
+      }
+    else if( cubit<NUM_CORNERS*numCubitsPerCorner + NUM_EDGES*numCubitsPerEdge )
+      {
+      return getEdgeColor(cubit,cubitface,numLayers,numCubitsPerCorner,numCubitsPerEdge);
+      }
+    else
+      {
+      return getCenterColor(cubit,cubitface,numLayers);
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // TODO
 
   void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top)
     {
-    paint.setColor(FACE_COLORS[face]);
+    paint.setColor(FACE_COLORS[face%NUM_FACES]);
     paint.setStyle(Paint.Style.FILL);
     canvas.drawRect(left,top,left+TEXTURE_HEIGHT,top+TEXTURE_HEIGHT,paint);
     }
diff --git a/src/main/java/org/distorted/objects/TwistyMinx.java b/src/main/java/org/distorted/objects/TwistyMinx.java
index 1c0ed99a..7dd3bb9f 100644
--- a/src/main/java/org/distorted/objects/TwistyMinx.java
+++ b/src/main/java/org/distorted/objects/TwistyMinx.java
@@ -192,7 +192,18 @@ abstract class TwistyMinx extends TwistyObject
            {  6, 2, 3 },
          };
 
-  static final int[] QUAT_INDICES = {0,2,3,1,40,31,41,30,39,35,36,34,56,32,43,21,48,28,42,23};
+  static final int[] QUAT_CORNER_INDICES
+    = {
+         0,  2,  3,  1, 40, 31, 41, 30, 39, 35,
+        36, 34, 56, 32, 43, 21, 48, 28, 42, 23
+      };
+
+  static final int[] QUAT_EDGE_INDICES
+    = {
+         0, 56, 40, 43, 59, 35, 34, 42,  3, 25,
+        49, 27, 36, 39, 51, 53, 32, 20, 47, 10,
+        17, 37, 30,  5, 28, 33, 45, 14, 44, 38
+      };
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
