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 int MAX_GESTURE_AGE = 50; ///< maximum age of a gesture before disallowing its use in algorithm
36 } // unnamed namespace
38 const PanGesture::PredictionMode PanGesture::DEFAULT_PREDICTION_MODE = PanGesture::AVERAGE;
39 const int PanGesture::NUM_PREDICTION_MODES = PanGesture::PREDICTION_2 + 1;
41 PanGesture* PanGesture::New()
43 return new PanGesture();
46 PanGesture::~PanGesture()
51 void PanGesture::AddGesture( const Dali::PanGesture& gesture )
53 mGestures[ mWritePosition ] = gesture;
55 // Update our write position.
57 mWritePosition %= PAN_GESTURE_HISTORY;
60 void PanGesture::RemoveOldHistory(PanInfoHistory& panHistory, uint currentTime, uint maxAge, uint minEvents)
62 PanInfoHistoryConstIter endIter = panHistory.end();
63 PanInfoHistoryIter iter = panHistory.begin();
64 while( iter != endIter && panHistory.size() > minEvents)
66 PanInfo currentGesture = *iter;
67 if( currentTime < currentGesture.time + maxAge )
71 iter = panHistory.erase(iter);
72 endIter = panHistory.end();
76 void PanGesture::SimpleAverageAlgorithm(bool justStarted, PanInfo& gestureOut)
82 gestureOut.screen.position += mLastEventGesture.screen.position;
83 gestureOut.local.position += mLastEventGesture.local.position;
84 gestureOut.screen.position *= 0.5f;
85 gestureOut.local.position *= 0.5f;
86 // make current displacement relative to previous update-frame now.
87 gestureOut.screen.displacement = gestureOut.screen.position - mLastEventGesture.screen.position;
88 gestureOut.local.displacement = gestureOut.local.position - mLastEventGesture.local.position;
93 void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
95 RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
96 size_t panHistorySize = panHistory.size();
97 if( panHistorySize == 0 )
99 // cant do any prediction without a history
103 PanInfoHistoryConstIter endIter = panHistory.end();
104 PanInfoHistoryIter iter = panHistory.begin();
105 Vector2 screenVelocity = gestureOut.screen.velocity;
106 Vector2 localVelocity = gestureOut.local.velocity;
108 bool havePreviousAcceleration = false;
109 bool previousVelocity = false;
110 float previousAccel = 0.0f;
111 unsigned int lastTime;
112 while( iter != endIter )
114 PanInfo currentGesture = *iter;
115 if( !previousVelocity )
117 // not yet set a previous velocity
118 screenVelocity = currentGesture.screen.velocity;
119 previousVelocity = true;
120 lastTime = currentGesture.time;
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 )
130 acceleration = velDiff / time;
132 float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
133 float newVelMag = 0.0f;
134 if( !havePreviousAcceleration )
136 newVelMag = velMag + (acceleration * interpolationTime);
137 havePreviousAcceleration = true;
141 newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime);
144 if( velMag > Math::MACHINE_EPSILON_1 )
146 velMod = newVelMag / velMag;
148 gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
149 gestureOut.local.velocity = currentGesture.local.velocity * velMod;
150 screenVelocity = currentGesture.screen.velocity;
151 localVelocity = currentGesture.local.velocity;
152 previousAccel = acceleration;
155 // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
156 // add interpolated distance and position to current
157 float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time);
158 // work out interpolated velocity
159 gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime);
160 gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime);
161 gestureOut.screen.position += gestureOut.screen.displacement;
162 gestureOut.local.position += gestureOut.local.displacement;
163 gestureOut.time += (lastVSyncTime - gestureOut.time);
166 void PanGesture::PredictiveAlgorithm2(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
168 // TODO - adapt PredictiveAlgorithm1 with better smoothing, still under development
169 RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
170 size_t panHistorySize = panHistory.size();
171 if( panHistorySize == 0 )
173 // cant do any prediction without a history
177 PanInfoHistoryConstIter endIter = panHistory.end();
178 PanInfoHistoryIter iter = panHistory.begin();
179 Vector2 screenVelocity = gestureOut.screen.velocity;
180 Vector2 localVelocity = gestureOut.local.velocity;
182 bool havePreviousAcceleration = false;
183 bool previousVelocity = false;
184 float previousAccel = 0.0f;
185 unsigned int lastTime;
186 while( iter != endIter )
188 PanInfo currentGesture = *iter;
189 if( !previousVelocity )
191 // not yet set a previous velocity
192 screenVelocity = currentGesture.screen.velocity;
193 previousVelocity = true;
194 lastTime = currentGesture.time;
198 float previousValueWeight = (float)(MAX_GESTURE_AGE - (lastVSyncTime - lastTime)) / (float)MAX_GESTURE_AGE;
199 float velMag = currentGesture.screen.velocity.Length();
200 float velDiff = velMag - screenVelocity.Length();
201 float acceleration = 0.0f;
202 float time = (float)(currentGesture.time - lastTime);
203 if( time > Math::MACHINE_EPSILON_1 )
205 acceleration = velDiff / time;
207 float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
208 float newVelMag = 0.0f;
209 if( !havePreviousAcceleration )
211 newVelMag = velMag + (acceleration * interpolationTime);
212 havePreviousAcceleration = true;
216 newVelMag = velMag + (((acceleration * (1.0f - previousValueWeight)) + (previousAccel * previousValueWeight)) * interpolationTime);
219 if( velMag > Math::MACHINE_EPSILON_1 )
221 velMod = newVelMag / velMag;
223 gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
224 gestureOut.local.velocity = currentGesture.local.velocity * velMod;
225 screenVelocity = currentGesture.screen.velocity;
226 localVelocity = currentGesture.local.velocity;
227 previousAccel = acceleration;
230 // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
231 // add interpolated distance and position to current
232 float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time);
233 // work out interpolated velocity
234 gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime);
235 gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime);
236 gestureOut.screen.position += gestureOut.screen.displacement;
237 gestureOut.local.position += gestureOut.local.displacement;
238 gestureOut.time += (lastVSyncTime - gestureOut.time);
241 bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime )
243 bool propertiesUpdated( false );
247 // clear current pan history
251 // create an event for this frame
252 bool justStarted ( false );
253 bool justFinished ( false );
254 bool eventFound( false );
256 // Not going through array from the beginning, using it as a circular buffer and only using unread
258 int eventsThisFrame = 0;
260 // create PanInfo to pass into prediction method
261 PanInfo nextGesture = mEventGesture;
262 // add new gestures and work out one full gesture for the frame
263 while(mReadPosition != mWritePosition)
265 // Copy the gesture first
266 PanInfo currentGesture(mGestures[mReadPosition]);
270 mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position ) );
272 nextGesture.local.position = currentGesture.local.position;
273 nextGesture.local.velocity = currentGesture.local.velocity;
274 nextGesture.screen.position = currentGesture.screen.position;
275 nextGesture.screen.velocity = currentGesture.screen.velocity;
278 nextGesture.local.displacement = currentGesture.local.displacement;
279 nextGesture.screen.displacement = currentGesture.screen.displacement;
283 nextGesture.local.displacement += currentGesture.local.displacement;
284 nextGesture.screen.displacement += currentGesture.screen.displacement;
287 nextGesture.time = currentGesture.time;
289 // add event to history
290 mPanHistory.push_back(currentGesture);
291 justStarted |= (currentGesture.state == Gesture::Started);
292 if( currentGesture.state == Gesture::Started )
295 // clear just finished as we have started new pan
296 justFinished = false;
298 justFinished |= (currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled);
300 // Update our read position.
303 mReadPosition %= PAN_GESTURE_HISTORY;
305 // set nextGesture to last gesture so it's position is correct and velocity is same as last frame
306 mEventGesture = nextGesture;
308 mInGesture |= justStarted;
310 bool updateProperties = false;
316 mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, mEventGesture.screen.position ) );
319 switch( mPredictionMode )
323 updateProperties = eventFound;
328 SimpleAverageAlgorithm(justStarted, nextGesture);
329 // make latest gesture equal to current gesture after averaging
330 updateProperties = true;
335 // make latest gesture equal to current gesture before interpolation
336 PredictiveAlgorithm1(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
337 updateProperties = true;
342 // make latest gesture equal to current gesture before interpolation
343 PredictiveAlgorithm2(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
344 updateProperties = true;
349 // always keep latest gesture up to date with event gesture
350 mLatestGesture = nextGesture;
352 if( updateProperties )
354 // only update properties if event received
355 // set latest gesture to raw pan info with unchanged time
356 mPanning.Set( mInGesture & !justFinished );
357 mScreenPosition.Set( nextGesture.screen.position );
358 mScreenDisplacement.Set( nextGesture.screen.displacement );
359 mLocalPosition.Set( nextGesture.local.position );
360 mLocalDisplacement.Set( nextGesture.local.displacement );
362 propertiesUpdated = true;
367 mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( nextGesture.time, nextGesture.screen.position ) );
370 mLastEventGesture = mEventGesture;
372 mInGesture &= ~justFinished;
374 if( mProfiling && justFinished )
376 mProfiling->PrintData();
377 mProfiling->ClearData();
380 return propertiesUpdated;
383 const GesturePropertyBool& PanGesture::GetPanningProperty() const
388 const GesturePropertyVector2& PanGesture::GetScreenPositionProperty() const
390 return mScreenPosition;
393 const GesturePropertyVector2& PanGesture::GetScreenDisplacementProperty() const
395 return mScreenDisplacement;
398 const GesturePropertyVector2& PanGesture::GetLocalPositionProperty() const
400 return mLocalPosition;
403 const GesturePropertyVector2& PanGesture::GetLocalDisplacementProperty() const
405 return mLocalDisplacement;
408 void PanGesture::EnableProfiling()
412 mProfiling = new PanGestureProfiling();
416 void PanGesture::ResetDefaultProperties( BufferIndex updateBufferIndex )
418 mScreenPosition.Reset();
419 mScreenDisplacement.Reset();
420 mLocalPosition.Reset();
421 mLocalDisplacement.Reset();
425 PanGesture::PanGesture()
430 mPredictionMode(DEFAULT_PREDICTION_MODE),
435 } // namespace SceneGraph
437 } // namespace Internal