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