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 unsigned int UPDATES_BETWEEN_PRINT( 120u );
37 unsigned int UPDATE_COUNT( 0u );
38 const int MAX_GESTURE_AGE = 100; ///< maximum age of a gesture before disallowing its use in algorithm
39 } // unnamed namespace
41 const PanGesture::PredictionMode PanGesture::DEFAULT_PREDICTION_MODE = PanGesture::AVERAGE;
42 const int PanGesture::NUM_PREDICTION_MODES = PanGesture::PREDICTION_2 + 1;
44 PanGesture* PanGesture::New()
46 return new PanGesture();
49 PanGesture::~PanGesture()
54 void PanGesture::AddGesture( const Dali::PanGesture& gesture )
56 mGestures[ mWritePosition ] = gesture;
58 // Update our write position.
60 mWritePosition %= PAN_GESTURE_HISTORY;
63 void PanGesture::RemoveOldHistory(PanInfoHistory& panHistory, uint currentTime, uint maxAge, uint minEvents)
65 PanInfoHistoryConstIter endIter = panHistory.end();
66 PanInfoHistoryIter iter = panHistory.begin();
67 while( iter != endIter && panHistory.size() > minEvents)
69 PanInfo currentGesture = *iter;
70 if( currentTime < currentGesture.time + maxAge )
74 panHistory.erase(iter);
75 endIter = panHistory.end();
79 void PanGesture::SimpleAverageAlgorithm(bool justStarted, PanInfo& gestureOut)
85 gestureOut.screen.position += mLatestGesture.screen.position;
86 gestureOut.local.position += mLatestGesture.local.position;
87 gestureOut.screen.position *= 0.5f;
88 gestureOut.local.position *= 0.5f;
89 // make current displacement relative to previous update-frame now.
90 gestureOut.screen.displacement -= mLatestGesture.screen.displacement;
91 gestureOut.local.displacement -= mLatestGesture.local.displacement;
96 void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
98 RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 1);
99 size_t panHistorySize = panHistory.size();
101 PanInfoHistoryConstIter endIter = panHistory.end();
102 PanInfoHistoryIter iter = panHistory.end() - (panHistorySize > 2 ? 2 : panHistorySize);
103 if( panHistorySize >= 2 )
105 // create average velocity and acceleration
106 // gestureOut is the combination of gesture events from this frame
107 PanInfo lastGesture = *iter;
109 float previousAccel = 0.0f;
110 while( iter != endIter )
112 PanInfo currentGesture = *iter;
113 lastGesture = *(iter - 1);
114 float velMag = currentGesture.screen.velocity.Length();
115 float velDiff = velMag - lastGesture.screen.velocity.Length();
116 float acceleration = 0.0f;
117 float time = (float)(currentGesture.time - lastGesture.time);
118 if( time >= Math::MACHINE_EPSILON_1 )
120 acceleration = velDiff / time;
122 float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
123 float newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime);
125 if( velMag > Math::MACHINE_EPSILON_1 )
127 velMod = newVelMag / velMag;
129 gestureOut.screen.velocity *= velMod;
130 gestureOut.local.velocity *= velMod;
132 previousAccel = acceleration;
136 // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
137 // add interpolated distance and position to current
138 float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time);
139 // work out interpolated velocity
140 gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime);
141 gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime);
142 gestureOut.screen.position += gestureOut.screen.displacement;
143 gestureOut.local.position += gestureOut.local.displacement;
144 gestureOut.time += interpolationTime;
147 void PanGesture::PredictiveAlgorithm2(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime)
149 // TODO - adapt PredictiveAlgorithm1 with better smoothing, still under development
150 RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 1);
151 size_t panHistorySize = panHistory.size();
153 PanInfoHistoryConstIter endIter = panHistory.end();
154 PanInfoHistoryIter iter = panHistory.end() - (panHistorySize > 2 ? 2 : panHistorySize);
155 if( panHistorySize >= 2 )
157 // create average velocity and acceleration
158 // gestureOut is the combination of gesture events from this frame
159 PanInfo lastGesture = *iter;
161 float previousAccel = 0.0f;
162 while( iter != endIter )
164 PanInfo currentGesture = *iter;
165 lastGesture = *(iter - 1);
166 float velMag = currentGesture.screen.velocity.Length();
167 float velDiff = velMag - lastGesture.screen.velocity.Length();
168 float acceleration = 0.0f;
169 float time = (float)(currentGesture.time - lastGesture.time);
170 if( time >= Math::MACHINE_EPSILON_1 )
172 acceleration = velDiff / time;
174 float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time);
175 float newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime);
177 if( velMag > Math::MACHINE_EPSILON_1 )
179 velMod = newVelMag / velMag;
181 gestureOut.screen.velocity *= velMod;
182 gestureOut.local.velocity *= velMod;
184 previousAccel = acceleration;
188 // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement
189 // add interpolated distance and position to current
190 float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time);
191 // work out interpolated velocity
192 gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime);
193 gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime);
194 gestureOut.screen.position += gestureOut.screen.displacement;
195 gestureOut.local.position += gestureOut.local.displacement;
196 gestureOut.time += interpolationTime;
199 bool PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime )
201 bool propertiesUpdated( false );
205 // clear current pan history
209 // create an event for this frame
210 bool justStarted ( false );
211 bool justFinished ( false );
212 bool eventFound( false );
214 // Not going through array from the beginning, using it as a circular buffer and only using unread
216 int eventsThisFrame = 0;
217 // set nextGesture to last gesture so it's position is correct and velocity is same as last frame
218 mEventGesture = mLatestGesture;
219 // add new gestures and work out one full gesture for the frame
220 while(mReadPosition != mWritePosition)
222 // Copy the gesture first
223 PanInfo currentGesture(mGestures[mReadPosition]);
227 mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position ) );
230 if ( currentGesture.time < mEventGesture.time )
235 mEventGesture.local.position = currentGesture.local.position;
236 mEventGesture.local.velocity = currentGesture.local.velocity;
237 mEventGesture.screen.position = currentGesture.screen.position;
238 mEventGesture.screen.velocity = currentGesture.screen.velocity;
241 mEventGesture.local.displacement = currentGesture.local.displacement;
242 mEventGesture.screen.displacement = currentGesture.screen.displacement;
247 mEventGesture.local.displacement += currentGesture.local.displacement;
248 mEventGesture.screen.displacement += currentGesture.screen.displacement;
250 mEventGesture.time = currentGesture.time;
252 // add event to history
253 mPanHistory.push_back(currentGesture);
254 justStarted |= (currentGesture.state == Gesture::Started);
255 if( currentGesture.state == Gesture::Started )
258 // clear just finished as we have started new pan
259 justFinished = false;
261 justFinished |= (currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled);
263 // Update our read position.
266 mReadPosition %= PAN_GESTURE_HISTORY;
269 // create PanInfo to pass into prediction method
270 PanInfo nextGesture(mEventGesture);
272 mInGesture |= justStarted;
274 bool updateProperties = false;
280 mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, mLatestGesture.screen.position ) );
283 switch( mPredictionMode )
287 updateProperties = eventFound;
288 // no prediction, just using latest event info
289 mLatestGesture = mEventGesture;
294 SimpleAverageAlgorithm(justStarted, nextGesture);
295 // make latest gesture equal to current gesture after averaging
296 updateProperties = true;
301 // make latest gesture equal to current gesture before interpolation
302 mLatestGesture = nextGesture;
303 PredictiveAlgorithm1(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
304 updateProperties = true;
309 // make latest gesture equal to current gesture before interpolation
310 mLatestGesture = nextGesture;
311 PredictiveAlgorithm2(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime);
312 updateProperties = true;
317 // always keep latest gesture up to date with event gesture
318 mLatestGesture = mEventGesture;
320 if( updateProperties )
322 // only update properties if event received
323 // set latest gesture to raw pan info with unchanged time
324 mScreenPosition.Set( nextGesture.screen.position );
325 mScreenDisplacement.Set( nextGesture.screen.displacement );
326 mLocalPosition.Set( nextGesture.local.position );
327 mLocalDisplacement.Set( nextGesture.local.displacement );
329 propertiesUpdated = true;
334 mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( nextGesture.time, nextGesture.screen.position ) );
338 mInGesture &= ~justFinished;
341 UPDATE_COUNT++ >= UPDATES_BETWEEN_PRINT )
343 mProfiling->PrintData();
344 mProfiling->ClearData();
348 return propertiesUpdated;
351 const GesturePropertyVector2& PanGesture::GetScreenPositionProperty() const
353 return mScreenPosition;
356 const GesturePropertyVector2& PanGesture::GetScreenDisplacementProperty() const
358 return mScreenDisplacement;
361 const GesturePropertyVector2& PanGesture::GetLocalPositionProperty() const
363 return mLocalPosition;
366 const GesturePropertyVector2& PanGesture::GetLocalDisplacementProperty() const
368 return mLocalDisplacement;
371 void PanGesture::EnableProfiling()
375 mProfiling = new PanGestureProfiling();
379 void PanGesture::ResetDefaultProperties( BufferIndex updateBufferIndex )
381 mScreenPosition.Reset();
382 mScreenDisplacement.Reset();
383 mLocalPosition.Reset();
384 mLocalDisplacement.Reset();
387 PanGesture::PanGesture()
392 mPredictionMode(DEFAULT_PREDICTION_MODE),
397 } // namespace SceneGraph
399 } // namespace Internal