Pan Gesture Prediction - Fixed issue where initial displacement could be close to...
[platform/core/uifw/dali-core.git] / dali / internal / update / gestures / scene-graph-pan-gesture.cpp
1 /*
2  * Copyright (c) 2014 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
23 // INTERNAL INCLUDES
24 #include <dali/internal/update/gestures/pan-gesture-profiling.h>
25
26 namespace Dali
27 {
28
29 namespace Internal
30 {
31
32 namespace SceneGraph
33 {
34 namespace
35 {
36 const int MAX_GESTURE_AGE = 50; ///< maximum age of a gesture before disallowing its use in algorithm
37 const unsigned int DEFAULT_PREDICTION_INTERPOLATION = 0; ///< how much to interpolate pan position and displacement from last vsync time
38 } // unnamed namespace
39
40 const PanGesture::PredictionMode PanGesture::DEFAULT_PREDICTION_MODE = PanGesture::AVERAGE;
41 const int PanGesture::NUM_PREDICTION_MODES = PanGesture::PREDICTION_2 + 1;
42
43 PanGesture* PanGesture::New()
44 {
45   return new PanGesture();
46 }
47
48 PanGesture::~PanGesture()
49 {
50   delete mProfiling;
51 }
52
53 void PanGesture::AddGesture( const Dali::PanGesture& gesture )
54 {
55   mGestures[ mWritePosition ] = gesture;
56
57   // Update our write position.
58   ++mWritePosition;
59   mWritePosition %= PAN_GESTURE_HISTORY;
60 }
61
62 void PanGesture::RemoveOldHistory(PanInfoHistory& panHistory, unsigned int currentTime, unsigned int maxAge, unsigned int minEvents)
63 {
64   PanInfoHistoryConstIter endIter = panHistory.end();
65   PanInfoHistoryIter iter = panHistory.begin();
66   while( iter != endIter && panHistory.size() > minEvents)
67   {
68     PanInfo currentGesture = *iter;
69     if( currentTime < currentGesture.time + maxAge )
70     {
71       break;
72     }
73     iter = panHistory.erase(iter);
74     endIter = panHistory.end();
75   }
76 }
77
78 void PanGesture::SimpleAverageAlgorithm(bool justStarted, PanInfo& gestureOut)
79 {
80   if( mInGesture )
81   {
82     if( !justStarted )
83     {
84       gestureOut.screen.position += mLastEventGesture.screen.position;
85       gestureOut.local.position += mLastEventGesture.local.position;
86       gestureOut.screen.position *= 0.5f;
87       gestureOut.local.position *= 0.5f;
88       // make current displacement relative to previous update-frame now.
89       gestureOut.screen.displacement = gestureOut.screen.position - mLastEventGesture.screen.position;
90       gestureOut.local.displacement = gestureOut.local.position - mLastEventGesture.local.position;
91     }
92   }
93 }
94
95 void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
96 {
97   RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
98   size_t panHistorySize = panHistory.size();
99   if( panHistorySize == 0 )
100   {
101     // cant do any prediction without a history
102     return;
103   }
104
105   PanInfoHistoryConstIter endIter = panHistory.end();
106   PanInfoHistoryIter iter = panHistory.begin();
107   Vector2 screenVelocity = gestureOut.screen.velocity;
108   Vector2 localVelocity = gestureOut.local.velocity;
109
110   bool havePreviousAcceleration = false;
111   bool previousVelocity = false;
112   float previousAccel = 0.0f;
113   unsigned int lastTime(0);
114   while( iter != endIter )
115   {
116     PanInfo currentGesture = *iter;
117     if( !previousVelocity )
118     {
119       // not yet set a previous velocity
120       screenVelocity = currentGesture.screen.velocity;
121       previousVelocity = true;
122       lastTime = currentGesture.time;
123       ++iter;
124       continue;
125     }
126     float velMag = currentGesture.screen.velocity.Length();
127     float velDiff = velMag - screenVelocity.Length();
128     float acceleration = 0.0f;
129     float time = (float)(currentGesture.time - lastTime);
130     if( time > Math::MACHINE_EPSILON_1 )
131     {
132       acceleration = velDiff / time;
133     }
134     float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
135     float newVelMag = 0.0f;
136     if( !havePreviousAcceleration )
137     {
138       newVelMag =  velMag + (acceleration * interpolationTime);
139       havePreviousAcceleration = true;
140     }
141     else
142     {
143       newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime);
144     }
145     float velMod = 1.0f;
146     if( velMag > Math::MACHINE_EPSILON_1 )
147     {
148       velMod = newVelMag / velMag;
149     }
150     gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
151     gestureOut.local.velocity = currentGesture.local.velocity * velMod;
152     screenVelocity = currentGesture.screen.velocity;
153     localVelocity = currentGesture.local.velocity;
154     previousAccel = acceleration;
155     ++iter;
156   }
157   // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
158   // add interpolated distance and position to current
159   float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time);
160   // work out interpolated velocity
161   gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime);
162   gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime);
163   gestureOut.screen.position += gestureOut.screen.displacement;
164   gestureOut.local.position += gestureOut.local.displacement;
165   gestureOut.time += (lastVSyncTime - gestureOut.time);
166 }
167
168 void PanGesture::PredictiveAlgorithm2(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
169 {
170   // TODO - adapt PredictiveAlgorithm1 with better smoothing, still under development
171   RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
172   size_t panHistorySize = panHistory.size();
173   if( panHistorySize == 0 )
174   {
175     // cant do any prediction without a history
176     return;
177   }
178
179   PanInfoHistoryConstIter endIter = panHistory.end();
180   PanInfoHistoryIter iter = panHistory.begin();
181   Vector2 screenVelocity = gestureOut.screen.velocity;
182   Vector2 localVelocity = gestureOut.local.velocity;
183   Vector2 screenDisplacement = gestureOut.screen.displacement;
184   Vector2 localDisplacement = gestureOut.local.displacement;
185
186   bool havePreviousAcceleration = false;
187   bool previousVelocity = false;
188   float previousAccel = 0.0f;
189   unsigned int lastTime(0);
190   unsigned int interpolationTime = (lastVSyncTime + mPredictionAmount) - gestureOut.time;
191   while( iter != endIter )
192   {
193     PanInfo currentGesture = *iter;
194     if( !previousVelocity )
195     {
196       // not yet set a previous velocity
197       screenVelocity = currentGesture.screen.velocity;
198       previousVelocity = true;
199       lastTime = currentGesture.time;
200       ++iter;
201       continue;
202     }
203     float previousValueWeight = (float)(MAX_GESTURE_AGE - (lastVSyncTime - lastTime)) / (float)MAX_GESTURE_AGE;
204     float velMag = currentGesture.screen.velocity.Length();
205     float velDiff = velMag - screenVelocity.Length();
206     float acceleration = 0.0f;
207     float time = (float)(currentGesture.time - lastTime);
208     if( time > Math::MACHINE_EPSILON_1 )
209     {
210       acceleration = velDiff / time;
211     }
212     float newVelMag = 0.0f;
213     int currentInterpolation = (lastVSyncTime + mPredictionAmount) - currentGesture.time;
214     if( !havePreviousAcceleration )
215     {
216       newVelMag =  velMag + (acceleration * currentInterpolation);
217       havePreviousAcceleration = true;
218     }
219     else
220     {
221       newVelMag = velMag + (((acceleration * (1.0f - previousValueWeight)) + (previousAccel * previousValueWeight)) * interpolationTime);
222     }
223     float velMod = 1.0f;
224     if( velMag > Math::MACHINE_EPSILON_1 )
225     {
226       velMod = newVelMag / velMag;
227     }
228     gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
229     gestureOut.local.velocity = currentGesture.local.velocity * velMod;
230     screenDisplacement = gestureOut.screen.displacement + (gestureOut.screen.velocity * interpolationTime);
231     localDisplacement = gestureOut.local.displacement + (gestureOut.local.velocity * interpolationTime);
232     screenVelocity = currentGesture.screen.velocity;
233     localVelocity = currentGesture.local.velocity;
234     previousAccel = acceleration;
235     ++iter;
236   }
237   // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
238   // add interpolated distance and position to current
239   // work out interpolated velocity
240   gestureOut.screen.displacement = screenDisplacement;
241   gestureOut.local.displacement = localDisplacement;
242   gestureOut.screen.position = (gestureOut.screen.position - gestureOut.screen.displacement) + screenDisplacement;
243   gestureOut.local.position = (gestureOut.local.position - gestureOut.local.displacement) + localDisplacement;
244   gestureOut.time += interpolationTime;
245 }
246
247 bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime )
248 {
249   bool propertiesUpdated( false );
250
251   if( !mInGesture )
252   {
253     // clear current pan history
254     mPanHistory.clear();
255   }
256
257   // create an event for this frame
258   bool justStarted ( false );
259   bool justFinished ( false );
260   bool eventFound( false );
261
262   // Not going through array from the beginning, using it as a circular buffer and only using unread
263   // values.
264   int eventsThisFrame = 0;
265
266   // create PanInfo to pass into prediction method
267   PanInfo nextGesture = mEventGesture;
268   // add new gestures and work out one full gesture for the frame
269   while(mReadPosition != mWritePosition)
270   {
271     // Copy the gesture first
272     PanInfo currentGesture(mGestures[mReadPosition]);
273
274     if( mProfiling )
275     {
276       mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position ) );
277     }
278     nextGesture.local.position = currentGesture.local.position;
279     nextGesture.local.velocity = currentGesture.local.velocity;
280     nextGesture.screen.position = currentGesture.screen.position;
281     nextGesture.screen.velocity = currentGesture.screen.velocity;
282     if( !eventFound )
283     {
284       nextGesture.local.displacement = currentGesture.local.displacement;
285       nextGesture.screen.displacement = currentGesture.screen.displacement;
286     }
287     else
288     {
289       nextGesture.local.displacement += currentGesture.local.displacement;
290       nextGesture.screen.displacement += currentGesture.screen.displacement;
291     }
292     eventFound = true;
293     nextGesture.time = currentGesture.time;
294
295     // add event to history
296     mPanHistory.push_back(currentGesture);
297     justStarted |= (currentGesture.state == Gesture::Started);
298     if( currentGesture.state == Gesture::Started )
299     {
300       justStarted = true;
301       // clear just finished as we have started new pan
302       justFinished = false;
303     }
304     justFinished |= (currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled);
305
306     // Update our read position.
307     ++eventsThisFrame;
308     ++mReadPosition;
309     mReadPosition %= PAN_GESTURE_HISTORY;
310   }
311   // set nextGesture to last gesture so it's position is correct and velocity is same as last frame
312   mEventGesture = nextGesture;
313
314   mInGesture |= justStarted;
315
316   bool updateProperties = false;
317
318   if ( mInGesture )
319   {
320     if( mProfiling )
321     {
322       mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, mEventGesture.screen.position ) );
323     }
324
325     switch( mPredictionMode )
326     {
327       case NONE:
328       {
329         updateProperties = eventFound;
330         break;
331       }
332       case AVERAGE:
333       {
334         SimpleAverageAlgorithm(justStarted, nextGesture);
335         // make latest gesture equal to current gesture after averaging
336         updateProperties = true;
337         break;
338       }
339       case PREDICTION_1:
340       {
341         // make latest gesture equal to current gesture before interpolation
342         PredictiveAlgorithm1(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
343         updateProperties = true;
344         break;
345       }
346       case PREDICTION_2:
347       {
348         // make latest gesture equal to current gesture before interpolation
349         PredictiveAlgorithm2(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
350         updateProperties = true;
351         break;
352       }
353     }
354
355     // always keep latest gesture up to date with event gesture
356     mLatestGesture = nextGesture;
357
358     if( updateProperties )
359     {
360       // only update properties if event received
361       // set latest gesture to raw pan info with unchanged time
362       mPanning.Set( mInGesture & !justFinished );
363       mScreenPosition.Set( nextGesture.screen.position );
364       mScreenDisplacement.Set( nextGesture.screen.displacement );
365       mLocalPosition.Set( nextGesture.local.position );
366       mLocalDisplacement.Set( nextGesture.local.displacement );
367
368       propertiesUpdated = true;
369     }
370
371     if( mProfiling )
372     {
373       mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( nextGesture.time, nextGesture.screen.position ) );
374     }
375   }
376   mLastEventGesture = mEventGesture;
377
378   mInGesture &= ~justFinished;
379
380   if( mProfiling && justFinished )
381   {
382     mProfiling->PrintData();
383     mProfiling->ClearData();
384   }
385
386   return propertiesUpdated;
387 }
388
389 const GesturePropertyBool& PanGesture::GetPanningProperty() const
390 {
391   return mPanning;
392 }
393
394 const GesturePropertyVector2& PanGesture::GetScreenPositionProperty() const
395 {
396   return mScreenPosition;
397 }
398
399 const GesturePropertyVector2& PanGesture::GetScreenDisplacementProperty() const
400 {
401   return mScreenDisplacement;
402 }
403
404 const GesturePropertyVector2& PanGesture::GetLocalPositionProperty() const
405 {
406   return mLocalPosition;
407 }
408
409 const GesturePropertyVector2& PanGesture::GetLocalDisplacementProperty() const
410 {
411   return mLocalDisplacement;
412 }
413
414 void PanGesture::SetPredictionMode(PredictionMode mode)
415 {
416   mPredictionMode = mode;
417 }
418
419 void PanGesture::SetPredictionAmount(unsigned int amount)
420 {
421   mPredictionAmount = amount;
422 }
423
424 void PanGesture::EnableProfiling()
425 {
426   if( !mProfiling )
427   {
428     mProfiling = new PanGestureProfiling();
429   }
430 }
431
432 void PanGesture::ResetDefaultProperties( BufferIndex updateBufferIndex )
433 {
434   mScreenPosition.Reset();
435   mScreenDisplacement.Reset();
436   mLocalPosition.Reset();
437   mLocalDisplacement.Reset();
438   mPanning.Reset();
439 }
440
441 PanGesture::PanGesture()
442 : mGestures(),
443   mWritePosition( 0 ),
444   mReadPosition( 0 ),
445   mInGesture( false ),
446   mPredictionMode(DEFAULT_PREDICTION_MODE),
447   mPredictionAmount(DEFAULT_PREDICTION_INTERPOLATION),
448   mProfiling( NULL )
449 {
450 }
451
452 } // namespace SceneGraph
453
454 } // namespace Internal
455
456 } // namespace Dali