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 const float DEFAULT_PREDICTION_INTERPOLATION = 0.0f; ///< how much to interpolate pan position and displacement from last vsync time
37 } // unnamed namespace
39 const PanGesture::PredictionMode PanGesture::DEFAULT_PREDICTION_MODE = PanGesture::PREDICTION_2;
40 const int PanGesture::NUM_PREDICTION_MODES = PanGesture::PREDICTION_2 + 1;
42 PanGesture* PanGesture::New()
44 return new PanGesture();
47 PanGesture::~PanGesture()
52 void PanGesture::AddGesture( const Dali::PanGesture& gesture )
54 mGestures[ mWritePosition ] = gesture;
56 // Update our write position.
58 mWritePosition %= PAN_GESTURE_HISTORY;
61 void PanGesture::RemoveOldHistory(PanInfoHistory& panHistory, uint currentTime, uint maxAge, uint minEvents)
63 PanInfoHistoryConstIter endIter = panHistory.end();
64 PanInfoHistoryIter iter = panHistory.begin();
65 while( iter != endIter && panHistory.size() > minEvents)
67 PanInfo currentGesture = *iter;
68 if( currentTime < currentGesture.time + maxAge )
72 iter = panHistory.erase(iter);
73 endIter = panHistory.end();
77 void PanGesture::SimpleAverageAlgorithm(bool justStarted, PanInfo& gestureOut)
83 gestureOut.screen.position += mLastEventGesture.screen.position;
84 gestureOut.local.position += mLastEventGesture.local.position;
85 gestureOut.screen.position *= 0.5f;
86 gestureOut.local.position *= 0.5f;
87 // make current displacement relative to previous update-frame now.
88 gestureOut.screen.displacement = gestureOut.screen.position - mLastEventGesture.screen.position;
89 gestureOut.local.displacement = gestureOut.local.position - mLastEventGesture.local.position;
94 void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
96 RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
97 size_t panHistorySize = panHistory.size();
98 if( panHistorySize == 0 )
100 // cant do any prediction without a history
104 PanInfoHistoryConstIter endIter = panHistory.end();
105 PanInfoHistoryIter iter = panHistory.begin();
106 Vector2 screenVelocity = gestureOut.screen.velocity;
107 Vector2 localVelocity = gestureOut.local.velocity;
109 bool havePreviousAcceleration = false;
110 bool previousVelocity = false;
111 float previousAccel = 0.0f;
112 unsigned int lastTime;
113 while( iter != endIter )
115 PanInfo currentGesture = *iter;
116 if( !previousVelocity )
118 // not yet set a previous velocity
119 screenVelocity = currentGesture.screen.velocity;
120 previousVelocity = true;
121 lastTime = currentGesture.time;
125 float velMag = currentGesture.screen.velocity.Length();
126 float velDiff = velMag - screenVelocity.Length();
127 float acceleration = 0.0f;
128 float time = (float)(currentGesture.time - lastTime);
129 if( time > Math::MACHINE_EPSILON_1 )
131 acceleration = velDiff / time;
133 float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
134 float newVelMag = 0.0f;
135 if( !havePreviousAcceleration )
137 newVelMag = velMag + (acceleration * interpolationTime);
138 havePreviousAcceleration = true;
142 newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime);
145 if( velMag > Math::MACHINE_EPSILON_1 )
147 velMod = newVelMag / velMag;
149 gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
150 gestureOut.local.velocity = currentGesture.local.velocity * velMod;
151 screenVelocity = currentGesture.screen.velocity;
152 localVelocity = currentGesture.local.velocity;
153 previousAccel = acceleration;
156 // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
157 // add interpolated distance and position to current
158 float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time);
159 // work out interpolated velocity
160 gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime);
161 gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime);
162 gestureOut.screen.position += gestureOut.screen.displacement;
163 gestureOut.local.position += gestureOut.local.displacement;
164 gestureOut.time += (lastVSyncTime - gestureOut.time);
167 void PanGesture::PredictiveAlgorithm2(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
169 // TODO - adapt PredictiveAlgorithm1 with better smoothing, still under development
170 RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 0);
171 size_t panHistorySize = panHistory.size();
172 if( panHistorySize == 0 )
174 // cant do any prediction without a history
178 PanInfoHistoryConstIter endIter = panHistory.end();
179 PanInfoHistoryIter iter = panHistory.begin();
180 Vector2 screenVelocity = gestureOut.screen.velocity;
181 Vector2 localVelocity = gestureOut.local.velocity;
183 bool havePreviousAcceleration = false;
184 bool previousVelocity = false;
185 float previousAccel = 0.0f;
186 unsigned int lastTime;
187 while( iter != endIter )
189 PanInfo currentGesture = *iter;
190 if( !previousVelocity )
192 // not yet set a previous velocity
193 screenVelocity = currentGesture.screen.velocity;
194 previousVelocity = true;
195 lastTime = currentGesture.time;
199 float previousValueWeight = (float)(MAX_GESTURE_AGE - (lastVSyncTime - lastTime)) / (float)MAX_GESTURE_AGE;
200 float velMag = currentGesture.screen.velocity.Length();
201 float velDiff = velMag - screenVelocity.Length();
202 float acceleration = 0.0f;
203 float time = (float)(currentGesture.time - lastTime);
204 if( time > Math::MACHINE_EPSILON_1 )
206 acceleration = velDiff / time;
208 float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
209 float newVelMag = 0.0f;
210 if( !havePreviousAcceleration )
212 newVelMag = velMag + (acceleration * interpolationTime);
213 havePreviousAcceleration = true;
217 newVelMag = velMag + (((acceleration * (1.0f - previousValueWeight)) + (previousAccel * previousValueWeight)) * interpolationTime);
220 if( velMag > Math::MACHINE_EPSILON_1 )
222 velMod = newVelMag / velMag;
224 gestureOut.screen.velocity = currentGesture.screen.velocity * velMod;
225 gestureOut.local.velocity = currentGesture.local.velocity * velMod;
226 screenVelocity = currentGesture.screen.velocity;
227 localVelocity = currentGesture.local.velocity;
228 previousAccel = acceleration;
231 // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
232 // add interpolated distance and position to current
233 unsigned int timeAdvance = ((nextVSyncTime - lastVSyncTime) * mPredictionAmount);
234 unsigned int interpolationTime = (lastVSyncTime + timeAdvance) - gestureOut.time;
235 // work out interpolated velocity
236 gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime);
237 gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime);
238 gestureOut.screen.position += gestureOut.screen.displacement;
239 gestureOut.local.position += gestureOut.local.displacement;
240 gestureOut.time += interpolationTime;
243 bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime )
245 bool propertiesUpdated( false );
249 // clear current pan history
253 // create an event for this frame
254 bool justStarted ( false );
255 bool justFinished ( false );
256 bool eventFound( false );
258 // Not going through array from the beginning, using it as a circular buffer and only using unread
260 int eventsThisFrame = 0;
262 // create PanInfo to pass into prediction method
263 PanInfo nextGesture = mEventGesture;
264 // add new gestures and work out one full gesture for the frame
265 while(mReadPosition != mWritePosition)
267 // Copy the gesture first
268 PanInfo currentGesture(mGestures[mReadPosition]);
272 mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position ) );
274 nextGesture.local.position = currentGesture.local.position;
275 nextGesture.local.velocity = currentGesture.local.velocity;
276 nextGesture.screen.position = currentGesture.screen.position;
277 nextGesture.screen.velocity = currentGesture.screen.velocity;
280 nextGesture.local.displacement = currentGesture.local.displacement;
281 nextGesture.screen.displacement = currentGesture.screen.displacement;
285 nextGesture.local.displacement += currentGesture.local.displacement;
286 nextGesture.screen.displacement += currentGesture.screen.displacement;
289 nextGesture.time = currentGesture.time;
291 // add event to history
292 mPanHistory.push_back(currentGesture);
293 justStarted |= (currentGesture.state == Gesture::Started);
294 if( currentGesture.state == Gesture::Started )
297 // clear just finished as we have started new pan
298 justFinished = false;
300 justFinished |= (currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled);
302 // Update our read position.
305 mReadPosition %= PAN_GESTURE_HISTORY;
307 // set nextGesture to last gesture so it's position is correct and velocity is same as last frame
308 mEventGesture = nextGesture;
310 mInGesture |= justStarted;
312 bool updateProperties = false;
318 mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, mEventGesture.screen.position ) );
321 switch( mPredictionMode )
325 updateProperties = eventFound;
330 SimpleAverageAlgorithm(justStarted, nextGesture);
331 // make latest gesture equal to current gesture after averaging
332 updateProperties = true;
337 // make latest gesture equal to current gesture before interpolation
338 PredictiveAlgorithm1(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
339 updateProperties = true;
344 // make latest gesture equal to current gesture before interpolation
345 PredictiveAlgorithm2(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
346 updateProperties = true;
351 // always keep latest gesture up to date with event gesture
352 mLatestGesture = nextGesture;
354 if( updateProperties )
356 // only update properties if event received
357 // set latest gesture to raw pan info with unchanged time
358 mPanning.Set( mInGesture & !justFinished );
359 mScreenPosition.Set( nextGesture.screen.position );
360 mScreenDisplacement.Set( nextGesture.screen.displacement );
361 mLocalPosition.Set( nextGesture.local.position );
362 mLocalDisplacement.Set( nextGesture.local.displacement );
364 propertiesUpdated = true;
369 mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( nextGesture.time, nextGesture.screen.position ) );
372 mLastEventGesture = mEventGesture;
374 mInGesture &= ~justFinished;
376 if( mProfiling && justFinished )
378 mProfiling->PrintData();
379 mProfiling->ClearData();
382 return propertiesUpdated;
385 const GesturePropertyBool& PanGesture::GetPanningProperty() const
390 const GesturePropertyVector2& PanGesture::GetScreenPositionProperty() const
392 return mScreenPosition;
395 const GesturePropertyVector2& PanGesture::GetScreenDisplacementProperty() const
397 return mScreenDisplacement;
400 const GesturePropertyVector2& PanGesture::GetLocalPositionProperty() const
402 return mLocalPosition;
405 const GesturePropertyVector2& PanGesture::GetLocalDisplacementProperty() const
407 return mLocalDisplacement;
410 void PanGesture::SetPredictionMode(PredictionMode mode)
412 mPredictionMode = mode;
415 void PanGesture::SetPredictionAmount(float amount)
417 mPredictionAmount = amount;
420 void PanGesture::EnableProfiling()
424 mProfiling = new PanGestureProfiling();
428 void PanGesture::ResetDefaultProperties( BufferIndex updateBufferIndex )
430 mScreenPosition.Reset();
431 mScreenDisplacement.Reset();
432 mLocalPosition.Reset();
433 mLocalDisplacement.Reset();
437 PanGesture::PanGesture()
442 mPredictionMode(DEFAULT_PREDICTION_MODE),
443 mPredictionAmount(DEFAULT_PREDICTION_INTERPOLATION),
448 } // namespace SceneGraph
450 } // namespace Internal