commit 8f53e513f78aa0a22e2b667cbc00f79c670721f9
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Sat Aug 1 22:37:04 2020 +0100

    Progress with the Dino.

diff --git a/src/main/java/org/distorted/objects/RubikCube.java b/src/main/java/org/distorted/objects/RubikCube.java
index 4682faa7..4c48de1d 100644
--- a/src/main/java/org/distorted/objects/RubikCube.java
+++ b/src/main/java/org/distorted/objects/RubikCube.java
@@ -152,6 +152,13 @@ class RubikCube extends RubikObject
     return FACE_COLORS.length;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumCubitFaces()
+    {
+    return FACE_COLORS.length;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   float getScreenRatio()
diff --git a/src/main/java/org/distorted/objects/RubikDino.java b/src/main/java/org/distorted/objects/RubikDino.java
index 731c9e59..8e31b318 100644
--- a/src/main/java/org/distorted/objects/RubikDino.java
+++ b/src/main/java/org/distorted/objects/RubikDino.java
@@ -23,10 +23,22 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import org.distorted.library.effect.MatrixEffectMove;
+import org.distorted.library.effect.MatrixEffectQuaternion;
+import org.distorted.library.effect.MatrixEffectRotate;
+import org.distorted.library.effect.MatrixEffectScale;
+import org.distorted.library.effect.VertexEffectDeform;
+import org.distorted.library.effect.VertexEffectMove;
+import org.distorted.library.effect.VertexEffectRotate;
+import org.distorted.library.effect.VertexEffectScale;
+import org.distorted.library.effect.VertexEffectSink;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshBase;
+import org.distorted.library.mesh.MeshJoined;
 import org.distorted.library.mesh.MeshRectangles;
+import org.distorted.library.mesh.MeshTriangles;
+import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
@@ -34,7 +46,9 @@ import org.distorted.library.type.Static4D;
 
 public class RubikDino extends RubikObject
 {
-  static final float SQ3 = (float)Math.sqrt(3);
+  private static final float SQ2 = (float)Math.sqrt(2);
+  private static final float SQ3 = (float)Math.sqrt(3);
+  private static final float ANGLE_FACES = (float)((180/Math.PI)*(2*Math.asin(SQ3/3))); // angle between two faces of a tetrahedron
 
   // the four rotation axis of a RubikDino. Must be normalized.
   static final Static3D[] AXIS = new Static3D[]
@@ -47,29 +61,46 @@ public class RubikDino extends RubikObject
 
   private static final int[] FACE_COLORS = new int[]
          {
-           0xffffff00, 0xffffffff,   // AXIS[0]right (right-YELLOW) AXIS[0]left (left  -WHITE)
-           0xff0000ff, 0xff00ff00,   // AXIS[1]right (top  -BLUE  ) AXIS[1]left (bottom-GREEN)
-           0xffff0000, 0xffb5651d    // AXIS[2]right (front-RED   ) AXIS[2]left (back  -BROWN)
+           0xffffff00, 0xffffffff,   // (right-YELLOW) (left  -WHITE)
+           0xff0000ff, 0xff00ff00,   // (top  -BLUE  ) (bottom-GREEN)
+           0xffff0000, 0xffb5651d    // (front-RED   ) (back  -BROWN)
          };
 
   // All legal rotation quats of a RubikDino
   private static final Static4D[] QUATS = new Static4D[]
          {
            new Static4D(  0.0f,  0.0f,  0.0f,  1.0f ),
+           new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
+           new Static4D(  0.0f,  1.0f,  0.0f,  0.0f ),
+           new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
            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 ),
            new Static4D(  0.5f, -0.5f,  0.5f, -0.5f ),
-           new Static4D(  0.5f, -0.5f, -0.5f, -0.5f ),
-           new Static4D(  1.0f,  0.0f,  0.0f,  0.0f ),
-           new Static4D(  0.0f,  0.0f,  1.0f,  0.0f ),
-           new Static4D(  0.0f, -1.0f,  0.0f,  0.0f )
+           new Static4D(  0.5f, -0.5f, -0.5f,  0.5f ),
+           new Static4D(  0.5f, -0.5f, -0.5f, -0.5f )
          };
 
-  private static MeshBase[] mMeshes;
+  // centers of the 12 edges. Must be in the same order like QUATs above.
+  private static final Static3D[] CENTERS = new Static3D[]
+         {
+           new Static3D( 0.0f, 0.5f, 0.5f ),
+           new Static3D( 0.0f,-0.5f, 0.5f ),
+           new Static3D( 0.0f, 0.5f,-0.5f ),
+           new Static3D( 0.0f,-0.5f,-0.5f ),
+           new Static3D( 0.5f, 0.5f, 0.0f ),
+           new Static3D( 0.5f, 0.0f, 0.5f ),
+           new Static3D(-0.5f, 0.0f,-0.5f ),
+           new Static3D( 0.5f,-0.5f, 0.0f ),
+           new Static3D( 0.5f, 0.0f,-0.5f ),
+           new Static3D(-0.5f,-0.5f, 0.0f ),
+           new Static3D(-0.5f, 0.5f, 0.0f ),
+           new Static3D(-0.5f, 0.0f, 0.5f )
+         };
+
+  private static MeshBase mMesh;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -79,11 +110,125 @@ public class RubikDino extends RubikObject
     super(size, 60, quat, texture, mesh, effects, moves, RubikObjectList.DINO, res, scrWidth);
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private MeshBase createTetrahedronMesh()
+    {
+    final float SQ2 = (float)Math.sqrt(2);
+    final float SQ3 = (float)Math.sqrt(3);
+    final int MESHES=4;
+
+    int association = 1;
+    MeshBase[] meshes = new MeshTriangles[MESHES];
+
+    meshes[0] = new MeshTriangles(9);
+    meshes[0].setEffectAssociation(0,association,0);
+
+    for(int i=1; i<MESHES; i++)
+      {
+      association <<= 1;
+      meshes[i] = meshes[0].copy(true);
+      meshes[i].setEffectAssociation(0,association,0);
+      }
+
+    MeshBase result = new MeshJoined(meshes);
+
+    Static3D a0 = new Static3D(         0,        1,       0 );
+    Static3D a1 = new Static3D(         0,  -1.0f/3, 2*SQ2/3 );
+    Static3D a2 = new Static3D(-SQ2*SQ3/3,  -1.0f/3,  -SQ2/3 );
+    Static3D a3 = new Static3D( SQ2*SQ3/3,  -1.0f/3,  -SQ2/3 );
+
+    float tetraHeight = SQ2*SQ3/3;
+    float d1 = 0.75f*tetraHeight;
+    float d2 =-0.10f*tetraHeight;
+    float d3 = 0.20f*tetraHeight;
+
+    Static3D dCen0 = new Static3D( d1*a0.get0(), d1*a0.get1(), d1*a0.get2() );
+    Static3D dCen1 = new Static3D( d1*a1.get0(), d1*a1.get1(), d1*a1.get2() );
+    Static3D dCen2 = new Static3D( d1*a2.get0(), d1*a2.get1(), d1*a2.get2() );
+    Static3D dCen3 = new Static3D( d1*a3.get0(), d1*a3.get1(), d1*a3.get2() );
+
+    Static3D dVec0 = new Static3D( d2*a0.get0(), d2*a0.get1(), d2*a0.get2() );
+    Static3D dVec1 = new Static3D( d2*a1.get0(), d2*a1.get1(), d2*a1.get2() );
+    Static3D dVec2 = new Static3D( d2*a2.get0(), d2*a2.get1(), d2*a2.get2() );
+    Static3D dVec3 = new Static3D( d2*a3.get0(), d2*a3.get1(), d2*a3.get2() );
+
+    Static4D dReg  = new Static4D(0,0,0,d3);
+    Static1D dRad  = new Static1D(1);
+
+    Static1D angle  = new Static1D(ANGLE_FACES);
+    Static3D axis1  = new Static3D(  -1, 0,      0);
+    Static3D axis2  = new Static3D(0.5f, 0, -SQ3/2);
+    Static3D axis3  = new Static3D(0.5f, 0, +SQ3/2);
+    Static3D center1= new Static3D(0,-SQ3*SQ2/12,-SQ3/6);
+    Static3D center2= new Static3D(0,-SQ3*SQ2/12,+SQ3/3);
+
+    Static3D center = new Static3D(0,0,0);
+    Static4D region = new Static4D(0,0,0,0.6f);
+
+    VertexEffectScale   effect1 = new VertexEffectScale ( new Static3D(1,SQ3/2,1) );
+    VertexEffectRotate  effect2 = new VertexEffectRotate( new Static1D(90), new Static3D(1,0,0), new Static3D(0,0,0) );
+    VertexEffectMove    effect3 = new VertexEffectMove  ( new Static3D(0,-SQ3*SQ2/12,SQ3/12) );
+    VertexEffectRotate  effect4 = new VertexEffectRotate( new Static1D(180), new Static3D(0,0,1), center1 );
+    VertexEffectRotate  effect5 = new VertexEffectRotate( angle, axis1, center1 );
+    VertexEffectRotate  effect6 = new VertexEffectRotate( angle, axis2, center2 );
+    VertexEffectRotate  effect7 = new VertexEffectRotate( angle, axis3, center2 );
+
+    VertexEffectDeform  effect8 = new VertexEffectDeform(dVec0, dRad, dCen0, dReg);
+    VertexEffectDeform  effect9 = new VertexEffectDeform(dVec1, dRad, dCen1, dReg);
+    VertexEffectDeform  effect10= new VertexEffectDeform(dVec2, dRad, dCen2, dReg);
+    VertexEffectDeform  effect11= new VertexEffectDeform(dVec3, dRad, dCen3, dReg);
+
+    VertexEffectSink effect12= new VertexEffectSink( new Static1D(1.3f), center, region );
+
+    effect4.setMeshAssociation(14,-1);  // apply to mesh[1], [2] and [3]
+    effect5.setMeshAssociation( 2,-1);  // apply only to mesh[1]
+    effect6.setMeshAssociation( 4,-1);  // apply only to mesh[2]
+    effect7.setMeshAssociation( 8,-1);  // apply only to mesh[3]
+
+    result.apply(effect1);
+    result.apply(effect2);
+    result.apply(effect3);
+    result.apply(effect4);
+    result.apply(effect5);
+    result.apply(effect6);
+    result.apply(effect7);
+    result.apply(effect8);
+    result.apply(effect9);
+    result.apply(effect10);
+    result.apply(effect11);
+    result.apply(effect12);
+
+    result.mergeEffComponents();
+
+    return result;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void createBasicMesh()
+    {
+    mMesh = createTetrahedronMesh();
+
+    Static3D axis = new Static3D(1,0,0);
+    Static3D cent = new Static3D(0,0,0);
+
+    MatrixEffectMove   moveEffect = new MatrixEffectMove  ( new Static3D(0.0f,SQ3*SQ2/12,SQ3/6) );
+    MatrixEffectRotate rot1Effect = new MatrixEffectRotate( new Static1D(180+ANGLE_FACES/2), axis, cent);
+    MatrixEffectScale  scalEffect = new MatrixEffectScale ( new Static3D(1.0f, SQ2/2, SQ2*SQ3/6) );
+    MatrixEffectRotate rot2Effect = new MatrixEffectRotate( new Static1D(-45), axis, cent);
+
+    mMesh.apply(moveEffect,0xffffffff,0);
+    mMesh.apply(rot1Effect,0xffffffff,0);
+    mMesh.apply(scalEffect,0xffffffff,0);
+    mMesh.apply(rot2Effect,0xffffffff,0);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   float getScreenRatio()
     {
-    return 0.5f;
+    return 1.0f;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -102,20 +247,29 @@ public class RubikDino extends RubikObject
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  Static3D[] getCubitPositions(int size)
+  int getNumCubitFaces()
     {
-    // TODO
+    return 4;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    return null;
+  Static3D[] getCubitPositions(int size)
+    {
+    return CENTERS;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   MeshBase createCubitMesh(int cubit)
     {
-    // TODO
+    if( mMesh==null ) createBasicMesh();
+
+    MeshBase mesh = mMesh.copy(true);
+    MatrixEffectQuaternion quat = new MatrixEffectQuaternion( QUATS[cubit], new Static3D(0,0,0) );
+    mesh.apply(quat,0xffffffff,0);
 
-    return null;
+    return mesh;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objects/RubikObject.java b/src/main/java/org/distorted/objects/RubikObject.java
index 6231ada8..2cee6464 100644
--- a/src/main/java/org/distorted/objects/RubikObject.java
+++ b/src/main/java/org/distorted/objects/RubikObject.java
@@ -58,7 +58,7 @@ public abstract class RubikObject extends DistortedNode
   private static final float MAX_SIZE_CHANGE = 1.3f;
   private static final float MIN_SIZE_CHANGE = 0.8f;
 
-  private static boolean mCreateFromDMesh = true;
+  private static boolean mCreateFromDMesh = false;
 
   private static final Static3D CENTER = new Static3D(0,0,0);
   static final int INTERIOR_COLOR = 0xff000000;
@@ -68,6 +68,7 @@ public abstract class RubikObject extends DistortedNode
   final Static3D[] ROTATION_AXIS;
   final Static4D[] QUATS;
   final int NUM_FACES;
+  final int NUM_CUBIT_FACES;
 
   private static float mInitScreenRatio,mObjectScreenRatio;
 
@@ -116,6 +117,7 @@ public abstract class RubikObject extends DistortedNode
     mObjectScreenRatio = getScreenRatio();
     mInitScreenRatio = mObjectScreenRatio;
     NUM_FACES = getNumFaces();
+    NUM_CUBIT_FACES = getNumCubitFaces();
 
     mSize = size;
     computeStartAndStep(mOrigPos);
@@ -494,11 +496,11 @@ public abstract class RubikObject extends DistortedNode
 
     for(int cubit=0; cubit<NUM_CUBITS; cubit++)
       {
-      final Static4D[] maps = new Static4D[NUM_FACES];
+      final Static4D[] maps = new Static4D[NUM_CUBIT_FACES];
 
       if( 2*ROTATION_AXIS.length == NUM_FACES )  // i.e. there are faces on both ends of the axis (cube)
         {
-        for(int i=0; i<NUM_FACES; i++)
+        for(int i=0; i<NUM_CUBIT_FACES; i++)
           {
           belongs = isOnFace(cubit, i/2, i%2==0 ? mSize-1:0 );
           maps[i] = new Static4D( (belongs?i:NUM_FACES)*ratio, 0.0f, ratio, 1.0f);
@@ -506,14 +508,22 @@ public abstract class RubikObject extends DistortedNode
         }
       else if( ROTATION_AXIS.length == NUM_FACES )  // just a single face on the right end of an axis (pyraminx)
         {
-        for(int i=0; i<NUM_FACES; i++)
+        for(int i=0; i<NUM_CUBIT_FACES; i++)
           {
           belongs = isOnFace(cubit, i, 0 );
           maps[i] = new Static4D( (belongs?i:NUM_FACES)*ratio, 0.0f, ratio, 1.0f);
           }
         }
+      else if( 3*ROTATION_AXIS.length == 2*NUM_FACES ) // Dino  TODO
+        {
+        for(int i=0; i<NUM_CUBIT_FACES; i++)
+          {
+          belongs = true;//isOnFace(cubit, i, 0 );
+          maps[i] = new Static4D( (belongs?i:NUM_FACES)*ratio, 0.0f, ratio, 1.0f);
+          }
+        }
 
-      mMesh.setTextureMap(maps,NUM_FACES*cubit);
+      mMesh.setTextureMap(maps,NUM_CUBIT_FACES*cubit);
       }
     }
 
@@ -522,10 +532,10 @@ public abstract class RubikObject extends DistortedNode
   public void setTextureMap(int cubit, int face, int newColor)
     {
     final float ratio = 1.0f/(NUM_FACES+1);
-    final Static4D[] maps = new Static4D[NUM_FACES];
+    final Static4D[] maps = new Static4D[NUM_CUBIT_FACES];
 
     maps[face] = new Static4D( newColor*ratio, 0.0f, ratio, 1.0f);
-    mMesh.setTextureMap(maps,NUM_FACES*cubit);
+    mMesh.setTextureMap(maps,NUM_CUBIT_FACES*cubit);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -700,6 +710,7 @@ public abstract class RubikObject extends DistortedNode
   abstract Static3D[] getCubitPositions(int size);
   abstract Static4D[] getQuats();
   abstract int getNumFaces();
+  abstract int getNumCubitFaces();
   abstract MeshBase createCubitMesh(int cubit);
   abstract void createFaceTexture(Canvas canvas, Paint paint, int face, int left, int top, int side);
   public abstract Static3D[] getRotationAxis();
diff --git a/src/main/java/org/distorted/objects/RubikPyraminx.java b/src/main/java/org/distorted/objects/RubikPyraminx.java
index f04cb93a..5edd1dd0 100644
--- a/src/main/java/org/distorted/objects/RubikPyraminx.java
+++ b/src/main/java/org/distorted/objects/RubikPyraminx.java
@@ -209,6 +209,13 @@ public class RubikPyraminx extends RubikObject
     return FACE_COLORS.length;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNumCubitFaces()
+    {
+    return FACE_COLORS.length;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   float getScreenRatio()
