Pan Gesture Prediction - Added smoothing phase 97/24097/1
authorJulien Heanley <j.heanley@partner.samsung.com>
Thu, 12 Jun 2014 13:40:43 +0000 (14:40 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Tue, 8 Jul 2014 13:19:39 +0000 (14:19 +0100)
Removed SimpleAverageAlgorithm, instead use:
          DALI_PAN_PREDICTION_MODE=0 and DALI_PAN_SMOOTHING_MODE=1
Any prediction method can be combined with any smoothing algorithm (currently only 1 simple algorithm)
Current prediction mode is SMOOTHING_LAST_VALUE(1)

For prediction use DALI_PAN_PREDICTION_MODE=1 with DALI_PAN_PREDICTION_AMOUNT
For smoothing use DALI_PAN_SMOOTHING_MODE=1 with DALI_PAN_SMOOTHING_AMOUNT(0.0 to 1.0)
Increase DALI_PAN_PREDICTION_AMOUNT to make up for touch distance increase due to smoothing

[problem]      Prediction modes are not very smooth
[cause]        Prediction calculations can exagerate movement
[solution]     Add smoothing phase

Change-Id: Ied98227e1dc8002be94bd0449ac09179b7125d75
Signed-off-by: Julien Heanley <j.heanley@partner.samsung.com>
automated-tests/src/dali/utc-Dali-PanGestureDetector.cpp
dali/integration-api/profiling.cpp
dali/integration-api/profiling.h
dali/internal/event/events/gesture-event-processor.cpp
dali/internal/event/events/gesture-event-processor.h
dali/internal/event/events/pan-gesture-processor.cpp
dali/internal/event/events/pan-gesture-processor.h
dali/internal/update/gestures/scene-graph-pan-gesture.cpp
dali/internal/update/gestures/scene-graph-pan-gesture.h

index 943c187..451c40c 100644 (file)
@@ -2013,6 +2013,7 @@ int UtcDaliPanGestureSetProperties(void)
   TestApplication application;
   TestRenderController& renderController( application.GetRenderController() );
   Integration::SetPanGesturePredictionMode(0);
+  Integration::SetPanGestureSmoothingMode(0);
 
   Actor actor = Actor::New();
   actor.SetSize(100.0f, 100.0f);
index a0a13cd..29c4d31 100644 (file)
@@ -117,6 +117,18 @@ void SetPanGesturePredictionAmount(unsigned int amount)
   eventProcessor.SetPanGesturePredictionAmount(amount);
 }
 
+void SetPanGestureSmoothingMode(int mode)
+{
+  GestureEventProcessor& eventProcessor = ThreadLocalStorage::Get().GetGestureEventProcessor();
+  eventProcessor.SetPanGestureSmoothingMode(mode);
+}
+
+void SetPanGestureSmoothingAmount( float amount )
+{
+  GestureEventProcessor& eventProcessor = ThreadLocalStorage::Get().GetGestureEventProcessor();
+  eventProcessor.SetPanGestureSmoothingAmount(amount);
+}
+
 namespace Profiling
 {
 
index 944d1ea..be348ba 100644 (file)
@@ -60,6 +60,20 @@ DALI_IMPORT_API void SetPanGesturePredictionMode( int mode );
  */
 DALI_IMPORT_API void SetPanGesturePredictionAmount(unsigned int amount);
 
+/**
+ * @brief Called to set how pan gestures smooth input
+ *
+ * @param[in] mode The smoothing mode to use
+ */
+DALI_IMPORT_API void SetPanGestureSmoothingMode( int mode );
+
+/**
+ * @brief Sets the prediction amount of the pan gesture
+ *
+ * @param[in] amount The smoothing amount [0.0f,1.0f] - 0.0f would be no smoothing, 1.0f maximum smoothing
+ */
+DALI_IMPORT_API void SetPanGestureSmoothingAmount( float amount );
+
 
 namespace Profiling
 {
index 2233eb3..4a13feb 100644 (file)
@@ -240,6 +240,16 @@ void GestureEventProcessor::SetPanGesturePredictionAmount( unsigned int amount )
   mPanGestureProcessor.SetPredictionAmount(amount);
 }
 
+void GestureEventProcessor::SetPanGestureSmoothingMode(int mode)
+{
+  mPanGestureProcessor.SetSmoothingMode(mode);
+}
+
+void GestureEventProcessor::SetPanGestureSmoothingAmount( float amount )
+{
+  mPanGestureProcessor.SetSmoothingAmount(amount);
+}
+
 } // namespace Internal
 
 } // namespace Dali
