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 const float DEFAULT_SMOOTHING_AMOUNT = 1.0f; ///< how much to interpolate pan position and displacement from last vsync time
39 } // unnamed namespace
41 const PanGesture::PredictionMode PanGesture::DEFAULT_PREDICTION_MODE = PanGesture::PREDICTION_NONE;
42 const int PanGesture::NUM_PREDICTION_MODES = PanGesture::PREDICTION_1 + 1;
44 const PanGesture::SmoothingMode PanGesture::DEFAULT_SMOOTHING_MODE = PanGesture::SMOOTHING_LAST_VALUE;
45 const int PanGesture::NUM_SMOOTHING_MODES = PanGesture::SMOOTHING_LAST_VALUE + 1;
47 PanGesture* PanGesture::New()
49 return new PanGesture();
52 PanGesture::~PanGesture()
57 void PanGesture::AddGesture( const Dali::PanGesture& gesture )
59 mGestures[ mWritePosition ] = gesture;
61 // Update our write position.
63 mWritePosition %= PAN_GESTURE_HISTORY;
66 void PanGesture::RemoveOldHistory(PanInfoHistory& panHistory, unsigned int currentTime, unsigned int maxAge, unsigned int minEvents)
68 PanInfoHistoryConstIter endIter = panHistory.end();
69 PanInfoHistoryIter iter = panHistory.begin();
70 while( iter != endIter && panHistory.size() > minEvents)
72 PanInfo currentGesture = *iter;
73 if( currentTime < currentGesture.time + maxAge )
77 iter = panHistory.erase(iter);
78 endIter = panHistory.end();
81 // dont want more than 5 previous predictions for smoothing
82 iter = mPredictionHistory.begin();
83 while( mPredictionHistory.size() > 1 && iter != mPredictionHistory.end() )
85 iter = mPredictionHistory.erase(iter);
89 void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
91 RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
92 size_t panHistorySize = panHistory.size();
93 if( panHistorySize == 0 )
95 // cant do any prediction without a history
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;
106 bool havePreviousAcceleration = false;
107 bool previousVelocity = false;
108 float previousAccel = 0.0f;
109 unsigned int lastTime(0);
111 unsigned int interpolationTime = lastVSyncTime + mPredictionAmount;
112 if( interpolationTime > gestureOut.time ) // Guard against the rare case when gestureOut.time > (lastVSyncTime + mPredictionAmount)
114 interpolationTime -= gestureOut.time;
118 interpolationTime = 0u;
121 while( iter != endIter )
123 PanInfo currentGesture = *iter;
124 if( !previousVelocity )
126 // not yet set a previous velocity
127 screenVelocity = currentGesture.screen.velocity;
128 previousVelocity = true;
129 lastTime = currentGesture.time;
133 float previousValueWeight = (float)(MAX_GESTURE_AGE - (lastVSyncTime - lastTime)) / (float)MAX_GESTURE_AGE;
134 float velMag = currentGesture.screen.velocity.Length();
135 float velDiff = velMag - screenVelocity.Length();
136 float acceleration = 0.0f;
139 if (currentGesture.time > lastTime) // Guard against invalid timestamps
141 time = static_cast<float>( currentGesture.time - lastTime );
143 if( time > Math::MACHINE_EPSILON_1 )
145 acceleration = velDiff / time;
148 float newVelMag = 0.0f;
149 int currentInterpolation = interpolationTime;
150 if( !havePreviousAcceleration )
153 havePreviousAcceleration = true;
157 newVelMag = velMag + (((acceleration * (1.0f - previousValueWeight)) + (previousAccel * previousValueWeight)) * currentInterpolation);
160 if( velMag > Math::MACHINE_EPSILON_1 )
162 velMod = newVelMag / velMag;
164 gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
165 gestureOut.local.velocity = currentGesture.local.velocity * velMod;
166 screenDisplacement = gestureOut.screen.displacement + (gestureOut.screen.velocity * interpolationTime);
167 localDisplacement = gestureOut.local.displacement + (gestureOut.local.velocity * interpolationTime);
168 screenVelocity = currentGesture.screen.velocity;
169 localVelocity = currentGesture.local.velocity;
170 previousAccel = acceleration;
173 // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
174 // add interpolated distance and position to current
175 // work out interpolated velocity
176 gestureOut.screen.position = (gestureOut.screen.position - gestureOut.screen.displacement) + screenDisplacement;
177 gestureOut.local.position = (gestureOut.local.position - gestureOut.local.displacement) + localDisplacement;
178 gestureOut.screen.displacement = screenDisplacement;
179 gestureOut.local.displacement = localDisplacement;
180 gestureOut.time += interpolationTime;
183 void PanGesture::SmoothingAlgorithm1(bool justStarted, PanInfo& gestureOut, unsigned int lastVSyncTime)
187 gestureOut.screen.position -= (gestureOut.screen.position - mLastGesture.screen.position) * 0.5f * (1.0f - mSmoothingAmount);
188 gestureOut.local.position -= (gestureOut.local.position - mLastGesture.local.position) * 0.5f * (1.0f - mSmoothingAmount);
189 // make current displacement relative to previous update-frame now.
190 gestureOut.screen.displacement = gestureOut.screen.position - mLastGesture.screen.position;
191 gestureOut.local.displacement = gestureOut.local.position - mLastGesture.local.position;
192 // calculate velocity relative to previous update-frame
193 unsigned int timeDiff( gestureOut.time - mLastGesture.time );
194 gestureOut.screen.velocity = gestureOut.screen.displacement / timeDiff;
195 gestureOut.local.velocity = gestureOut.local.displacement / timeDiff;
199 void PanGesture::SmoothingAlgorithm2(bool justStarted, PanInfo& gestureOut, unsigned int lastVSyncTime)
202 mPredictionHistory.push_back(gestureOut);
204 // now smooth current pan event
205 PanInfoHistoryConstIter endIter = mPredictionHistory.end() - 1;
206 PanInfoHistoryIter iter = mPredictionHistory.begin();
208 float distanceMod = 1.0f;
210 while( iter != endIter )
212 PanInfo currentGesture = *iter;
213 float newDistanceMod = currentGesture.screen.displacement.Length() / gestureOut.screen.displacement.Length();
214 distanceMod = ((distanceMod * weight) + (newDistanceMod * (1.0f - weight)));
218 gestureOut.screen.position -= gestureOut.screen.displacement;
219 gestureOut.local.position -= gestureOut.local.displacement;
220 gestureOut.screen.displacement *= distanceMod;
221 gestureOut.local.displacement *= distanceMod;
222 gestureOut.screen.position += gestureOut.screen.displacement;
223 gestureOut.local.position += gestureOut.local.displacement;
226 bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime )
230 // clear current pan history
232 mPredictionHistory.clear();
235 // create an event for this frame
236 bool justStarted ( false );
237 bool justFinished ( false );
238 bool eventFound( false );
240 // Not going through array from the beginning, using it as a circular buffer and only using unread
242 int eventsThisFrame = 0;
244 // create PanInfo to pass into prediction method
245 mLastEventGesture = mEventGesture;
246 mLastGesture = mLatestGesture;
247 // add new gestures and work out one full gesture for the frame
248 while(mReadPosition != mWritePosition)
250 // Copy the gesture first
251 PanInfo currentGesture(mGestures[mReadPosition]);
255 mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position ) );
257 mEventGesture.local.position = currentGesture.local.position;
258 mEventGesture.local.velocity = currentGesture.local.velocity;
259 mEventGesture.screen.position = currentGesture.screen.position;
260 mEventGesture.screen.velocity = currentGesture.screen.velocity;
263 mEventGesture.local.displacement = currentGesture.local.displacement;
264 mEventGesture.screen.displacement = currentGesture.screen.displacement;
268 mEventGesture.local.displacement += currentGesture.local.displacement;
269 mEventGesture.screen.displacement += currentGesture.screen.displacement;
272 mEventGesture.time = currentGesture.time;
274 // add event to history
275 mPanHistory.push_back(currentGesture);
276 if( currentGesture.state == Gesture::Started )
279 // clear just finished as we have started new pan
280 justFinished = false;
282 justFinished |= (currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled);
284 // Update our read position.
287 mReadPosition %= PAN_GESTURE_HISTORY;
289 mLatestGesture = mEventGesture;
291 mInGesture |= justStarted;
293 bool updateProperties = false;
299 mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, mEventGesture.screen.position ) );
302 switch( mPredictionMode )
304 case PREDICTION_NONE:
306 updateProperties = eventFound;
307 // dont want event time
308 unsigned int time = mLastGesture.time;
309 mLastGesture = mLastEventGesture;
310 mLastGesture.time = time;
311 mLatestGesture.time = lastVSyncTime;
316 // make latest gesture equal to current gesture before interpolation
317 PredictiveAlgorithm1(eventsThisFrame, mLatestGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
318 updateProperties = true;
323 switch( mSmoothingMode )
330 case SMOOTHING_LAST_VALUE:
332 SmoothingAlgorithm1(justStarted, mLatestGesture, lastVSyncTime);
337 if( updateProperties )
339 // only update properties if event received
340 // set latest gesture to raw pan info with unchanged time
341 mPanning.Set( mInGesture & !justFinished );
342 mScreenPosition.Set( mLatestGesture.screen.position );
343 mScreenDisplacement.Set( mLatestGesture.screen.displacement );
344 mScreenVelocity.Set( mLatestGesture.screen.velocity );
345 mLocalPosition.Set( mLatestGesture.local.position );
346 mLocalDisplacement.Set( mLatestGesture.local.displacement );
347 mLocalVelocity.Set( mLatestGesture.local.velocity );
352 mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( mLatestGesture.time, mLatestGesture.screen.position ) );
356 mInGesture &= ~justFinished;
358 if( mProfiling && justFinished )
360 mProfiling->PrintData();
361 mProfiling->ClearData();
364 return updateProperties;
367 const GesturePropertyBool& PanGesture::GetPanningProperty() const
372 const GesturePropertyVector2& PanGesture::GetScreenPositionProperty() const
374 return mScreenPosition;
377 const GesturePropertyVector2& PanGesture::GetScreenVelocityProperty() const
379 return mScreenVelocity;
382 const GesturePropertyVector2& PanGesture::GetScreenDisplacementProperty() const
384 return mScreenDisplacement;
387 const GesturePropertyVector2& PanGesture::GetLocalPositionProperty() const
389 return mLocalPosition;
392 const GesturePropertyVector2& PanGesture::GetLocalDisplacementProperty() const
394 return mLocalDisplacement;
397 const GesturePropertyVector2& PanGesture::GetLocalVelocityProperty() const
399 return mLocalVelocity;
402 void PanGesture::SetPredictionMode(PredictionMode mode)
404 mPredictionMode = mode;
407 void PanGesture::SetPredictionAmount(unsigned int amount)
409 mPredictionAmount = amount;
412 void PanGesture::SetSmoothingMode(SmoothingMode mode)
414 mSmoothingMode = mode;
417 void PanGesture::SetSmoothingAmount(float amount)
419 mSmoothingAmount = amount;
422 void PanGesture::EnableProfiling()
426 mProfiling = new PanGestureProfiling();
430 void PanGesture::ResetDefaultProperties( BufferIndex updateBufferIndex )
432 mScreenPosition.Reset();
433 mScreenDisplacement.Reset();
434 mLocalPosition.Reset();
435 mLocalDisplacement.Reset();
439 PanGesture::PanGesture()
444 mPredictionMode(DEFAULT_PREDICTION_MODE),
445 mPredictionAmount(DEFAULT_PREDICTION_INTERPOLATION),
446 mSmoothingMode(DEFAULT_SMOOTHING_MODE),
447 mSmoothingAmount(DEFAULT_SMOOTHING_AMOUNT),
452 } // namespace SceneGraph
454 } // namespace Internal