commit c7b00dfb81c3a2094f5f884226457fd6a3b1c03e
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Fri Jun 26 14:54:30 2020 +0100

    Introduce two-fingered object resize.

diff --git a/src/main/java/org/distorted/main/RubikSurfaceView.java b/src/main/java/org/distorted/main/RubikSurfaceView.java
index b7b70151..5471882d 100644
--- a/src/main/java/org/distorted/main/RubikSurfaceView.java
+++ b/src/main/java/org/distorted/main/RubikSurfaceView.java
@@ -72,7 +72,7 @@ public class RubikSurfaceView extends GLSurfaceView
     private boolean mDragging, mBeginningRotation, mContinuingRotation;
     private int mScreenWidth, mScreenHeight, mScreenMin;
 
-    private float mRotAngle;
+    private float mRotAngle, mInitDistance;
     private int mPtrID1, mPtrID2;
     private float mX, mY;
     private float mStartRotX, mStartRotY;
@@ -374,6 +374,13 @@ public class RubikSurfaceView extends GLSurfaceView
         mTemp.set(dragQuat);
 
         mRotAngle = angleNow;
+
+        float distNow  = (float)Math.sqrt( (x-x2)*(x-x2) + (y-y2)*(y-y2) );
+        float distQuot = mInitDistance<0 ? 1.0f : distNow/ mInitDistance;
+        mInitDistance = distNow;
+
+        RubikObject object = mPreRender.getObject();
+        object.setObjectRatio(distQuot);
         }
       else
         {
@@ -575,6 +582,7 @@ public class RubikSurfaceView extends GLSurfaceView
           float y2 = event.getY(pointer);
 
           mRotAngle = getAngle(x,-y,x2,-y2);
+          mInitDistance = -1;
           }
 
         mX = (x - mScreenWidth*0.5f)/mScreenMin;
@@ -595,6 +603,7 @@ public class RubikSurfaceView extends GLSurfaceView
           float y2 = event.getY(pointer);
 
           mRotAngle = getAngle(x,-y,x2,-y2);
+          mInitDistance = -1;
           }
 
         if( mBeginningRotation || mContinuingRotation )