index be003e9..2522e48 100644 (file)
@@ -123,7 +123,7 @@ public: // Called by Core
   void EnablePanGestureProfiling();
 
   /**
-   * @brief Called to set how pan gestures predict and smooth input
+   * @brief Called to set how pan gestures predict input
    *
    * @param[in] mode The prediction mode to use
    */
@@ -136,6 +136,20 @@ public: // Called by Core
    */
   void SetPanGesturePredictionAmount( unsigned int amount );
 
+  /**
+   * @brief Called to set how pan gestures smooth input
+   *
+   * @param[in] mode The smoothing mode to use
+   */
+  void SetPanGestureSmoothingMode( int mode );
+
+  /**
+   * @brief Sets the prediction amount of the pan gesture
+   *
+   * @param[in] amount The smoothing amount [0.0f,1.0f] - 0.0f would be no smoothing, 1.0f maximum smoothing
+   */
+  void SetPanGestureSmoothingAmount( float amount );
+
 private:
 
   // Undefined
index 3385553..dd908c7 100644 (file)
@@ -331,6 +331,22 @@ void PanGestureProcessor::SetPredictionAmount(unsigned int amount)
   mSceneObject->SetPredictionAmount(amount);
 }
 
+void PanGestureProcessor::SetSmoothingMode(int mode)
+{
+  if( (mode < 0)
+      || (mode >= SceneGraph::PanGesture::NUM_SMOOTHING_MODES) )
+  {
+    mode = SceneGraph::PanGesture::DEFAULT_SMOOTHING_MODE;
+  }
+  SceneGraph::PanGesture::SmoothingMode modeEnum = static_cast<SceneGraph::PanGesture::SmoothingMode>(mode);
+  mSceneObject->SetSmoothingMode(modeEnum);
+}
+
+void PanGestureProcessor::SetSmoothingAmount(float amount)
+{
+  mSceneObject->SetSmoothingAmount(amount);
+}
+
 void PanGestureProcessor::UpdateDetection()
 {
   DALI_ASSERT_DEBUG(!mGestureDetectors.empty());
index 290e9a2..2691405 100644 (file)
@@ -133,6 +133,24 @@ public: // To be called by GestureEventProcessor
    */
   void SetPredictionAmount(unsigned int amount);
 
+  /**
+   * Called to set the prediction mode for pan gestures
+   *
+   * @param[in] mode The prediction mode
+   *
+   * Valid modes:
+   * 0 - No smoothing
+   * 1 - average between last 2 values
+   */
+  void SetSmoothingMode(int mode);
+
+  /**
+   * @brief Sets the smoothing amount of the pan gesture
+   *
+   * @param[in] amount The smotthing amount from 0.0f (none) to 1.0f (full)
+   */
+  void SetSmoothingAmount(float amount);
+
 private:
 
   // Undefined
index 4ee7ddd..ccf2b8d 100644 (file)
@@ -35,10 +35,14 @@ namespace
 {
 const int MAX_GESTURE_AGE = 50; ///< maximum age of a gesture before disallowing its use in algorithm
 const unsigned int DEFAULT_PREDICTION_INTERPOLATION = 0; ///< how much to interpolate pan position and displacement from last vsync time
+const float DEFAULT_SMOOTHING_AMOUNT = 1.0f; ///< how much to interpolate pan position and displacement from last vsync time
 } // unnamed namespace
 
-const PanGesture::PredictionMode PanGesture::DEFAULT_PREDICTION_MODE = PanGesture::AVERAGE;
-const int PanGesture::NUM_PREDICTION_MODES = PanGesture::PREDICTION_2 + 1;
+const PanGesture::PredictionMode PanGesture::DEFAULT_PREDICTION_MODE = PanGesture::PREDICTION_NONE;
+const int PanGesture::NUM_PREDICTION_MODES = PanGesture::PREDICTION_1 + 1;
+
+const PanGesture::SmoothingMode PanGesture::DEFAULT_SMOOTHING_MODE = PanGesture::SMOOTHING_LAST_VALUE;
+const int PanGesture::NUM_SMOOTHING_MODES = PanGesture::SMOOTHING_LAST_VALUE + 1;
 
 PanGesture* PanGesture::New()
 {
@@ -73,28 +77,12 @@ void PanGesture::RemoveOldHistory(PanInfoHistory& panHistory, unsigned int curre
     iter = panHistory.erase(iter);
     endIter = panHistory.end();
   }
-}
 
-void PanGesture::SimpleAverageAlgorithm(bool justStarted, PanInfo& gestureOut, unsigned int lastVSyncTime)
-{
-  if( mInGesture )
+  // dont want more than 5 previous predictions for smoothing
+  iter = mPredictionHistory.begin();
+  while( mPredictionHistory.size() > 1 && iter != mPredictionHistory.end() )
   {
-    if( !justStarted )
-    {
-      gestureOut.screen.position += mLastEventGesture.screen.position;
-      gestureOut.local.position += mLastEventGesture.local.position;
-      gestureOut.screen.position *= 0.5f;
-      gestureOut.local.position *= 0.5f;
-      // make current displacement relative to previous update-frame now.
-      gestureOut.screen.displacement = gestureOut.screen.position - mLastEventGesture.screen.position;
-      gestureOut.local.displacement = gestureOut.local.position - mLastEventGesture.local.position;
-      // calculate velocity relative to previous update-frame
-      unsigned int timeDiff( lastVSyncTime - mLastEventGesture.time );
-      gestureOut.screen.velocity = gestureOut.screen.displacement / timeDiff;
-      gestureOut.local.velocity = gestureOut.local.displacement / timeDiff;
-    }
-
-    gestureOut.time = lastVSyncTime;
+    iter = mPredictionHistory.erase(iter);
   }
 }
 
@@ -112,11 +100,14 @@ void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut,
   PanInfoHistoryIter iter = panHistory.begin();
   Vector2 screenVelocity = gestureOut.screen.velocity;
   Vector2 localVelocity = gestureOut.local.velocity;
+  Vector2 screenDisplacement = gestureOut.screen.displacement;
+  Vector2 localDisplacement = gestureOut.local.displacement;
 
   bool havePreviousAcceleration = false;
   bool previousVelocity = false;
   float previousAccel = 0.0f;
   unsigned int lastTime(0);
+  unsigned int interpolationTime = (lastVSyncTime + mPredictionAmount) - gestureOut.time;
   while( iter != endIter )
   {
     PanInfo currentGesture = *iter;
@@ -129,6 +120,7 @@ void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut,
       ++iter;
       continue;
     }
+    float previousValueWeight = (float)(MAX_GESTURE_AGE - (lastVSyncTime - lastTime)) / (float)MAX_GESTURE_AGE;
     float velMag = currentGesture.screen.velocity.Length();
     float velDiff = velMag - screenVelocity.Length();
     float acceleration = 0.0f;
@@ -137,16 +129,16 @@ void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut,
     {
       acceleration = velDiff / time;
     }
-    float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
     float newVelMag = 0.0f;
+    int currentInterpolation = interpolationTime; //(lastVSyncTime + mPredictionAmount) - currentGesture.time;
     if( !havePreviousAcceleration )
     {
-      newVelMag =  velMag + (acceleration * interpolationTime);
+      newVelMag =  velMag;
       havePreviousAcceleration = true;
     }
     else
     {
-      newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime);
+      newVelMag = velMag + (((acceleration * (1.0f - previousValueWeight)) + (previousAccel * previousValueWeight)) * currentInterpolation);
     }
     float velMod = 1.0f;
     if( velMag > Math::MACHINE_EPSILON_1 )
