forked from organicmaps/organicmaps
Perspective animation.
This commit is contained in:
parent
83cccde2f5
commit
8412a44ed7
5 changed files with 348 additions and 107 deletions
|
@ -3,9 +3,6 @@
|
|||
|
||||
#include "base/logging.hpp"
|
||||
|
||||
#include "boost/variant/variant.hpp"
|
||||
#include "boost/variant/get.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
|
@ -75,6 +72,11 @@ void Interpolator::Advance(double elapsedSeconds)
|
|||
m_elapsedTime += elapsedSeconds;
|
||||
}
|
||||
|
||||
void Interpolator::Finish()
|
||||
{
|
||||
m_elapsedTime = m_duration + m_delay + 1.0;
|
||||
}
|
||||
|
||||
void Interpolator::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
m_duration = min(m_duration, maxDuration);
|
||||
|
@ -172,6 +174,12 @@ void PositionInterpolator::Advance(double elapsedSeconds)
|
|||
m_position = InterpolatePoint(m_startPosition, m_endPosition, GetT());
|
||||
}
|
||||
|
||||
void PositionInterpolator::Finish()
|
||||
{
|
||||
TBase::Finish();
|
||||
m_position = m_endPosition;
|
||||
}
|
||||
|
||||
// static
|
||||
double AngleInterpolator::GetRotateDuration(double startAngle, double endAngle)
|
||||
{
|
||||
|
@ -199,6 +207,12 @@ void AngleInterpolator::Advance(double elapsedSeconds)
|
|||
m_angle = InterpolateDouble(m_startAngle, m_endAngle, GetT());
|
||||
}
|
||||
|
||||
void AngleInterpolator::Finish()
|
||||
{
|
||||
TBase::Finish();
|
||||
m_angle = m_endAngle;
|
||||
}
|
||||
|
||||
// static
|
||||
double ScaleInterpolator::GetScaleDuration(double startScale, double endScale)
|
||||
{
|
||||
|
@ -230,6 +244,12 @@ void ScaleInterpolator::Advance(double elapsedSeconds)
|
|||
m_scale = InterpolateDouble(m_startScale, m_endScale, GetT());
|
||||
}
|
||||
|
||||
void ScaleInterpolator::Finish()
|
||||
{
|
||||
TBase::Finish();
|
||||
m_scale = m_endScale;
|
||||
}
|
||||
|
||||
MapLinearAnimation::MapLinearAnimation(m2::PointD const & startPos, m2::PointD const & endPos,
|
||||
double startAngle, double endAngle,
|
||||
double startScale, double endScale, ScreenBase const & convertor)
|
||||
|
@ -296,6 +316,17 @@ void MapLinearAnimation::Advance(double elapsedSeconds)
|
|||
m_positionInterpolator->Advance(elapsedSeconds);
|
||||
}
|
||||
|
||||
void MapLinearAnimation::Finish()
|
||||
{
|
||||
if (m_angleInterpolator != nullptr)
|
||||
m_angleInterpolator->Finish();
|
||||
if (m_scaleInterpolator != nullptr)
|
||||
m_scaleInterpolator->Finish();
|
||||
if (m_positionInterpolator != nullptr)
|
||||
m_positionInterpolator->Finish();
|
||||
Animation::Finish();
|
||||
}
|
||||
|
||||
void MapLinearAnimation::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
if (m_angleInterpolator != nullptr)
|
||||
|
@ -325,7 +356,7 @@ bool MapLinearAnimation::IsFinished() const
|
|||
&& (m_positionInterpolator == nullptr || m_positionInterpolator->IsFinished()));
|
||||
}
|
||||
|
||||
Animation::TPropValue MapLinearAnimation::GetProperty(TObject object, TProperty property) const
|
||||
Animation::PropertyValue MapLinearAnimation::GetProperty(TObject object, TProperty property) const
|
||||
{
|
||||
ASSERT(object == Animation::MapPlane, ());
|
||||
|
||||
|
@ -381,6 +412,12 @@ void MapScaleAnimation::Advance(double elapsedSeconds)
|
|||
m_scaleInterpolator->Advance(elapsedSeconds);
|
||||
}
|
||||
|
||||
void MapScaleAnimation::Finish()
|
||||
{
|
||||
m_scaleInterpolator->Finish();
|
||||
Animation::Finish();
|
||||
}
|
||||
|
||||
void MapScaleAnimation::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
m_scaleInterpolator->SetMaxDuration(maxDuration);
|
||||
|
@ -396,7 +433,7 @@ bool MapScaleAnimation::IsFinished() const
|
|||
return m_scaleInterpolator->IsFinished();
|
||||
}
|
||||
|
||||
Animation::TPropValue MapScaleAnimation::GetProperty(TObject object, TProperty property) const
|
||||
Animation::PropertyValue MapScaleAnimation::GetProperty(TObject object, TProperty property) const
|
||||
{
|
||||
|
||||
if (property == Animation::Position)
|
||||
|
@ -453,6 +490,14 @@ void MapFollowAnimation::Advance(double elapsedSeconds)
|
|||
m_pixelPosInterpolator->Advance(elapsedSeconds);
|
||||
}
|
||||
|
||||
void MapFollowAnimation::Finish()
|
||||
{
|
||||
m_angleInterpolator->Finish();
|
||||
m_scaleInterpolator->Finish();
|
||||
m_pixelPosInterpolator->Finish();
|
||||
Animation::Finish();
|
||||
}
|
||||
|
||||
void MapFollowAnimation::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
m_angleInterpolator->SetMaxDuration(maxDuration);
|
||||
|
@ -479,7 +524,7 @@ bool MapFollowAnimation::IsFinished() const
|
|||
&& (m_scaleInterpolator == nullptr || m_scaleInterpolator->IsFinished()));
|
||||
}
|
||||
|
||||
Animation::TPropValue MapFollowAnimation::GetProperty(TObject object, TProperty property) const
|
||||
Animation::PropertyValue MapFollowAnimation::GetProperty(TObject object, TProperty property) const
|
||||
{
|
||||
|
||||
if (property == Animation::Position)
|
||||
|
@ -503,6 +548,66 @@ Animation::TPropValue MapFollowAnimation::GetProperty(TObject object, TProperty
|
|||
return 0.0;
|
||||
}
|
||||
|
||||
PerspectiveSwitchAnimation::PerspectiveSwitchAnimation(double startAngle, double endAngle)
|
||||
: Animation(false, false)
|
||||
{
|
||||
m_angleInterpolator = make_unique_dp<AngleInterpolator>(startAngle, endAngle);
|
||||
m_objects.insert(Animation::MapPlane);
|
||||
m_properties.insert(Animation::AnglePerspective);
|
||||
}
|
||||
|
||||
Animation::TObjectProperties const & PerspectiveSwitchAnimation::GetProperties(TObject object) const
|
||||
{
|
||||
ASSERT(object == Animation::MapPlane, ());
|
||||
return m_properties;
|
||||
}
|
||||
|
||||
bool PerspectiveSwitchAnimation::HasProperty(TObject object, TProperty property) const
|
||||
{
|
||||
return HasObject(object) && m_properties.find(property) != m_properties.end();
|
||||
}
|
||||
|
||||
void PerspectiveSwitchAnimation::Advance(double elapsedSeconds)
|
||||
{
|
||||
m_angleInterpolator->Advance(elapsedSeconds);
|
||||
}
|
||||
|
||||
void PerspectiveSwitchAnimation::Finish()
|
||||
{
|
||||
m_angleInterpolator->Finish();
|
||||
Animation::Finish();
|
||||
}
|
||||
|
||||
void PerspectiveSwitchAnimation::SetMaxDuration(double maxDuration)
|
||||
{
|
||||
m_angleInterpolator->SetMaxDuration(maxDuration);
|
||||
}
|
||||
|
||||
double PerspectiveSwitchAnimation::GetDuration() const
|
||||
{
|
||||
return m_angleInterpolator->GetDuration();
|
||||
}
|
||||
|
||||
bool PerspectiveSwitchAnimation::IsFinished() const
|
||||
{
|
||||
return m_angleInterpolator->IsFinished();
|
||||
}
|
||||
|
||||
Animation::PropertyValue PerspectiveSwitchAnimation::GetProperty(TObject object, TProperty property) const
|
||||
{
|
||||
ASSERT(object == Animation::MapPlane, ());
|
||||
|
||||
switch (property)
|
||||
{
|
||||
case Animation::AnglePerspective:
|
||||
return m_angleInterpolator->GetAngle();
|
||||
break;
|
||||
default:
|
||||
ASSERT(!"Wrong property", ());
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
Animation::TObjectProperties const & ParallelAnimation::GetProperties(TObject object) const
|
||||
{
|
||||
|
@ -557,6 +662,13 @@ void ParallelAnimation::Advance(double elapsedSeconds)
|
|||
}
|
||||
}
|
||||
|
||||
void ParallelAnimation::Finish()
|
||||
{
|
||||
for (auto & anim : m_animations)
|
||||
anim->Finish();
|
||||
Animation::Finish();
|
||||
}
|
||||
|
||||
Animation::TAnimObjects const & SequenceAnimation::GetObjects() const
|
||||
{
|
||||
ASSERT(!m_animations.empty(), ());
|
||||
|
@ -615,16 +727,19 @@ AnimationSystem::AnimationSystem()
|
|||
|
||||
}
|
||||
|
||||
m2::AnyRectD AnimationSystem::GetRect(ScreenBase const & currentScreen)
|
||||
double AnimationSystem::GetPerspectiveAngle(double currentAngle)
|
||||
{
|
||||
return GetProperty(Animation::MapPlane, Animation::AnglePerspective, currentAngle).m_valueD;
|
||||
}
|
||||
|
||||
m2::AnyRectD AnimationSystem::GetRect(ScreenBase const & currentScreen, bool & viewportChanged)
|
||||
{
|
||||
const Animation::TObject obj = Animation::MapPlane;
|
||||
viewportChanged |= m_lastScreen != nullptr && (m_lastScreen->isPerspective() != currentScreen.isPerspective());
|
||||
m_lastScreen = make_unique_dp<ScreenBase>(currentScreen);
|
||||
double scale = boost::get<double>(
|
||||
GetProperty(obj, Animation::Scale, currentScreen.GetScale()));
|
||||
double angle = boost::get<double>(
|
||||
GetProperty(obj, Animation::Angle, currentScreen.GetAngle()));
|
||||
m2::PointD pos = boost::get<m2::PointD>(
|
||||
GetProperty(obj, Animation::Position, currentScreen.GlobalRect().GlobalZero()));
|
||||
double scale = GetProperty(obj, Animation::Scale, currentScreen.GetScale()).m_valueD;
|
||||
double angle = GetProperty(obj, Animation::Angle, currentScreen.GetAngle()).m_valueD;
|
||||
m2::PointD pos = GetProperty(obj, Animation::Position, currentScreen.GlobalRect().GlobalZero()).m_valuePointD;
|
||||
m2::RectD rect = currentScreen.PixelRect();
|
||||
rect.Offset(-rect.Center());
|
||||
rect.Scale(scale);
|
||||
|
@ -633,12 +748,13 @@ m2::AnyRectD AnimationSystem::GetRect(ScreenBase const & currentScreen)
|
|||
|
||||
bool AnimationSystem::AnimationExists(Animation::TObject object) const
|
||||
{
|
||||
if (m_animationChain.empty())
|
||||
return false;
|
||||
for (auto const & anim : m_animationChain.front())
|
||||
if (!m_animationChain.empty())
|
||||
{
|
||||
if (anim->HasObject(object))
|
||||
return true;
|
||||
for (auto const & anim : m_animationChain.front())
|
||||
{
|
||||
if (anim->HasObject(object))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (auto it = m_propertyCache.begin(); it != m_propertyCache.end(); ++it)
|
||||
{
|
||||
|
@ -692,12 +808,65 @@ void AnimationSystem::AddAnimation(drape_ptr<Animation> && animation, bool force
|
|||
|
||||
void AnimationSystem::PushAnimation(drape_ptr<Animation> && animation)
|
||||
{
|
||||
animation->OnStart();
|
||||
if (m_animationChain.empty())
|
||||
animation->OnStart();
|
||||
|
||||
TAnimationList list;
|
||||
list.emplace_back(move(animation));
|
||||
|
||||
m_animationChain.emplace_back(move(list));
|
||||
}
|
||||
|
||||
void AnimationSystem::FinishAnimations(Animation::Type type, bool rewind)
|
||||
{
|
||||
if (m_animationChain.empty())
|
||||
return;
|
||||
|
||||
TAnimationList & frontList = m_animationChain.front();
|
||||
for (auto it = frontList.begin(); it != frontList.end();)
|
||||
{
|
||||
auto & anim = *it;
|
||||
if (anim->GetType() == type)
|
||||
{
|
||||
if (rewind)
|
||||
anim->Finish();
|
||||
SaveAnimationResult(*anim);
|
||||
it = frontList.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
if (frontList.empty())
|
||||
StartNextAnimations();
|
||||
}
|
||||
|
||||
void AnimationSystem::FinishObjectAnimations(Animation::TObject object, bool rewind)
|
||||
{
|
||||
if (m_animationChain.empty())
|
||||
return;
|
||||
|
||||
TAnimationList & frontList = m_animationChain.front();
|
||||
for (auto it = frontList.begin(); it != frontList.end();)
|
||||
{
|
||||
auto & anim = *it;
|
||||
if (anim->HasObject(object))
|
||||
{
|
||||
if (rewind)
|
||||
anim->Finish();
|
||||
SaveAnimationResult(*anim);
|
||||
it = frontList.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
if (frontList.empty())
|
||||
StartNextAnimations();
|
||||
}
|
||||
|
||||
void AnimationSystem::Advance(double elapsedSeconds)
|
||||
{
|
||||
if (m_animationChain.empty())
|
||||
|
@ -719,9 +888,11 @@ void AnimationSystem::Advance(double elapsedSeconds)
|
|||
++it;
|
||||
}
|
||||
}
|
||||
if (frontList.empty())
|
||||
StartNextAnimations();
|
||||
}
|
||||
|
||||
Animation::TPropValue AnimationSystem::GetProperty(Animation::TObject object, Animation::TProperty property, Animation::TPropValue current) const
|
||||
Animation::PropertyValue AnimationSystem::GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue current) const
|
||||
{
|
||||
if (!m_animationChain.empty())
|
||||
{
|
||||
|
@ -734,7 +905,7 @@ Animation::TPropValue AnimationSystem::GetProperty(Animation::TObject object, An
|
|||
auto it = m_propertyCache.find(make_pair(object, property));
|
||||
if (it != m_propertyCache.end())
|
||||
{
|
||||
Animation::TPropValue value(it->second);
|
||||
Animation::PropertyValue value(it->second);
|
||||
m_propertyCache.erase(it);
|
||||
return value;
|
||||
}
|
||||
|
@ -752,4 +923,16 @@ void AnimationSystem::SaveAnimationResult(Animation const & animation)
|
|||
}
|
||||
}
|
||||
|
||||
void AnimationSystem::StartNextAnimations()
|
||||
{
|
||||
m_animationChain.pop_front();
|
||||
if (m_animationChain.empty())
|
||||
return;
|
||||
for (auto & anim : m_animationChain.front())
|
||||
{
|
||||
// TODO: use propertyCache to load start values to the next animations
|
||||
anim->OnStart();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace df
|
||||
|
|
|
@ -10,8 +10,6 @@
|
|||
#include "std/deque.hpp"
|
||||
#include "std/noncopyable.hpp"
|
||||
|
||||
#include "boost/variant/variant_fwd.hpp"
|
||||
|
||||
namespace df
|
||||
{
|
||||
|
||||
|
@ -40,22 +38,53 @@ public:
|
|||
{
|
||||
Position,
|
||||
Scale,
|
||||
Angle
|
||||
Angle,
|
||||
AnglePerspective
|
||||
};
|
||||
|
||||
enum PropertyValueType
|
||||
{
|
||||
ValueD,
|
||||
ValuePointD
|
||||
};
|
||||
|
||||
struct PropertyValue
|
||||
{
|
||||
PropertyValue()
|
||||
{
|
||||
}
|
||||
|
||||
PropertyValue(double value)
|
||||
: m_type(ValueD),
|
||||
m_valueD(value)
|
||||
{}
|
||||
|
||||
PropertyValue(m2::PointD value)
|
||||
: m_type(ValuePointD),
|
||||
m_valuePointD(value)
|
||||
{}
|
||||
|
||||
PropertyValueType m_type;
|
||||
union
|
||||
{
|
||||
m2::PointD m_valuePointD;
|
||||
double m_valueD;
|
||||
};
|
||||
};
|
||||
|
||||
using TObject = uint32_t;
|
||||
using TProperty = uint32_t;
|
||||
using TPropValue = boost::variant<double, m2::PointD>;
|
||||
using TAnimObjects = set<TObject>;
|
||||
using TObjectProperties = set<TProperty>;
|
||||
using TAction = function<void(Animation const &)>;
|
||||
|
||||
Animation(bool couldBeInterrupted, bool couldBeMixed)
|
||||
: m_couldBeInterrupted(couldBeInterrupted)
|
||||
, m_couldBeMixed(couldBeMixed)
|
||||
{}
|
||||
|
||||
virtual void OnStart() {}
|
||||
virtual void OnFinish() {}
|
||||
virtual void OnStart() {if (m_onStartAction != nullptr) m_onStartAction(*this);}
|
||||
virtual void OnFinish() {if (m_onFinishAction != nullptr) m_onFinishAction(*this);}
|
||||
virtual void Interrupt() {}
|
||||
|
||||
virtual Type GetType() const = 0;
|
||||
|
@ -70,8 +99,13 @@ public:
|
|||
virtual bool IsFinished() const = 0;
|
||||
|
||||
virtual void Advance(double elapsedSeconds) = 0;
|
||||
virtual void Finish() { OnFinish(); }
|
||||
|
||||
virtual TPropValue GetProperty(TObject object, TProperty property) const = 0;
|
||||
virtual PropertyValue GetProperty(TObject object, TProperty property) const = 0;
|
||||
|
||||
void SetOnStartAction(TAction const & action) { m_onStartAction = action; }
|
||||
void SetOnFinishAction(TAction const & action) { m_onFinishAction = action; }
|
||||
void SetOnInterruptAction(TAction const & action) { m_onInterruptAction = action; }
|
||||
|
||||
bool CouldBeInterrupted() const { return m_couldBeInterrupted; }
|
||||
bool CouldBeMixed() const { return m_couldBeMixed; }
|
||||
|
@ -79,6 +113,9 @@ public:
|
|||
bool CouldBeMixedWith(Animation const & animation);
|
||||
|
||||
protected:
|
||||
TAction m_onStartAction;
|
||||
TAction m_onFinishAction;
|
||||
TAction m_onInterruptAction;
|
||||
bool m_couldBeInterrupted;
|
||||
bool m_couldBeMixed;
|
||||
};
|
||||
|
@ -91,6 +128,7 @@ public:
|
|||
|
||||
bool IsFinished() const;
|
||||
virtual void Advance(double elapsedSeconds);
|
||||
virtual void Finish();
|
||||
void SetMaxDuration(double maxDuration);
|
||||
void SetMinDuration(double minDuration);
|
||||
double GetDuration() const;
|
||||
|
@ -121,6 +159,7 @@ public:
|
|||
static double GetPixelMoveDuration(m2::PointD const & startPosition, m2::PointD const & endPosition, m2::RectD const & pixelRect);
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
virtual m2::PointD GetPosition() const { return m_position; }
|
||||
|
||||
private:
|
||||
|
@ -140,6 +179,7 @@ public:
|
|||
static double GetScaleDuration(double startScale, double endScale);
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
virtual double GetScale() const { return m_scale; }
|
||||
|
||||
private:
|
||||
|
@ -159,6 +199,7 @@ public:
|
|||
static double GetRotateDuration(double startAngle, double endAngle);
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
virtual double GetAngle() const { return m_angle; }
|
||||
|
||||
private:
|
||||
|
@ -195,6 +236,7 @@ public:
|
|||
bool HasProperty(TObject object, TProperty property) const override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
private:
|
||||
drape_ptr<PositionInterpolator> m_positionInterpolator;
|
||||
|
@ -205,9 +247,8 @@ private:
|
|||
|
||||
class PerspectiveSwitchAnimation : public Animation
|
||||
{
|
||||
PerspectiveSwitchAnimation()
|
||||
: Animation(false, false)
|
||||
{}
|
||||
public:
|
||||
PerspectiveSwitchAnimation(double startAngle, double endAngle);
|
||||
|
||||
Animation::Type GetType() const override { return Animation::MapPerspective; }
|
||||
|
||||
|
@ -223,6 +264,13 @@ class PerspectiveSwitchAnimation : public Animation
|
|||
bool HasProperty(TObject object, TProperty property) const override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
void SetMaxDuration(double maxDuration) override;
|
||||
double GetDuration() const override;
|
||||
bool IsFinished() const override;
|
||||
|
||||
PropertyValue GetProperty(TObject object, TProperty property) const override;
|
||||
|
||||
private:
|
||||
drape_ptr<AngleInterpolator> m_angleInterpolator;
|
||||
|
@ -256,12 +304,13 @@ public:
|
|||
bool HasProperty(TObject object, TProperty property) const override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
void SetMaxDuration(double maxDuration) override;
|
||||
double GetDuration() const override;
|
||||
bool IsFinished() const override;
|
||||
|
||||
TPropValue GetProperty(TObject object, TProperty property) const override;
|
||||
PropertyValue GetProperty(TObject object, TProperty property) const override;
|
||||
|
||||
private:
|
||||
drape_ptr<AngleInterpolator> m_angleInterpolator;
|
||||
|
@ -291,12 +340,13 @@ public:
|
|||
bool HasProperty(TObject object, TProperty property) const override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
void SetMaxDuration(double maxDuration) override;
|
||||
double GetDuration() const override;
|
||||
bool IsFinished() const override;
|
||||
|
||||
TPropValue GetProperty(TObject object, TProperty property) const override;
|
||||
PropertyValue GetProperty(TObject object, TProperty property) const override;
|
||||
|
||||
private:
|
||||
drape_ptr<ScaleInterpolator> m_scaleInterpolator;
|
||||
|
@ -329,12 +379,13 @@ public:
|
|||
bool HasProperty(TObject object, TProperty property) const override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
void SetMaxDuration(double maxDuration) override;
|
||||
double GetDuration() const override;
|
||||
bool IsFinished() const override;
|
||||
|
||||
TPropValue GetProperty(TObject object, TProperty property) const override;
|
||||
PropertyValue GetProperty(TObject object, TProperty property) const override;
|
||||
|
||||
private:
|
||||
drape_ptr<ScaleInterpolator> m_scaleInterpolator;
|
||||
|
@ -388,6 +439,7 @@ public:
|
|||
void OnFinish() override;
|
||||
|
||||
void Advance(double elapsedSeconds) override;
|
||||
void Finish() override;
|
||||
|
||||
private:
|
||||
list<drape_ptr<Animation>> m_animations;
|
||||
|
@ -400,27 +452,32 @@ class AnimationSystem : private noncopyable
|
|||
public:
|
||||
static AnimationSystem & Instance();
|
||||
|
||||
m2::AnyRectD GetRect(ScreenBase const & currentScreen);
|
||||
m2::AnyRectD GetRect(ScreenBase const & currentScreen, bool & viewportChanged);
|
||||
double GetPerspectiveAngle(double currentAngle);
|
||||
|
||||
bool AnimationExists(Animation::TObject object) const;
|
||||
|
||||
void AddAnimation(drape_ptr<Animation> && animation, bool force);
|
||||
void PushAnimation(drape_ptr<Animation> && animation);
|
||||
|
||||
void FinishAnimations(Animation::Type type, bool rewind);
|
||||
void FinishObjectAnimations(Animation::TObject object, bool rewind);
|
||||
|
||||
void Advance(double elapsedSeconds);
|
||||
|
||||
ScreenBase const & GetLastScreen() { return *m_lastScreen.get(); }
|
||||
|
||||
private:
|
||||
Animation::TPropValue GetProperty(Animation::TObject object, Animation::TProperty property, Animation::TPropValue current) const;
|
||||
Animation::PropertyValue GetProperty(Animation::TObject object, Animation::TProperty property, Animation::PropertyValue current) const;
|
||||
void SaveAnimationResult(Animation const & animation);
|
||||
void StartNextAnimations();
|
||||
|
||||
AnimationSystem();
|
||||
|
||||
private:
|
||||
using TAnimationList = list<drape_ptr<Animation>>;
|
||||
using TAnimationChain = deque<TAnimationList>;
|
||||
using TPropertyCache = map<pair<Animation::TObject, Animation::TProperty>, Animation::TPropValue>;
|
||||
using TPropertyCache = map<pair<Animation::TObject, Animation::TProperty>, Animation::PropertyValue>;
|
||||
TAnimationChain m_animationChain;
|
||||
mutable TPropertyCache m_propertyCache;
|
||||
|
||||
|
|
|
@ -747,14 +747,15 @@ void FrontendRenderer::FollowRoute(int preferredZoomLevel, int preferredZoomLeve
|
|||
double rotationAngle, double angleFOV)
|
||||
{
|
||||
|
||||
m_myPositionController->ActivateRouting(!m_enablePerspectiveInNavigation ? preferredZoomLevel
|
||||
: preferredZoomLevelIn3d);
|
||||
|
||||
if (m_enablePerspectiveInNavigation)
|
||||
{
|
||||
bool immediatelyStart = !m_myPositionController->IsRotationAvailable();
|
||||
AddUserEvent(EnablePerspectiveEvent(rotationAngle, angleFOV, true /* animated */, immediatelyStart));
|
||||
}
|
||||
|
||||
m_myPositionController->ActivateRouting(!m_enablePerspectiveInNavigation ? preferredZoomLevel
|
||||
: preferredZoomLevelIn3d);
|
||||
m_overlayTree->SetFollowingMode(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -145,7 +145,7 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool &
|
|||
modelViewChange = !events.empty() || m_state == STATE_SCALE || m_state == STATE_DRAG;
|
||||
for (UserEvent const & e : events)
|
||||
{
|
||||
if (m_perspectiveAnimation != nullptr && FilterEventWhile3dAnimation(e.m_type))
|
||||
if (m_perspectiveAnimation && FilterEventWhile3dAnimation(e.m_type))
|
||||
continue;
|
||||
|
||||
bool breakAnim = false;
|
||||
|
@ -167,7 +167,7 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool &
|
|||
TouchCancel(m_touches);
|
||||
break;
|
||||
case UserEvent::EVENT_SET_RECT:
|
||||
if (m_perspectiveAnimation != nullptr)
|
||||
if (m_perspectiveAnimation)
|
||||
{
|
||||
m_pendingEvent.reset(new UserEvent(e.m_rectEvent));
|
||||
break;
|
||||
|
@ -199,26 +199,20 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool &
|
|||
}
|
||||
break;
|
||||
case UserEvent::EVENT_FOLLOW_AND_ROTATE:
|
||||
m_pendingPerspective = false;
|
||||
breakAnim = SetFollowAndRotate(e.m_followAndRotate.m_userPos, e.m_followAndRotate.m_pixelZero,
|
||||
e.m_followAndRotate.m_azimuth, e.m_followAndRotate.m_preferredZoomLevel,
|
||||
e.m_followAndRotate.m_isAnim);
|
||||
TouchCancel(m_touches);
|
||||
break;
|
||||
case UserEvent::EVENT_ENABLE_PERSPECTIVE:
|
||||
if (!e.m_enable3dMode.m_immediatelyStart)
|
||||
{
|
||||
m_pendingPerspective = true;
|
||||
m_pendingEvent.reset(new UserEvent(e.m_enable3dMode));
|
||||
}
|
||||
else
|
||||
SetEnable3dMode(e.m_enable3dMode.m_rotationAngle, e.m_enable3dMode.m_angleFOV,
|
||||
e.m_enable3dMode.m_isAnim, viewportChanged);
|
||||
SetEnable3dMode(e.m_enable3dMode.m_rotationAngle, e.m_enable3dMode.m_angleFOV,
|
||||
e.m_enable3dMode.m_isAnim, e.m_enable3dMode.m_immediatelyStart,
|
||||
viewportChanged);
|
||||
m_discardedFOV = m_discardedAngle = 0.0;
|
||||
break;
|
||||
case UserEvent::EVENT_DISABLE_PERSPECTIVE:
|
||||
if (m_navigator.Screen().isPerspective())
|
||||
SetDisable3dModeAnimation();
|
||||
SetDisable3dModeAnimation(viewportChanged);
|
||||
m_discardedFOV = m_discardedAngle = 0.0;
|
||||
break;
|
||||
case UserEvent::EVENT_SWITCH_VIEW_MODE:
|
||||
|
@ -226,11 +220,12 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool &
|
|||
{
|
||||
m_discardedFOV = m_navigator.Screen().GetAngleFOV();
|
||||
m_discardedAngle = m_navigator.Screen().GetRotationAngle();
|
||||
SetDisable3dModeAnimation();
|
||||
SetDisable3dModeAnimation(viewportChanged);
|
||||
}
|
||||
else if (m_discardedFOV > 0.0)
|
||||
{
|
||||
SetEnable3dMode(m_discardedAngle, m_discardedFOV, true /* isAnim */, viewportChanged);
|
||||
SetEnable3dMode(m_discardedAngle, m_discardedFOV, true /* isAnim */, true /* immediatelyStart */,
|
||||
viewportChanged);
|
||||
m_discardedFOV = m_discardedAngle = 0.0;
|
||||
}
|
||||
break;
|
||||
|
@ -256,44 +251,17 @@ ScreenBase const & UserEventStream::ProcessEvents(bool & modelViewChange, bool &
|
|||
}
|
||||
if (AnimationSystem::Instance().AnimationExists(Animation::MapPlane))
|
||||
{
|
||||
m2::AnyRectD const rect = AnimationSystem::Instance().GetRect(GetCurrentScreen());
|
||||
m2::AnyRectD const rect = AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged);
|
||||
m_navigator.SetFromRect(rect);
|
||||
modelViewChange = true;
|
||||
}
|
||||
|
||||
if (m_pendingEvent != nullptr &&
|
||||
m_pendingEvent->m_type == UserEvent::EVENT_ENABLE_PERSPECTIVE &&
|
||||
!m_pendingPerspective && m_animation == nullptr)
|
||||
{
|
||||
SetEnable3dMode(m_pendingEvent->m_enable3dMode.m_rotationAngle,
|
||||
m_pendingEvent->m_enable3dMode.m_angleFOV,
|
||||
m_pendingEvent->m_enable3dMode.m_isAnim,
|
||||
viewportChanged);
|
||||
modelViewChange = true;
|
||||
m_pendingEvent.reset();
|
||||
}
|
||||
|
||||
if (m_perspectiveAnimation != nullptr)
|
||||
{
|
||||
double const angle = m_perspectiveAnimation->GetRotationAngle();
|
||||
m_navigator.SetRotationIn3dMode(angle);
|
||||
modelViewChange = true;
|
||||
TouchCancel(m_touches);
|
||||
|
||||
if (m_perspectiveAnimation->IsFinished())
|
||||
ScreenBase const & screen = GetCurrentScreen();
|
||||
if (screen.isPerspective())
|
||||
{
|
||||
if (angle == 0.0)
|
||||
{
|
||||
m_navigator.Disable3dMode();
|
||||
viewportChanged = true;
|
||||
|
||||
if (m_pendingEvent != nullptr && m_pendingEvent->m_type == UserEvent::EVENT_SET_RECT)
|
||||
SetRect(m_pendingEvent->m_rectEvent.m_rect, m_pendingEvent->m_rectEvent.m_zoom,
|
||||
m_pendingEvent->m_rectEvent.m_applyRotation, m_pendingEvent->m_rectEvent.m_isAnim);
|
||||
}
|
||||
m_pendingEvent.reset();
|
||||
m_perspectiveAnimation.reset();
|
||||
double const angle = AnimationSystem::Instance().GetPerspectiveAngle(screen.GetRotationAngle());
|
||||
m_navigator.SetRotationIn3dMode(angle);
|
||||
//TouchCancel(m_touches);
|
||||
}
|
||||
modelViewChange = true;
|
||||
}
|
||||
|
||||
if (GetValidTouchesCount(m_touches) == 1)
|
||||
|
@ -555,32 +523,64 @@ bool UserEventStream::FilterEventWhile3dAnimation(UserEvent::EEventType type) co
|
|||
type != UserEvent::EVENT_SET_RECT;
|
||||
}
|
||||
|
||||
void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV, bool isAnim, bool & viewportChanged)
|
||||
void UserEventStream::SetEnable3dMode(double maxRotationAngle, double angleFOV,
|
||||
bool isAnim, bool immediatelyStart,
|
||||
bool & viewportChanged)
|
||||
{
|
||||
bool const finishAnimation = m_animation != nullptr && m_animation->GetType() == ModelViewAnimationType::Default;
|
||||
ResetCurrentAnimation(finishAnimation);
|
||||
AnimationSystem::Instance().FinishAnimations(Animation::MapLinear, true /* rewind */);
|
||||
|
||||
m_navigator.SetFromRect(AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged));
|
||||
|
||||
double const startAngle = isAnim ? 0.0 : maxRotationAngle;
|
||||
if (isAnim)
|
||||
double const endAngle = maxRotationAngle;
|
||||
if (isAnim || !immediatelyStart)
|
||||
{
|
||||
double const endAngle = maxRotationAngle;
|
||||
double const rotateDuration = PerspectiveAnimation::GetRotateDuration(startAngle, endAngle);
|
||||
m_perspectiveAnimation.reset(
|
||||
new PerspectiveAnimation(rotateDuration, 0.0 /* delay */, startAngle, endAngle));
|
||||
drape_ptr<PerspectiveSwitchAnimation> anim = make_unique_dp<PerspectiveSwitchAnimation>(startAngle, endAngle);
|
||||
anim->SetOnStartAction([this, startAngle, endAngle, angleFOV](Animation const &)
|
||||
{
|
||||
m_perspectiveAnimation = true;
|
||||
m_navigator.Enable3dMode(startAngle, endAngle, angleFOV);
|
||||
});
|
||||
anim->SetOnFinishAction([this](Animation const &)
|
||||
{
|
||||
m_perspectiveAnimation = false;
|
||||
});
|
||||
if (immediatelyStart)
|
||||
{
|
||||
//AnimationSystem::Instance().FinishObjectAnimations(Animation::MapPlane, false /* rewind */);
|
||||
AnimationSystem::Instance().AddAnimation(move(anim), true /* force */);
|
||||
}
|
||||
else
|
||||
AnimationSystem::Instance().PushAnimation(move(anim));
|
||||
}
|
||||
m_navigator.Enable3dMode(startAngle, maxRotationAngle, angleFOV);
|
||||
viewportChanged = true;
|
||||
}
|
||||
|
||||
void UserEventStream::SetDisable3dModeAnimation()
|
||||
void UserEventStream::SetDisable3dModeAnimation(bool & viewportChanged)
|
||||
{
|
||||
bool const finishAnimation = m_animation != nullptr && m_animation->GetType() == ModelViewAnimationType::Default;
|
||||
ResetCurrentAnimation(finishAnimation);
|
||||
AnimationSystem::Instance().FinishAnimations(Animation::MapLinear, true /* rewind */);
|
||||
//AnimationSystem::Instance().FinishObjectAnimations(Animation::MapPlane, false /* rewind */);
|
||||
m_navigator.SetFromRect(AnimationSystem::Instance().GetRect(GetCurrentScreen(), viewportChanged));
|
||||
|
||||
double const startAngle = m_navigator.Screen().GetRotationAngle();
|
||||
double const endAngle = 0.0;
|
||||
double const rotateDuration = PerspectiveAnimation::GetRotateDuration(startAngle, endAngle);
|
||||
m_perspectiveAnimation.reset(new PerspectiveAnimation(rotateDuration, 0.0 /* delay */, startAngle, endAngle));
|
||||
|
||||
drape_ptr<PerspectiveSwitchAnimation> anim = make_unique_dp<PerspectiveSwitchAnimation>(startAngle, endAngle);
|
||||
anim->SetOnStartAction([this](Animation const &)
|
||||
{
|
||||
m_perspectiveAnimation = true;
|
||||
});
|
||||
anim->SetOnFinishAction([this](Animation const &)
|
||||
{
|
||||
m_perspectiveAnimation = false;
|
||||
m_navigator.Disable3dMode();
|
||||
if (m_pendingEvent != nullptr && m_pendingEvent->m_type == UserEvent::EVENT_SET_RECT)
|
||||
{
|
||||
SetRect(m_pendingEvent->m_rectEvent.m_rect, m_pendingEvent->m_rectEvent.m_zoom,
|
||||
m_pendingEvent->m_rectEvent.m_applyRotation, m_pendingEvent->m_rectEvent.m_isAnim);
|
||||
m_pendingEvent.reset();
|
||||
}
|
||||
});
|
||||
AnimationSystem::Instance().AddAnimation(move(anim), true /* force */);
|
||||
}
|
||||
|
||||
void UserEventStream::ResetCurrentAnimation(bool finishAnimation)
|
||||
|
@ -1160,7 +1160,7 @@ bool UserEventStream::IsWaitingForActionCompletion() const
|
|||
|
||||
bool UserEventStream::IsInPerspectiveAnimation() const
|
||||
{
|
||||
return m_perspectiveAnimation != nullptr;
|
||||
return m_perspectiveAnimation;
|
||||
}
|
||||
|
||||
void UserEventStream::SetKineticScrollEnabled(bool enabled)
|
||||
|
|
|
@ -310,8 +310,9 @@ private:
|
|||
double azimuth, int preferredZoomLevel, bool isAnim);
|
||||
|
||||
bool FilterEventWhile3dAnimation(UserEvent::EEventType type) const;
|
||||
void SetEnable3dMode(double maxRotationAngle, double angleFOV, bool isAnim, bool & viewportChanged);
|
||||
void SetDisable3dModeAnimation();
|
||||
void SetEnable3dMode(double maxRotationAngle, double angleFOV,
|
||||
bool isAnim, bool immediatelyStart, bool & viewportChanged);
|
||||
void SetDisable3dModeAnimation(bool & viewportChanged);
|
||||
|
||||
m2::AnyRectD GetCurrentRect() const;
|
||||
|
||||
|
@ -376,8 +377,7 @@ private:
|
|||
|
||||
drape_ptr<BaseModelViewAnimation> m_animation;
|
||||
|
||||
unique_ptr<PerspectiveAnimation> m_perspectiveAnimation;
|
||||
bool m_pendingPerspective = false;
|
||||
bool m_perspectiveAnimation;
|
||||
unique_ptr<UserEvent> m_pendingEvent;
|
||||
double m_discardedFOV = 0.0;
|
||||
double m_discardedAngle = 0.0;
|
||||
|
|
Loading…
Add table
Reference in a new issue