diff --git a/src/main/java/org/distorted/objects/RubikObject.java b/src/main/java/org/distorted/objects/RubikObject.java
index a487609c..3abbcc30 100644
--- a/src/main/java/org/distorted/objects/RubikObject.java
+++ b/src/main/java/org/distorted/objects/RubikObject.java
@@ -52,6 +52,10 @@ import java.io.InputStream;
 
 public abstract class RubikObject extends DistortedNode
   {
+  private static final float NODE_RATIO = 1.32f;
+  private static final float MAX_SIZE_CHANGE = 1.3f;
+  private static final float MIN_SIZE_CHANGE = 0.8f;
+
   private static final Static3D CENTER = new Static3D(0,0,0);
   static final int INTERIOR_COLOR = 0xff000000;
   private static final int POST_ROTATION_MILLISEC = 500;
@@ -61,7 +65,7 @@ public abstract class RubikObject extends DistortedNode
   final Static4D[] QUATS;
   final int NUM_FACES;
 
-  static float OBJECT_SCREEN_RATIO;
+  private static float mInitScreenRatio,mObjectScreenRatio;
 
   private final int NUM_CUBITS;
   private final int mNodeSize;
@@ -78,6 +82,7 @@ public abstract class RubikObject extends DistortedNode
   private VertexEffectRotate mRotateEffect;
   private Dynamic1D mRotationAngle;
   private Static3D mRotationAxis;
+  private Static3D mObjectScale;
 
   float mStart, mStep;
 
@@ -96,7 +101,7 @@ public abstract class RubikObject extends DistortedNode
 
     mNodeSize = screenWidth;
 
-    resizeFBO(mNodeSize, mNodeSize);
+    resizeFBO(mNodeSize, (int)(NODE_RATIO*mNodeSize));
 
     mList = list;
     mOrigPos = getCubitPositions(size);
@@ -104,12 +109,13 @@ public abstract class RubikObject extends DistortedNode
     QUATS = getQuats();
     NUM_CUBITS  = mOrigPos.length;
     ROTATION_AXIS = getRotationAxis();
-    OBJECT_SCREEN_RATIO = getScreenRatio();
+    mObjectScreenRatio = getScreenRatio();
+    mInitScreenRatio = mObjectScreenRatio;
     NUM_FACES = getNumFaces();
 
     mSize = size;
     computeStartAndStep(mOrigPos);
-    mNodeScale= new Static3D(1,1,1);
+    mNodeScale= new Static3D(1,NODE_RATIO,1);
     mQuat = quat;
 
     mRotationAngle= new Dynamic1D();
@@ -120,8 +126,9 @@ public abstract class RubikObject extends DistortedNode
     mRotationAngleMiddle = new Static1D(0);
     mRotationAngleFinal  = new Static1D(0);
 
-    float scale = OBJECT_SCREEN_RATIO*mNodeSize/mSize;
-    mScaleEffect = new MatrixEffectScale(new Static3D(scale,scale,scale));
+    float scale = mObjectScreenRatio*mNodeSize/mSize;
+    mObjectScale= new Static3D(scale,scale,scale);
+    mScaleEffect = new MatrixEffectScale(mObjectScale);
     mQuatEffect  = new MatrixEffectQuaternion(quat, CENTER);
 
     MatrixEffectScale nodeScaleEffect = new MatrixEffectScale(mNodeScale);
@@ -173,6 +180,32 @@ public abstract class RubikObject extends DistortedNode
     setProjection(fov, 0.1f);
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void setObjectRatio(float sizeChange)
+    {
+    mObjectScreenRatio *= (1.0f+sizeChange)/2;
+
+    if( mObjectScreenRatio > MAX_SIZE_CHANGE*mInitScreenRatio)
+      {
+      mObjectScreenRatio = MAX_SIZE_CHANGE*mInitScreenRatio;
+      }
+    if( mObjectScreenRatio < MIN_SIZE_CHANGE*mInitScreenRatio)
+      {
+      mObjectScreenRatio = MIN_SIZE_CHANGE*mInitScreenRatio;
+      }
+
+    float scale = mObjectScreenRatio*mNodeSize/mSize;
+    mObjectScale.set(scale,scale,scale);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static float getObjectRatio()
+    {
+    return mObjectScreenRatio;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Cast centers of all Cubits on the first rotation Axis and compute the leftmost and rightmost
 // one. From there compute the 'start' (i.e. the leftmost) and 'step' (i.e. distance between two
@@ -356,7 +389,7 @@ public abstract class RubikObject extends DistortedNode
   public void recomputeScaleFactor(int scrWidth, int scrHeight)
     {
     float factor = Math.min(scrWidth,scrHeight);
-    mNodeScale.set(factor,factor,factor);
+    mNodeScale.set(factor,NODE_RATIO*factor,factor);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -615,7 +648,7 @@ public abstract class RubikObject extends DistortedNode
 
     if( tmp!=0 ) return NEAREST*tmp;
 
-    return speed> 1.3f ? NEAREST*(angle>0 ? 1:-1) : 0;
+    return speed> 1.2f ? NEAREST*(angle>0 ? 1:-1) : 0;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/objects/RubikObjectMovement.java b/src/main/java/org/distorted/objects/RubikObjectMovement.java
index 100f87c3..77f06fbb 100644
--- a/src/main/java/org/distorted/objects/RubikObjectMovement.java
+++ b/src/main/java/org/distorted/objects/RubikObjectMovement.java
@@ -247,13 +247,15 @@ public abstract class RubikObjectMovement
 
   public boolean faceTouched(Static4D rotatedTouchPoint, Static4D rotatedCamera)
     {
-    mPoint[0]  = rotatedTouchPoint.get0()/RubikObject.OBJECT_SCREEN_RATIO;
-    mPoint[1]  = rotatedTouchPoint.get1()/RubikObject.OBJECT_SCREEN_RATIO;
-    mPoint[2]  = rotatedTouchPoint.get2()/RubikObject.OBJECT_SCREEN_RATIO;
+    float objectRatio = RubikObject.getObjectRatio();
 
-    mCamera[0] = rotatedCamera.get0()/RubikObject.OBJECT_SCREEN_RATIO;
-    mCamera[1] = rotatedCamera.get1()/RubikObject.OBJECT_SCREEN_RATIO;
-    mCamera[2] = rotatedCamera.get2()/RubikObject.OBJECT_SCREEN_RATIO;
+    mPoint[0]  = rotatedTouchPoint.get0()/objectRatio;
+    mPoint[1]  = rotatedTouchPoint.get1()/objectRatio;
+    mPoint[2]  = rotatedTouchPoint.get2()/objectRatio;
+
+    mCamera[0] = rotatedCamera.get0()/objectRatio;
+    mCamera[1] = rotatedCamera.get1()/objectRatio;
+    mCamera[2] = rotatedCamera.get2()/objectRatio;
 
     for( mLastTouchedAxis=0; mLastTouchedAxis<mNumAxis; mLastTouchedAxis++)
       {
@@ -276,9 +278,11 @@ public abstract class RubikObjectMovement
 
   public Static2D newRotation(Static4D rotatedTouchPoint)
     {
-    mPoint[0] = rotatedTouchPoint.get0()/RubikObject.OBJECT_SCREEN_RATIO;
-    mPoint[1] = rotatedTouchPoint.get1()/RubikObject.OBJECT_SCREEN_RATIO;
-    mPoint[2] = rotatedTouchPoint.get2()/RubikObject.OBJECT_SCREEN_RATIO;
+    float objectRatio = RubikObject.getObjectRatio();
+
+    mPoint[0] = rotatedTouchPoint.get0()/objectRatio;
+    mPoint[1] = rotatedTouchPoint.get1()/objectRatio;
+    mPoint[2] = rotatedTouchPoint.get2()/objectRatio;
 
     castTouchPointOntoFace(mAxis[mLastTouchedAxis], mLastTouchedLR, mTouch);
     convertTo2Dcoords(mTouch, mAxis[mLastTouchedAxis], mLastTouchedLR, mMove2D);