@@ -155,6 +147,8 @@ void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut,
     }
     gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
     gestureOut.local.velocity = currentGesture.local.velocity * velMod;
+    screenDisplacement = gestureOut.screen.displacement + (gestureOut.screen.velocity * interpolationTime);
+    localDisplacement = gestureOut.local.displacement + (gestureOut.local.velocity * interpolationTime);
     screenVelocity = currentGesture.screen.velocity;
     localVelocity = currentGesture.local.velocity;
     previousAccel = acceleration;
@@ -162,92 +156,55 @@ void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut,
   }
   // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
   // add interpolated distance and position to current
-  float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time);
   // work out interpolated velocity
-  gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime);
-  gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime);
-  gestureOut.screen.position += gestureOut.screen.displacement;
-  gestureOut.local.position += gestureOut.local.displacement;
-  gestureOut.time += (lastVSyncTime - gestureOut.time);
+  gestureOut.screen.position = (gestureOut.screen.position - gestureOut.screen.displacement) + screenDisplacement;
+  gestureOut.local.position = (gestureOut.local.position - gestureOut.local.displacement) + localDisplacement;
+  gestureOut.screen.displacement = screenDisplacement;
+  gestureOut.local.displacement = localDisplacement;
+  gestureOut.time += interpolationTime;
 }
 
