(PanGesture) Added environment variable "PAN_PREDICTION_MODE" for selecting gesture...
[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 Flora License, Version 1.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://floralicense.org/license/
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 // CLASS HEADER
18 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
19
20 // EXTERNAL INCLUDES
21
22 // INTERNAL INCLUDES
23 #include <dali/internal/update/gestures/pan-gesture-profiling.h>
24
25 namespace Dali
26 {
27
28 namespace Internal
29 {
30
31 namespace SceneGraph
32 {
33 namespace
34 {
35 const unsigned int UPDATES_BETWEEN_PRINT( 120u );
36 unsigned int UPDATE_COUNT( 0u );
37 const int MAX_GESTURE_AGE = 100; ///< maximum age of a gesture before disallowing its use in algorithm
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, uint currentTime, uint maxAge, uint 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     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 += mLatestGesture.screen.position;
85       gestureOut.local.position += mLatestGesture.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 -= mLatestGesture.screen.displacement;
90       gestureOut.local.displacement -= mLatestGesture.local.displacement;
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, 1);
98   size_t panHistorySize = panHistory.size();
99
100   PanInfoHistoryConstIter endIter = panHistory.end();
101   PanInfoHistoryIter iter = panHistory.end() - (panHistorySize > 2 ? 2 : panHistorySize);
102   if( panHistorySize >= 2 )
103   {
104     // create average velocity and acceleration
105     // gestureOut is the combination of gesture events from this frame
106     PanInfo lastGesture = *iter;
107     ++iter;
108     float previousAccel = 0.0f;
109     while( iter != endIter )
110     {
111       PanInfo currentGesture = *iter;
112       lastGesture = *(iter - 1);
113       float velMag = currentGesture.screen.velocity.Length();
114       float velDiff = velMag - lastGesture.screen.velocity.Length();
115       float acceleration = 0.0f;
116       float time = (float)(currentGesture.time - lastGesture.time);
117       if( time >= Math::MACHINE_EPSILON_1 )
118       {
119         acceleration = velDiff / time;
120       }
121       float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
122       float newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime);
123       float velMod = 1.0f;
124       if( velMag > Math::MACHINE_EPSILON_1 )
125       {
126         velMod = newVelMag / velMag;
127       }
128       gestureOut.screen.velocity *= velMod;
129       gestureOut.local.velocity *= velMod;
130       lastGesture = *iter;
131       previousAccel = acceleration;
132       ++iter;
133     }
134   }
135   // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
136   // add interpolated distance and position to current
137   float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time);
138   // work out interpolated velocity
139   gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime);
140   gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime);
141   gestureOut.screen.position += gestureOut.screen.displacement;
142   gestureOut.local.position += gestureOut.local.displacement;
143   gestureOut.time += interpolationTime;
144 }
145
146 void PanGesture::PredictiveAlgorithm2(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
147 {
148   // TODO - adapt PredictiveAlgorithm1 with better smoothing, still under development
149   RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 1);
150   size_t panHistorySize = panHistory.size();
151
152   PanInfoHistoryConstIter endIter = panHistory.end();
153   PanInfoHistoryIter iter = panHistory.end() - (panHistorySize > 2 ? 2 : panHistorySize);
154   if( panHistorySize >= 2 )
155   {
156     // create average velocity and acceleration
157     // gestureOut is the combination of gesture events from this frame
158     PanInfo lastGesture = *iter;
159     ++iter;
160     float previousAccel = 0.0f;
161     while( iter != endIter )
162     {
163       PanInfo currentGesture = *iter;
164       lastGesture = *(iter - 1);
165       float velMag = currentGesture.screen.velocity.Length();
166       float velDiff = velMag - lastGesture.screen.velocity.Length();
167       float acceleration = 0.0f;
168       float time = (float)(currentGesture.time - lastGesture.time);
169       if( time >= Math::MACHINE_EPSILON_1 )
170       {
171         acceleration = velDiff / time;
172       }
173       float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
174       float newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime);
175       float velMod = 1.0f;
176       if( velMag > Math::MACHINE_EPSILON_1 )
177       {
178         velMod = newVelMag / velMag;
179       }
180       gestureOut.screen.velocity *= velMod;
181       gestureOut.local.velocity *= velMod;
182       lastGesture = *iter;
183       previousAccel = acceleration;
184       ++iter;
185     }
186   }
187   // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
188   // add interpolated distance and position to current
189   float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time);
190   // work out interpolated velocity
191   gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime);
192   gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime);
193   gestureOut.screen.position += gestureOut.screen.displacement;
194   gestureOut.local.position += gestureOut.local.displacement;
195   gestureOut.time += interpolationTime;
196 }
197
198 void PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime )
199 {
200   if( !mInGesture )
201   {
202     // clear current pan history
203     mPanHistory.clear();
204   }
205
206   // create an event for this frame
207   bool justStarted ( false );
208   bool justFinished ( false );
209   bool eventFound( false );
210
211   // Not going through array from the beginning, using it as a circular buffer and only using unread
212   // values.
213   int eventsThisFrame = 0;
214   // set nextGesture to last gesture so it's position is correct and velocity is same as last frame
215   mEventGesture = mLatestGesture;
216   // add new gestures and work out one full gesture for the frame
217   while(mReadPosition != mWritePosition)
218   {
219     // Copy the gesture first
220     PanInfo currentGesture(mGestures[mReadPosition]);
221
222     if( mProfiling )
223     {
224       mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position ) );
225     }
226
227     if ( currentGesture.time < mEventGesture.time )
228     {
229       break;
230     }
231
232     mEventGesture.local.position = currentGesture.local.position;
233     mEventGesture.local.velocity = currentGesture.local.velocity;
234     mEventGesture.screen.position = currentGesture.screen.position;
235     mEventGesture.screen.velocity = currentGesture.screen.velocity;
236     if( !eventFound )
237     {
238       mEventGesture.local.displacement = currentGesture.local.displacement;
239       mEventGesture.screen.displacement = currentGesture.screen.displacement;
240       eventFound = true;
241     }
242     else
243     {
244       mEventGesture.local.displacement += currentGesture.local.displacement;
245       mEventGesture.screen.displacement += currentGesture.screen.displacement;
246     }
247     mEventGesture.time = currentGesture.time;
248
249     // add event to history
250     mPanHistory.push_back(currentGesture);
251     justStarted |= (currentGesture.state == Gesture::Started);
252     if( currentGesture.state == Gesture::Started )
253     {
254       justStarted = true;
255       // clear just finished as we have started new pan
256       justFinished = false;
257     }
258     justFinished |= (currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled);
259
260     // Update our read position.
261     ++mReadPosition;
262     ++eventsThisFrame;
263     mReadPosition %= PAN_GESTURE_HISTORY;
264   }
265
266   // create PanInfo to pass into prediction method
267   PanInfo nextGesture(mEventGesture);
268
269   mInGesture |= justStarted;
270
271   bool updateProperties = false;
272
273   if ( mInGesture )
274   {
275     if( mProfiling )
276     {
277       mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, mLatestGesture.screen.position ) );
278     }
279
280     switch( mPredictionMode )
281     {
282       case NONE:
283       {
284         updateProperties = eventFound;
285         // no prediction, just using latest event info
286         mLatestGesture = mEventGesture;
287         break;
288       }
289       case AVERAGE:
290       {
291         SimpleAverageAlgorithm(justStarted, nextGesture);
292         // make latest gesture equal to current gesture after averaging
293         updateProperties = true;
294         break;
295       }
296       case PREDICTION_1:
297       {
298         // make latest gesture equal to current gesture before interpolation
299         mLatestGesture = nextGesture;
300         PredictiveAlgorithm1(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
301         updateProperties = true;
302         break;
303       }
304       case PREDICTION_2:
305       {
306         // make latest gesture equal to current gesture before interpolation
307         mLatestGesture = nextGesture;
308         PredictiveAlgorithm2(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
309         updateProperties = true;
310         break;
311       }
312     }
313
314     // always keep latest gesture up to date with event gesture
315     mLatestGesture = mEventGesture;
316
317     if( updateProperties )
318     {
319       // only update properties if event received
320       // set latest gesture to raw pan info with unchanged time
321       mScreenPosition.Set( nextGesture.screen.position );
322       mScreenDisplacement.Set( nextGesture.screen.displacement );
323       mLocalPosition.Set( nextGesture.local.position );
324       mLocalDisplacement.Set( nextGesture.local.displacement );
325     }
326
327     if( mProfiling )
328     {
329       mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( nextGesture.time, nextGesture.screen.position ) );
330     }
331   }
332
333   mInGesture &= ~justFinished;
334
335   if( mProfiling &&
336       UPDATE_COUNT++ >= UPDATES_BETWEEN_PRINT )
337   {
338     mProfiling->PrintData();
339     mProfiling->ClearData();
340     UPDATE_COUNT = 0u;
341   }
342 }
343
344 const GesturePropertyVector2& PanGesture::GetScreenPositionProperty() const
345 {
346   return mScreenPosition;
347 }
348
349 const GesturePropertyVector2& PanGesture::GetScreenDisplacementProperty() const
350 {
351   return mScreenDisplacement;
352 }
353
354 const GesturePropertyVector2& PanGesture::GetLocalPositionProperty() const
355 {
356   return mLocalPosition;
357 }
358
359 const GesturePropertyVector2& PanGesture::GetLocalDisplacementProperty() const
360 {
361   return mLocalDisplacement;
362 }
363
364 void PanGesture::EnableProfiling()
365 {
366   if( !mProfiling )
367   {
368     mProfiling = new PanGestureProfiling();
369   }
370 }
371
372 void PanGesture::ResetDefaultProperties( BufferIndex updateBufferIndex )
373 {
374   mScreenPosition.Reset();
375   mScreenDisplacement.Reset();
376   mLocalPosition.Reset();
377   mLocalDisplacement.Reset();
378 }
379
380 PanGesture::PanGesture()
381 : mGestures(),
382   mWritePosition( 0 ),
383   mReadPosition( 0 ),
384   mInGesture( false ),
385   mPredictionMode(DEFAULT_PREDICTION_MODE),
386   mProfiling( NULL )
387 {
388 }
389
390 } // namespace SceneGraph
391
392 } // namespace Internal
393
394 } // namespace Dali