commit d0418bda351f592d69035a063379470f71181598
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Sat Apr 6 14:13:40 2019 +0100

    Improve the Rubik App - rotation works now.

diff --git a/src/main/java/org/distorted/examples/rubik/RubikRenderer.java b/src/main/java/org/distorted/examples/rubik/RubikRenderer.java
index 4a6f032..3a352d1 100644
--- a/src/main/java/org/distorted/examples/rubik/RubikRenderer.java
+++ b/src/main/java/org/distorted/examples/rubik/RubikRenderer.java
@@ -46,7 +46,7 @@ import javax.microedition.khronos.opengles.GL10;
 
 class RubikRenderer implements GLSurfaceView.Renderer
 {
-            static final int NUM_CUBES =   3;
+            static final int NUM_CUBES =   4;
     private static final int SIZE      = 200;
     private static final float CUBE_SCREEN_RATIO = 0.5f;
 
@@ -63,9 +63,9 @@ class RubikRenderer implements GLSurfaceView.Renderer
     private Static4D[][][] mQuatScramble;
     private Static3D[][][] mRotationAxis;
     private Dynamic1D[][][] mRotationAngle;
+    private Static3D[][][] mCurrentPosition;
     private Static1D mRotationAngleStatic;
-    private int mRotAxis;
-    private int mRotRow;
+    private int mRotAxis, mRotRow;
 
     private int mScreenWidth, mScreenHeight;
 
@@ -91,11 +91,12 @@ class RubikRenderer implements GLSurfaceView.Renderer
       mEffects = new DistortedEffects[NUM_CUBES][NUM_CUBES][NUM_CUBES];
       Static3D[][][] cubeVectors = new Static3D[NUM_CUBES][NUM_CUBES][NUM_CUBES];
 
-      mQuatScramble = new Static4D[NUM_CUBES][NUM_CUBES][NUM_CUBES];
-      mRotationAxis = new Static3D[NUM_CUBES][NUM_CUBES][NUM_CUBES];
-      mRotationAngle= new Dynamic1D[NUM_CUBES][NUM_CUBES][NUM_CUBES];
+      mQuatScramble   = new Static4D[NUM_CUBES][NUM_CUBES][NUM_CUBES];
+      mRotationAxis   = new Static3D[NUM_CUBES][NUM_CUBES][NUM_CUBES];
+      mRotationAngle  = new Dynamic1D[NUM_CUBES][NUM_CUBES][NUM_CUBES];
+      mCurrentPosition= new Static3D[NUM_CUBES][NUM_CUBES][NUM_CUBES];
 
-      float sinkDegree = 3.0f - 1.7f/NUM_CUBES; // f(1)=1.3, f(inf)=3
+      float sinkDegree = 3.0f - 1.8f/NUM_CUBES; // f(1)=1.2, f(inf)=3
 
       VertexEffectSink sink = new VertexEffectSink( new Static1D(sinkDegree),
                                                     new Static3D(SIZE*0.5f, SIZE*0.5f, SIZE*0.5f),
@@ -149,11 +150,12 @@ class RubikRenderer implements GLSurfaceView.Renderer
               tmpTop   = (y== NUM_CUBES -1 ? mapTop   :mapBlack);
               tmpBottom= (y==            0 ? mapBottom:mapBlack);
 
-              mCubes[x][y][z] = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom);
-              cubeVectors[x][y][z] = new Static3D( SIZE*(x-nc), SIZE*(y-nc), SIZE*(z-nc) );
-              mQuatScramble[x][y][z] = new Static4D(0,0,0,1);
-              mRotationAngle[x][y][z] = new Dynamic1D();
-              mRotationAxis[x][y][z] = new Static3D(1,0,0);
+              mCubes[x][y][z]           = new MeshCubes(vertices,vertices,vertices, tmpFront, tmpBack, tmpLeft, tmpRight, tmpTop, tmpBottom);
+              cubeVectors[x][y][z]      = new Static3D( SIZE*(x-nc), SIZE*(y-nc), SIZE*(z-nc) );
+              mQuatScramble[x][y][z]    = new Static4D(0,0,0,1);
+              mRotationAngle[x][y][z]   = new Dynamic1D();
+              mRotationAxis[x][y][z]    = new Static3D(1,0,0);
+              mCurrentPosition[x][y][z] = new Static3D(x,y,z);
 
               mEffects[x][y][z] = new DistortedEffects();
               mEffects[x][y][z].apply(sink);
@@ -324,7 +326,7 @@ class RubikRenderer implements GLSurfaceView.Renderer
 
     void continueRotation(float angle)
       {
-      mRotationAngleStatic.set1(120.0f*angle/mScreenMin);
+      mRotationAngleStatic.set1(200.0f*angle/mScreenMin);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -360,6 +362,7 @@ class RubikRenderer implements GLSurfaceView.Renderer
                 {
                 mRotationAngle[x][y][z].removeAll();
                 mQuatScramble[x][y][z].set(RubikSurfaceView.quatMultiply(quat,mQuatScramble[x][y][z]));
+                modifyCurrentPosition(x,y,z,quat);
                 }
               }
       }
