commit 9cd7695f2f236e7682426eb0f04f4a1fc1e6b866
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Wed Mar 11 01:26:06 2020 +0000

    Improve RubikCubeMovement

diff --git a/src/main/java/org/distorted/magic/RubikRenderer.java b/src/main/java/org/distorted/magic/RubikRenderer.java
index 1d3cea11..648b0fe0 100644
--- a/src/main/java/org/distorted/magic/RubikRenderer.java
+++ b/src/main/java/org/distorted/magic/RubikRenderer.java
@@ -242,6 +242,12 @@ public class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
        mCanRotate      = false;
        mCanUI          = false;
        mRotationFinishedID = mNewObject.finishRotationNow(this);
+
+       if( mRotationFinishedID==0 ) // failed to add effect - should never happen
+         {
+         mCanRotate = true;
+         mCanUI     = true;
+         }
        }
 
      if( mRemoveRotation )
diff --git a/src/main/java/org/distorted/object/RubikCube.java b/src/main/java/org/distorted/object/RubikCube.java
index 76b44be9..2d01e4c8 100644
--- a/src/main/java/org/distorted/object/RubikCube.java
+++ b/src/main/java/org/distorted/object/RubikCube.java
@@ -40,14 +40,14 @@ import org.distorted.library.type.Static4D;
 class RubikCube extends RubikObject
 {
   // the three rotation axis of a RubikCube. Must be normalized.
-  private static final Static3D[] AXIS = new Static3D[]
+  static final Static3D[] AXIS = new Static3D[]
          {
            new Static3D(1,0,0),
            new Static3D(0,1,0),
            new Static3D(0,0,1)
          };
 
-  private static final int[] FACE_COLORS = new int[]
+  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)
diff --git a/src/main/java/org/distorted/object/RubikCubeMovement.java b/src/main/java/org/distorted/object/RubikCubeMovement.java
index 08341442..3524320d 100644
--- a/src/main/java/org/distorted/object/RubikCubeMovement.java
+++ b/src/main/java/org/distorted/object/RubikCubeMovement.java
@@ -38,7 +38,8 @@ class RubikCubeMovement extends RubikObjectMovement
     private static final int VECTZ  = 2;  //
 
     private float[] mPoint, mCamera, mDiff, mTouch;
