+ // Dynamically change the prediction amount according to the pan velocity acceleration.
+ if( !frameInfo.justStarted )
+ {
+ if( frameInfo.eventsThisFrame <= 1 )
+ {
+ frameInfo.acceleration = frameGesture.screen.velocity.Length() - mLastUnmodifiedGesture.screen.velocity.Length();
+ }
+
+ // Ignore tiny velocity fluctuation to avoid unnecessary prediction amount change
+ if( fabsf( frameInfo.acceleration ) > ACCELERATION_THRESHOLD )
+ {
+ mCurrentPredictionAmount += mPredictionAmountAdjustment * ( frameInfo.acceleration > Math::MACHINE_EPSILON_0 ? 1.0f : -1.0f );
+ if( mCurrentPredictionAmount > mMaxPredictionAmount + mPredictionAmountAdjustment ) // Guard against unsigned int overflow
+ {
+ mCurrentPredictionAmount = 0;
+ }
+ }
+ }
+ else
+ {
+ mCurrentPredictionAmount = mPredictionAmount; // Reset the prediction amount for each new gesture
+ }
+
+ mCurrentPredictionAmount = std::max( mMinPredictionAmount, std::min( mCurrentPredictionAmount, mMaxPredictionAmount ) );
+
+ // Calculate the delta of positions before the prediction
+ Vector2 deltaPosition = frameGesture.screen.position - mLastUnmodifiedGesture.screen.position;
+
+ // Make latest gesture equal to current gesture before interpolation
+ PredictiveAlgorithm1( frameInfo.eventsThisFrame, frameGesture, mPanHistory, lastVSyncTime, nextVSyncTime );
+
+ // Calculate the delta of positions after the prediction.
+ Vector2 deltaPredictedPosition = frameGesture.screen.position - mLastGesture.screen.position;
+
+ // If the change in the prediction has a different sign than the change in the actual position,
+ // there is overshot (i.e. the current prediction is too large). Return the previous prediction
+ // to give the user's finger a chance to catch up with where we have panned to.
+ bool overshotXAxis = false;
+ bool overshotYAxis = false;
+ if( (deltaPosition.x > Math::MACHINE_EPSILON_0 && deltaPredictedPosition.x < Math::MACHINE_EPSILON_0 )
+ || (deltaPosition.x < Math::MACHINE_EPSILON_0 && deltaPredictedPosition.x > Math::MACHINE_EPSILON_0 ) )
+ {
+ overshotXAxis = true;
+ frameGesture.screen.position.x = mLastGesture.screen.position.x;
+ }
+
+ if( (deltaPosition.y > Math::MACHINE_EPSILON_0 && deltaPredictedPosition.y < Math::MACHINE_EPSILON_0 )
+ || (deltaPosition.y < Math::MACHINE_EPSILON_0 && deltaPredictedPosition.y > Math::MACHINE_EPSILON_0 ) )
+ {
+ overshotYAxis = true;
+ frameGesture.screen.position.y = mLastGesture.screen.position.y;
+ }
+
+ // If there is overshot in one axis, reduce the possible overshot in the other axis,
+ // and reduce the prediction amount so that it doesn't overshoot as easily next time.
+ if(overshotXAxis || overshotYAxis)
+ {
+ mCurrentPredictionAmount -= mPredictionAmountAdjustment;
+ if( mCurrentPredictionAmount > mMaxPredictionAmount + mPredictionAmountAdjustment ) // Guard against unsigned int overflow
+ {
+ mCurrentPredictionAmount = 0;
+ }
+ mCurrentPredictionAmount = std::max( mMinPredictionAmount, std::min( mCurrentPredictionAmount, mMaxPredictionAmount ) );
+
+ if( overshotXAxis && !overshotYAxis )
+ {
+ frameGesture.screen.position.y = ( mLastGesture.screen.position.y + frameGesture.screen.position.y ) * 0.5f;
+ }
+
+ if( overshotYAxis && !overshotXAxis )
+ {
+ frameGesture.screen.position.x = ( mLastGesture.screen.position.x + frameGesture.screen.position.x ) * 0.5f;
+ }
+ }
+