@@ -370,14 +373,47 @@ class RubikRenderer implements GLSurfaceView.Renderer
       {
       switch(vector)
         {
-        case RubikSurfaceView.VECTX: return x==row;
-        case RubikSurfaceView.VECTY: return y==row;
-        case RubikSurfaceView.VECTZ: return z==row;
+        case RubikSurfaceView.VECTX: return mCurrentPosition[x][y][z].get1()==row;
+        case RubikSurfaceView.VECTY: return mCurrentPosition[x][y][z].get2()==row;
+        case RubikSurfaceView.VECTZ: return mCurrentPosition[x][y][z].get3()==row;
         }
 
       return false;
       }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    private void modifyCurrentPosition(int x, int y, int z, Static4D quat)
+      {
+      Static3D current = mCurrentPosition[x][y][z];
+      float beforeX = current.get1();
+      float beforeY = current.get2();
+      float beforeZ = current.get3();
+
+      float diff = 0.5f*(NUM_CUBES-1);
+
+      float cubitCenterX = beforeX - diff;
+      float cubitCenterY = beforeY - diff;
+      float cubitCenterZ = beforeZ - diff;
+
+      Static4D cubitCenter =  new Static4D(cubitCenterX, cubitCenterY, cubitCenterZ, 0);
+      Static4D rotatedCenter = RubikSurfaceView.rotateVectorByQuat( cubitCenter, quat);
+
+      float rotatedX = rotatedCenter.get1() + diff;
+      float rotatedY = rotatedCenter.get2() + diff;
+      float rotatedZ = rotatedCenter.get3() + diff;
+
+      int roundedX = (int)(rotatedX+0.1f);
+      int roundedY = (int)(rotatedY+0.1f);
+      int roundedZ = (int)(rotatedZ+0.1f);
+
+      //android.util.Log.e("rubik", "before: ("+((int)beforeX)+","+((int)beforeY)+","+((int)beforeZ)+") after: ("+roundedX+","+roundedY+","+roundedZ+")");
+
+      mCurrentPosition[x][y][z].set1(roundedX);
+      mCurrentPosition[x][y][z].set2(roundedY);
+      mCurrentPosition[x][y][z].set3(roundedZ);
+      }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     float getScreenWidth()
diff --git a/src/main/java/org/distorted/examples/rubik/RubikSurfaceView.java b/src/main/java/org/distorted/examples/rubik/RubikSurfaceView.java
index 1c7de11..b6e4608 100644
--- a/src/main/java/org/distorted/examples/rubik/RubikSurfaceView.java
+++ b/src/main/java/org/distorted/examples/rubik/RubikSurfaceView.java
@@ -100,17 +100,11 @@ class RubikSurfaceView extends GLSurfaceView
          {
          case MotionEvent.ACTION_DOWN: mX = x;
                                        mY = y;
-
                                        mLastTouchedFace = faceTouched(x,y);
 
-                                       if( mLastTouchedFace != NONE )
-                                         {
-                                         mRotating = true;
-                                         }
-                                       else
-                                         {
-                                         mDragging = true;
-                                         }
+                                       if( mLastTouchedFace != NONE ) mRotating = true;
+                                       else                           mDragging = true;
+
                                        break;
          case MotionEvent.ACTION_MOVE: if( mDragging )
                                          {
@@ -297,12 +291,45 @@ class RubikSurfaceView extends GLSurfaceView
       return new Static4D(tx,ty,tz,tw);
       }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// rotate 'vector' by quat^(-1)  ( i.e. return (quat^-1)*vector*quat )
+
+    static Static4D rotateVectorByInvertedQuat(Static4D vector, Static4D quat)
+      {
+      float qx = quat.get1();
+      float qy = quat.get2();
+      float qz = quat.get3();
+      float qw = quat.get4();
+
+      Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw);
+      Static4D tmp = quatMultiply(quatInverted,vector);
+
+      return quatMultiply(tmp,quat);
+      }
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// rotate 'vector' by quat  ( i.e. return quat*vector*(quat^-1) )
+
+    static Static4D rotateVectorByQuat(Static4D vector, Static4D quat)
+      {
+      float qx = quat.get1();
+      float qy = quat.get2();
+      float qz = quat.get3();
+      float qw = quat.get4();
+
+      Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw);
+      Static4D tmp = quatMultiply(quat,vector);
+
+      return quatMultiply(tmp,quatInverted);
+      }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private Static4D quatFromDrag(float dragX, float dragY)
       {
       float axisX = dragY;  // inverted X and Y - rotation axis is
-      float axisY = dragX;  // perpendicular to (dragX,dragY)
+      float axisY = dragX;  // perpendicular to (dragX,dragY)   Why not (-dragY, dragX) ? because Y axis is also inverted!
       float axisZ = 0;
       float axisL = (float)Math.sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ);
 
