From: Julien Heanley Date: Fri, 4 Apr 2014 10:24:37 +0000 (+0100) Subject: (PanGesture) Added environment variable "PAN_PREDICTION_MODE" for selecting gesture... X-Git-Tag: dali-2014-wk20-release~35 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F56%2F19956%2F1;p=platform%2Fcore%2Fuifw%2Fdali-core.git (PanGesture) Added environment variable "PAN_PREDICTION_MODE" for selecting gesture algorithm Change-Id: I726d7567c67f7ecdec18c102d788d932500d1b43 Signed-off-by: Andrew Cox --- diff --git a/dali/integration-api/profiling.cpp b/dali/integration-api/profiling.cpp index 5642215..3ee01c5 100644 --- a/dali/integration-api/profiling.cpp +++ b/dali/integration-api/profiling.cpp @@ -49,6 +49,12 @@ void EnableProfiling( ProfilingType type ) } } +void SetPanGesturePredictionMode( int mode ) +{ + GestureEventProcessor& eventProcessor = ThreadLocalStorage::Get().GetGestureEventProcessor(); + eventProcessor.SetPanGesturePredictionMode(mode); +} + } // namespace Integration } // namespace Dali diff --git a/dali/integration-api/profiling.h b/dali/integration-api/profiling.h index e63adeb..3bd3d94 100644 --- a/dali/integration-api/profiling.h +++ b/dali/integration-api/profiling.h @@ -43,6 +43,15 @@ enum ProfilingType */ DALI_IMPORT_API void EnableProfiling( ProfilingType type ); +/** + * @brief Called by adaptor to set the pan gesture prediction mode from + * an environment variable + * + * @pre Should be called after Core creation. + * @param mode The pan gesture prediction mode. + */ +DALI_IMPORT_API void SetPanGesturePredictionMode( int mode ); + } // namespace Integration } // namespace Dali diff --git a/dali/internal/event/events/gesture-event-processor.cpp b/dali/internal/event/events/gesture-event-processor.cpp index 1b6c4c6..4b1f4c5 100644 --- a/dali/internal/event/events/gesture-event-processor.cpp +++ b/dali/internal/event/events/gesture-event-processor.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include namespace Dali @@ -228,6 +229,11 @@ void GestureEventProcessor::EnablePanGestureProfiling() mPanGestureProcessor.EnableProfiling(); } +void GestureEventProcessor::SetPanGesturePredictionMode(int mode) +{ + mPanGestureProcessor.SetPredictionMode(mode); +} + } // namespace Internal } // namespace Dali diff --git a/dali/internal/event/events/gesture-event-processor.h b/dali/internal/event/events/gesture-event-processor.h index 1ba7fa4..4b944cb 100644 --- a/dali/internal/event/events/gesture-event-processor.h +++ b/dali/internal/event/events/gesture-event-processor.h @@ -121,6 +121,13 @@ public: // Called by Core */ void EnablePanGestureProfiling(); + /** + * @brief Called to set how pan gestures predict and smooth input + * + * @param[in] mode The prediction mode to use + */ + void SetPanGesturePredictionMode( int mode ); + private: // Undefined diff --git a/dali/internal/event/events/pan-gesture-processor.cpp b/dali/internal/event/events/pan-gesture-processor.cpp index 6995854..1644f7b 100644 --- a/dali/internal/event/events/pan-gesture-processor.cpp +++ b/dali/internal/event/events/pan-gesture-processor.cpp @@ -422,6 +422,17 @@ void PanGestureProcessor::EnableProfiling() mSceneObject->EnableProfiling(); } +void PanGestureProcessor::SetPredictionMode(int mode) +{ + if( (mode < 0) + || (mode >= SceneGraph::PanGesture::NUM_PREDICTION_MODES) ) + { + mode = SceneGraph::PanGesture::DEFAULT_PREDICTION_MODE; + } + SceneGraph::PanGesture::PredictionMode modeEnum = static_cast(mode); + mSceneObject->SetPredictionMode(modeEnum); +} + void PanGestureProcessor::UpdateDetection() { DALI_ASSERT_DEBUG(!mGestureDetectors.empty()); diff --git a/dali/internal/event/events/pan-gesture-processor.h b/dali/internal/event/events/pan-gesture-processor.h index ddbbdab..a75362d 100644 --- a/dali/internal/event/events/pan-gesture-processor.h +++ b/dali/internal/event/events/pan-gesture-processor.h @@ -112,6 +112,19 @@ public: // To be called by GestureEventProcessor */ void EnableProfiling(); + /** + * Called to set the prediction mode for pan gestures + * + * @param[in] mode The prediction mode + * + * Valid modes: + * 0 - No prediction + * 1 - Average Smoothing (no actual prediction) + * 2 - Interpolation using last vsync time and event time + * 3 - Same as 2 for now, in progress + */ + void SetPredictionMode(int mode); + private: // Undefined diff --git a/dali/internal/update/gestures/scene-graph-pan-gesture.cpp b/dali/internal/update/gestures/scene-graph-pan-gesture.cpp index 5de7928..1b9c71f 100644 --- a/dali/internal/update/gestures/scene-graph-pan-gesture.cpp +++ b/dali/internal/update/gestures/scene-graph-pan-gesture.cpp @@ -30,17 +30,16 @@ namespace Internal namespace SceneGraph { - namespace { - -const unsigned int ARRAY_SIZE( 4u ); - const unsigned int UPDATES_BETWEEN_PRINT( 120u ); unsigned int UPDATE_COUNT( 0u ); - +const int MAX_GESTURE_AGE = 100; ///< maximum age of a gesture before disallowing its use in algorithm } // unnamed namespace +const PanGesture::PredictionMode PanGesture::DEFAULT_PREDICTION_MODE = PanGesture::AVERAGE; +const int PanGesture::NUM_PREDICTION_MODES = PanGesture::PREDICTION_2 + 1; + PanGesture* PanGesture::New() { return new PanGesture(); @@ -55,91 +54,280 @@ void PanGesture::AddGesture( const Dali::PanGesture& gesture ) { mGestures[ mWritePosition ] = gesture; - // Update our write position (so now this new value can be read) - // Note: we want to overwrite oldest gesture information even if it hasn't been read. + // Update our write position. ++mWritePosition; - mWritePosition %= ARRAY_SIZE; + mWritePosition %= PAN_GESTURE_HISTORY; +} + +void PanGesture::RemoveOldHistory(PanInfoHistory& panHistory, uint currentTime, uint maxAge, uint minEvents) +{ + PanInfoHistoryConstIter endIter = panHistory.end(); + PanInfoHistoryIter iter = panHistory.begin(); + while( iter != endIter && panHistory.size() > minEvents) + { + PanInfo currentGesture = *iter; + if( currentTime < currentGesture.time + maxAge ) + { + break; + } + panHistory.erase(iter); + endIter = panHistory.end(); + } +} + +void PanGesture::SimpleAverageAlgorithm(bool justStarted, PanInfo& gestureOut) +{ + if( mInGesture ) + { + if( !justStarted ) + { + gestureOut.screen.position += mLatestGesture.screen.position; + gestureOut.local.position += mLatestGesture.local.position; + gestureOut.screen.position *= 0.5f; + gestureOut.local.position *= 0.5f; + // make current displacement relative to previous update-frame now. + gestureOut.screen.displacement -= mLatestGesture.screen.displacement; + gestureOut.local.displacement -= mLatestGesture.local.displacement; + } + } +} + +void PanGesture::PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime) +{ + RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 1); + size_t panHistorySize = panHistory.size(); + + PanInfoHistoryConstIter endIter = panHistory.end(); + PanInfoHistoryIter iter = panHistory.end() - (panHistorySize > 2 ? 2 : panHistorySize); + if( panHistorySize >= 2 ) + { + // create average velocity and acceleration + // gestureOut is the combination of gesture events from this frame + PanInfo lastGesture = *iter; + ++iter; + float previousAccel = 0.0f; + while( iter != endIter ) + { + PanInfo currentGesture = *iter; + lastGesture = *(iter - 1); + float velMag = currentGesture.screen.velocity.Length(); + float velDiff = velMag - lastGesture.screen.velocity.Length(); + float acceleration = 0.0f; + float time = (float)(currentGesture.time - lastGesture.time); + if( time >= Math::MACHINE_EPSILON_1 ) + { + acceleration = velDiff / time; + } + float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time); + float newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime); + float velMod = 1.0f; + if( velMag > Math::MACHINE_EPSILON_1 ) + { + velMod = newVelMag / velMag; + } + gestureOut.screen.velocity *= velMod; + gestureOut.local.velocity *= velMod; + lastGesture = *iter; + previousAccel = acceleration; + ++iter; + } + } + // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement + // add interpolated distance and position to current + float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time); + // work out interpolated velocity + gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime); + gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime); + gestureOut.screen.position += gestureOut.screen.displacement; + gestureOut.local.position += gestureOut.local.displacement; + gestureOut.time += interpolationTime; +} + +void PanGesture::PredictiveAlgorithm2(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime) +{ + // TODO - adapt PredictiveAlgorithm1 with better smoothing, still under development + RemoveOldHistory(panHistory, lastVSyncTime, MAX_GESTURE_AGE, 1); + size_t panHistorySize = panHistory.size(); + + PanInfoHistoryConstIter endIter = panHistory.end(); + PanInfoHistoryIter iter = panHistory.end() - (panHistorySize > 2 ? 2 : panHistorySize); + if( panHistorySize >= 2 ) + { + // create average velocity and acceleration + // gestureOut is the combination of gesture events from this frame + PanInfo lastGesture = *iter; + ++iter; + float previousAccel = 0.0f; + while( iter != endIter ) + { + PanInfo currentGesture = *iter; + lastGesture = *(iter - 1); + float velMag = currentGesture.screen.velocity.Length(); + float velDiff = velMag - lastGesture.screen.velocity.Length(); + float acceleration = 0.0f; + float time = (float)(currentGesture.time - lastGesture.time); + if( time >= Math::MACHINE_EPSILON_1 ) + { + acceleration = velDiff / time; + } + float interpolationTime = (float)((int)lastVSyncTime - (int)currentGesture.time); + float newVelMag = velMag + (((acceleration + previousAccel) * 0.5f) * interpolationTime); + float velMod = 1.0f; + if( velMag > Math::MACHINE_EPSILON_1 ) + { + velMod = newVelMag / velMag; + } + gestureOut.screen.velocity *= velMod; + gestureOut.local.velocity *= velMod; + lastGesture = *iter; + previousAccel = acceleration; + ++iter; + } + } + // gestureOut's position is currently equal to the last event's position and its displacement is equal to last frame's total displacement + // add interpolated distance and position to current + float interpolationTime = (float)((int)lastVSyncTime - (int)gestureOut.time); + // work out interpolated velocity + gestureOut.screen.displacement = (gestureOut.screen.velocity * interpolationTime); + gestureOut.local.displacement = (gestureOut.local.velocity * interpolationTime); + gestureOut.screen.position += gestureOut.screen.displacement; + gestureOut.local.position += gestureOut.local.displacement; + gestureOut.time += interpolationTime; } void PanGesture::UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime ) { - unsigned int time( 0u ); + if( !mInGesture ) + { + // clear current pan history + mPanHistory.clear(); + } + + // create an event for this frame bool justStarted ( false ); bool justFinished ( false ); - - // If our read position is not same as write position, then there - // must be new values on circular buffer to read. + bool eventFound( false ); + + // Not going through array from the beginning, using it as a circular buffer and only using unread + // values. + int eventsThisFrame = 0; + // set nextGesture to last gesture so it's position is correct and velocity is same as last frame + mEventGesture = mLatestGesture; + // add new gestures and work out one full gesture for the frame while(mReadPosition != mWritePosition) { - const PanInfo& currentGesture = mGestures[mReadPosition]; + // Copy the gesture first + PanInfo currentGesture(mGestures[mReadPosition]); if( mProfiling ) { mProfiling->mRawData.push_back( PanGestureProfiling::Position( currentGesture.time, currentGesture.screen.position ) ); } - if ( currentGesture.time > time ) + if ( currentGesture.time < mEventGesture.time ) { - justStarted |= (currentGesture.state == Gesture::Started); - justFinished |= (currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled); - - // use position values direct from gesture. - mLatestGesture.screen.position = currentGesture.screen.position; - mLatestGesture.local.position = currentGesture.local.position; + break; + } - // change displacement to be relative to initial touch, instead of relative to last touch-frame. - if(currentGesture.state == Gesture::Started) - { - mLatestGesture.screen.displacement = currentGesture.screen.displacement; - mLatestGesture.local.displacement = currentGesture.local.displacement; - } - else - { - mLatestGesture.screen.displacement += currentGesture.screen.displacement; - mLatestGesture.local.displacement += currentGesture.local.displacement; - } + mEventGesture.local.position = currentGesture.local.position; + mEventGesture.local.velocity = currentGesture.local.velocity; + mEventGesture.screen.position = currentGesture.screen.position; + mEventGesture.screen.velocity = currentGesture.screen.velocity; + if( !eventFound ) + { + mEventGesture.local.displacement = currentGesture.local.displacement; + mEventGesture.screen.displacement = currentGesture.screen.displacement; + eventFound = true; + } + else + { + mEventGesture.local.displacement += currentGesture.local.displacement; + mEventGesture.screen.displacement += currentGesture.screen.displacement; + } + mEventGesture.time = currentGesture.time; - time = currentGesture.time; + // add event to history + mPanHistory.push_back(currentGesture); + justStarted |= (currentGesture.state == Gesture::Started); + if( currentGesture.state == Gesture::Started ) + { + justStarted = true; + // clear just finished as we have started new pan + justFinished = false; } + justFinished |= (currentGesture.state == Gesture::Finished || currentGesture.state == Gesture::Cancelled); + // Update our read position. ++mReadPosition; - mReadPosition %= ARRAY_SIZE; + ++eventsThisFrame; + mReadPosition %= PAN_GESTURE_HISTORY; } + // create PanInfo to pass into prediction method + PanInfo nextGesture(mEventGesture); + mInGesture |= justStarted; + bool updateProperties = false; + if ( mInGesture ) { - PanInfo gesture(mLatestGesture); - if( mProfiling ) { - mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, gesture.screen.position ) ); + mProfiling->mLatestData.push_back( PanGestureProfiling::Position( lastVSyncTime, mLatestGesture.screen.position ) ); } - if( !justStarted ) // only use previous frame if this is the continuing. + switch( mPredictionMode ) { - // If previous gesture exists, then produce position as 50/50 interpolated blend of these two points. - gesture.screen.position += mPreviousGesture.screen.position; - gesture.local.position += mPreviousGesture.local.position; - gesture.screen.position *= 0.5f; - gesture.local.position *= 0.5f; - // make current displacement relative to previous update-frame now. - gesture.screen.displacement -= mPreviousGesture.screen.displacement; - gesture.local.displacement -= mPreviousGesture.local.displacement; + case NONE: + { + updateProperties = eventFound; + // no prediction, just using latest event info + mLatestGesture = mEventGesture; + break; + } + case AVERAGE: + { + SimpleAverageAlgorithm(justStarted, nextGesture); + // make latest gesture equal to current gesture after averaging + updateProperties = true; + break; + } + case PREDICTION_1: + { + // make latest gesture equal to current gesture before interpolation + mLatestGesture = nextGesture; + PredictiveAlgorithm1(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime); + updateProperties = true; + break; + } + case PREDICTION_2: + { + // make latest gesture equal to current gesture before interpolation + mLatestGesture = nextGesture; + PredictiveAlgorithm2(eventsThisFrame, nextGesture, mPanHistory, lastVSyncTime, nextVSyncTime); + updateProperties = true; + break; + } } - if( mProfiling ) + // always keep latest gesture up to date with event gesture + mLatestGesture = mEventGesture; + + if( updateProperties ) { - mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( lastVSyncTime, gesture.screen.position ) ); + // only update properties if event received + // set latest gesture to raw pan info with unchanged time + mScreenPosition.Set( nextGesture.screen.position ); + mScreenDisplacement.Set( nextGesture.screen.displacement ); + mLocalPosition.Set( nextGesture.local.position ); + mLocalDisplacement.Set( nextGesture.local.displacement ); } - mPreviousGesture = mLatestGesture; - - mScreenPosition.Set( gesture.screen.position ); - mScreenDisplacement.Set( gesture.screen.displacement ); - mLocalPosition.Set( gesture.local.position ); - mLocalDisplacement.Set( gesture.local.displacement ); + if( mProfiling ) + { + mProfiling->mAveragedData.push_back( PanGestureProfiling::Position( nextGesture.time, nextGesture.screen.position ) ); + } } mInGesture &= ~justFinished; @@ -194,6 +382,7 @@ PanGesture::PanGesture() mWritePosition( 0 ), mReadPosition( 0 ), mInGesture( false ), + mPredictionMode(DEFAULT_PREDICTION_MODE), mProfiling( NULL ) { } diff --git a/dali/internal/update/gestures/scene-graph-pan-gesture.h b/dali/internal/update/gestures/scene-graph-pan-gesture.h index b32e2f0..1d0d6a0 100644 --- a/dali/internal/update/gestures/scene-graph-pan-gesture.h +++ b/dali/internal/update/gestures/scene-graph-pan-gesture.h @@ -43,81 +43,16 @@ class PanGesture : public PropertyOwner { public: - /** - * Create a new PanGesture - */ - static PanGesture* New(); - - /** - * Virtual destructor - */ - virtual ~PanGesture(); - - /** - * Adds a PanGesture to the internal circular-buffer waiting to be handled by UpdateProperties. - * @param[in] gesture The latest pan gesture. - */ - void AddGesture( const Dali::PanGesture& gesture ); - - /** - * Called by the update manager so that we can update the value of our properties. - * @param[in] lastVSyncTime The last VSync time (in milliseconds). - * @param[in] nextVSyncTime The estimated time of the next VSync (in milliseconds). - */ - virtual void UpdateProperties( unsigned int lastVSyncTime, unsigned int nextVSyncTime ); - - /** - * Retrieves a reference to the screen position property. - * @return The screen position property. - */ - const GesturePropertyVector2& GetScreenPositionProperty() const; - - /** - * Retrieves a reference to the screen displacement property. - * @return The screen displacement property. - */ - const GesturePropertyVector2& GetScreenDisplacementProperty() const; - - /** - * Retrieves a reference to the local position property. - * @return The local position property. - */ - const GesturePropertyVector2& GetLocalPositionProperty() const; - - /** - * Retrieves a reference to the local displacement property. - * @return The local displacement property. - */ - const GesturePropertyVector2& GetLocalDisplacementProperty() const; - - /** - * Called to provide pan-gesture profiling information. - */ - void EnableProfiling(); - -private: - - /** - * Protected constructor. - */ - PanGesture(); - - // Undefined - PanGesture(const PanGesture&); - - // Undefined - PanGesture& operator=(const PanGesture&); - - // PropertyOwner - virtual void ResetDefaultProperties( BufferIndex updateBufferIndex ); + enum PredictionMode + { + NONE, + AVERAGE, + PREDICTION_1, + PREDICTION_2 + }; -private: - - // Properties - GesturePropertyVector2 mScreenPosition; ///< screen-position - GesturePropertyVector2 mScreenDisplacement; ///< screen-displacement - GesturePropertyVector2 mLocalPosition; ///< local-position - GesturePropertyVector2 mLocalDisplacement; ///< local-displacement + static const PredictionMode DEFAULT_PREDICTION_MODE; + static const int NUM_PREDICTION_MODES; // Latest Pan Information @@ -169,7 +104,8 @@ private: */ PanInfo() : time( 0u ), - state( Gesture::Clear ) + state( Gesture::Clear ), + read( true ) { } @@ -180,7 +116,8 @@ private: : time( rhs.time ), state( rhs.state ), local( rhs.local ), - screen( rhs.screen ) + screen( rhs.screen ), + read( true ) { } @@ -218,21 +155,141 @@ private: } // Data - unsigned int time; Gesture::State state; Info local; Info screen; + volatile bool read; }; - PanInfo mGestures[4]; ///< Circular buffer storing the 4 most recent gestures. + typedef std::vector PanInfoHistory; + typedef PanInfoHistory::iterator PanInfoHistoryIter; + typedef PanInfoHistory::const_iterator PanInfoHistoryConstIter; + +private: + static const unsigned int PAN_GESTURE_HISTORY = 4u; + +public: + + /** + * Create a new PanGesture + */ + static PanGesture* New(); + + /** + * Virtual destructor + */ + virtual ~PanGesture(); + + /** + * Adds a PanGesture to the internal circular-buffer waiting to be handled by UpdateProperties. + * @param[in] gesture The latest pan gesture. + */ + void AddGesture( const Dali::PanGesture& gesture ); + + /** + * @brief Removes pan events from the history that are older than maxAge, leaving at least minEvents + * + * @param[in] panHistory The pan event history container + * @param[in] currentTime The current frame time + * @param[in] maxAge Maximum age of an event before removing (in millis) + * @param[in] minEvents The minimum number of events to leave in history, oldest events are removed before newest + */ + void RemoveOldHistory(PanInfoHistory& panHistory, uint currentTime, uint maxAge, uint minEvents); + + /** + * USes last two gestures + * + * @param[out] gestureOut Output gesture using average values from last two gestures + */ + void SimpleAverageAlgorithm(bool justStarted, PanInfo& gestureOut); + + /** + * Uses elapsed time and time stamps + */ + void PredictiveAlgorithm1(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime); + + /** + * Uses elapsed time, time stamps and future render time + */ + void PredictiveAlgorithm2(int eventsThisFrame, PanInfo& gestureOut, PanInfoHistory& panHistory, unsigned int lastVSyncTime, unsigned int nextVSyncTime); + + /** + * Called by the update manager so that we can update the value of our properties. + * @param[in] nextRenderTime The estimated time of the next render (in milliseconds). + */ + virtual void UpdateProperties( unsigned int lastRenderTime, unsigned int nextRenderTime ); + + /** + * Retrieves a reference to the screen position property. + * @return The screen position property. + */ + const GesturePropertyVector2& GetScreenPositionProperty() const; + + /** + * Retrieves a reference to the screen displacement property. + * @return The screen displacement property. + */ + const GesturePropertyVector2& GetScreenDisplacementProperty() const; + + /** + * Retrieves a reference to the local position property. + * @return The local position property. + */ + const GesturePropertyVector2& GetLocalPositionProperty() const; + + /** + * Retrieves a reference to the local displacement property. + * @return The local displacement property. + */ + const GesturePropertyVector2& GetLocalDisplacementProperty() const; + + /** + * @brief Sets the prediction mode of the pan gesture + * + * @param[in] mode The prediction mode + */ + void SetPredictionMode(PredictionMode mode) { mPredictionMode = mode; } + + /** + * Called to provide pan-gesture profiling information. + */ + void EnableProfiling(); + +private: + + /** + * Protected constructor. + */ + PanGesture(); + + // Undefined + PanGesture(const PanGesture&); + + // Undefined + PanGesture& operator=(const PanGesture&); + + // PropertyOwner + virtual void ResetDefaultProperties( BufferIndex updateBufferIndex ); + +private: + + // Properties + GesturePropertyVector2 mScreenPosition; ///< screen-position + GesturePropertyVector2 mScreenDisplacement; ///< screen-displacement + GesturePropertyVector2 mLocalPosition; ///< local-position + GesturePropertyVector2 mLocalDisplacement; ///< local-displacement + + PanInfo mGestures[PAN_GESTURE_HISTORY]; ///< Circular buffer storing the 4 most recent gestures. + PanInfoHistory mPanHistory; unsigned int mWritePosition; ///< The next PanInfo buffer to write to. (starts at 0) unsigned int mReadPosition; ///< The next PanInfo buffer to read. (starts at 0) + PanInfo mEventGesture; ///< Result of all pan events received since last frame PanInfo mLatestGesture; ///< The latest gesture. (this update frame) - PanInfo mPreviousGesture; ///< The previous gesture. (one update frame ago) bool mInGesture; ///< True if the gesture is currently being handled i.e. between Started <-> Finished/Cancelled + PredictionMode mPredictionMode; ///< The pan gesture prediction mode PanGestureProfiling* mProfiling; ///< NULL unless pan-gesture profiling information is required. };