commit 27e6c301032b1f9faa8ed0d4b71231e432461db3
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Sun Jun 7 16:29:59 2020 +0100

    Progreess porting RubikCube to the new SingleMesh mode.

diff --git a/src/main/java/org/distorted/main/RubikRenderer.java b/src/main/java/org/distorted/main/RubikRenderer.java
index 58c5131f..8aad826a 100644
--- a/src/main/java/org/distorted/main/RubikRenderer.java
+++ b/src/main/java/org/distorted/main/RubikRenderer.java
@@ -24,6 +24,7 @@ import android.opengl.GLSurfaceView;
 
 import org.distorted.effects.BaseEffect;
 import org.distorted.library.effect.EffectType;
+import org.distorted.library.effect.VertexEffectRotate;
 import org.distorted.library.main.DistortedLibrary;
 import org.distorted.library.main.DistortedScreen;
 
@@ -77,6 +78,7 @@ public class RubikRenderer implements GLSurfaceView.Renderer
    public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
       {
       DistortedLibrary.setMax(EffectType.VERTEX,15);
+      VertexEffectRotate.enable();
       BaseEffect.Type.enableEffects();
 
       try
diff --git a/src/main/java/org/distorted/objects/Cubit.java b/src/main/java/org/distorted/objects/Cubit.java
index e4d3b6e1..736ed329 100644
--- a/src/main/java/org/distorted/objects/Cubit.java
+++ b/src/main/java/org/distorted/objects/Cubit.java
@@ -21,15 +21,8 @@ package org.distorted.objects;
 
 import android.content.SharedPreferences;
 
-import com.google.firebase.crashlytics.FirebaseCrashlytics;
-
-import org.distorted.library.effect.MatrixEffectMove;
 import org.distorted.library.effect.MatrixEffectQuaternion;
-import org.distorted.library.effect.MatrixEffectRotate;
 import org.distorted.library.main.DistortedEffects;
-import org.distorted.library.message.EffectListener;
-import org.distorted.library.type.Dynamic1D;
-import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 import org.distorted.main.RubikSurfaceView;
@@ -38,17 +31,13 @@ import org.distorted.main.RubikSurfaceView;
 
 class Cubit
   {
-  private static final int POST_ROTATION_MILLISEC = 500;
   private static final Static3D MATRIX_CENTER = new Static3D(0,0,0);
 
   private final Static3D mOrigPosition;
 
   private RubikObject mParent;
-  private Static3D mRotationAxis;
-  private MatrixEffectRotate mRotateEffect;
   private Static3D mCurrentPosition;
   private int mNumAxis;
-  private Dynamic1D mRotationAngle;
 
   DistortedEffects mEffect;
   Static4D mQuatScramble;
@@ -62,27 +51,18 @@ class Cubit
     float y = position.get1();
     float z = position.get2();
 
-    Static3D vector = new Static3D(x,y,z);
-
     mParent          = parent;
     mOrigPosition    = new Static3D(x,y,z);
     mQuatScramble    = new Static4D(0,0,0,1);
-    mRotationAngle   = new Dynamic1D();
-    mRotationAxis    = new Static3D(1,0,0);
+
     mCurrentPosition = position;
-    mRotateEffect    = new MatrixEffectRotate(mRotationAngle, mRotationAxis, MATRIX_CENTER);
 
     mNumAxis     = mParent.ROTATION_AXIS.length;
     mRotationRow = new float[mNumAxis];
     computeRotationRow();
 
     mEffect = new DistortedEffects();
-    mEffect.apply( new MatrixEffectMove(vector) );
     mEffect.apply( new MatrixEffectQuaternion(mQuatScramble, MATRIX_CENTER));
-    mEffect.apply(mRotateEffect);
-    mEffect.apply(mParent.mQuatAEffect);
-    mEffect.apply(mParent.mQuatCEffect);
-    mEffect.apply(mParent.mScaleEffect);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -190,6 +170,22 @@ class Cubit
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int computeAssociation()
+    {
+    int row, result = 0, accumulativeShift = 0;
+
+    for(int axis=0; axis<mNumAxis; axis++)
+      {
+      row = (int)(mRotationRow[axis]+0.5f);
+      result += (1<<(row+accumulativeShift));
+      accumulativeShift += RubikObjectList.MAX_SIZE;
+      }
+
+    return result;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void savePreferences(SharedPreferences.Editor editor)
@@ -295,61 +291,11 @@ class Cubit
 
   void removeRotationNow(Static4D quat)
     {
-    mRotationAngle.removeAll();
     mQuatScramble.set(RubikSurfaceView.quatMultiply(quat,mQuatScramble));
     normalizeScrambleQuat( mQuatScramble );
     modifyCurrentPosition(quat);
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void beginNewRotation(int axis)
-    {
-    mRotationAxis.set( mParent.ROTATION_AXIS[axis] );
-    mRotationAngle.add(mParent.mRotationAngleStatic);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void addNewRotation(int axis, long durationMillis, int angle)
-    {
-    mRotationAxis.set( mParent.ROTATION_AXIS[axis] );
-    mRotationAngle.setDuration(durationMillis);
-    mRotationAngle.resetToBeginning();
-    mRotationAngle.add(new Static1D(0));
-    mRotationAngle.add(new Static1D(angle));
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  void resetRotationAngle()
-    {
-    mRotationAngle.setDuration(POST_ROTATION_MILLISEC);
-    mRotationAngle.resetToBeginning();
-    mRotationAngle.removeAll();
-    mRotationAngle.add(mParent.mRotationAngleStatic);
-    mRotationAngle.add(mParent.mRotationAngleMiddle);
-    mRotationAngle.add(mParent.mRotationAngleFinal);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  float getAngle()
-    {
-    int pointNum = mRotationAngle.getNumPoints();
-
-    if( pointNum>=1 )
-      {
-      return mRotationAngle.getPoint(pointNum-1).get0();
-      }
-    else
-      {
-      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
-      crashlytics.log("points in RotationAngle: "+pointNum);
-      return 0;
-      }
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void solve()
@@ -359,14 +305,6 @@ class Cubit
     computeRotationRow();
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  long setUpCallback(EffectListener listener)
-    {
-    mRotateEffect.notifyWhenFinished(listener);
-    return mRotateEffect.getID();
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   float getDistSquared(float[] point)
diff --git a/src/main/java/org/distorted/objects/RubikObject.java b/src/main/java/org/distorted/objects/RubikObject.java
index b1600c8b..afc60742 100644
--- a/src/main/java/org/distorted/objects/RubikObject.java
+++ b/src/main/java/org/distorted/objects/RubikObject.java
@@ -24,10 +24,13 @@ import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 
+import com.google.firebase.crashlytics.FirebaseCrashlytics;
+
 import org.distorted.library.effect.Effect;
 import org.distorted.library.effect.MatrixEffectMove;
 import org.distorted.library.effect.MatrixEffectQuaternion;
 import org.distorted.library.effect.MatrixEffectScale;
+import org.distorted.library.effect.VertexEffectRotate;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedNode;
 import org.distorted.library.main.DistortedTexture;
@@ -35,6 +38,7 @@ import org.distorted.library.mesh.MeshBase;
 import org.distorted.library.mesh.MeshJoined;
 import org.distorted.library.mesh.MeshRectangles;
 import org.distorted.library.message.EffectListener;
+import org.distorted.library.type.Dynamic1D;
 import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
@@ -43,10 +47,12 @@ import org.distorted.library.type.Static4D;
 
 public abstract class RubikObject extends DistortedNode
   {
+  private static final Static3D VERTEX_CENTER = new Static3D(0,0,0);
   static final int INTERIOR_COLOR = 0xff000000;
   public static final int NODE_FBO_SIZE = 600;
-
+  private static final int POST_ROTATION_MILLISEC = 500;
   private static final int TEXTURE_HEIGHT = 128;
+
   final float[] LEGAL_QUATS;
   final Static3D[] ROTATION_AXIS;
   final int NUM_FACES;
@@ -64,6 +70,9 @@ public abstract class RubikObject extends DistortedNode
   private RubikObjectList mList;
   private MeshBase mMesh;
   private DistortedEffects mEffects;
+  private VertexEffectRotate mRotateEffect;
+  private Dynamic1D mRotationAngle;
+  private Static3D mRotationAxis;
 
   float mStart, mStep;
 
@@ -97,6 +106,10 @@ public abstract class RubikObject extends DistortedNode
     mNodeScale= new Static3D(1,1,1);
     mQuatAccumulated = quatAcc;
 
+    mRotationAngle= new Dynamic1D();
+    mRotationAxis = new Static3D(1,0,0);
+    mRotateEffect = new VertexEffectRotate(mRotationAngle, mRotationAxis, VERTEX_CENTER);
+
     mRotationAngleStatic = new Static1D(0);
     mRotationAngleMiddle = new Static1D(0);
     mRotationAngleFinal  = new Static1D(0);
@@ -116,9 +129,10 @@ public abstract class RubikObject extends DistortedNode
 
     for(int i=0; i<NUM_CUBITS; i++)
       {
+      mCubits[i] = new Cubit(this,mOrigPos[i]);
       cubitMesh[i] = createCubitMesh(i);
       cubitMesh[i].apply(new MatrixEffectMove(mOrigPos[i]),1,0);
-      mCubits[i] = new Cubit(this,mOrigPos[i]);
+      cubitMesh[i].setEffectAssociation(0, mCubits[i].computeAssociation(), i);
       }
 
     mMesh = new MeshJoined(cubitMesh);
@@ -126,6 +140,7 @@ public abstract class RubikObject extends DistortedNode
     resetAllTextureMaps();
 
     mEffects = new DistortedEffects();
+    mEffects.apply(mRotateEffect);
     mEffects.apply(mQuatAEffect);
     mEffects.apply(mQuatCEffect);
     mEffects.apply(mScaleEffect);
@@ -453,101 +468,95 @@ public abstract class RubikObject extends DistortedNode
       return;
       }
 
-    mRotAxis       = axis;
-    mRotRowBitmap  = (1<<row);
-
+    mRotAxis     = axis;
+    mRotRowBitmap= (1<<row);
     mRotationAngleStatic.set0(0.0f);
-
-    for(int i=0; i<NUM_CUBITS; i++)
-      if( belongsToRotation(i,mRotAxis,mRotRowBitmap) )
-        {
-        mCubits[i].beginNewRotation(axis);
-        }
-     }
+    mRotationAxis.set( ROTATION_AXIS[axis] );
+    mRotationAngle.add(mRotationAngleStatic);
+    mRotateEffect.setMeshAssociation( mRotRowBitmap<<(axis*RubikObjectList.MAX_SIZE) , -1);
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public long addNewRotation( int axis, int rowBitmap, int angle, long durationMillis, EffectListener listener )
-     {
-     long effectID=0;
-     int firstCubit = -1;
-
-     mRotAxis       = axis;
-     mRotRowBitmap  = rowBitmap;
+    {
+    mRotAxis     = axis;
+    mRotRowBitmap= rowBitmap;
 
-     mRotationAngleStatic.set0(0.0f);
+    mRotationAngleStatic.set0(0.0f);
+    mRotationAxis.set( ROTATION_AXIS[axis] );
+    mRotationAngle.setDuration(durationMillis);
+    mRotationAngle.resetToBeginning();
+    mRotationAngle.add(new Static1D(0));
+    mRotationAngle.add(new Static1D(angle));
+    mRotateEffect.setMeshAssociation( mRotRowBitmap<<(axis*RubikObjectList.MAX_SIZE) , -1);
+    mRotateEffect.notifyWhenFinished(listener);
+
+    return mRotateEffect.getID();
+    }
 
-     for(int i=0; i<NUM_CUBITS; i++)
-       if( belongsToRotation(i,mRotAxis,mRotRowBitmap) )
-         {
-         mCubits[i].addNewRotation(axis,durationMillis,angle);
-         if( firstCubit<0 ) firstCubit = i;
-         }
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
-     if( firstCubit>=0 ) effectID = mCubits[firstCubit].setUpCallback(listener);
+  public long finishRotationNow(EffectListener listener)
+    {
+    float angle = getAngle();
+    int nearestAngleInDegrees = computeNearestAngle(angle);
+    mRotationAngleStatic.set0(angle);
+    mRotationAngleFinal.set0(nearestAngleInDegrees);
+    mRotationAngleMiddle.set0( nearestAngleInDegrees + (nearestAngleInDegrees-angle)*0.2f );
+
+    mRotationAngle.setDuration(POST_ROTATION_MILLISEC);
+    mRotationAngle.resetToBeginning();
+    mRotationAngle.removeAll();
+    mRotationAngle.add(mRotationAngleStatic);
+    mRotationAngle.add(mRotationAngleMiddle);
+    mRotationAngle.add(mRotationAngleFinal);
+    mRotateEffect.notifyWhenFinished(listener);
+
+    return mRotateEffect.getID();
+    }
 
-     return effectID;
-     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public long finishRotationNow(EffectListener listener)
+  private float getAngle()
     {
-    int firstCubit= -1;
-    long effectID =  0;
+    int pointNum = mRotationAngle.getNumPoints();
 
-    for(int i=0; i<NUM_CUBITS; i++)
+    if( pointNum>=1 )
       {
-      if( belongsToRotation(i,mRotAxis,mRotRowBitmap) )
-        {
-        if( firstCubit<0 )
-          {
-          firstCubit=i;
-
-          float angle = mCubits[i].getAngle();
-          int nearestAngleInDegrees = computeNearestAngle(angle);
-          mRotationAngleStatic.set0(angle);
-          mRotationAngleFinal.set0(nearestAngleInDegrees);
-          mRotationAngleMiddle.set0( nearestAngleInDegrees + (nearestAngleInDegrees-angle)*0.2f );
-          }
-        mCubits[i].resetRotationAngle();
-        }
+      return mRotationAngle.getPoint(pointNum-1).get0();
+      }
+    else
+      {
+      FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance();
+      crashlytics.log("points in RotationAngle: "+pointNum);
+      return 0;
       }
-
-    if( firstCubit>=0 ) effectID = mCubits[firstCubit].setUpCallback(listener);
-
-    return effectID;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public void removeRotationNow()
      {
-     boolean first = true;
-     Static4D quat = null;
+     float angle = getAngle();
+     int nearestAngleInDegrees = computeNearestAngle(angle);
+     double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
+     float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
+     float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
+     float axisX = ROTATION_AXIS[mRotAxis].get0();
+     float axisY = ROTATION_AXIS[mRotAxis].get1();
+     float axisZ = ROTATION_AXIS[mRotAxis].get2();
+     Static4D quat = new Static4D( axisX*sinA, axisY*sinA, axisZ*sinA, cosA);
+
+     mRotationAngle.removeAll();
+     mRotationAngleStatic.set0(0);
 
      for(int i=0; i<NUM_CUBITS; i++)
        if( belongsToRotation(i,mRotAxis,mRotRowBitmap) )
          {
-         if( first )
-           {
-           first = false;
-
-           float angle = mCubits[i].getAngle();
-           int nearestAngleInDegrees = computeNearestAngle(angle);
-           double nearestAngleInRadians = nearestAngleInDegrees*Math.PI/180;
-           float sinA =-(float)Math.sin(nearestAngleInRadians*0.5);
-           float cosA = (float)Math.cos(nearestAngleInRadians*0.5);
-           float axisX = ROTATION_AXIS[mRotAxis].get0();
-           float axisY = ROTATION_AXIS[mRotAxis].get1();
-           float axisZ = ROTATION_AXIS[mRotAxis].get2();
-           quat = new Static4D( axisX*sinA, axisY*sinA, axisZ*sinA, cosA);
-           }
-
          mCubits[i].removeRotationNow(quat);
          }
-
-     mRotationAngleStatic.set0(0);
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
