commit 791e7ee81788fa37f769b4dc7701c5247ae8f780
Author: leszek <leszek@koltunski.pl>
Date:   Tue Feb 18 01:18:58 2025 +0100

    progress

diff --git a/src/main/java/org/distorted/objectlib/main/TwistyObjectControllable.java b/src/main/java/org/distorted/objectlib/main/TwistyObjectControllable.java
index a2cc1f09..739dc099 100644
--- a/src/main/java/org/distorted/objectlib/main/TwistyObjectControllable.java
+++ b/src/main/java/org/distorted/objectlib/main/TwistyObjectControllable.java
@@ -241,10 +241,11 @@ public abstract class TwistyObjectControllable extends TwistyObjectWithStickers
 
   private int computeNearestAngle(int axis, int row, float angle, float speed)
     {
-    int ghostAngle = mGhost.ghostNearestAngle(axis,row,angle);
+    int basicDeg = 360/mBasicAngles[axis][row];
+    int ghostAngle = mGhost.nearestGhostAngle(axis,angle,basicDeg);
 
     angle -= ghostAngle;
-    int basicDeg = 360/mBasicAngles[axis][row];
+
     int numRot = (int)(angle/basicDeg + 0.5f);
     if( angle< -(basicDeg*0.5) ) numRot-=1;
     if( numRot==0 && speed>1.1f ) numRot = (angle>0 ? 1:-1);
diff --git a/src/main/java/org/distorted/objectlib/main/TwistyObjectGhost.java b/src/main/java/org/distorted/objectlib/main/TwistyObjectGhost.java
index 8704d167..fd1eb640 100644
--- a/src/main/java/org/distorted/objectlib/main/TwistyObjectGhost.java
+++ b/src/main/java/org/distorted/objectlib/main/TwistyObjectGhost.java
@@ -78,6 +78,7 @@ class TwistyObjectGhost
         {
         mGhostEffectAngle[l] = new Static1D(mGhostRowState[l]*mGhostAngle);
         mGhostEffect[l] = new VertexEffectRotate(mGhostEffectAngle[l], mGhostAxis, new Static3D(0, 0, 0));
+        mGhostEffect[l].setMeshAssociation( 1<<(mGhostAxisParallelTo*mMaxNumLayers + l), -1 );
         effects.apply(mGhostEffect[l]);
         computeGhostQuaternion(mGhostOrigQuat[l],mGhostOrigAxis,mGhostRowState[l]*mGhostAngle);
         }
@@ -110,126 +111,46 @@ class TwistyObjectGhost
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// If such a move is possible, return + or - mGhostAngle. Else, return 0.
-// When is it possible? This depends of the value of mGhostRowBitmap's 'left' and 'right' bits.
-//
-// If 'row' is one of the left bits, and
-//   it is 0: move 'up'   possible iff all bits are zeroes [ so now it is -10000 -> rotate to 01111]
-//            move 'down' possible iff all right bits are ones
-//   it is 1: move 'up'   always possible
-//            move 'down' never possible
-//
-// If 'row' is one of the right bits, and
-//   it is 0: move 'up'   never possible
-//            move 'down' always possible
-//   it is 1: move 'up'   possible iff all the left bits are zeroes
-//            move 'down' possible iff all the bits are ones [so now it is 11112 -> contr-rotate to 00001]
+// If we are not blocked, or we are blocked but the move is along the currently unblocked axis,
+// then we can always move any row 1 or 2 ghostAngles up or down.
+// If 'angle' is closest to such multiples of ghostAngles, then return the closest multiple.
+// Otherwise return 0.
 
-  int ghostNearestAngle(int axis, int row, float angle)
+  int nearestGhostAngle(int axis, float angle, int basicDeg)
     {
-    int ret = 0;
-
     if( mGhostAngle!=0 )
       {
-      boolean moveDo = angleIsDown(axis,row,angle);
-      boolean moveUp = angleIsUp(axis,row,angle);
-      boolean isLeft = (row<mGhostFirstRow[axis])^mGhostAxisInverted;
-      boolean isZero = (mGhostRowBitmap&(1<<row))==0;
+      int numRot = (int)(angle/basicDeg + 0.5f);
+      if( angle< -(basicDeg*0.5) ) numRot-=1;
+      int intAngle = (int)angle;
+      int distToNormalAngle = Math.abs(intAngle - numRot*basicDeg);
+      int distTo1 = Math.abs(intAngle -   mGhostAngle);
+      int distTo2 = Math.abs(intAngle - 2*mGhostAngle);
+      int distTo3 = Math.abs(intAngle +   mGhostAngle);
+      int distTo4 = Math.abs(intAngle + 2*mGhostAngle);
+      int min12 = Math.min(distTo1,distTo2);
+      int min34 = Math.min(distTo3,distTo4);
+      int min   = Math.min( min12,min34 );
+
+      if( distToNormalAngle<=min ) return 0;
 
       if( !mGhostBlocked )
         {
-        ret = retAngle(axis,isLeft,isZero,moveUp,moveDo);
-
-        if( ret!=0 )
-          {
-          mGhostAxis.set(mAxis[axis]);
-          mGhostAxisParallelTo = axis;
-          mGhostAxisInverted   = false;
-          }
-        }
-      else if( axis==mGhostAxisParallelTo )
-        {
-        ret = retAngle(axis,isLeft,isZero,moveUp,moveDo);
+        mGhostAxis.set(mAxis[axis]);
+        mGhostAxisParallelTo = axis;
+        mGhostAxisInverted   = false;
         }
-      }
-
-    return ret;
-    }
-/*
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private boolean angleIsDown(int axis, int row, float angle)
-    {
-    int basicDeg   = 360/mBasicAngles[axis][row];
-    boolean moveDo = moveIsDown(basicDeg,angle);
-    boolean moveUp = moveIsUp(basicDeg,angle);
-
-    return ((moveDo&(!mGhostAxisInverted)) || moveUp&mGhostAxisInverted);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private boolean angleIsUp(int axis, int row, float angle)
-    {
-    int basicDeg   = 360/mBasicAngles[axis][row];
-    boolean moveDo = moveIsDown(basicDeg,angle);
-    boolean moveUp = moveIsUp(basicDeg,angle);
-
-    return ((moveUp&(!mGhostAxisInverted)) || moveDo&mGhostAxisInverted);
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private boolean moveIsDown(int basic, float angle)
-    {
-    float A = (2*angle-mGhostAngle)/basic;
-    boolean even = ((int)A)%2 == 0;
-    return (A>=0) == even;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private boolean moveIsUp(int basic, float angle)
-    {
-    float A = (2*angle+mGhostAngle)/basic;
-    boolean even = ((int)A)%2 == 0;
-    return (A>=0) != even;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private int retAngle(int axis, boolean isLeft, boolean isZero, boolean moveUp, boolean moveDo)
-    {
-    int mult = mGhostAxisInverted ? -1 : 1;
-
-    if( isLeft )
-      {
-      if( isZero )
-        {
-        if( moveUp ) return allBitsAreZeroes()     ? -mult*mGhostAngle : 0;
-        if( moveDo ) return rightBitsAreOnes(axis) ?  mult*mGhostAngle : 0;
-        }
-      else
+      if( !mGhostBlocked || axis==mGhostAxisParallelTo )
         {
-        if( moveUp ) return -mult*mGhostAngle;
-        }
-      }
-    else
-      {
-      if( isZero )
-        {
-        if( moveDo ) return  mult*mGhostAngle;
-        }
-      else
-        {
-        if( moveUp ) return leftBitsAreZeroes(axis) ? -mult*mGhostAngle : 0;
-        if( moveDo ) return allBitsAreOnes(axis)    ?  mult*mGhostAngle : 0;
+        if( min12<min34 ) return distTo1<distTo2 ? +mGhostAngle : +2*mGhostAngle;
+        else              return distTo3<distTo4 ? -mGhostAngle : -2*mGhostAngle;
         }
       }
 
     return 0;
     }
-*/
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Called when removing a rotation, before all cubits have been rotated.
 // Return only the 'nonGhostAngle' i.e. one from which ghostAngle has been removed.
@@ -241,13 +162,7 @@ class TwistyObjectGhost
 
     if( mGhostAngle!=0 && nonGhostAngle!=0 )
       {
-      boolean moveDo = angleIsDown(axis,0,angleInDegrees);
-      boolean moveUp = angleIsUp(axis,0,angleInDegrees);
-      boolean ghostMove = ( moveUp || moveDo );
-      int mult = mGhostAxisInverted ? -1 : 1;
-
-      if( moveDo ) nonGhostAngle -= mult*mGhostAngle;
-      if( moveUp ) nonGhostAngle += mult*mGhostAngle;
+      // ....
 
       if( mGhostBlocked && axis!=mGhostAxisParallelTo )
         {
@@ -262,11 +177,13 @@ class TwistyObjectGhost
           mGhostAxis.set(mAxis[axis]);
           mGhostAxisParallelTo = axis;
           mGhostAxisInverted   = false;
+
+          for(int l=0; l<mMaxNumLayers; l++)
+            mGhostEffect[l].setMeshAssociation( 1<<(mGhostAxisParallelTo*mMaxNumLayers + l), -1);
           }
         }
 
       mGhostBlocked = ( mGhostRowBitmap!=0 );
-      mGhostEffect.setMeshAssociation(mGhostRowBitmap<<(mGhostAxisParallelTo*mMaxNumLayers),-1);
       }
 
     return nonGhostAngle;