@@ -321,27 +348,6 @@ class RubikSurfaceView extends GLSurfaceView
       return new Static4D(0f, 0f, 0f, 1f);
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private int returnFrontFace()
-      {
-      Static4D rotated = rotateVector(new Static4D(0,0,1,0));
-
-      float rotatedX = rotated.get1();
-      float rotatedY = rotated.get2();
-      float rotatedZ = rotated.get3();
-
-      float absX = rotatedX>0 ? rotatedX : -rotatedX;
-      float absY = rotatedY>0 ? rotatedY : -rotatedY;
-      float absZ = rotatedZ>0 ? rotatedZ : -rotatedZ;
-
-      if( absX>absY && absX>absZ ) return rotatedX>0 ? RIGHT:LEFT;
-      if( absY>absX && absY>absZ ) return rotatedY>0 ? TOP:BOTTOM;
-      if( absZ>absX && absZ>absY ) return rotatedZ>0 ? FRONT:BACK;
-
-      return NONE;
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private boolean faceIsVisible(int face)
@@ -349,7 +355,7 @@ class RubikSurfaceView extends GLSurfaceView
       float cameraDistance = mRenderer.returnCameraDistance();
       float cubeHalfSize   = mRenderer.returnCubeSize()*0.5f;
 
-      Static4D rotated = rotateVector(new Static4D(0,0,cameraDistance,0));
+      Static4D rotated = rotateVectorByInvertedQuat(new Static4D(0,0,cameraDistance,0), mQuatAccumulated);
 
       switch(face)
         {
@@ -364,22 +370,6 @@ class RubikSurfaceView extends GLSurfaceView
       return false;
       }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// rotate 'vector' by quaternion q=mQuatAccumulated^(-1)  ( i.e. return (q^-1)*vector*q )
-
-    private Static4D rotateVector(Static4D vector)
-      {
-      float qx = mQuatAccumulated.get1();
-      float qy = mQuatAccumulated.get2();
-      float qz = mQuatAccumulated.get3();
-      float qw = mQuatAccumulated.get4();
-
-      Static4D quatInverted= new Static4D(-qx,-qy,-qz,qw);
-      Static4D tmp = quatMultiply(quatInverted,vector);
-
-      return quatMultiply(tmp,mQuatAccumulated);
-      }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     private int faceTouched(int xTouch, int yTouch)
@@ -417,7 +407,7 @@ class RubikSurfaceView extends GLSurfaceView
       float halfScrWidth  = mRenderer.getScreenWidth() *0.5f;
       float halfScrHeight = mRenderer.getScreenHeight()*0.5f;
       Static4D touchPoint = new Static4D(x-halfScrWidth, halfScrHeight-y, 0, 0);
-      Static4D rotatedTouchPoint= rotateVector(touchPoint);
+      Static4D rotatedTouchPoint= rotateVectorByInvertedQuat(touchPoint, mQuatAccumulated);
 
       mPoiX = rotatedTouchPoint.get1();
       mPoiY = rotatedTouchPoint.get2();
@@ -431,7 +421,7 @@ class RubikSurfaceView extends GLSurfaceView
       float cameraDistance = mRenderer.returnCameraDistance();
 
       Static4D cameraPoint = new Static4D(0, 0, cameraDistance, 0);
-      Static4D rotatedCamera= rotateVector(cameraPoint);
+      Static4D rotatedCamera= rotateVectorByInvertedQuat(cameraPoint, mQuatAccumulated);
 
       mCamX = rotatedCamera.get1();
       mCamY = rotatedCamera.get2();