-    private int mRotationVect, mLastTouchedFace;
+    private int mRotationVect, mLastTouchedAxis, mLastTouchedLR;
+    private int mNumAxis, mNumFacesPerAxis;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -49,60 +50,31 @@ class RubikCubeMovement extends RubikObjectMovement
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private int retFaceSign(int face)
-      {
-      return (face==FRONT || face==RIGHT || face==TOP) ? 1:-1;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private int retFaceRotationSign(int face)
+    private int retFaceRotationSign(int axis, int lr)
       {
+      int face = axis*mNumFacesPerAxis + lr;
       return (face==BACK || face==RIGHT || face==TOP) ? 1:-1;
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// retFace{X,Y,Z}axis: 3 functions which return which real AXIS gets mapped to which when we look
-// directly at a given face. For example, when we look at the RIGHT face of the cube (with TOP still
-// in the top) then the 'real' X axis becomes the 'Z' axis, thus retFaceXaxis(RIGHT) = VECTZ.
 
-    private int retFaceXaxis(int face)
+    private int retFaceXaxis(int axis)
       {
-      return face==LEFT || face==RIGHT ? VECTZ : VECTX;
+      return axis==0 ? VECTZ : VECTX;
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private int retFaceYaxis(int face)
+    private int retFaceYaxis(int axis)
       {
-      return face==TOP || face==BOTTOM ? VECTZ : VECTY;
+      return axis==1 ? VECTZ : VECTY;
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    private int retFaceAxis(int face)
+    private boolean faceIsVisible(int axis, int lr)
       {
-      switch(face)
-        {
-        case FRONT :
-        case BACK  : return VECTZ;
-        case LEFT  :
-        case RIGHT : return VECTX;
-        case TOP   :
-        case BOTTOM: return VECTY;
-        }
-
-      return -1;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private boolean faceIsVisible(int face)
-      {
-      int sign = retFaceSign(face);
-      int zAxis= retFaceAxis(face);
-
-      return sign*mCamera[zAxis] > 0.5f;
+      return (lr==0 ? -1:1)*mCamera[axis] > 0.5f;
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -110,13 +82,10 @@ class RubikCubeMovement extends RubikObjectMovement
 // cast this touch point onto the surface defined by the 'face' and write the cast coords to 'output'.
 // Center of the 'face' = (0,0), third coord always +- cubeHalfSize.
 
-    private void castTouchPointOntoFace(int face, float[] output)
+    private void castTouchPointOntoFace(int axis, int lr, float[] output)
       {
-      int sign = retFaceSign(face);
-      int zAxis= retFaceAxis(face);
-      float diff = mPoint[zAxis]-mCamera[zAxis];
-
-      float ratio =  diff!=0.0f ? (sign*0.5f-mCamera[zAxis])/diff : 0.0f;
+      float diff = mPoint[axis]-mCamera[axis];
+      float ratio =  diff!=0.0f ? ( (lr-0.5f)-mCamera[axis])/diff : 0.0f;
 
       output[0] = (mPoint[0]-mCamera[0])*ratio + mCamera[0];
       output[1] = (mPoint[1]-mCamera[1])*ratio + mCamera[1];
@@ -131,6 +100,9 @@ class RubikCubeMovement extends RubikObjectMovement
       mCamera= new float[3];
       mDiff  = new float[3];
       mTouch = new float[3];
+
+      mNumAxis = RubikCube.AXIS.length;
+      mNumFacesPerAxis = RubikCube.FACE_COLORS.length / mNumAxis;
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -147,15 +119,18 @@ class RubikCubeMovement extends RubikObjectMovement
       mCamera[1] = rotatedCamera.get1()/RubikObject.OBJECT_SCREEN_RATIO;
       mCamera[2] = rotatedCamera.get2()/RubikObject.OBJECT_SCREEN_RATIO;
 
-      for( mLastTouchedFace=LEFT; mLastTouchedFace<=FRONT; mLastTouchedFace++)
+      for( mLastTouchedAxis=0; mLastTouchedAxis<mNumAxis; mLastTouchedAxis++)
         {
-        if( faceIsVisible(mLastTouchedFace) )
+        for( mLastTouchedLR=0; mLastTouchedLR<mNumFacesPerAxis; mLastTouchedLR++)
           {
-          castTouchPointOntoFace(mLastTouchedFace, mTouch);
-
-          if( mTouch[0]<=0.5f && mTouch[0]>=-0.5f &&
-              mTouch[1]<=0.5f && mTouch[1]>=-0.5f &&
-              mTouch[2]<=0.5f && mTouch[2]>=-0.5f  ) return true;
+          if( faceIsVisible(mLastTouchedAxis, mLastTouchedLR) )
+            {
+            castTouchPointOntoFace(mLastTouchedAxis, mLastTouchedLR, mTouch);
+
+            if( mTouch[0]<=0.5f && mTouch[0]>=-0.5f &&
+                mTouch[1]<=0.5f && mTouch[1]>=-0.5f &&
+                mTouch[2]<=0.5f && mTouch[2]>=-0.5f  )  return true;
+            }
           }
         }
 
@@ -170,14 +145,14 @@ class RubikCubeMovement extends RubikObjectMovement
       mPoint[1] = rotatedTouchPoint.get1()/RubikObject.OBJECT_SCREEN_RATIO;
       mPoint[2] = rotatedTouchPoint.get2()/RubikObject.OBJECT_SCREEN_RATIO;
 
-      castTouchPointOntoFace(mLastTouchedFace,mDiff);
+      castTouchPointOntoFace(mLastTouchedAxis, mLastTouchedLR, mDiff);
 
       mDiff[0] -= mTouch[0];
       mDiff[1] -= mTouch[1];
       mDiff[2] -= mTouch[2];
 
-      int xAxis = retFaceXaxis(mLastTouchedFace);
-      int yAxis = retFaceYaxis(mLastTouchedFace);
+      int xAxis = retFaceXaxis(mLastTouchedAxis);
+      int yAxis = retFaceYaxis(mLastTouchedAxis);
       mRotationVect = (isVertical( mDiff[xAxis], mDiff[yAxis]) ? xAxis : yAxis);
       float offset= mTouch[mRotationVect]+0.5f;
 
@@ -192,13 +167,13 @@ class RubikCubeMovement extends RubikObjectMovement
 
     public float continueRotation(Static4D rotatedTouchPoint)
       {
-      mDiff[0] = rotatedTouchPoint.get0()/RubikObject.OBJECT_SCREEN_RATIO-mTouch[0];
-      mDiff[1] = rotatedTouchPoint.get1()/RubikObject.OBJECT_SCREEN_RATIO-mTouch[1];
-      mDiff[2] = rotatedTouchPoint.get2()/RubikObject.OBJECT_SCREEN_RATIO-mTouch[2];
+      mDiff[0] = rotatedTouchPoint.get0()/RubikObject.OBJECT_SCREEN_RATIO - mTouch[0];
+      mDiff[1] = rotatedTouchPoint.get1()/RubikObject.OBJECT_SCREEN_RATIO - mTouch[1];
+      mDiff[2] = rotatedTouchPoint.get2()/RubikObject.OBJECT_SCREEN_RATIO - mTouch[2];
 
-      int xAxis= retFaceXaxis(mLastTouchedFace);
-      int yAxis= retFaceYaxis(mLastTouchedFace);
-      int sign = retFaceRotationSign(mLastTouchedFace);
+      int xAxis= retFaceXaxis(mLastTouchedAxis);
+      int yAxis= retFaceYaxis(mLastTouchedAxis);
+      int sign = retFaceRotationSign(mLastTouchedAxis, mLastTouchedLR);
       float angle = (mRotationVect==xAxis ? mDiff[yAxis] : -mDiff[xAxis]);
 
       return sign*angle*0.5f;
diff --git a/src/main/java/org/distorted/object/RubikObject.java b/src/main/java/org/distorted/object/RubikObject.java
index fff5852e..3cb00a28 100644
--- a/src/main/java/org/distorted/object/RubikObject.java
+++ b/src/main/java/org/distorted/object/RubikObject.java
@@ -394,6 +394,17 @@ public abstract class RubikObject extends DistortedNode
 
   public void beginNewRotation(int axis, int row )
     {
+    if( axis<0 || axis>=ROTATION_AXIS.length )
+      {
+      android.util.Log.e("object", "invalid rotation axis: "+axis);
+      return;
+      }
+    if( row<0 || row>=mSize )
+      {
+      android.util.Log.e("object", "invalid rotation row: "+row);
+      return;
+      }
+
     mRotAxis = axis;
     mRotRow  = row;
 