-void PanGesture::PredictiveAlgorithm2(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
+void PanGesture::SmoothingAlgorithm1(bool justStarted, PanInfo& gestureOut, unsigned int lastVSyncTime)
 {
-  // TODO - adapt PredictiveAlgorithm1 with better smoothing, still under development
-  RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
-  size_t panHistorySize = panHistory.size();
-  if( panHistorySize == 0 )
+  if( !justStarted )
   {
-    // cant do any prediction without a history
-    return;
+    gestureOut.screen.position -= (gestureOut.screen.position - mLastGesture.screen.position) * 0.5f * (1.0f - mSmoothingAmount);
+    gestureOut.local.position -= (gestureOut.local.position - mLastGesture.local.position) * 0.5f * (1.0f - mSmoothingAmount);
+    // make current displacement relative to previous update-frame now.
+    gestureOut.screen.displacement = gestureOut.screen.position - mLastGesture.screen.position;
+    gestureOut.local.displacement = gestureOut.local.position - mLastGesture.local.position;
+    // calculate velocity relative to previous update-frame
+    unsigned int timeDiff( gestureOut.time - mLastGesture.time );
+    gestureOut.screen.velocity = gestureOut.screen.displacement / timeDiff;
+    gestureOut.local.velocity = gestureOut.local.displacement / timeDiff;
   }
+}
 
-  PanInfoHistoryConstIter endIter = panHistory.end();
-  PanInfoHistoryIter iter = panHistory.begin();
-  Vector2 screenVelocity = gestureOut.screen.velocity;
-  Vector2 localVelocity = gestureOut.local.velocity;
-  Vector2 screenDisplacement = gestureOut.screen.displacement;
-  Vector2 localDisplacement = gestureOut.local.displacement;
+void PanGesture::SmoothingAlgorithm2(bool justStarted, PanInfo& gestureOut, unsigned int lastVSyncTime)
+{
+  // push back result
+  mPredictionHistory.push_back(gestureOut);
 
-  bool havePreviousAcceleration = false;
-  bool previousVelocity = false;
-  float previousAccel = 0.0f;
-  unsigned int lastTime(0);
-  unsigned int interpolationTime = (lastVSyncTime + mPredictionAmount) - gestureOut.time;
+  // now smooth current pan event
+  PanInfoHistoryConstIter endIter = mPredictionHistory.end() - 1;
+  PanInfoHistoryIter iter = mPredictionHistory.begin();
+
+  float distanceMod = 1.0f;
+  float weight = 0.8f;
   while( iter != endIter )
   {
     PanInfo currentGesture = *iter;
-    if( !previousVelocity )
-    {
-      // not yet set a previous velocity
-      screenVelocity = currentGesture.screen.velocity;
-      previousVelocity = true;
-      lastTime = currentGesture.time;
-      ++iter;
-      continue;
-    }
-    float previousValueWeight = (float)(MAX_GESTURE_AGE - (lastVSyncTime - lastTime)) / (float)MAX_GESTURE_AGE;
-    float velMag = currentGesture.screen.velocity.Length();
-    float velDiff = velMag - screenVelocity.Length();
-    float acceleration = 0.0f;
-    float time = (float)(currentGesture.time - lastTime);
-    if( time > Math::MACHINE_EPSILON_1 )
-    {
-      acceleration = velDiff / time;
-    }
-    float newVelMag = 0.0f;
-    int currentInterpolation = (lastVSyncTime + mPredictionAmount) - currentGesture.time;
-    if( !havePreviousAcceleration )
-    {
-      newVelMag =  velMag + (acceleration * currentInterpolation);
-      havePreviousAcceleration = true;
-    }
-    else
-    {
-      newVelMag = velMag + (((acceleration * (1.0f - previousValueWeight)) + (previousAccel * previousValueWeight)) * interpolationTime);
-    }
-    float velMod = 1.0f;
-    if( velMag > Math::MACHINE_EPSILON_1 )
-    {
-      velMod = newVelMag / velMag;
-    }
-    gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
-    gestureOut.local.velocity = currentGesture.local.velocity * velMod;
-    screenDisplacement = gestureOut.screen.displacement + (gestureOut.screen.velocity * interpolationTime);
-    localDisplacement = gestureOut.local.displacement + (gestureOut.local.velocity * interpolationTime);
-    screenVelocity = currentGesture.screen.velocity;
-    localVelocity = currentGesture.local.velocity;
-    previousAccel = acceleration;
+    float newDistanceMod = currentGesture.screen.displacement.Length() / gestureOut.screen.displacement.Length();
+    distanceMod = ((distanceMod * weight) + (newDistanceMod * (1.0f - weight)));
+    weight -= 0.15f;
     ++iter;
   }
-  // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
-  // add interpolated distance and position to current
-  // work out interpolated velocity
-  gestureOut.screen.displacement = screenDisplacement;
-  gestureOut.local.displacement = localDisplacement;
-  gestureOut.screen.position = (gestureOut.screen.position - gestureOut.screen.displacement) + screenDisplacement;
-  gestureOut.local.position = (gestureOut.local.position - gestureOut.local.displacement) + localDisplacement;
-  gestureOut.time += interpolationTime;
+  gestureOut.screen.position -= gestureOut.screen.displacement;
+  gestureOut.local.position -= gestureOut.local.displacement;
+  gestureOut.screen.displacement *= distanceMod;
+  gestureOut.local.displacement *= distanceMod;
+  gestureOut.screen.position += gestureOut.screen.displacement;
+  gestureOut.local.position += gestureOut.local.displacement;
 }
 
 bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime )
