diff --git a/drape_frontend/animation/base_interpolator.cpp b/drape_frontend/animation/base_interpolator.cpp new file mode 100644 index 0000000000..8c2eaa8b6f --- /dev/null +++ b/drape_frontend/animation/base_interpolator.cpp @@ -0,0 +1,41 @@ +#include "drape_frontend/animation/base_interpolator.hpp" +#include "drape_frontend/animation/interpolation_holder.hpp" + +#include "base/assert.hpp" +#include "base/logging.hpp" + +namespace df +{ + +BaseInterpolator::BaseInterpolator(double duration) + : m_elapsedTime(0.0) + , m_duration(duration) +{ + ASSERT(m_duration > 0.0, ()); + InterpolationHolder::Instance().RegisterInterpolator(this); +} + +BaseInterpolator::~BaseInterpolator() +{ + InterpolationHolder::Instance().DeregisterInterpolator(this); +} + +bool BaseInterpolator::IsFinished() const +{ + return m_elapsedTime > m_duration; +} + +void BaseInterpolator::Advance(double elapsedSeconds) +{ + m_elapsedTime += elapsedSeconds; +} + +double BaseInterpolator::GetT() const +{ + if (IsFinished()) + return 1.0; + + return m_elapsedTime / m_duration; +} + +} diff --git a/drape_frontend/animation/base_interpolator.hpp b/drape_frontend/animation/base_interpolator.hpp new file mode 100644 index 0000000000..33a0dbf53a --- /dev/null +++ b/drape_frontend/animation/base_interpolator.hpp @@ -0,0 +1,23 @@ +#pragma once + +namespace df +{ + +class BaseInterpolator +{ +public: + BaseInterpolator(double duration); + virtual ~BaseInterpolator(); + + bool IsFinished() const; + void Advance(double elapsedSeconds); + +protected: + double GetT() const; + +private: + double m_elapsedTime; + double m_duration; +}; + +} diff --git a/drape_frontend/animation/base_viewport_animation.hpp b/drape_frontend/animation/base_viewport_animation.hpp new file mode 100644 index 0000000000..0e6f7f94d3 --- /dev/null +++ b/drape_frontend/animation/base_viewport_animation.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "drape_frontend/animation/base_interpolator.hpp" +#include "drape_frontend/navigator.hpp" + +namespace df +{ + +class BaseViewportAnimation : public BaseInterpolator +{ +public: + BaseViewportAnimation(double duration) : BaseInterpolator(duration) {} + virtual void Apply(Navigator & navigator) = 0; +}; + +} diff --git a/drape_frontend/animation/interpolation_holder.cpp b/drape_frontend/animation/interpolation_holder.cpp new file mode 100644 index 0000000000..95a8533ed0 --- /dev/null +++ b/drape_frontend/animation/interpolation_holder.cpp @@ -0,0 +1,49 @@ +#include "drape_frontend/animation/base_interpolator.hpp" +#include "drape_frontend/animation/interpolation_holder.hpp" + +#include "base/assert.hpp" + +#include "std/algorithm.hpp" +#include "std/bind.hpp" + +namespace df +{ + +InterpolationHolder & InterpolationHolder::Instance() +{ + static InterpolationHolder holder; + return holder; +} + +bool InterpolationHolder::Advance(double elapsedSeconds) +{ + bool hasAnimations = !m_interpolations.empty(); + TInterpolatorSet::iterator iter = m_interpolations.begin(); + while (iter != m_interpolations.end()) + { + (*iter)->Advance(elapsedSeconds); + if ((*iter)->IsFinished()) + iter = m_interpolations.erase(iter); + else + ++iter; + } + + return hasAnimations; +} + +InterpolationHolder::~InterpolationHolder() +{ + ASSERT(m_interpolations.empty(), ()); +} + +void InterpolationHolder::RegisterInterpolator(BaseInterpolator * interpolator) +{ + VERIFY(m_interpolations.insert(interpolator).second, ()); +} + +void InterpolationHolder::DeregisterInterpolator(BaseInterpolator * interpolator) +{ + m_interpolations.erase(interpolator); +} + +} diff --git a/drape_frontend/animation/interpolation_holder.hpp b/drape_frontend/animation/interpolation_holder.hpp new file mode 100644 index 0000000000..3cd0e3c372 --- /dev/null +++ b/drape_frontend/animation/interpolation_holder.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "base/macros.hpp" + +#include "std/set.hpp" + +namespace df +{ + +class BaseInterpolator; +class InterpolationHolder +{ +public: + static InterpolationHolder & Instance(); + bool Advance(double elapsedSeconds); + +private: + InterpolationHolder() = default; + ~InterpolationHolder(); + DISALLOW_COPY_AND_MOVE(InterpolationHolder) + +private: + friend class BaseInterpolator; + void RegisterInterpolator(BaseInterpolator * interpolator); + void DeregisterInterpolator(BaseInterpolator * interpolator); + + using TInterpolatorSet = set; + TInterpolatorSet m_interpolations; +}; + +} diff --git a/drape_frontend/animation/interpolations.cpp b/drape_frontend/animation/interpolations.cpp new file mode 100644 index 0000000000..ddef8de248 --- /dev/null +++ b/drape_frontend/animation/interpolations.cpp @@ -0,0 +1,12 @@ +#include "drape_frontend/animation/interpolations.hpp" + +namespace df +{ + +m2::PointD Interpolate(m2::PointD const & startPt, m2::PointD const & endPt, double t) +{ + m2::PointD diff = endPt - startPt; + return startPt + diff * t; +} + +} // namespace df diff --git a/drape_frontend/animation/interpolations.hpp b/drape_frontend/animation/interpolations.hpp new file mode 100644 index 0000000000..6f809043af --- /dev/null +++ b/drape_frontend/animation/interpolations.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "geometry/point2d.hpp" + +namespace df +{ + m2::PointD Interpolate(m2::PointD const & startPt, m2::PointD const & endPt, double t); +} // namespace df diff --git a/drape_frontend/animation/modelview_center_animation.cpp b/drape_frontend/animation/modelview_center_animation.cpp new file mode 100644 index 0000000000..b8a1c8c353 --- /dev/null +++ b/drape_frontend/animation/modelview_center_animation.cpp @@ -0,0 +1,22 @@ +#include "drape_frontend/animation/modelview_center_animation.hpp" +#include "drape_frontend/animation/interpolations.hpp" + +namespace df +{ + +ModelViewCenterAnimation::ModelViewCenterAnimation(m2::PointD const & start, + m2::PointD const & end, + double duration) + : BaseViewportAnimation(duration) + , m_startPt(start) + , m_endPt(end) +{ +} + +void ModelViewCenterAnimation::Apply(Navigator & navigator) +{ + m2::PointD center = Interpolate(m_startPt, m_endPt, GetT()); + navigator.CenterViewport(center); +} + +} diff --git a/drape_frontend/animation/modelview_center_animation.hpp b/drape_frontend/animation/modelview_center_animation.hpp new file mode 100644 index 0000000000..b9e6b32c23 --- /dev/null +++ b/drape_frontend/animation/modelview_center_animation.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "drape_frontend/animation/base_viewport_animation.hpp" + +namespace df +{ + +class ModelViewCenterAnimation : public BaseViewportAnimation +{ +public: + ModelViewCenterAnimation(m2::PointD const & start, m2::PointD const & end, double duration); + + void Apply(Navigator & navigator) override; + +private: + m2::PointD m_startPt; + m2::PointD m_endPt; +}; + +} diff --git a/drape_frontend/drape_frontend.pro b/drape_frontend/drape_frontend.pro index 55058614dd..f8c3cf092c 100755 --- a/drape_frontend/drape_frontend.pro +++ b/drape_frontend/drape_frontend.pro @@ -9,6 +9,10 @@ INCLUDEPATH *= $$ROOT_DIR/3party/protobuf/src DEFINES += DRAW_INFO SOURCES += \ + animation/base_interpolator.cpp \ + animation/modelview_center_animation.cpp \ + animation/interpolation_holder.cpp \ + animation/interpolations.cpp \ apply_feature_functors.cpp \ area_shape.cpp \ backend_renderer.cpp \ @@ -45,9 +49,14 @@ SOURCES += \ viewport.cpp \ visual_params.cpp \ my_position.cpp \ - user_event_stream.cpp + user_event_stream.cpp \ HEADERS += \ + animation/base_viewport_animation.hpp \ + animation/modelview_center_animation.hpp \ + animation/interpolation_holder.hpp \ + animation/interpolations.hpp \ + animation/base_interpolator.hpp \ apply_feature_functors.hpp \ area_shape.hpp \ backend_renderer.hpp \ @@ -89,4 +98,4 @@ HEADERS += \ viewport.hpp \ visual_params.hpp \ my_position.hpp \ - user_event_stream.hpp + user_event_stream.hpp \ diff --git a/drape_frontend/frontend_renderer.cpp b/drape_frontend/frontend_renderer.cpp index d45d7a2f26..d1ccf88856 100755 --- a/drape_frontend/frontend_renderer.cpp +++ b/drape_frontend/frontend_renderer.cpp @@ -1,3 +1,4 @@ +#include "drape_frontend/animation/interpolation_holder.hpp" #include "drape_frontend/frontend_renderer.hpp" #include "drape_frontend/message_subclasses.hpp" #include "drape_frontend/visual_params.hpp" @@ -457,6 +458,7 @@ void FrontendRenderer::Routine::Do() //double processingTime = InitAvarageTimePerMessage; // By init we think that one message processed by 1ms timer.Reset(); + double frameTime = 0.0; bool isInactiveLastFrame = false; bool viewChanged = true; ScreenBase modelView = m_renderer.UpdateScene(viewChanged); @@ -465,9 +467,10 @@ void FrontendRenderer::Routine::Do() context->setDefaultFramebuffer(); m_renderer.m_texMng->UpdateDynamicTextures(); m_renderer.RenderScene(modelView); + bool const animActive = InterpolationHolder::Instance().Advance(frameTime); modelView = m_renderer.UpdateScene(viewChanged); - bool const isInactiveCurrentFrame = (!viewChanged && m_renderer.IsQueueEmpty()); + bool const isInactiveCurrentFrame = (!viewChanged && m_renderer.IsQueueEmpty() && !animActive); if (isInactiveLastFrame && isInactiveCurrentFrame) { @@ -494,6 +497,7 @@ void FrontendRenderer::Routine::Do() } context->present(); + frameTime = timer.ElapsedSeconds(); timer.Reset(); m_renderer.CheckRenderingEnabled(); diff --git a/drape_frontend/user_event_stream.cpp b/drape_frontend/user_event_stream.cpp index ec94e000ac..6a359e6d55 100644 --- a/drape_frontend/user_event_stream.cpp +++ b/drape_frontend/user_event_stream.cpp @@ -1,3 +1,4 @@ +#include "drape_frontend/animation/modelview_center_animation.hpp" #include "drape_frontend/user_event_stream.hpp" #include "drape_frontend/visual_params.hpp" @@ -97,6 +98,19 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool & } } + if (m_animation != nullptr) + { + if (m_state != STATE_EMPTY) + m_animation.reset(); + else + { + m_animation->Apply(m_navigator); + modelViewChange = true; + if (m_animation->IsFinished()) + m_animation.reset(); + } + } + if (m_state == STATE_TAP_DETECTION && m_validTouchesCount == 1) DetectLongTap(m_touches[0]); diff --git a/drape_frontend/user_event_stream.hpp b/drape_frontend/user_event_stream.hpp index 51398cb4ca..c5b0c9a3f2 100644 --- a/drape_frontend/user_event_stream.hpp +++ b/drape_frontend/user_event_stream.hpp @@ -1,6 +1,7 @@ #pragma once #include "drape_frontend/navigator.hpp" +#include "drape_frontend/animation/base_viewport_animation.hpp" #include "geometry/point2d.hpp" #include "geometry/rect2d.hpp" @@ -209,6 +210,8 @@ private: array m_touches; size_t m_validTouchesCount; + unique_ptr m_animation; + #ifdef DEBUG TTestBridge m_testFn; #endif