2 // Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 // http://floralicense.org/license/
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.
18 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
23 #include <dali/internal/update/gestures/pan-gesture-profiling.h>
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
40 const PanGesture::PredictionMode PanGesture::DEFAULT_PREDICTION_MODE = PanGesture::AVERAGE;
41 const int PanGesture::NUM_PREDICTION_MODES = PanGesture::PREDICTION_2 + 1;
43 PanGesture* PanGesture::New()
45 return new PanGesture();
48 PanGesture::~PanGesture()
53 void PanGesture::AddGesture( const Dali::PanGesture& gesture )
55 mGestures[ mWritePosition ] = gesture;
57 // Update our write position.
59 mWritePosition %= PAN_GESTURE_HISTORY;
62 void PanGesture::RemoveOldHistory(PanInfoHistory& panHistory, uint currentTime, uint maxAge, uint minEvents)
64 PanInfoHistoryConstIter endIter = panHistory.end();
65 PanInfoHistoryIter iter = panHistory.begin();
66 while( iter != endIter && panHistory.size() > minEvents)
68 PanInfo currentGesture = *iter;
69 if( currentTime < currentGesture.time + maxAge )
73 iter = panHistory.erase(iter);
74 endIter = panHistory.end();
78 void PanGesture::SimpleAverageAlgorithm(bool justStarted, PanInfo& gestureOut)
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;
95 void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
97 RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 1);
98 size_t panHistorySize = panHistory.size();
100 PanInfoHistoryConstIter endIter = panHistory.end();
101 PanInfoHistoryIter iter = panHistory.end() - (panHistorySize > 2 ? 2 : panHistorySize);
102 if( panHistorySize >= 2 )
104 // create average velocity and acceleration
105 // gestureOut is the combination of gesture events from this frame
106 PanInfo lastGesture = *iter;
108 float previousAccel = 0.0f;
109 while( iter != endIter )
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 )
119 acceleration = velDiff / time;
121 float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
122 float newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime);
124 if( velMag > Math::MACHINE_EPSILON_1 )
126 velMod = newVelMag / velMag;
128 gestureOut.screen.velocity *= velMod;
129 gestureOut.local.velocity *= velMod;
131 previousAccel = acceleration;
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;
146 void PanGesture::PredictiveAlgorithm2(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
148 // TODO - adapt PredictiveAlgorithm1 with better smoothing, still under development
149 RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 1);
150 size_t panHistorySize = panHistory.size();
152 PanInfoHistoryConstIter endIter = panHistory.end();
153 PanInfoHistoryIter iter = panHistory.end() - (panHistorySize > 2 ? 2 : panHistorySize);
154 if( panHistorySize >= 2 )
156 // create average velocity and acceleration
157 // gestureOut is the combination of gesture events from this frame
158 PanInfo lastGesture = *iter;
160 float previousAccel = 0.0f;
161 while( iter != endIter )
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 )
171 acceleration = velDiff / time;
173 float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
174 float newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime);
176 if( velMag > Math::MACHINE_EPSILON_1 )
178 velMod = newVelMag / velMag;
180 gestureOut.screen.velocity *= velMod;
181 gestureOut.local.velocity *= velMod;
183 previousAccel = acceleration;
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;
198 bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime )
200 bool propertiesUpdated( false );
204 // clear current pan history
208 // create an event for this frame
209 bool justStarted ( false );
210 bool justFinished ( false );
211 bool eventFound( false );
213 // Not going through array from the beginning, using it as a circular buffer and only using unread
215 int eventsThisFrame = 0;
216 // set nextGesture to last gesture so it's position is correct and velocity is same as last frame
217 mEventGesture = mLatestGesture;
218 // add new gestures and work out one full gesture for the frame
219 while(mReadPosition != mWritePosition)
221 // Copy the gesture first
222 PanInfo currentGesture(mGestures[mReadPosition]);
226 mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position ) );
229 if ( currentGesture.time < mEventGesture.time )
234 mEventGesture.local.position = currentGesture.local.position;
235 mEventGesture.local.velocity = currentGesture.local.velocity;
236 mEventGesture.screen.position = currentGesture.screen.position;
237 mEventGesture.screen.velocity = currentGesture.screen.velocity;
240 mEventGesture.local.displacement = currentGesture.local.displacement;
241 mEventGesture.screen.displacement = currentGesture.screen.displacement;
246 mEventGesture.local.displacement += currentGesture.local.displacement;
247 mEventGesture.screen.displacement += currentGesture.screen.displacement;
249 mEventGesture.time = currentGesture.time;
251 // add event to history
252 mPanHistory.push_back(currentGesture);
253 justStarted |= (currentGesture.state == Gesture::Started);
254 if( currentGesture.state == Gesture::Started )
257 // clear just finished as we have started new pan
258 justFinished = false;
260 justFinished |= (currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled);
262 // Update our read position.
265 mReadPosition %= PAN_GESTURE_HISTORY;
268 // create PanInfo to pass into prediction method
269 PanInfo nextGesture(mEventGesture);
271 mInGesture |= justStarted;
273 bool updateProperties = false;
279 mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, mLatestGesture.screen.position ) );
282 switch( mPredictionMode )
286 updateProperties = eventFound;
287 // no prediction, just using latest event info
288 mLatestGesture = mEventGesture;
293 SimpleAverageAlgorithm(justStarted, nextGesture);
294 // make latest gesture equal to current gesture after averaging
295 updateProperties = true;
300 // make latest gesture equal to current gesture before interpolation
301 mLatestGesture = nextGesture;
302 PredictiveAlgorithm1(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
303 updateProperties = true;
308 // make latest gesture equal to current gesture before interpolation
309 mLatestGesture = nextGesture;
310 PredictiveAlgorithm2(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
311 updateProperties = true;
316 // always keep latest gesture up to date with event gesture
317 mLatestGesture = mEventGesture;
319 if( updateProperties )
321 // only update properties if event received
322 // set latest gesture to raw pan info with unchanged time
323 mScreenPosition.Set( nextGesture.screen.position );
324 mScreenDisplacement.Set( nextGesture.screen.displacement );
325 mLocalPosition.Set( nextGesture.local.position );
326 mLocalDisplacement.Set( nextGesture.local.displacement );
328 propertiesUpdated = true;
333 mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( nextGesture.time, nextGesture.screen.position ) );
337 mInGesture &= ~justFinished;
340 UPDATE_COUNT++ >= UPDATES_BETWEEN_PRINT )
342 mProfiling->PrintData();
343 mProfiling->ClearData();
347 return propertiesUpdated;
350 const GesturePropertyVector2& PanGesture::GetScreenPositionProperty() const
352 return mScreenPosition;
355 const GesturePropertyVector2& PanGesture::GetScreenDisplacementProperty() const
357 return mScreenDisplacement;
360 const GesturePropertyVector2& PanGesture::GetLocalPositionProperty() const
362 return mLocalPosition;
365 const GesturePropertyVector2& PanGesture::GetLocalDisplacementProperty() const
367 return mLocalDisplacement;
370 void PanGesture::EnableProfiling()
374 mProfiling = new PanGestureProfiling();
378 void PanGesture::ResetDefaultProperties( BufferIndex updateBufferIndex )
380 mScreenPosition.Reset();
381 mScreenDisplacement.Reset();
382 mLocalPosition.Reset();
383 mLocalDisplacement.Reset();
386 PanGesture::PanGesture()
391 mPredictionMode(DEFAULT_PREDICTION_MODE),
396 } // namespace SceneGraph
398 } // namespace Internal