@@ -256,6 +213,7 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
   {
     // clear current pan history
     mPanHistory.clear();
+    mPredictionHistory.clear();
   }
 
   // create an event for this frame
@@ -268,7 +226,8 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
   int eventsThisFrame = 0;
 
   // create PanInfo to pass into prediction method
-  PanInfo nextGesture = mEventGesture;
+  mLastEventGesture = mEventGesture;
+  mLastGesture = mLatestGesture;
   // add new gestures and work out one full gesture for the frame
   while(mReadPosition != mWritePosition)
   {
@@ -279,26 +238,25 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
     {
       mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position ) );
     }
-    nextGesture.local.position = currentGesture.local.position;
-    nextGesture.local.velocity = currentGesture.local.velocity;
-    nextGesture.screen.position = currentGesture.screen.position;
-    nextGesture.screen.velocity = currentGesture.screen.velocity;
+    mEventGesture.local.position = currentGesture.local.position;
+    mEventGesture.local.velocity = currentGesture.local.velocity;
+    mEventGesture.screen.position = currentGesture.screen.position;
+    mEventGesture.screen.velocity = currentGesture.screen.velocity;
     if( !eventFound )
     {
-      nextGesture.local.displacement = currentGesture.local.displacement;
-      nextGesture.screen.displacement = currentGesture.screen.displacement;
+      mEventGesture.local.displacement = currentGesture.local.displacement;
+      mEventGesture.screen.displacement = currentGesture.screen.displacement;
     }
     else
     {
-      nextGesture.local.displacement += currentGesture.local.displacement;
-      nextGesture.screen.displacement += currentGesture.screen.displacement;
+      mEventGesture.local.displacement += currentGesture.local.displacement;
+      mEventGesture.screen.displacement += currentGesture.screen.displacement;
     }
     eventFound = true;
-    nextGesture.time = currentGesture.time;
+    mEventGesture.time = currentGesture.time;
 
     // add event to history
     mPanHistory.push_back(currentGesture);
