diff --git a/Telegram/ThirdParty/qtlottie b/Telegram/ThirdParty/qtlottie index 741b80b10c..ff75b08c3a 160000 --- a/Telegram/ThirdParty/qtlottie +++ b/Telegram/ThirdParty/qtlottie @@ -1 +1 @@ -Subproject commit 741b80b10cf8b2a06ed7dfda1bf9d64896ac0249 +Subproject commit ff75b08c3adabaa33f7f879e12119de8ab1c2153 diff --git a/Telegram/ThirdParty/qtlottie_helper/QtBodymovin/private/bmproperty_p.h b/Telegram/ThirdParty/qtlottie_helper/QtBodymovin/private/bmproperty_p.h index b51a1e2448..9455efe0c0 100644 --- a/Telegram/ThirdParty/qtlottie_helper/QtBodymovin/private/bmproperty_p.h +++ b/Telegram/ThirdParty/qtlottie_helper/QtBodymovin/private/bmproperty_p.h @@ -71,6 +71,13 @@ struct EasingSegment { T endValue; BezierEasing easing; QPainterPath bezier; + + double bezierLength = 0.; + struct BezierPoint { + QPointF point; + double length = 0.; + }; + std::vector bezierPoints; }; template diff --git a/Telegram/ThirdParty/qtlottie_helper/QtBodymovin/private/bmspatialproperty_p.h b/Telegram/ThirdParty/qtlottie_helper/QtBodymovin/private/bmspatialproperty_p.h index 1fe0c849b5..b87deb7294 100644 --- a/Telegram/ThirdParty/qtlottie_helper/QtBodymovin/private/bmspatialproperty_p.h +++ b/Telegram/ThirdParty/qtlottie_helper/QtBodymovin/private/bmspatialproperty_p.h @@ -101,6 +101,20 @@ public: easing.bezier.moveTo(s); easing.bezier.cubicTo(c1, c2, e); + + const auto kCount = 150; + easing.bezierPoints.reserve(kCount); + for (auto k = 0; k < kCount; ++k) { + const auto percent = double(k) / (kCount - 1.); + auto point = EasingSegment::BezierPoint(); + point.point = easing.bezier.pointAtPercent(percent); + if (k > 0) { + const auto delta = (point.point - easing.bezierPoints[k - 1].point); + point.length = std::sqrt(QPointF::dotProduct(delta, delta)); + easing.bezierLength += point.length; + } + easing.bezierPoints.push_back(point); + } } virtual bool update(int frame) override @@ -110,18 +124,34 @@ public: int adjustedFrame = qBound(m_startFrame, frame, m_endFrame); if (const EasingSegment *easing = getEasingSegment(adjustedFrame)) { - if (easing->state == EasingSegmentState::Complete) { - int length = (easing->endFrame - easing->startFrame); - qreal progress = (length > 0) - ? ((adjustedFrame - easing->startFrame) * 1.0) / length - : 1.; - qreal easedValue = easing->easing.valueForProgress(progress); - m_value = easing->bezier.pointAtPercent(easedValue); - } else { - // In case of incomplete easing we should just take the final point. - //m_value = m_bezierPath.pointAtPercent(1.); - m_value = easing->endValue; - } + if (easing->state == EasingSegmentState::Complete) { + int length = (easing->endFrame - easing->startFrame); + qreal progress = (length > 0) + ? ((adjustedFrame - easing->startFrame) * 1.0) / length + : 1.; + qreal easedValue = easing->easing.valueForProgress(progress); + //m_value = easing->bezier.pointAtPercent(easedValue); + + const auto distance = easedValue * easing->bezierLength; + auto segmentPerc = 0.; + auto addedLength = 0.; + const auto count = easing->bezierPoints.size(); + for (auto j = 0; j != count; ++j) { + addedLength += easing->bezierPoints[j].length; + if (distance == 0. || easedValue == 0. || j == count - 1) { + m_value = easing->bezierPoints[j].point; + break; + } else if (distance >= addedLength && distance < addedLength + easing->bezierPoints[j + 1].length) { + segmentPerc = (distance - addedLength) / easing->bezierPoints[j + 1].length; + m_value = easing->bezierPoints[j].point + (easing->bezierPoints[j + 1].point - easing->bezierPoints[j].point) * segmentPerc; + break; + } + } + } else { + // In case of incomplete easing we should just take the final point. + //m_value = m_bezierPath.pointAtPercent(1.); + m_value = easing->endValue; + } } return true;