Revert "[Tizen] Adds transition effect"
[platform/core/uifw/dali-core.git] / dali / internal / update / gestures / scene-graph-pan-gesture.cpp
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
20
21 // EXTERNAL INCLUDES
22 #include <cmath>
23
24 // INTERNAL INCLUDES
25 #include <dali/integration-api/debug.h>
26 #include <dali/internal/update/gestures/pan-gesture-profiling.h>
27
28 namespace Dali
29 {
30 namespace Internal
31 {
32 namespace SceneGraph
33 {
34 namespace
35 {
36 // TODO: Experimental - for changing in code only:
37 const bool TEST_TUNE_ENABLE_OVERSHOOT_PROTECTION = false;
38
39 // Internal defaults:
40 const int   MAX_GESTURE_AGE        = 200;               ///< maximum age of a gesture before disallowing its use in algorithm TODO: Possibly make this configurable.
41 const float ACCELERATION_THRESHOLD = 0.1f;              ///< minimum pan velocity change to trigger dynamic change of prediction amount.
42 const float OUTPUT_TIME_DIFFERENCE = (1000.0f / 60.0f); ///< This is used to optionally override actual times if they make results worse.
43 const float ACCELERATION_SMOOTHING = 0.44f;             ///< Smoothes acceleration changes from one frame to another.
44 const float ACCELERATION_CAP       = 0.0004f;           ///< Limits acceleration changes from one frame to another.
45
46 // Defaults for Environment Variables:
47
48 // Prediction Mode 1:
49 const unsigned int DEFAULT_MAX_PREDICTION_AMOUNT        = 32; ///< the upper bound of the range to clamp the prediction interpolation.
50 const unsigned int DEFAULT_MIN_PREDICTION_AMOUNT        = 0;  ///< the lower bound of the range to clamp the prediction interpolation.
51 const unsigned int DEFAULT_PREDICTION_AMOUNT_ADJUSTMENT = 2;  ///< the amount of prediction interpolation to adjust (in milliseconds) each time when pan velocity changes.
52
53 // Prediction Mode 2:
54 const bool  DEFAULT_USE_ACTUAL_TIMES                = false; ///< Disable to optionally override actual times if they make results worse.
55 const int   DEFAULT_INTERPOLATION_TIME_RANGE        = 255;   ///< Time into past history (ms) to use points to interpolate the first point.
56 const bool  DEFAULT_SCALAR_ONLY_PREDICTION_ENABLED  = false; ///< If enabled, prediction is done using velocity alone (no integration or acceleration).
57 const bool  DEFAULT_TWO_POINT_PREDICTION_ENABLED    = true;  ///< If enabled, a second interpolated point is predicted and combined with the first to get more stable values.
58 const int   DEFAULT_TWO_POINT_PAST_INTERPOLATE_TIME = 42;    ///< The target time in the past to generate the second interpolated point.
59 const float DEFAULT_TWO_POINT_VELOCITY_BIAS         = 0.35f; ///< The ratio of first and second interpolated points to use for velocity. 0.0f = 100% of first point. 1.0f = 100% of second point.
60 const float DEFAULT_TWO_POINT_ACCELERATION_BIAS     = 0.10f; ///< The ratio of first and second interpolated points to use for acceleration. 0.0f = 100% of first point. 1.0f = 100% of second point.
61 const int   DEFAULT_MULTITAP_SMOOTHING_RANGE        = 34;    ///< The range in time (ms) of points in the history to smooth the final output against.
62
63 // Prediction Modes 1 & 2.
64 const unsigned int DEFAULT_PREDICTION_AMOUNT[2] = {5, 57};        ///< how much to interpolate pan position and displacement from last vsync time (in milliseconds)
65 const float        DEFAULT_SMOOTHING_AMOUNT[2]  = {0.25f, 0.23f}; ///< how much to smooth final result from last vsync time
66
67 } // unnamed namespace
68
69 const PanGesture::PredictionMode PanGesture::DEFAULT_PREDICTION_MODE = PanGesture::PREDICTION_NONE;
70 const int                        PanGesture::NUM_PREDICTION_MODES    = PanGesture::PREDICTION_2 + 1;
71
72 const PanGesture::SmoothingMode PanGesture::DEFAULT_SMOOTHING_MODE = PanGesture::SMOOTHING_LAST_VALUE;
73 const int                       PanGesture::NUM_SMOOTHING_MODES    = PanGesture::SMOOTHING_MULTI_TAP + 1;
74
75 PanGesture* PanGesture::New()
76 {
77   return new PanGesture();
78 }
79
80 PanGesture::~PanGesture()
81 {
82   delete mProfiling;
83 }
84
85 void PanGesture::AddGesture(const Internal::PanGesture& gesture)
86 {
87   Dali::Mutex::ScopedLock lock(mMutex);
88   mGestures[mWritePosition] = gesture;
89
90   // Update our write position.
91   ++mWritePosition;
92   mWritePosition %= PAN_GESTURE_HISTORY;
93 }
94
95 void PanGesture::RemoveOldHistory(PanInfoHistory& panHistory, unsigned int currentTime, unsigned int maxAge, unsigned int minEvents)
96 {
97   PanInfoHistoryConstIter endIter = panHistory.end();
98   PanInfoHistoryIter      iter    = panHistory.begin();
99   while(iter != endIter && panHistory.size() > minEvents)
100   {
101     PanInfo currentGesture = *iter;
102     if(currentTime < currentGesture.time + maxAge)
103     {
104       break;
105     }
106     iter    = panHistory.erase(iter);
107     endIter = panHistory.end();
108   }
109
110   // dont want more than 5 previous predictions for smoothing
111   iter = mPredictionHistory.begin();
112   while(mPredictionHistory.size() > 1 && iter != mPredictionHistory.end())
113   {
114     iter = mPredictionHistory.erase(iter);
115   }
116 }
117
118 void PanGesture::PredictionMode1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
119 {
120   RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
121   size_t panHistorySize = panHistory.size();
122   if(panHistorySize == 0)
123   {
124     // cant do any prediction without a history
125     return;
126   }
127
128   PanInfoHistoryConstIter endIter            = panHistory.end();
129   PanInfoHistoryIter      iter               = panHistory.begin();
130   Vector2                 screenVelocity     = gestureOut.screen.velocity;
131   Vector2                 localVelocity      = gestureOut.local.velocity;
132   Vector2                 screenDisplacement = gestureOut.screen.displacement;
133   Vector2                 localDisplacement  = gestureOut.local.displacement;
134
135   bool         havePreviousAcceleration = false;
136   bool         previousVelocity         = false;
137   float        previousAccel            = 0.0f;
138   unsigned int lastTime(0);
139
140   unsigned int interpolationTime = lastVSyncTime + mCurrentPredictionAmount;
141
142   if(interpolationTime > gestureOut.time) // Guard against the rare case when gestureOut.time > (lastVSyncTime + mCurrentPredictionAmount)
143   {
144     interpolationTime -= gestureOut.time;
145   }
146   else
147   {
148     interpolationTime = 0u;
149   }
150
151   while(iter != endIter)
152   {
153     PanInfo currentGesture = *iter;
154     if(!previousVelocity)
155     {
156       // not yet set a previous velocity
157       screenVelocity   = currentGesture.screen.velocity;
158       previousVelocity = true;
159       lastTime         = currentGesture.time;
160       ++iter;
161       continue;
162     }
163     float previousValueWeight = (static_cast<float>(MAX_GESTURE_AGE) - static_cast<float>(lastVSyncTime - lastTime)) / static_cast<float>(MAX_GESTURE_AGE);
164     float velMag              = currentGesture.screen.velocity.Length();
165     float velDiff             = velMag - screenVelocity.Length();
166     float acceleration        = 0.0f;
167
168     float time(0.f);
169     if(currentGesture.time > lastTime) // Guard against invalid timestamps
170     {
171       time = static_cast<float>(currentGesture.time - lastTime);
172     }
173     if(time > Math::MACHINE_EPSILON_1)
174     {
175       acceleration = velDiff / time;
176     }
177
178     float newVelMag            = 0.0f;
179     int   currentInterpolation = interpolationTime;
180     if(!havePreviousAcceleration)
181     {
182       newVelMag                = velMag;
183       havePreviousAcceleration = true;
184     }
185     else
186     {
187       newVelMag = velMag + (((acceleration * (1.0f - previousValueWeight)) + (previousAccel * previousValueWeight)) * static_cast<float>(currentInterpolation));
188     }
189     float velMod = 1.0f;
190     if(velMag > Math::MACHINE_EPSILON_1)
191     {
192       velMod = newVelMag / velMag;
193     }
194     gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
195     gestureOut.local.velocity  = currentGesture.local.velocity * velMod;
196     screenDisplacement         = gestureOut.screen.displacement + (gestureOut.screen.velocity * static_cast<float>(interpolationTime));
197     localDisplacement          = gestureOut.local.displacement + (gestureOut.local.velocity * static_cast<float>(interpolationTime));
198     screenVelocity             = currentGesture.screen.velocity;
199     localVelocity              = currentGesture.local.velocity;
200     previousAccel              = acceleration;
201     ++iter;
202   }
203   // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
204   // add interpolated distance and position to current
205   // work out interpolated velocity
206   gestureOut.screen.position     = (gestureOut.screen.position - gestureOut.screen.displacement) + screenDisplacement;
207   gestureOut.local.position      = (gestureOut.local.position - gestureOut.local.displacement) + localDisplacement;
208   gestureOut.screen.displacement = screenDisplacement;
209   gestureOut.local.displacement  = localDisplacement;
210   gestureOut.time += interpolationTime;
211 }
212
213 void PanGesture::BlendPoints(PanInfo& gesture, PanInfo& lastGesture, float blendValue)
214 {
215   gesture.screen.position -= (gesture.screen.position - lastGesture.screen.position) * 0.5f * (1.0f - blendValue);
216   gesture.local.position -= (gesture.local.position - lastGesture.local.position) * 0.5f * (1.0f - blendValue);
217   // Make current displacement relative to previous update-frame now.
218   gesture.screen.displacement = gesture.screen.position - lastGesture.screen.position;
219   gesture.local.displacement  = gesture.local.position - lastGesture.local.position;
220   // Calculate velocity relative to previous update-frame
221   float timeDifference    = static_cast<float>(gesture.time - lastGesture.time);
222   gesture.screen.velocity = gesture.screen.displacement / timeDifference;
223   gesture.local.velocity  = gesture.local.displacement / timeDifference;
224 }
225
226 bool PanGesture::ReadGestures(FrameGestureInfo& info, unsigned int currentTimestamp)
227 {
228   unsigned int previousReadPosition = 0;
229   bool         eventFound           = false;
230   info.frameGesture                 = mLastUnmodifiedGesture;
231
232   while(mReadPosition != mWritePosition)
233   {
234     // Copy the gesture first
235     PanInfo currentGesture(mGestures[mReadPosition]);
236
237     if(mProfiling)
238     {
239       mProfiling->mRawData.push_back(PanGestureProfiling::Position(currentGesture.time, currentGesture.screen.position, currentGesture.screen.displacement, currentGesture.screen.velocity, currentGesture.state));
240     }
241     info.frameGesture.local.position  = currentGesture.local.position;
242     info.frameGesture.local.velocity  = currentGesture.local.velocity;
243     info.frameGesture.screen.position = currentGesture.screen.position;
244     info.frameGesture.screen.velocity = currentGesture.screen.velocity;
245
246     if(info.eventsThisFrame > 0)
247     {
248       info.acceleration = currentGesture.screen.velocity.Length() - mGestures[previousReadPosition].screen.velocity.Length();
249     }
250
251     if(!eventFound)
252     {
253       info.frameGesture.local.displacement  = currentGesture.local.displacement;
254       info.frameGesture.screen.displacement = currentGesture.screen.displacement;
255       eventFound                            = true;
256     }
257     else
258     {
259       info.frameGesture.local.displacement += currentGesture.local.displacement;
260       info.frameGesture.screen.displacement += currentGesture.screen.displacement;
261     }
262     info.frameGesture.time = currentGesture.time;
263
264     // add event to history
265     mPanHistory.push_back(currentGesture);
266     if(currentGesture.state == GestureState::STARTED)
267     {
268       info.justStarted = true;
269       // clear just finished as we have started new pan
270       info.justFinished = false;
271     }
272     info.justFinished |= (currentGesture.state == GestureState::FINISHED || currentGesture.state == GestureState::CANCELLED);
273
274     // Update our read position.
275     previousReadPosition = mReadPosition;
276     ++info.eventsThisFrame;
277     ++mReadPosition;
278     mReadPosition %= PAN_GESTURE_HISTORY;
279   }
280   // This code does not determine if the data will be used.
281   return false;
282 }
283
284 bool PanGesture::ReadAndResampleGestures(FrameGestureInfo& info, unsigned int currentTimestamp)
285 {
286   PanInfo                 lastReadGesture;
287   Dali::Mutex::ScopedLock lock(mMutex);
288   while(mReadPosition != mWritePosition)
289   {
290     // Copy the gesture first
291     lastReadGesture = mGestures[mReadPosition];
292     if(mProfiling)
293     {
294       mProfiling->mRawData.push_back(PanGestureProfiling::Position(lastReadGesture.time, lastReadGesture.screen.position, lastReadGesture.screen.displacement, lastReadGesture.screen.velocity, lastReadGesture.state));
295     }
296
297     info.frameGesture.screen.position += lastReadGesture.screen.position;
298     info.frameGesture.local.position += lastReadGesture.local.position;
299     info.frameGesture.screen.velocity += lastReadGesture.screen.velocity;
300     info.frameGesture.local.velocity += lastReadGesture.local.velocity;
301
302     if(lastReadGesture.state == GestureState::STARTED)
303     {
304       // Clear just finished as we have started new pan.
305       info.justFinished = false;
306       info.justStarted  = true;
307     }
308     else
309     {
310       info.justFinished |= (lastReadGesture.state == GestureState::FINISHED || lastReadGesture.state == GestureState::CANCELLED);
311     }
312
313     // Add event to history
314     mPanHistory.push_back(lastReadGesture);
315
316     // Update our read position.
317     ++info.eventsThisFrame;
318     ++mReadPosition;
319     mReadPosition %= PAN_GESTURE_HISTORY;
320   }
321
322   bool updateProperties = false;
323   if(info.eventsThisFrame > 0)
324   {
325     // Some events were read this frame.
326     mTargetGesture = lastReadGesture;
327
328     if(info.eventsThisFrame > 1)
329     {
330       const float eventsThisFrame = static_cast<float>(info.eventsThisFrame);
331       info.frameGesture.screen.position /= eventsThisFrame;
332       info.frameGesture.local.position /= eventsThisFrame;
333       info.frameGesture.screen.velocity /= eventsThisFrame;
334       info.frameGesture.local.velocity /= eventsThisFrame;
335
336       info.frameGesture.screen.displacement = info.frameGesture.screen.position - mLastGesture.screen.position;
337       info.frameGesture.local.displacement  = info.frameGesture.local.position - mLastGesture.local.position;
338
339       mNotAtTarget = true;
340     }
341     else
342     {
343       info.frameGesture.screen.displacement = lastReadGesture.screen.displacement;
344       info.frameGesture.local.displacement  = lastReadGesture.local.displacement;
345     }
346
347     info.frameGesture.time = currentTimestamp;
348
349     updateProperties = true;
350   }
351   else
352   {
353     // 0 Events this frame.
354     if(mNotAtTarget)
355     {
356       mNotAtTarget      = false;
357       info.frameGesture = mTargetGesture;
358       updateProperties  = true;
359     }
360     else
361     {
362       info.frameGesture = mLastGesture;
363     }
364   }
365
366   return updateProperties;
367 }
368
369 bool PanGesture::UpdateProperties(unsigned int lastVSyncTime, unsigned int nextVSyncTime)
370 {
371   if(mPredictionMode == PREDICTION_2)
372   {
373     // TODO: Have the two prediction modes share more behavior so some parts of mode 2 can
374     // be used with mode 1 etc. Needs code moving and more importantly testing.
375     return NewAlgorithm(lastVSyncTime, nextVSyncTime);
376   }
377
378   if(!mInGesture)
379   {
380     // clear current pan history
381     mPanHistory.clear();
382     mPredictionHistory.clear();
383   }
384
385   FrameGestureInfo frameInfo;
386   bool             updateProperties = false;
387
388   // Read input data.
389   // If we are using a form of prediction, read all the input as-is.
390   if(mPredictionMode != PREDICTION_NONE)
391   {
392     // Read input required for prediction algorithms.
393     updateProperties = ReadGestures(frameInfo, lastVSyncTime);
394   }
395   else
396   {
397     // Read and resample input.
398     updateProperties = ReadAndResampleGestures(frameInfo, lastVSyncTime);
399   }
400
401   PanInfo frameGesture      = frameInfo.frameGesture;
402   PanInfo unmodifiedGesture = frameGesture;
403
404   // Process input data.
405   mInGesture |= frameInfo.justStarted;
406   if(mInGesture)
407   {
408     // Profiling.
409     if(mProfiling)
410     {
411       mProfiling->mLatestData.push_back(PanGestureProfiling::Position(lastVSyncTime, frameGesture.screen.position, frameGesture.screen.displacement, frameGesture.screen.velocity, frameGesture.state));
412     }
413
414     // Perform prediction.
415     if(mPredictionMode == PREDICTION_1)
416     {
417       // Dynamically change the prediction amount according to the pan velocity acceleration.
418       if(!frameInfo.justStarted)
419       {
420         if(frameInfo.eventsThisFrame <= 1)
421         {
422           frameInfo.acceleration = frameGesture.screen.velocity.Length() - mLastUnmodifiedGesture.screen.velocity.Length();
423         }
424
425         // Ignore tiny velocity fluctuation to avoid unnecessary prediction amount change
426         if(fabsf(frameInfo.acceleration) > ACCELERATION_THRESHOLD)
427         {
428           mCurrentPredictionAmount += static_cast<unsigned int>(static_cast<float>(mPredictionAmountAdjustment) * (frameInfo.acceleration > Math::MACHINE_EPSILON_0 ? 1.0f : -1.0f));
429           if(mCurrentPredictionAmount > mMaxPredictionAmount + mPredictionAmountAdjustment) // Guard against unsigned int overflow
430           {
431             mCurrentPredictionAmount = 0;
432           }
433         }
434       }
435       else
436       {
437         if(!mPredictionAmountOverridden)
438         {
439           // If the prediction amount has not been modified, default to the correct amount for this algorithm.
440           mPredictionAmount = DEFAULT_PREDICTION_AMOUNT[0];
441         }
442         mCurrentPredictionAmount = mPredictionAmount; // Reset the prediction amount for each new gesture
443       }
444
445       mCurrentPredictionAmount = std::max(mMinPredictionAmount, std::min(mCurrentPredictionAmount, mMaxPredictionAmount));
446
447       // Calculate the delta of positions before the prediction
448       Vector2 deltaPosition = frameGesture.screen.position - mLastUnmodifiedGesture.screen.position;
449
450       // Make latest gesture equal to current gesture before interpolation
451       PredictionMode1(frameInfo.eventsThisFrame, frameGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
452
453       // Calculate the delta of positions after the prediction.
454       Vector2 deltaPredictedPosition = frameGesture.screen.position - mLastGesture.screen.position;
455
456       // If the change in the prediction has a different sign than the change in the actual position,
457       // there is overshot (i.e. the current prediction is too large). Return the previous prediction
458       // to give the user's finger a chance to catch up with where we have panned to.
459       bool overshotXAxis = false;
460       bool overshotYAxis = false;
461       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))
462       {
463         overshotXAxis                  = true;
464         frameGesture.screen.position.x = mLastGesture.screen.position.x;
465       }
466
467       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))
468       {
469         overshotYAxis                  = true;
470         frameGesture.screen.position.y = mLastGesture.screen.position.y;
471       }
472
473       // If there is overshot in one axis, reduce the possible overshot in the other axis,
474       // and reduce the prediction amount so that it doesn't overshoot as easily next time.
475       if(overshotXAxis || overshotYAxis)
476       {
477         mCurrentPredictionAmount -= mPredictionAmountAdjustment;
478         if(mCurrentPredictionAmount > mMaxPredictionAmount + mPredictionAmountAdjustment) // Guard against unsigned int overflow
479         {
480           mCurrentPredictionAmount = 0;
481         }
482         mCurrentPredictionAmount = std::max(mMinPredictionAmount, std::min(mCurrentPredictionAmount, mMaxPredictionAmount));
483
484         if(overshotXAxis && !overshotYAxis)
485         {
486           frameGesture.screen.position.y = (mLastGesture.screen.position.y + frameGesture.screen.position.y) * 0.5f;
487         }
488
489         if(overshotYAxis && !overshotXAxis)
490         {
491           frameGesture.screen.position.x = (mLastGesture.screen.position.x + frameGesture.screen.position.x) * 0.5f;
492         }
493       }
494
495       updateProperties = true;
496     }
497
498     // Perform smoothing.
499     switch(mSmoothingMode)
500     {
501       case SMOOTHING_NONE:
502       case SMOOTHING_MULTI_TAP:
503       {
504         // No smoothing
505         // TODO: Old algorithm to be able to use multitap smoothing.
506         break;
507       }
508       case SMOOTHING_LAST_VALUE:
509       {
510         if(!frameInfo.justStarted)
511         {
512           if(!mSmoothingAmountOverridden)
513           {
514             // If the smoothing amount has not been modified, default to the correct amount for this algorithm.
515             mSmoothingAmount = DEFAULT_SMOOTHING_AMOUNT[0];
516           }
517           BlendPoints(frameGesture, mLastGesture, mSmoothingAmount);
518         }
519         break;
520       }
521     }
522
523     if(updateProperties)
524     {
525       // only update properties if event received
526       // set latest gesture to raw pan info with unchanged time
527       mPanning.Set(mInGesture & !frameInfo.justFinished);
528       mScreenPosition.Set(frameGesture.screen.position);
529       mScreenDisplacement.Set(frameGesture.screen.displacement);
530       mScreenVelocity.Set(frameGesture.screen.velocity);
531       mLocalPosition.Set(frameGesture.local.position);
532       mLocalDisplacement.Set(frameGesture.local.displacement);
533       mLocalVelocity.Set(frameGesture.local.velocity);
534     }
535
536     if(mProfiling)
537     {
538       mProfiling->mAveragedData.push_back(PanGestureProfiling::Position(frameGesture.time, frameGesture.screen.position, frameGesture.screen.displacement, frameGesture.screen.velocity, frameGesture.state));
539     }
540   }
541
542   mLastGesture           = frameGesture;
543   mLastUnmodifiedGesture = unmodifiedGesture;
544
545   mInGesture = mInGesture && !frameInfo.justFinished;
546   if(mProfiling && frameInfo.justFinished)
547   {
548     mProfiling->PrintData();
549     mProfiling->ClearData();
550   }
551
552   return updateProperties;
553 }
554
555 const GesturePropertyBool& PanGesture::GetPanningProperty() const
556 {
557   return mPanning;
558 }
559
560 const GesturePropertyVector2& PanGesture::GetScreenPositionProperty() const
561 {
562   return mScreenPosition;
563 }
564
565 const GesturePropertyVector2& PanGesture::GetScreenVelocityProperty() const
566 {
567   return mScreenVelocity;
568 }
569
570 const GesturePropertyVector2& PanGesture::GetScreenDisplacementProperty() const
571 {
572   return mScreenDisplacement;
573 }
574
575 const GesturePropertyVector2& PanGesture::GetLocalPositionProperty() const
576 {
577   return mLocalPosition;
578 }
579
580 const GesturePropertyVector2& PanGesture::GetLocalDisplacementProperty() const
581 {
582   return mLocalDisplacement;
583 }
584
585 const GesturePropertyVector2& PanGesture::GetLocalVelocityProperty() const
586 {
587   return mLocalVelocity;
588 }
589
590 void PanGesture::SetPredictionMode(PredictionMode mode)
591 {
592   mPredictionMode = mode;
593 }
594
595 void PanGesture::SetPredictionAmount(unsigned int amount)
596 {
597   mPredictionAmount           = amount;
598   mPredictionAmountOverridden = true;
599 }
600
601 void PanGesture::SetMaximumPredictionAmount(unsigned int amount)
602 {
603   mMaxPredictionAmount = amount;
604 }
605
606 void PanGesture::SetMinimumPredictionAmount(unsigned int amount)
607 {
608   mMinPredictionAmount = amount;
609 }
610
611 void PanGesture::SetPredictionAmountAdjustment(unsigned int amount)
612 {
613   mPredictionAmountAdjustment = amount;
614 }
615
616 void PanGesture::SetSmoothingMode(SmoothingMode mode)
617 {
618   mSmoothingMode = mode;
619 }
620
621 void PanGesture::SetSmoothingAmount(float amount)
622 {
623   mSmoothingAmount           = amount;
624   mSmoothingAmountOverridden = true;
625 }
626
627 void PanGesture::SetUseActualTimes(bool value)
628 {
629   mUseActualTimes = value;
630 }
631
632 void PanGesture::SetInterpolationTimeRange(int value)
633 {
634   mInterpolationTimeRange = value;
635 }
636
637 void PanGesture::SetScalarOnlyPredictionEnabled(bool value)
638 {
639   mScalarOnlyPredictionEnabled = value;
640 }
641
642 void PanGesture::SetTwoPointPredictionEnabled(bool value)
643 {
644   mTwoPointPredictionEnabled = value;
645 }
646
647 void PanGesture::SetTwoPointInterpolatePastTime(int value)
648 {
649   mTwoPointPastInterpolateTime = value;
650 }
651
652 void PanGesture::SetTwoPointVelocityBias(float value)
653 {
654   mTwoPointVelocityBias = value;
655 }
656
657 void PanGesture::SetTwoPointAccelerationBias(float value)
658 {
659   mTwoPointAccelerationBias = value;
660 }
661
662 void PanGesture::SetMultitapSmoothingRange(int value)
663 {
664   mMultiTapSmoothingRange = value;
665 }
666
667 void PanGesture::EnableProfiling()
668 {
669   if(!mProfiling)
670   {
671     mProfiling = new PanGestureProfiling();
672   }
673 }
674
675 void PanGesture::ResetDefaultProperties(BufferIndex updateBufferIndex)
676 {
677   mScreenPosition.Reset();
678   mScreenDisplacement.Reset();
679   mLocalPosition.Reset();
680   mLocalDisplacement.Reset();
681   mPanning.Reset();
682 }
683
684 PanGesture::PanGesture()
685 : mPanning(),
686   mGestures(),
687   mWritePosition(0),
688   mReadPosition(0),
689   mNotAtTarget(false),
690   mInGesture(false),
691   mPredictionAmountOverridden(false),
692   mSmoothingAmountOverridden(false),
693   mProfiling(nullptr),
694
695   // Set environment variable defaults:
696   mPredictionMode(DEFAULT_PREDICTION_MODE),
697   mPredictionAmount(DEFAULT_PREDICTION_AMOUNT[0]),
698   mCurrentPredictionAmount(DEFAULT_PREDICTION_AMOUNT[0]),
699   mMaxPredictionAmount(DEFAULT_MAX_PREDICTION_AMOUNT),
700   mMinPredictionAmount(DEFAULT_MIN_PREDICTION_AMOUNT),
701   mPredictionAmountAdjustment(DEFAULT_PREDICTION_AMOUNT_ADJUSTMENT),
702   mSmoothingMode(DEFAULT_SMOOTHING_MODE),
703   mSmoothingAmount(DEFAULT_SMOOTHING_AMOUNT[0]),
704   mUseActualTimes(DEFAULT_USE_ACTUAL_TIMES),
705   mInterpolationTimeRange(DEFAULT_INTERPOLATION_TIME_RANGE),
706   mScalarOnlyPredictionEnabled(DEFAULT_SCALAR_ONLY_PREDICTION_ENABLED),
707   mTwoPointPredictionEnabled(DEFAULT_TWO_POINT_PREDICTION_ENABLED),
708   mTwoPointPastInterpolateTime(DEFAULT_TWO_POINT_PAST_INTERPOLATE_TIME),
709   mTwoPointVelocityBias(DEFAULT_TWO_POINT_VELOCITY_BIAS),
710   mTwoPointAccelerationBias(DEFAULT_TWO_POINT_ACCELERATION_BIAS),
711   mMultiTapSmoothingRange(DEFAULT_MULTITAP_SMOOTHING_RANGE)
712 {
713 }
714
715 // Prediction mode 2 related code and functions follow:
716
717 unsigned int PanGesture::ReadFrameEvents()
718 {
719   unsigned int eventsThisFrame;
720   // Copy the events into a linear buffer while holding the mutex.
721   // This is so the lock is not held while any processing is done.
722   Dali::Mutex::ScopedLock lock(mMutex);
723   for(eventsThisFrame = 0; mReadPosition != mWritePosition; ++eventsThisFrame)
724   {
725     mReadGestures[eventsThisFrame] = mGestures[mReadPosition];
726     ++mReadPosition;
727     mReadPosition %= PAN_GESTURE_HISTORY;
728   }
729   return eventsThisFrame;
730 }
731
732 // TODO: eventsThisFrame parameter can be removed if we use a smarter container.
733 bool PanGesture::InputRateConversion(PanInfo& rateConvertedGesture, unsigned int eventsThisFrame, unsigned int currentFrameTime, unsigned int lastFrameTime, bool& justStarted, bool& justFinished)
734 {
735   // TODO: Lots of variables on the stack. Needs optimizing.
736   PanInfo      readGesture;
737   PanInfo      firstReadGesture;
738   unsigned int eventsKeptThisFrame = 0;
739
740   for(unsigned int readPosition = 0; readPosition < eventsThisFrame; ++readPosition)
741   {
742     // Copy the gesture first
743     readGesture = mReadGestures[readPosition];
744
745     if(mProfiling)
746     {
747       mProfiling->mRawData.push_back(PanGestureProfiling::Position(readGesture.time, readGesture.screen.position, readGesture.screen.displacement, readGesture.screen.velocity, readGesture.state));
748     }
749
750     if(readGesture.state == GestureState::STARTED)
751     {
752       // Clear pan data.
753       mPanHistory.clear();
754       mPredictionHistory.clear();
755       mLastAcceleration.local              = Vector2::ZERO;
756       mLastAcceleration.screen             = Vector2::ZERO;
757       mLastInterpolatedAcceleration.local  = Vector2::ZERO;
758       mLastInterpolatedAcceleration.screen = Vector2::ZERO;
759       mLastInitialAcceleration.local       = Vector2::ZERO;
760       mLastInitialAcceleration.screen      = Vector2::ZERO;
761       PanInfo startInfo;
762       mLastGesture                 = startInfo;
763       mLastSecondInterpolatedPoint = startInfo;
764       mLastPredictedPoint          = startInfo;
765       mLastFrameReadGesture        = startInfo;
766       rateConvertedGesture         = startInfo;
767       firstReadGesture             = readGesture;
768       eventsKeptThisFrame          = 0;
769       mNotAtTarget                 = false;
770       justFinished                 = false;
771       justStarted                  = true;
772       mInGesture                   = true;
773
774       if(!mPredictionAmountOverridden)
775       {
776         // If the prediction amount has not been modified, default to the correct amount for this algorithm.
777         mPredictionAmount = DEFAULT_PREDICTION_AMOUNT[1];
778       }
779       mCurrentPredictionAmount = mPredictionAmount;
780     }
781     else
782     {
783       justFinished |= (readGesture.state == GestureState::FINISHED || readGesture.state == GestureState::CANCELLED);
784     }
785
786     rateConvertedGesture.screen.position += readGesture.screen.position;
787     rateConvertedGesture.local.position += readGesture.local.position;
788     rateConvertedGesture.screen.velocity += readGesture.screen.velocity;
789     rateConvertedGesture.local.velocity += readGesture.local.velocity;
790     rateConvertedGesture.screen.displacement += readGesture.screen.displacement;
791     rateConvertedGesture.local.displacement += readGesture.local.displacement;
792
793     ++eventsKeptThisFrame;
794   }
795
796   bool storeGesture = false;
797   if(eventsKeptThisFrame > 0)
798   {
799     // Some events were read this frame.
800     if(eventsKeptThisFrame > 1)
801     {
802       const float eventDivisor = static_cast<float>(eventsKeptThisFrame);
803       rateConvertedGesture.screen.position /= eventDivisor;
804       rateConvertedGesture.local.position /= eventDivisor;
805       rateConvertedGesture.screen.velocity /= eventDivisor;
806       rateConvertedGesture.local.velocity /= eventDivisor;
807       rateConvertedGesture.screen.displacement /= eventDivisor;
808       rateConvertedGesture.local.displacement /= eventDivisor;
809
810       mTargetGesture = readGesture;
811       mNotAtTarget   = true;
812     }
813     else
814     {
815       mNotAtTarget = false;
816     }
817
818     rateConvertedGesture.time = currentFrameTime;
819     storeGesture              = true;
820   }
821   else
822   {
823     // We did not get any event this frame.
824     // If we just started (or aren't in a gesture), exit.
825     if(!mInGesture || justStarted)
826     {
827       // We cannot guess what the event could be as we have no other events to base the guess from.
828       return false;
829     }
830
831     // As we are currently in a gesture, we can estimate an event.
832     readGesture      = mLastFrameReadGesture;
833     readGesture.time = currentFrameTime;
834
835     // Take the last event, halve the acceleration, and use that.
836     const float accelerationDegrade = 2.0f;
837     Vector2     degradedAccelerationLocal(mLastAcceleration.local /= accelerationDegrade);
838     Vector2     degradedAccelerationScreen(mLastAcceleration.screen /= accelerationDegrade);
839
840     float outputTimeGranularity(GetDivisibleTimeDifference(currentFrameTime, lastFrameTime, 1.0f, OUTPUT_TIME_DIFFERENCE));
841
842     readGesture.local.velocity      = degradedAccelerationLocal * outputTimeGranularity;
843     readGesture.local.displacement  = readGesture.local.velocity * outputTimeGranularity;
844     readGesture.local.position      = mLastFrameReadGesture.local.position + readGesture.local.displacement;
845     readGesture.screen.velocity     = degradedAccelerationScreen * outputTimeGranularity;
846     readGesture.screen.displacement = readGesture.screen.velocity * outputTimeGranularity;
847     readGesture.screen.position     = mLastFrameReadGesture.screen.position + readGesture.screen.displacement;
848
849     rateConvertedGesture = readGesture;
850     eventsKeptThisFrame  = 1;
851     storeGesture         = true;
852   }
853
854   if(eventsKeptThisFrame > 0)
855   {
856     // Store last read gesture.
857     readGesture.time      = currentFrameTime;
858     mLastFrameReadGesture = readGesture;
859
860     if(eventsKeptThisFrame > 2)
861     {
862       DALI_LOG_WARNING("Got events this frame:%d (more than 2 will compromise result)\n", eventsKeptThisFrame);
863     }
864   }
865
866   if(storeGesture)
867   {
868     // Store final converted result.
869     mPanHistory.push_back(rateConvertedGesture);
870   }
871   return true;
872 }
873
874 bool PanGesture::InterpolatePoint(PanInfoHistory& history, unsigned int currentTime, unsigned int targetTime, unsigned int range, PanInfo& outPoint, RelativeVectors& acceleration, int outputTimeGranularity, bool eraseUnused)
875 {
876   unsigned int maxHistoryTime            = targetTime - range;
877   unsigned int tapsUsed                  = 0;
878   outPoint.time                          = targetTime;
879   float              divisor             = 0.0f;
880   float              accelerationDivisor = 0.0f;
881   PanInfoHistoryIter historyBegin        = history.begin();
882   PanInfoHistoryIter lastIt              = history.end();
883   bool               pointGenerated      = false;
884   bool               havePreviousPoint   = false;
885   RelativeVectors    newAcceleration;
886
887   // Iterate through point history to perform interpolation.
888   for(PanInfoHistoryIter it = historyBegin; it != history.end();)
889   {
890     unsigned int gestureTime = it->time;
891
892     if(gestureTime < maxHistoryTime)
893     {
894       // Too far in the past, discard.
895       // Clean history as we go (if requested).
896       if(eraseUnused)
897       {
898         it = history.erase(it);
899       }
900       else
901       {
902         ++it;
903         continue;
904       }
905     }
906     else
907     {
908       float timeDelta(static_cast<float>(abs(int(targetTime - gestureTime))));
909       // Handle low time deltas.
910       if(timeDelta < 1.0f)
911       {
912         timeDelta = 1.0f;
913       }
914
915       outPoint.local.position += it->local.position / timeDelta;
916       outPoint.screen.position += it->screen.position / timeDelta;
917       outPoint.local.velocity += it->local.velocity / timeDelta;
918       outPoint.screen.velocity += it->screen.velocity / timeDelta;
919       outPoint.local.displacement += it->local.displacement / timeDelta;
920       outPoint.screen.displacement += it->screen.displacement / timeDelta;
921
922       divisor += 1.0f / timeDelta;
923
924       // Acceleration requires a previous point.
925       if(havePreviousPoint)
926       {
927         // Time delta of input.
928         float timeDifference(GetDivisibleTimeDifference(it->time, lastIt->time, 1.0f, OUTPUT_TIME_DIFFERENCE));
929
930         newAcceleration.local += ((it->local.velocity - lastIt->local.velocity) / timeDifference) / timeDelta;
931         newAcceleration.screen += ((it->screen.velocity - lastIt->screen.velocity) / timeDifference) / timeDelta;
932
933         accelerationDivisor += 1.0f / timeDelta;
934       }
935       else
936       {
937         havePreviousPoint = true;
938       }
939
940       tapsUsed++;
941       lastIt = it;
942       ++it;
943     }
944   }
945
946   // Divide results by their respective divisors.
947   if(tapsUsed > 0)
948   {
949     if(divisor > 0.0f)
950     {
951       outPoint.local.position /= divisor;
952       outPoint.screen.position /= divisor;
953       outPoint.local.velocity /= divisor;
954       outPoint.screen.velocity /= divisor;
955       outPoint.local.displacement /= divisor;
956       outPoint.screen.displacement /= divisor;
957     }
958
959     if(tapsUsed > 1)
960     {
961       if(accelerationDivisor > 0.0f)
962       {
963         newAcceleration.local /= accelerationDivisor;
964         newAcceleration.screen /= accelerationDivisor;
965       }
966
967       float accelerationSmoothing(ACCELERATION_SMOOTHING);
968       newAcceleration.local  = (acceleration.local * accelerationSmoothing) + (newAcceleration.local * (1.0f - accelerationSmoothing));
969       newAcceleration.screen = (acceleration.screen * accelerationSmoothing) + (newAcceleration.screen * (1.0f - accelerationSmoothing));
970     }
971     else
972     {
973       // If we just started, last velocity was 0. So difference of zero to current velocity over time gives acceleration of the first point.
974       newAcceleration.local  = outPoint.local.velocity / static_cast<float>(outputTimeGranularity);
975       newAcceleration.screen = outPoint.screen.velocity / static_cast<float>(outputTimeGranularity);
976     }
977     pointGenerated = true;
978   }
979
980   acceleration.local  = newAcceleration.local;
981   acceleration.screen = newAcceleration.screen;
982   return pointGenerated;
983 }
984
985 float PanGesture::GetDivisibleTimeDifference(int timeA, int timeB, float minimumDelta, float overrideDifference)
986 {
987   float timeDifference(overrideDifference);
988   if(mUseActualTimes)
989   {
990     timeDifference = static_cast<float>(abs(timeA - timeB));
991     if(timeDifference < minimumDelta)
992     {
993       timeDifference = minimumDelta;
994     }
995   }
996   return timeDifference;
997 }
998
999 void PanGesture::LimitAccelerationChange(RelativeVectors& currentAcceleration, RelativeVectors& lastAcceleration, float changeLimit)
1000 {
1001   // We don't use the float parameter version of clamp here, as that will create the capping vectors twice in total.
1002   Vector2 capMinimum(-changeLimit, -changeLimit);
1003   Vector2 capMaximum(changeLimit, changeLimit);
1004   Vector2 accelerationDeltaLocal(currentAcceleration.local - lastAcceleration.local);
1005   Vector2 accelerationDeltaScreen(currentAcceleration.screen - lastAcceleration.screen);
1006   accelerationDeltaLocal.Clamp(capMinimum, capMaximum);
1007   accelerationDeltaScreen.Clamp(capMinimum, capMaximum);
1008   currentAcceleration.local  = lastAcceleration.local + accelerationDeltaLocal;
1009   currentAcceleration.screen = lastAcceleration.screen + accelerationDeltaScreen;
1010 }
1011
1012 void PanGesture::PredictionMode2(PanInfo& startPoint, RelativeVectors& accelerationToUse, PanInfo& predictedPoint, unsigned int currentFrameTime, unsigned int previousFrameTime, bool noPreviousData)
1013 {
1014   // Do the prediction (based on mode).
1015   if(mScalarOnlyPredictionEnabled)
1016   {
1017     // We are doing scalar based prediction.
1018     // This divisor is to help tuning by giving the scalar only result
1019     // a similar prediction amount to the integrated result.
1020     float scalarVelocityMultiplier = static_cast<float>(mCurrentPredictionAmount) / 1.364f;
1021     predictedPoint.local.position  = startPoint.local.position + (startPoint.local.velocity * scalarVelocityMultiplier);
1022     predictedPoint.screen.position = startPoint.screen.position + (startPoint.screen.velocity * scalarVelocityMultiplier);
1023   }
1024   else
1025   {
1026     // We are doing integration based prediction.
1027     float predictionDelta = static_cast<float>(mCurrentPredictionAmount);
1028
1029     predictedPoint.local.position = startPoint.local.position + (startPoint.local.velocity * predictionDelta) +
1030                                     (accelerationToUse.local * (predictionDelta * predictionDelta * 0.5f));
1031     predictedPoint.screen.position = startPoint.screen.position + (startPoint.screen.velocity * predictionDelta) +
1032                                      (accelerationToUse.screen * (predictionDelta * predictionDelta * 0.5f));
1033   }
1034
1035   // Calculate remaining gesture data from the result.
1036   float timeDifference(GetDivisibleTimeDifference(currentFrameTime, previousFrameTime, 1.0f, OUTPUT_TIME_DIFFERENCE));
1037   if(noPreviousData)
1038   {
1039     predictedPoint.local.displacement  = predictedPoint.local.position - startPoint.local.position;
1040     predictedPoint.screen.displacement = predictedPoint.screen.position - startPoint.screen.position;
1041   }
1042   else
1043   {
1044     predictedPoint.local.displacement  = predictedPoint.local.position - mLastPredictedPoint.local.position;
1045     predictedPoint.screen.displacement = predictedPoint.screen.position - mLastPredictedPoint.screen.position;
1046   }
1047   predictedPoint.local.velocity  = predictedPoint.local.displacement / timeDifference;
1048   predictedPoint.screen.velocity = predictedPoint.screen.displacement / timeDifference;
1049
1050   // TODO: Experimental - not used at run time. Left in code for reference only.
1051   if(TEST_TUNE_ENABLE_OVERSHOOT_PROTECTION)
1052   {
1053     // Overshoot protection
1054     if(!noPreviousData)
1055     {
1056       if((mLastPredictedPoint.local.velocity.x > Math::MACHINE_EPSILON_0 && predictedPoint.local.velocity.x < Math::MACHINE_EPSILON_0) || (mLastPredictedPoint.local.velocity.x < Math::MACHINE_EPSILON_0 && predictedPoint.local.velocity.x > Math::MACHINE_EPSILON_0))
1057       {
1058         predictedPoint.local.position.x  = mLastPredictedPoint.local.position.x;
1059         predictedPoint.screen.position.x = mLastPredictedPoint.screen.position.x;
1060         mPredictionHistory.clear();
1061       }
1062       if((mLastPredictedPoint.local.velocity.y > Math::MACHINE_EPSILON_0 && predictedPoint.local.velocity.y < Math::MACHINE_EPSILON_0) || (mLastPredictedPoint.local.velocity.y < Math::MACHINE_EPSILON_0 && predictedPoint.local.velocity.y > Math::MACHINE_EPSILON_0))
1063       {
1064         predictedPoint.local.position.y  = mLastPredictedPoint.local.position.y;
1065         predictedPoint.screen.position.y = mLastPredictedPoint.screen.position.y;
1066         mPredictionHistory.clear();
1067       }
1068     }
1069   }
1070
1071   predictedPoint.time = currentFrameTime;
1072   mLastPredictedPoint = predictedPoint;
1073 }
1074
1075 // TODO: This needs a better name! It is called this instead of prediction mode 2 because:
1076 // 1) It is the entire workflow, not just prediction.
1077 // 2) To make it less confusing as there is a function that does prediction alone called PerformPredictionMode2.
1078 // Ultimately we need to combine the old and new code modularly so there is one code path that can optionally run different functions based on configuration.
1079 // At the moment, the differences between the inputs & outputs of these different functions prevent that, but this can be resolved.
1080 bool PanGesture::NewAlgorithm(unsigned int lastVSyncTime, unsigned int nextVSyncTime)
1081 {
1082   if(!mInGesture)
1083   {
1084     // clear current pan history
1085     mPanHistory.clear();
1086     mPredictionHistory.clear();
1087   }
1088
1089   /*#########################################################################################
1090     #### Read in all gestures received this frame first (holding a lock for a short time)
1091     #########################################################################################*/
1092
1093   unsigned int eventsThisFrame = ReadFrameEvents();
1094
1095   /*#########################################################################################
1096     #### Perform input rate-conversion on all gestures received this frame.
1097     #### This also populates the pan history.
1098     #########################################################################################*/
1099
1100   bool    justStarted  = false;
1101   bool    justFinished = false;
1102   PanInfo rateConvertedGesture;
1103   if(!InputRateConversion(rateConvertedGesture, eventsThisFrame, nextVSyncTime, lastVSyncTime, justStarted, justFinished))
1104   {
1105     // There's nothing we can do with the input, exit.
1106     return false;
1107   }
1108
1109   /*#########################################################################################
1110     #### If we are in gesture, Get first interpolated point with: target time = current time
1111     #########################################################################################*/
1112
1113   bool            performUpdate = false;
1114   RelativeVectors currentAcceleration;
1115   currentAcceleration.local  = mLastInitialAcceleration.local;
1116   currentAcceleration.screen = mLastInitialAcceleration.screen;
1117
1118   if(mInGesture || justStarted)
1119   {
1120     // Get first interpolated point.
1121     // TODO: Erase time should be maximum of both interpolated point ranges in past.
1122     PanInfo targetPoint;
1123     float   outputTimeGranularity(GetDivisibleTimeDifference(nextVSyncTime, lastVSyncTime, 1.0f, OUTPUT_TIME_DIFFERENCE));
1124     bool    pointGenerated = InterpolatePoint(mPanHistory, nextVSyncTime, nextVSyncTime, mInterpolationTimeRange, targetPoint, currentAcceleration, static_cast<int>(outputTimeGranularity), true); // truncated
1125     if(pointGenerated)
1126     {
1127       mLastInitialAcceleration.local  = currentAcceleration.local;
1128       mLastInitialAcceleration.screen = currentAcceleration.screen;
1129       performUpdate                   = true;
1130     }
1131     else
1132     {
1133       targetPoint                = rateConvertedGesture;
1134       currentAcceleration.local  = mLastInitialAcceleration.local;
1135       currentAcceleration.screen = mLastInitialAcceleration.screen;
1136       // TODO: Potentially do something to substitute lack of generated point (and perform update).
1137     }
1138
1139     /*#########################################################################################
1140       #### Limit the change of acceleration of the first interpolated point since last time
1141       #########################################################################################*/
1142
1143     if(!justStarted)
1144     {
1145       LimitAccelerationChange(currentAcceleration, mLastAcceleration, ACCELERATION_CAP);
1146     }
1147     mLastAcceleration.local  = currentAcceleration.local;
1148     mLastAcceleration.screen = currentAcceleration.screen;
1149
1150     /*#########################################################################################
1151       #### Get second interpolated point, and blend the resultant velocity and acceleration (optional)
1152       #########################################################################################*/
1153
1154     PanInfo         outPoint;
1155     RelativeVectors interpolatedAcceleration;
1156     if(mTwoPointPredictionEnabled)
1157     {
1158       // Get second interpolated point with target time = current time - past interpolate time.
1159       unsigned int    pastInterpolateTime = nextVSyncTime - mTwoPointPastInterpolateTime;
1160       PanInfo         outPoint;
1161       RelativeVectors interpolatedAcceleration;
1162       interpolatedAcceleration.local  = mLastInterpolatedAcceleration.local;
1163       interpolatedAcceleration.screen = mLastInterpolatedAcceleration.screen;
1164       if(!InterpolatePoint(mPanHistory, nextVSyncTime, pastInterpolateTime, mTwoPointPastInterpolateTime, outPoint, interpolatedAcceleration, static_cast<int>(outputTimeGranularity), false)) // truncated
1165       {
1166         if(justStarted)
1167         {
1168           outPoint = targetPoint;
1169         }
1170         else
1171         {
1172           outPoint = mLastSecondInterpolatedPoint;
1173         }
1174       }
1175       mLastInterpolatedAcceleration.local  = interpolatedAcceleration.local;
1176       mLastInterpolatedAcceleration.screen = interpolatedAcceleration.screen;
1177       mLastSecondInterpolatedPoint         = outPoint;
1178
1179       // Combine the first interpolated point and the second interpolated point.
1180       // by mixing them with the configured amount. This is done for acceleration and velocity.
1181       // It could be optionally done for position too, but this typically is worse as it means we have to predict further ahead.
1182       float currentVelocityMultiplier(1.0f - mTwoPointVelocityBias);
1183       float lastVelocityMultiplier(mTwoPointVelocityBias);
1184       targetPoint.local.velocity  = (outPoint.local.velocity * lastVelocityMultiplier) + (targetPoint.local.velocity * currentVelocityMultiplier);
1185       targetPoint.screen.velocity = (outPoint.screen.velocity * lastVelocityMultiplier) + (targetPoint.screen.velocity * currentVelocityMultiplier);
1186       float currentAccelerationMultiplier(1.0f - mTwoPointAccelerationBias);
1187       float lastAccelerationMultiplier(mTwoPointAccelerationBias);
1188       currentAcceleration.local  = (interpolatedAcceleration.local * lastAccelerationMultiplier) + (currentAcceleration.local * currentAccelerationMultiplier);
1189       currentAcceleration.screen = (interpolatedAcceleration.screen * lastAccelerationMultiplier) + (currentAcceleration.screen * currentAccelerationMultiplier);
1190     }
1191
1192     /*#########################################################################################
1193       #### Perform prediction
1194       #########################################################################################*/
1195
1196     PanInfo predictedPoint;
1197     PredictionMode2(targetPoint, currentAcceleration, predictedPoint, nextVSyncTime, lastVSyncTime, justStarted);
1198     targetPoint = predictedPoint;
1199
1200     /*#########################################################################################
1201       #### Smoothing
1202       #########################################################################################*/
1203
1204     // If we are using multi-tap smoothing, keep a history of predicted results.
1205     if(mSmoothingMode == SMOOTHING_MULTI_TAP)
1206     {
1207       mPredictionHistory.push_back(targetPoint);
1208     }
1209
1210     if(!justStarted)
1211     {
1212       float outputTimeGranularity(GetDivisibleTimeDifference(nextVSyncTime, lastVSyncTime, 1.0f, OUTPUT_TIME_DIFFERENCE));
1213       if(mSmoothingMode == SMOOTHING_MULTI_TAP)
1214       {
1215         // Perform Multi-tap Smoothing.
1216         RelativeVectors blank;
1217         InterpolatePoint(mPredictionHistory, nextVSyncTime, nextVSyncTime, mMultiTapSmoothingRange, targetPoint, blank, static_cast<int>(outputTimeGranularity), true); // truncated
1218       }
1219       else
1220       {
1221         // Perform Single-tap Smoothing.
1222         if(!mSmoothingAmountOverridden)
1223         {
1224           // If the smoothing amount has not been modified, default to the correct amount for this algorithm.
1225           mSmoothingAmount = DEFAULT_SMOOTHING_AMOUNT[1];
1226         }
1227         BlendPoints(targetPoint, mLastGesture, mSmoothingAmount);
1228       }
1229
1230       /*#########################################################################################
1231         #### Finalize other point data (from position)
1232         #########################################################################################*/
1233
1234       targetPoint.local.displacement  = targetPoint.local.position - mLastGesture.local.position;
1235       targetPoint.local.velocity      = targetPoint.local.displacement / outputTimeGranularity;
1236       targetPoint.screen.displacement = targetPoint.screen.position - mLastGesture.screen.position;
1237       targetPoint.screen.velocity     = targetPoint.screen.displacement / outputTimeGranularity;
1238     }
1239
1240     /*#########################################################################################
1241       #### Send out the new point, by setting the properties
1242       #### (Constraints will automatically react to this)
1243       #########################################################################################*/
1244
1245     if(performUpdate)
1246     {
1247       mPanning.Set(mInGesture & !justFinished);
1248       mScreenPosition.Set(targetPoint.screen.position);
1249       mScreenDisplacement.Set(targetPoint.screen.displacement);
1250       mScreenVelocity.Set(targetPoint.screen.velocity);
1251       mLocalPosition.Set(targetPoint.local.position);
1252       mLocalDisplacement.Set(targetPoint.local.displacement);
1253       mLocalVelocity.Set(targetPoint.local.velocity);
1254
1255       mLastGesture = targetPoint;
1256
1257       if(mProfiling)
1258       {
1259         mProfiling->mAveragedData.push_back(PanGestureProfiling::Position(targetPoint.time, targetPoint.screen.position, targetPoint.screen.displacement, targetPoint.screen.velocity, targetPoint.state));
1260       }
1261     }
1262   }
1263
1264   mInGesture = mInGesture && !justFinished;
1265
1266   return performUpdate;
1267 }
1268
1269 } // namespace SceneGraph
1270
1271 } // namespace Internal
1272
1273 } // namespace Dali