-    justStarted |= (currentGesture.state == Gesture::Started);
     if( currentGesture.state == Gesture::Started )
     {
       justStarted = true;
@@ -312,8 +270,7 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
     ++mReadPosition;
     mReadPosition %= PAN_GESTURE_HISTORY;
   }
-  // set nextGesture to last gesture so it's position is correct and velocity is same as last frame
-  mEventGesture = nextGesture;
+  mLatestGesture = mEventGesture;
 
   mInGesture |= justStarted;
 
@@ -328,56 +285,57 @@ bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int next
 
     switch( mPredictionMode )
     {
-      case NONE:
+      case PREDICTION_NONE:
       {
         updateProperties = eventFound;
+        // dont want event time
+        unsigned int time = mLastGesture.time;
+        mLastGesture = mLastEventGesture;
+        mLastGesture.time = time;
+        mLatestGesture.time = lastVSyncTime;
         break;
       }
-      case AVERAGE:
+      case PREDICTION_1:
       {
-        SimpleAverageAlgorithm(justStarted, nextGesture, lastVSyncTime);
-        // make latest gesture equal to current gesture after averaging
+        // make latest gesture equal to current gesture before interpolation
+        PredictiveAlgorithm1(eventsThisFrame, mLatestGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
         updateProperties = true;
         break;
       }
-      case PREDICTION_1:
+    }
+
+    switch( mSmoothingMode )
+    {
+      case SMOOTHING_NONE:
       {
-        // make latest gesture equal to current gesture before interpolation
-        PredictiveAlgorithm1(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
-        updateProperties = true;
+        // no smoothing
         break;
       }
-      case PREDICTION_2:
+      case SMOOTHING_LAST_VALUE:
       {
-        // make latest gesture equal to current gesture before interpolation
-        PredictiveAlgorithm2(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
-        updateProperties = true;
+        SmoothingAlgorithm1(justStarted, mLatestGesture, lastVSyncTime);
         break;
       }
     }
 
-    // always keep latest gesture up to date with event gesture
-    mLatestGesture = nextGesture;
-
     if( updateProperties )
     {
       // only update properties if event received
       // set latest gesture to raw pan info with unchanged time
       mPanning.Set( mInGesture & !justFinished );
-      mScreenPosition.Set( nextGesture.screen.position );
-      mScreenDisplacement.Set( nextGesture.screen.displacement );
-      mScreenVelocity.Set( nextGesture.screen.velocity );
-      mLocalPosition.Set( nextGesture.local.position );
-      mLocalDisplacement.Set( nextGesture.local.displacement );
-      mLocalVelocity.Set( nextGesture.local.velocity );
+      mScreenPosition.Set( mLatestGesture.screen.position );
+      mScreenDisplacement.Set( mLatestGesture.screen.displacement );
+      mScreenVelocity.Set( mLatestGesture.screen.velocity );
+      mLocalPosition.Set( mLatestGesture.local.position );
+      mLocalDisplacement.Set( mLatestGesture.local.displacement );
+      mLocalVelocity.Set( mLatestGesture.local.velocity );
     }
 
     if( mProfiling )
     {
-      mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( nextGesture.time, nextGesture.screen.position ) );
+      mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( mLatestGesture.time, mLatestGesture.screen.position ) );
     }
   }
-  mLastEventGesture = mEventGesture;
 
   mInGesture &= ~justFinished;
 
@@ -435,6 +393,16 @@ void PanGesture::SetPredictionAmount(unsigned int amount)
   mPredictionAmount = amount;
 }
 
