2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/update/gestures/scene-graph-pan-gesture.h>
24 #include <dali/internal/update/gestures/pan-gesture-profiling.h>
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 } // 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, unsigned int currentTime, unsigned int maxAge, unsigned int 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 += mLastEventGesture.screen.position;
85 gestureOut.local.position += mLastEventGesture.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 = gestureOut.screen.position - mLastEventGesture.screen.position;
90 gestureOut.local.displacement = gestureOut.local.position - mLastEventGesture.local.position;
95 void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
97 RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
98 size_t panHistorySize = panHistory.size();
99 if( panHistorySize == 0 )
101 // cant do any prediction without a history
105 PanInfoHistoryConstIter endIter = panHistory.end();
106 PanInfoHistoryIter iter = panHistory.begin();
107 Vector2 screenVelocity = gestureOut.screen.velocity;
108 Vector2 localVelocity = gestureOut.local.velocity;
110 bool havePreviousAcceleration = false;
111 bool previousVelocity = false;
112 float previousAccel = 0.0f;
113 unsigned int lastTime(0);
114 while( iter != endIter )
116 PanInfo currentGesture = *iter;
117 if( !previousVelocity )
119 // not yet set a previous velocity
120 screenVelocity = currentGesture.screen.velocity;
121 previousVelocity = true;
122 lastTime = currentGesture.time;
126 float velMag = currentGesture.screen.velocity.Length();
127 float velDiff = velMag - screenVelocity.Length();
128 float acceleration = 0.0f;
129 float time = (float)(currentGesture.time - lastTime);
130 if( time > Math::MACHINE_EPSILON_1 )
132 acceleration = velDiff / time;
134 float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
135 float newVelMag = 0.0f;
136 if( !havePreviousAcceleration )
138 newVelMag = velMag + (acceleration * interpolationTime);
139 havePreviousAcceleration = true;
143 newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime);
146 if( velMag > Math::MACHINE_EPSILON_1 )
148 velMod = newVelMag / velMag;
150 gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
151 gestureOut.local.velocity = currentGesture.local.velocity * velMod;
152 screenVelocity = currentGesture.screen.velocity;
153 localVelocity = currentGesture.local.velocity;
154 previousAccel = acceleration;
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 float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time);
160 // work out interpolated velocity
161 gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime);
162 gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime);
163 gestureOut.screen.position += gestureOut.screen.displacement;
164 gestureOut.local.position += gestureOut.local.displacement;
165 gestureOut.time += (lastVSyncTime - gestureOut.time);
168 void PanGesture::PredictiveAlgorithm2(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
170 // TODO - adapt PredictiveAlgorithm1 with better smoothing, still under development
171 RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
172 size_t panHistorySize = panHistory.size();
173 if( panHistorySize == 0 )
175 // cant do any prediction without a history
179 PanInfoHistoryConstIter endIter = panHistory.end();
180 PanInfoHistoryIter iter = panHistory.begin();
181 Vector2 screenVelocity = gestureOut.screen.velocity;
182 Vector2 localVelocity = gestureOut.local.velocity;
183 Vector2 screenDisplacement = gestureOut.screen.displacement;
184 Vector2 localDisplacement = gestureOut.local.displacement;
186 bool havePreviousAcceleration = false;
187 bool previousVelocity = false;
188 float previousAccel = 0.0f;
189 unsigned int lastTime(0);
190 unsigned int interpolationTime = (lastVSyncTime + mPredictionAmount) - gestureOut.time;
191 while( iter != endIter )
193 PanInfo currentGesture = *iter;
194 if( !previousVelocity )
196 // not yet set a previous velocity
197 screenVelocity = currentGesture.screen.velocity;
198 previousVelocity = true;
199 lastTime = currentGesture.time;
203 float previousValueWeight = (float)(MAX_GESTURE_AGE - (lastVSyncTime - lastTime)) / (float)MAX_GESTURE_AGE;
204 float velMag = currentGesture.screen.velocity.Length();
205 float velDiff = velMag - screenVelocity.Length();
206 float acceleration = 0.0f;
207 float time = (float)(currentGesture.time - lastTime);
208 if( time > Math::MACHINE_EPSILON_1 )
210 acceleration = velDiff / time;
212 float newVelMag = 0.0f;
213 int currentInterpolation = (lastVSyncTime + mPredictionAmount) - currentGesture.time;
214 if( !havePreviousAcceleration )
216 newVelMag = velMag + (acceleration * currentInterpolation);
217 havePreviousAcceleration = true;
221 newVelMag = velMag + (((acceleration * (1.0f - previousValueWeight)) + (previousAccel * previousValueWeight)) * interpolationTime);
224 if( velMag > Math::MACHINE_EPSILON_1 )
226 velMod = newVelMag / velMag;
228 gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
229 gestureOut.local.velocity = currentGesture.local.velocity * velMod;
230 screenDisplacement = gestureOut.screen.displacement + (gestureOut.screen.velocity * interpolationTime);
231 localDisplacement = gestureOut.local.displacement + (gestureOut.local.velocity * interpolationTime);
232 screenVelocity = currentGesture.screen.velocity;
233 localVelocity = currentGesture.local.velocity;
234 previousAccel = acceleration;
237 // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
238 // add interpolated distance and position to current
239 // work out interpolated velocity
240 gestureOut.screen.displacement = screenDisplacement;
241 gestureOut.local.displacement = localDisplacement;
242 gestureOut.screen.position = (gestureOut.screen.position - gestureOut.screen.displacement) + screenDisplacement;
243 gestureOut.local.position = (gestureOut.local.position - gestureOut.local.displacement) + localDisplacement;
244 gestureOut.time += interpolationTime;
247 bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime )
249 bool propertiesUpdated( false );
253 // clear current pan history
257 // create an event for this frame
258 bool justStarted ( false );
259 bool justFinished ( false );
260 bool eventFound( false );
262 // Not going through array from the beginning, using it as a circular buffer and only using unread
264 int eventsThisFrame = 0;
266 // create PanInfo to pass into prediction method
267 PanInfo nextGesture = mEventGesture;
268 // add new gestures and work out one full gesture for the frame
269 while(mReadPosition != mWritePosition)
271 // Copy the gesture first
272 PanInfo currentGesture(mGestures[mReadPosition]);
276 mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position ) );
278 nextGesture.local.position = currentGesture.local.position;
279 nextGesture.local.velocity = currentGesture.local.velocity;
280 nextGesture.screen.position = currentGesture.screen.position;
281 nextGesture.screen.velocity = currentGesture.screen.velocity;
284 nextGesture.local.displacement = currentGesture.local.displacement;
285 nextGesture.screen.displacement = currentGesture.screen.displacement;
289 nextGesture.local.displacement += currentGesture.local.displacement;
290 nextGesture.screen.displacement += currentGesture.screen.displacement;
293 nextGesture.time = currentGesture.time;
295 // add event to history
296 mPanHistory.push_back(currentGesture);
297 justStarted |= (currentGesture.state == Gesture::Started);
298 if( currentGesture.state == Gesture::Started )
301 // clear just finished as we have started new pan
302 justFinished = false;
304 justFinished |= (currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled);
306 // Update our read position.
309 mReadPosition %= PAN_GESTURE_HISTORY;
311 // set nextGesture to last gesture so it's position is correct and velocity is same as last frame
312 mEventGesture = nextGesture;
314 mInGesture |= justStarted;
316 bool updateProperties = false;
322 mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, mEventGesture.screen.position ) );
325 switch( mPredictionMode )
329 updateProperties = eventFound;
334 SimpleAverageAlgorithm(justStarted, nextGesture);
335 // make latest gesture equal to current gesture after averaging
336 updateProperties = true;
341 // make latest gesture equal to current gesture before interpolation
342 PredictiveAlgorithm1(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
343 updateProperties = true;
348 // make latest gesture equal to current gesture before interpolation
349 PredictiveAlgorithm2(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
350 updateProperties = true;
355 // always keep latest gesture up to date with event gesture
356 mLatestGesture = nextGesture;
358 if( updateProperties )
360 // only update properties if event received
361 // set latest gesture to raw pan info with unchanged time
362 mPanning.Set( mInGesture & !justFinished );
363 mScreenPosition.Set( nextGesture.screen.position );
364 mScreenDisplacement.Set( nextGesture.screen.displacement );
365 mLocalPosition.Set( nextGesture.local.position );
366 mLocalDisplacement.Set( nextGesture.local.displacement );
368 propertiesUpdated = true;
373 mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( nextGesture.time, nextGesture.screen.position ) );
376 mLastEventGesture = mEventGesture;
378 mInGesture &= ~justFinished;
380 if( mProfiling && justFinished )
382 mProfiling->PrintData();
383 mProfiling->ClearData();
386 return propertiesUpdated;
389 const GesturePropertyBool& PanGesture::GetPanningProperty() const
394 const GesturePropertyVector2& PanGesture::GetScreenPositionProperty() const
396 return mScreenPosition;
399 const GesturePropertyVector2& PanGesture::GetScreenDisplacementProperty() const
401 return mScreenDisplacement;
404 const GesturePropertyVector2& PanGesture::GetLocalPositionProperty() const
406 return mLocalPosition;
409 const GesturePropertyVector2& PanGesture::GetLocalDisplacementProperty() const
411 return mLocalDisplacement;
414 void PanGesture::SetPredictionMode(PredictionMode mode)
416 mPredictionMode = mode;
419 void PanGesture::SetPredictionAmount(unsigned int amount)
421 mPredictionAmount = amount;
424 void PanGesture::EnableProfiling()
428 mProfiling = new PanGestureProfiling();
432 void PanGesture::ResetDefaultProperties( BufferIndex updateBufferIndex )
434 mScreenPosition.Reset();
435 mScreenDisplacement.Reset();
436 mLocalPosition.Reset();
437 mLocalDisplacement.Reset();
441 PanGesture::PanGesture()
446 mPredictionMode(DEFAULT_PREDICTION_MODE),
447 mPredictionAmount(DEFAULT_PREDICTION_INTERPOLATION),
452 } // namespace SceneGraph
454 } // namespace Internal