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