+void PanGesture::SetSmoothingMode(SmoothingMode mode)
+{
+  mSmoothingMode = mode;
+}
+
+void PanGesture::SetSmoothingAmount(float amount)
+{
+  mSmoothingAmount = amount;
+}
+
 void PanGesture::EnableProfiling()
 {
   if( !mProfiling )
@@ -459,6 +427,8 @@ PanGesture::PanGesture()
   mInGesture( false ),
   mPredictionMode(DEFAULT_PREDICTION_MODE),
   mPredictionAmount(DEFAULT_PREDICTION_INTERPOLATION),
+  mSmoothingMode(DEFAULT_SMOOTHING_MODE),
+  mSmoothingAmount(DEFAULT_SMOOTHING_AMOUNT),
   mProfiling( NULL )
 {
 }
index 964379e..99d8688 100644 (file)
@@ -46,15 +46,22 @@ public:
 
   enum PredictionMode
   {
-    NONE,
-    AVERAGE,
-    PREDICTION_1,
-    PREDICTION_2
+    PREDICTION_NONE = 0,
+    PREDICTION_1
+  };
+
+  enum SmoothingMode
+  {
+    SMOOTHING_NONE,           // no smoothing
+    SMOOTHING_LAST_VALUE,     // smooth between last value and latest value
   };
 
   static const PredictionMode DEFAULT_PREDICTION_MODE;
   static const int NUM_PREDICTION_MODES;
 
+  static const SmoothingMode DEFAULT_SMOOTHING_MODE;
+  static const int NUM_SMOOTHING_MODES;
+
   // Latest Pan Information
 
   /**
@@ -199,23 +206,23 @@ public:
   void RemoveOldHistory(PanInfoHistory& panHistory, unsigned int currentTime, unsigned int maxAge, unsigned int minEvents);
 
   /**
-   * USes last two gestures
+   * Uses elapsed time and time stamps
+   */
+  void PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime);
+
+  /**
+   * Uses last two gestures
    *
    * @param[in]  justStarted Whether the pan has just started.
    * @param[out] gestureOut Output gesture using average values from last two gestures
    * @param[in]  lastVSyncTime The time to set on gestureOut.
    */
-  void SimpleAverageAlgorithm(bool justStarted, PanInfo& gestureOut, unsigned int lastVSyncTime);
-
-  /**
-   * Uses elapsed time and time stamps
-   */
-  void PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime);
+  void SmoothingAlgorithm1(bool justStarted, PanInfo& gestureOut, unsigned int lastVSyncTime);
 
   /**
-   * Uses elapsed time, time stamps and future render time
+   * Future smoothing method, implementation not complete
    */
-  void PredictiveAlgorithm2(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime);
+  void SmoothingAlgorithm2(bool justStarted, PanInfo& gestureOut, unsigned int lastVSyncTime);
 
   /**
    * Called by the update manager so that we can update the value of our properties.
@@ -281,6 +288,20 @@ public:
   void SetPredictionAmount(unsigned int amount);
 
   /**
+   * @brief Sets the prediction mode of the pan gesture
+   *
+   * @param[in] mode The prediction mode
+   */
+  void SetSmoothingMode(SmoothingMode mode);
+
+  /**
+   * @brief Sets the amount of smoothing to apply for the current smoothing mode
+   *
+   * @param[in] amount The amount of smoothing [0.0f,1.0f]
+   */
+  void SetSmoothingAmount(float amount);
+
+  /**
    * Called to provide pan-gesture profiling information.
    */
   void EnableProfiling();
@@ -314,16 +335,20 @@ private:
 
   PanInfo mGestures[PAN_GESTURE_HISTORY];         ///< Circular buffer storing the 4 most recent gestures.
   PanInfoHistory mPanHistory;
+  PanInfoHistory mPredictionHistory;
   unsigned int mWritePosition;  ///< The next PanInfo buffer to write to. (starts at 0)
   unsigned int mReadPosition;   ///< The next PanInfo buffer to read. (starts at 0)
 
   PanInfo mEventGesture;        ///< Result of all pan events received this frame
   PanInfo mLastEventGesture;    ///< The last frame's event gesture.
+  PanInfo mLastGesture;         ///< The latest gesture. (this update frame)
   PanInfo mLatestGesture;       ///< The latest gesture. (this update frame)
   bool mInGesture;              ///< True if the gesture is currently being handled i.e. between Started <-> Finished/Cancelled
 
   PredictionMode mPredictionMode;  ///< The pan gesture prediction mode
   unsigned int mPredictionAmount;  ///< how far into future to predict in milliseconds
+  SmoothingMode mSmoothingMode;    ///< The pan gesture prediction mode
+  float         mSmoothingAmount;  ///< How much smoothing to apply [0.0f,1.0f]
   PanGestureProfiling* mProfiling; ///< NULL unless pan-gesture profiling information is required.
 };