diff options
author | Kwanghyo Park <kwanghyo.park@qt.io> | 2022-06-21 15:50:56 +0300 |
---|---|---|
committer | Qt Cherry-pick Bot <cherrypick_bot@qt-project.org> | 2022-12-14 08:05:54 +0000 |
commit | 528ca10ab1c7044ecca2ceea92fd3f73bf44e800 (patch) | |
tree | 6ffea207c545dc36e64dc8f726ead1060f4d0918 /src | |
parent | 930db8b306ce3f2fd89d05ff952020ceee988672 (diff) |
Fix an error on parsing property animation keyframes
There was update on bodymovin schema on animating property.
Applying those updates.
Preserve old implementation for backward compatibility.
Task-number: QTBUG-102550
Change-Id: I1ca18ca727e267b6e5e442e1fae4b5aa72572ece
Reviewed-by: Kwanghyo Park <kwanghyo.park@qt.io>
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Reviewed-by: Janne Koskinen <janne.p.koskinen@qt.io>
(cherry picked from commit f467e29f74fd121b62ad66cb70da9a4b7f6e3248)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
Diffstat (limited to 'src')
45 files changed, 362 insertions, 157 deletions
diff --git a/src/bodymovin/bmbase_p.h b/src/bodymovin/bmbase_p.h index a2bad4e..9d39f2c 100644 --- a/src/bodymovin/bmbase_p.h +++ b/src/bodymovin/bmbase_p.h @@ -17,6 +17,7 @@ #include <QJsonObject> #include <QList> +#include <QVersionNumber> #include <QtBodymovin/bmglobal.h> #include <QtBodymovin/private/bmconstants_p.h> @@ -24,7 +25,6 @@ #include <QtBodymovin/private/lottierenderer_p.h> QT_BEGIN_NAMESPACE - class BODYMOVIN_EXPORT BMBase { public: @@ -69,6 +69,7 @@ protected: QJsonObject m_definition; int m_type; bool m_hidden = false; + QVersionNumber m_version; QString m_name; QString m_matchName; bool m_autoOrient = false; diff --git a/src/bodymovin/bmbasictransform.cpp b/src/bodymovin/bmbasictransform.cpp index 025ea1d..b9ddbe3 100644 --- a/src/bodymovin/bmbasictransform.cpp +++ b/src/bodymovin/bmbasictransform.cpp @@ -23,10 +23,11 @@ BMBasicTransform::BMBasicTransform(const BMBasicTransform &other) m_opacity = other.m_opacity; } -BMBasicTransform::BMBasicTransform(const QJsonObject &definition, BMBase *parent) +BMBasicTransform::BMBasicTransform(const QJsonObject &definition, const QVersionNumber &version, + BMBase *parent) { setParent(parent); - construct(definition); + construct(definition, version); } BMBase *BMBasicTransform::clone() const @@ -34,7 +35,7 @@ BMBase *BMBasicTransform::clone() const return new BMBasicTransform(*this); } -void BMBasicTransform::construct(const QJsonObject &definition) +void BMBasicTransform::construct(const QJsonObject &definition, const QVersionNumber &version) { BMBase::parse(definition); @@ -43,38 +44,38 @@ void BMBasicTransform::construct(const QJsonObject &definition) QJsonObject anchors = definition.value(QLatin1String("a")).toObject(); anchors = resolveExpression(anchors); - m_anchorPoint.construct(anchors); + m_anchorPoint.construct(anchors, version); if (definition.value(QLatin1String("p")).toObject().contains(QLatin1String("s"))) { QJsonObject posX = definition.value(QLatin1String("p")).toObject().value(QLatin1String("x")).toObject(); posX = resolveExpression(posX); - m_xPos.construct(posX); + m_xPos.construct(posX, version); QJsonObject posY = definition.value(QLatin1String("p")).toObject().value(QLatin1String("y")).toObject(); posY = resolveExpression(posY); - m_yPos.construct(posY); + m_yPos.construct(posY, version); m_splitPosition = true; } else { QJsonObject position = definition.value(QLatin1String("p")).toObject(); position = resolveExpression(position); - m_position.construct(position); + m_position.construct(position, version); } QJsonObject scale = definition.value(QLatin1String("s")).toObject(); scale = resolveExpression(scale); - m_scale.construct(scale); + m_scale.construct(scale, version); QJsonObject rotation = definition.value(QLatin1String("r")).toObject(); rotation = resolveExpression(rotation); - m_rotation.construct(rotation); + m_rotation.construct(rotation, version); // If this is the base class for BMRepeaterTransform, // opacity is not present if (definition.contains(QLatin1String("o"))) { QJsonObject opacity = definition.value(QLatin1String("o")).toObject(); opacity = resolveExpression(opacity); - m_opacity.construct(opacity); + m_opacity.construct(opacity, version); } } diff --git a/src/bodymovin/bmbasictransform_p.h b/src/bodymovin/bmbasictransform_p.h index 819a6be..dff200d 100644 --- a/src/bodymovin/bmbasictransform_p.h +++ b/src/bodymovin/bmbasictransform_p.h @@ -30,11 +30,12 @@ class BODYMOVIN_EXPORT BMBasicTransform : public BMShape public: BMBasicTransform() = default; explicit BMBasicTransform(const BMBasicTransform &other); - BMBasicTransform(const QJsonObject &definition, BMBase *parent = nullptr); + BMBasicTransform(const QJsonObject &definition, const QVersionNumber &version, + BMBase *parent = nullptr); BMBase *clone() const override; - void construct(const QJsonObject &definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/bodymovin/bmellipse.cpp b/src/bodymovin/bmellipse.cpp index e4c2e81..983c362 100644 --- a/src/bodymovin/bmellipse.cpp +++ b/src/bodymovin/bmellipse.cpp @@ -17,10 +17,10 @@ BMEllipse::BMEllipse(const BMEllipse &other) m_size = other.m_size; } -BMEllipse::BMEllipse(const QJsonObject &definition, BMBase *parent) +BMEllipse::BMEllipse(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) { setParent(parent); - construct(definition); + construct(definition, version); } BMBase *BMEllipse::clone() const @@ -28,8 +28,7 @@ BMBase *BMEllipse::clone() const return new BMEllipse(*this); } - -void BMEllipse::construct(const QJsonObject &definition) +void BMEllipse::construct(const QJsonObject &definition, const QVersionNumber &version) { BMBase::parse(definition); if (m_hidden) @@ -39,11 +38,11 @@ void BMEllipse::construct(const QJsonObject &definition) QJsonObject position = definition.value(QLatin1String("p")).toObject(); position = resolveExpression(position); - m_position.construct(position); + m_position.construct(position, version); QJsonObject size = definition.value(QLatin1String("s")).toObject(); size = resolveExpression(size); - m_size.construct(size); + m_size.construct(size, version); m_direction = definition.value(QLatin1String("d")).toInt(); } diff --git a/src/bodymovin/bmellipse_p.h b/src/bodymovin/bmellipse_p.h index 08167b2..b4b7c47 100644 --- a/src/bodymovin/bmellipse_p.h +++ b/src/bodymovin/bmellipse_p.h @@ -36,11 +36,12 @@ class BODYMOVIN_EXPORT BMEllipse : public BMShape public: BMEllipse() = default; explicit BMEllipse(const BMEllipse &other); - BMEllipse(const QJsonObject &definition, BMBase *parent = nullptr); + BMEllipse(const QJsonObject &definition, const QVersionNumber &version, + BMBase *parent = nullptr); BMBase *clone() const override; - void construct(const QJsonObject &definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/bodymovin/bmfill.cpp b/src/bodymovin/bmfill.cpp index 071a614..df79e05 100644 --- a/src/bodymovin/bmfill.cpp +++ b/src/bodymovin/bmfill.cpp @@ -12,7 +12,7 @@ BMFill::BMFill(const BMFill &other) m_opacity = other.m_opacity; } -BMFill::BMFill(const QJsonObject &definition, BMBase *parent) +BMFill::BMFill(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) { setParent(parent); BMBase::parse(definition); @@ -22,11 +22,11 @@ BMFill::BMFill(const QJsonObject &definition, BMBase *parent) qCDebug(lcLottieQtBodymovinParser) << "BMFill::construct():" << m_name; QJsonObject color = definition.value(QLatin1String("c")).toObject(); - m_color.construct(color); + m_color.construct(color, version); QJsonObject opacity = definition.value(QLatin1String("o")).toObject(); opacity = resolveExpression(opacity); - m_opacity.construct(opacity); + m_opacity.construct(opacity, version); } BMBase *BMFill::clone() const diff --git a/src/bodymovin/bmfill_p.h b/src/bodymovin/bmfill_p.h index 67e9f27..c589e48 100644 --- a/src/bodymovin/bmfill_p.h +++ b/src/bodymovin/bmfill_p.h @@ -28,7 +28,7 @@ class BODYMOVIN_EXPORT BMFill : public BMShape public: BMFill() = default; explicit BMFill(const BMFill &other); - BMFill(const QJsonObject &definition, BMBase *parent = nullptr); + BMFill(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent = nullptr); BMBase *clone() const override; diff --git a/src/bodymovin/bmfilleffect.cpp b/src/bodymovin/bmfilleffect.cpp index 648393c..b19aba0 100644 --- a/src/bodymovin/bmfilleffect.cpp +++ b/src/bodymovin/bmfilleffect.cpp @@ -22,7 +22,7 @@ BMBase *BMFillEffect::clone() const return new BMFillEffect(*this); } -void BMFillEffect::construct(const QJsonObject &definition) +void BMFillEffect::construct(const QJsonObject &definition, const QVersionNumber &version) { m_type = BM_EFFECT_FILL; @@ -33,8 +33,8 @@ void BMFillEffect::construct(const QJsonObject &definition) // TODO: Check are property positions really fixed in the effect? - m_color.construct(properties.at(2).toObject().value(QLatin1String("v")).toObject()); - m_opacity.construct(properties.at(6).toObject().value(QLatin1String("v")).toObject()); + m_color.construct(properties.at(2).toObject().value(QLatin1String("v")).toObject(), version); + m_opacity.construct(properties.at(6).toObject().value(QLatin1String("v")).toObject(), version); if (!qFuzzyCompare(properties.at(0).toObject().value(QLatin1String("v")).toObject().value(QLatin1String("k")).toDouble(), 0.0)) qCWarning(lcLottieQtBodymovinParser)<< "BMFillEffect: Property 'Fill mask' not supported"; @@ -49,8 +49,8 @@ void BMFillEffect::construct(const QJsonObject &definition) qCWarning(lcLottieQtBodymovinParser) << "BMFillEffect: Property 'Horizontal feather' not supported"; if (!qFuzzyCompare(properties.at(5).toObject().value(QLatin1String("v")).toObject().value(QLatin1String("k")).toDouble(), 0.0)) - qCWarning(lcLottieQtBodymovinParser) << "BMFillEffect: Property 'Vertical feather' not supported"; - + qCWarning(lcLottieQtBodymovinParser) + << "BMFillEffect: Property 'Vertical feather' not supported"; } void BMFillEffect::updateProperties(int frame) diff --git a/src/bodymovin/bmfilleffect_p.h b/src/bodymovin/bmfilleffect_p.h index b71dd96..a2f5043 100644 --- a/src/bodymovin/bmfilleffect_p.h +++ b/src/bodymovin/bmfilleffect_p.h @@ -33,7 +33,7 @@ public: BMBase *clone() const override; - void construct(const QJsonObject &definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/bodymovin/bmfreeformshape.cpp b/src/bodymovin/bmfreeformshape.cpp index 0cfd83b..ded4e92 100644 --- a/src/bodymovin/bmfreeformshape.cpp +++ b/src/bodymovin/bmfreeformshape.cpp @@ -19,10 +19,11 @@ BMFreeFormShape::BMFreeFormShape(const BMFreeFormShape &other) m_vertexMap = other.m_vertexMap; } -BMFreeFormShape::BMFreeFormShape(const QJsonObject &definition, BMBase *parent) +BMFreeFormShape::BMFreeFormShape(const QJsonObject &definition, const QVersionNumber &version, + BMBase *parent) { setParent(parent); - construct(definition); + construct(definition, version); } BMBase *BMFreeFormShape::clone() const @@ -30,9 +31,10 @@ BMBase *BMFreeFormShape::clone() const return new BMFreeFormShape(*this); } -void BMFreeFormShape::construct(const QJsonObject &definition) +void BMFreeFormShape::construct(const QJsonObject &definition, const QVersionNumber &version) { BMBase::parse(definition); + m_version = version; if (m_hidden) return; @@ -289,9 +291,9 @@ void BMFreeFormShape::finalizeVertices() coObj.insert(QLatin1String("k"), m_vertexInfos.value(i)->coKeyframes); VertexInfo vertexInfo; - vertexInfo.pos.construct(posObj); - vertexInfo.ci.construct(ciObj); - vertexInfo.co.construct(coObj); + vertexInfo.pos.construct(posObj, m_version); + vertexInfo.ci.construct(ciObj, m_version); + vertexInfo.co.construct(coObj, m_version); m_vertexList.push_back(vertexInfo); } qDeleteAll(m_vertexInfos); diff --git a/src/bodymovin/bmfreeformshape_p.h b/src/bodymovin/bmfreeformshape_p.h index 220e1b2..b46d3f7 100644 --- a/src/bodymovin/bmfreeformshape_p.h +++ b/src/bodymovin/bmfreeformshape_p.h @@ -35,11 +35,12 @@ class BODYMOVIN_EXPORT BMFreeFormShape : public BMShape public: BMFreeFormShape(); explicit BMFreeFormShape(const BMFreeFormShape &other); - BMFreeFormShape(const QJsonObject &definition, BMBase *parent = nullptr); + BMFreeFormShape(const QJsonObject &definition, const QVersionNumber &version, + BMBase *parent = nullptr); BMBase *clone() const override; - void construct(const QJsonObject &definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/bodymovin/bmgfill.cpp b/src/bodymovin/bmgfill.cpp index b2c109d..84e8f37 100644 --- a/src/bodymovin/bmgfill.cpp +++ b/src/bodymovin/bmgfill.cpp @@ -42,7 +42,7 @@ BMBase *BMGFill::clone() const return new BMGFill(*this); } -BMGFill::BMGFill(const QJsonObject &definition, BMBase *parent) +BMGFill::BMGFill(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) { setParent(parent); @@ -82,22 +82,22 @@ BMGFill::BMGFill(const QJsonObject &definition, BMBase *parent) QJsonObject opacity = definition.value(QLatin1String("o")).toObject(); opacity = resolveExpression(opacity); - m_opacity.construct(opacity); + m_opacity.construct(opacity, version); QJsonObject startPoint = definition.value(QLatin1String("s")).toObject(); startPoint = resolveExpression(startPoint); - m_startPoint.construct(startPoint); + m_startPoint.construct(startPoint, version); QJsonObject endPoint = definition.value(QLatin1String("e")).toObject(); endPoint = resolveExpression(endPoint); - m_endPoint.construct(endPoint); + m_endPoint.construct(endPoint, version); QJsonObject highlight = definition.value(QLatin1String("h")).toObject(); - m_highlightLength.construct(highlight); + m_highlightLength.construct(highlight, version); QJsonObject angle = definition.value(QLatin1String("a")).toObject(); angle = resolveExpression(angle); - m_highlightAngle.construct(angle); + m_highlightAngle.construct(angle, version); m_highlightAngle.setValue(0.0); } diff --git a/src/bodymovin/bmgfill_p.h b/src/bodymovin/bmgfill_p.h index 532673b..2d162b8 100644 --- a/src/bodymovin/bmgfill_p.h +++ b/src/bodymovin/bmgfill_p.h @@ -30,7 +30,7 @@ class BODYMOVIN_EXPORT BMGFill : public BMShape public: BMGFill() = default; explicit BMGFill(const BMGFill &other); - BMGFill(const QJsonObject &definition, BMBase *parent = nullptr); + BMGFill(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent = nullptr); ~BMGFill() override; BMBase *clone() const override; diff --git a/src/bodymovin/bmgroup.cpp b/src/bodymovin/bmgroup.cpp index a51ae62..a8ce2bf 100644 --- a/src/bodymovin/bmgroup.cpp +++ b/src/bodymovin/bmgroup.cpp @@ -13,10 +13,10 @@ QT_BEGIN_NAMESPACE -BMGroup::BMGroup(const QJsonObject &definition, BMBase *parent) +BMGroup::BMGroup(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) { setParent(parent); - construct(definition); + construct(definition, version); } BMBase *BMGroup::clone() const @@ -24,7 +24,7 @@ BMBase *BMGroup::clone() const return new BMGroup(*this); } -void BMGroup::construct(const QJsonObject &definition) +void BMGroup::construct(const QJsonObject &definition, const QVersionNumber &version) { BMBase::parse(definition); if (m_hidden) @@ -37,7 +37,7 @@ void BMGroup::construct(const QJsonObject &definition) QJsonArray::const_iterator itemIt = groupItems.constEnd(); while (itemIt != groupItems.constBegin()) { itemIt--; - BMShape *shape = BMShape::construct((*itemIt).toObject(), this); + BMShape *shape = BMShape::construct((*itemIt).toObject(), version, this); if (shape) { // Transform affects how group contents are drawn. // It must be traversed first when drawing diff --git a/src/bodymovin/bmgroup_p.h b/src/bodymovin/bmgroup_p.h index cc565cf..b08b46d 100644 --- a/src/bodymovin/bmgroup_p.h +++ b/src/bodymovin/bmgroup_p.h @@ -32,11 +32,11 @@ class BODYMOVIN_EXPORT BMGroup : public BMShape { public: BMGroup() = default; - BMGroup(const QJsonObject &definition, BMBase *parent = nullptr); + BMGroup(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent = nullptr); BMBase *clone() const override; - void construct(const QJsonObject& definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/bodymovin/bmimage.cpp b/src/bodymovin/bmimage.cpp index 3b0f19c..124a1a8 100644 --- a/src/bodymovin/bmimage.cpp +++ b/src/bodymovin/bmimage.cpp @@ -19,10 +19,10 @@ BMImage::BMImage(const BMImage &other) m_image = other.m_image; } -BMImage::BMImage(const QJsonObject &definition, BMBase *parent) +BMImage::BMImage(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) { setParent(parent); - construct(definition); + construct(definition, version); } BMBase *BMImage::clone() const @@ -30,7 +30,7 @@ BMBase *BMImage::clone() const return new BMImage(*this); } -void BMImage::construct(const QJsonObject &definition) +void BMImage::construct(const QJsonObject &definition, const QVersionNumber &version) { BMBase::parse(definition); if (m_hidden) @@ -60,11 +60,11 @@ void BMImage::construct(const QJsonObject &definition) QJsonObject position = definition.value(QLatin1String("p")).toObject(); position = resolveExpression(position); - m_position.construct(position); + m_position.construct(position, version); QJsonObject radius = definition.value(QLatin1String("r")).toObject(); radius = resolveExpression(radius); - m_radius.construct(radius); + m_radius.construct(radius, version); } void BMImage::updateProperties(int frame) diff --git a/src/bodymovin/bmimage_p.h b/src/bodymovin/bmimage_p.h index 20d4a57..d04c8b2 100644 --- a/src/bodymovin/bmimage_p.h +++ b/src/bodymovin/bmimage_p.h @@ -30,11 +30,11 @@ class BODYMOVIN_EXPORT BMImage : public BMBase public: BMImage() = default; explicit BMImage(const BMImage &other); - BMImage(const QJsonObject &definition, BMBase *parent = nullptr); + BMImage(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent = nullptr); BMBase *clone() const override; - void construct(const QJsonObject &definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/bodymovin/bmimagelayer.cpp b/src/bodymovin/bmimagelayer.cpp index 8090132..cd675c9 100644 --- a/src/bodymovin/bmimagelayer.cpp +++ b/src/bodymovin/bmimagelayer.cpp @@ -24,13 +24,14 @@ BMImageLayer::BMImageLayer(const BMImageLayer &other) m_appliedTrim = other.m_appliedTrim; } -BMImageLayer::BMImageLayer(const QJsonObject &definition) +BMImageLayer::BMImageLayer(const QJsonObject &definition, const QVersionNumber &version) { m_type = BM_LAYER_IMAGE_IX; + m_version = version; BMLayer::parse(definition); - BMImage *image = new BMImage(definition, this); + BMImage *image = new BMImage(definition, version, this); appendChild(image); if (m_hidden) @@ -47,13 +48,13 @@ BMImageLayer::BMImageLayer(const QJsonObject &definition) } QJsonObject trans = definition.value(QLatin1String("ks")).toObject(); - m_layerTransform = new BMBasicTransform(trans, this); + m_layerTransform = new BMBasicTransform(trans, version, this); QJsonArray items = definition.value(QLatin1String("shapes")).toArray(); QJsonArray::const_iterator itemIt = items.constEnd(); while (itemIt != items.constBegin()) { itemIt--; - BMShape *shape = BMShape::construct((*itemIt).toObject(), this); + BMShape *shape = BMShape::construct((*itemIt).toObject(), version, this); if (shape) appendChild(shape); } diff --git a/src/bodymovin/bmimagelayer_p.h b/src/bodymovin/bmimagelayer_p.h index 8f935a8..332f9ca 100644 --- a/src/bodymovin/bmimagelayer_p.h +++ b/src/bodymovin/bmimagelayer_p.h @@ -31,7 +31,7 @@ class BODYMOVIN_EXPORT BMImageLayer : public BMLayer public: BMImageLayer() = default; explicit BMImageLayer(const BMImageLayer &other); - BMImageLayer(const QJsonObject &definition); + BMImageLayer(const QJsonObject &definition, const QVersionNumber &version); ~BMImageLayer() override; BMBase *clone() const override; diff --git a/src/bodymovin/bmlayer.cpp b/src/bodymovin/bmlayer.cpp index 533f3e7..4b3a7cc 100644 --- a/src/bodymovin/bmlayer.cpp +++ b/src/bodymovin/bmlayer.cpp @@ -47,7 +47,7 @@ BMBase *BMLayer::clone() const return new BMLayer(*this); } -BMLayer *BMLayer::construct(QJsonObject definition) +BMLayer *BMLayer::construct(QJsonObject definition, const QVersionNumber &version) { qCDebug(lcLottieQtBodymovinParser) << "BMLayer::construct()"; @@ -56,11 +56,11 @@ BMLayer *BMLayer::construct(QJsonObject definition) switch (type) { case 2: qCDebug(lcLottieQtBodymovinParser) << "Parse image layer"; - layer = new BMImageLayer(definition); + layer = new BMImageLayer(definition, version); break; case 4: qCDebug(lcLottieQtBodymovinParser) << "Parse shape layer"; - layer = new BMShapeLayer(definition); + layer = new BMShapeLayer(definition, version); break; default: qCWarning(lcLottieQtBodymovinParser) << "Unsupported layer type:" << type; @@ -244,7 +244,7 @@ void BMLayer::parseEffects(const QJsonArray &definition, BMBase *effectRoot) case 21: { BMFillEffect *fill = new BMFillEffect; - fill->construct(effect); + fill->construct(effect, m_version); effectRoot->appendChild(fill); break; } diff --git a/src/bodymovin/bmlayer_p.h b/src/bodymovin/bmlayer_p.h index 92311bb..d32e04e 100644 --- a/src/bodymovin/bmlayer_p.h +++ b/src/bodymovin/bmlayer_p.h @@ -32,11 +32,11 @@ public: BMBase *clone() const override; - static BMLayer *construct(QJsonObject definition); + static BMLayer *construct(QJsonObject definition, const QVersionNumber &version); bool active(int frame) const override; - void parse(const QJsonObject &definition) override; + void parse(const QJsonObject &definition) override; void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/bodymovin/bmproperty_p.h b/src/bodymovin/bmproperty_p.h index 89acd77..04adeb3 100644 --- a/src/bodymovin/bmproperty_p.h +++ b/src/bodymovin/bmproperty_p.h @@ -49,7 +49,7 @@ class BODYMOVIN_EXPORT BMProperty public: virtual ~BMProperty() = default; - virtual void construct(const QJsonObject &definition) + virtual void construct(const QJsonObject &definition, const QVersionNumber &version) { if (definition.value(QLatin1String("s")).toVariant().toInt()) qCWarning(lcLottieQtBodymovinParser) @@ -60,11 +60,25 @@ public: if (m_animated) { QJsonArray keyframes = definition.value(QLatin1String("k")).toArray(); QJsonArray::const_iterator it = keyframes.constBegin(); - while (it != keyframes.constEnd()) { - EasingSegment<T> easing = parseKeyframe((*it).toObject(), - fromExpression); - addEasing(easing); - ++it; + + bool schemaChanged = (version >= QVersionNumber(5, 5, 0)); + + if (!schemaChanged) { + while (it != keyframes.constEnd()) { + EasingSegment<T> easing = parseKeyframe((*it).toObject(), fromExpression); + addEasing(easing); + ++it; + } + } else { + while (it != (keyframes.constEnd() - 1)) { + EasingSegment<T> easing = + parseKeyframe((*it).toObject(), (*(it + 1)).toObject(), fromExpression); + addEasing(easing); + ++it; + } + int lastFrame = (*it).toObject().value(QLatin1String("t")).toVariant().toInt(); + m_easingCurves.last().endFrame = lastFrame; + this->m_endFrame = lastFrame; } m_value = T(); } else @@ -138,8 +152,7 @@ protected: return m_currentEasing; } - virtual EasingSegment<T> parseKeyframe(const QJsonObject keyframe, - bool fromExpression) + virtual EasingSegment<T> parseKeyframe(const QJsonObject keyframe, bool fromExpression) { Q_UNUSED(fromExpression); @@ -155,7 +168,7 @@ protected: this->m_endFrame = startTime; easing.startFrame = startTime; easing.endFrame = startTime; - if (m_easingCurves.size()) { + if (m_easingCurves.length()) { easing.startValue = m_easingCurves.last().endValue; easing.endValue = m_easingCurves.last().endValue; } @@ -188,6 +201,41 @@ protected: return easing; } + virtual EasingSegment<T> parseKeyframe(const QJsonObject keyframe, + const QJsonObject nextKeyframe, bool fromExpression) + { + Q_UNUSED(fromExpression); + + EasingSegment<T> easing; + + int startTime = keyframe.value(QLatin1String("t")).toVariant().toInt(); + + if (m_startFrame > startTime) + m_startFrame = startTime; + + easing.startValue = getValue(keyframe.value(QLatin1String("s")).toArray()); + easing.endValue = getValue(nextKeyframe.value(QLatin1String("s")).toArray()); + easing.startFrame = startTime; + + QJsonObject easingIn = keyframe.value(QLatin1String("i")).toObject(); + QJsonObject easingOut = keyframe.value(QLatin1String("o")).toObject(); + + qreal eix = easingIn.value(QLatin1String("x")).toArray().at(0).toDouble(); + qreal eiy = easingIn.value(QLatin1String("y")).toArray().at(0).toDouble(); + + qreal eox = easingOut.value(QLatin1String("x")).toArray().at(0).toDouble(); + qreal eoy = easingOut.value(QLatin1String("y")).toArray().at(0).toDouble(); + + QPointF c1 = QPointF(eox, eoy); + QPointF c2 = QPointF(eix, eiy); + + easing.easing.addCubicBezierSegment(c1, c2, QPointF(1.0, 1.0)); + + easing.complete = true; + + return easing; + } + virtual T getValue(const QJsonValue &value) { if (value.isArray()) @@ -237,8 +285,7 @@ protected: return T(); } - EasingSegment<T> parseKeyframe(const QJsonObject keyframe, - bool fromExpression) override + EasingSegment<T> parseKeyframe(const QJsonObject keyframe, bool fromExpression) override { QJsonArray startValues = keyframe.value(QLatin1String("s")).toArray(); QJsonArray endValues = keyframe.value(QLatin1String("e")).toArray(); @@ -255,7 +302,7 @@ protected: this->m_endFrame = startTime; easingCurve.startFrame = startTime; easingCurve.endFrame = startTime; - if (this->m_easingCurves.size()) { + if (this->m_easingCurves.length()) { easingCurve.startValue = this->m_easingCurves.last().endValue; easingCurve.endValue = this->m_easingCurves.last().endValue; } @@ -300,6 +347,79 @@ protected: qreal eix = eixArr.takeAt(0).toDouble(); qreal eiy = eiyArr.takeAt(0).toDouble(); + qreal eox = eoxArr.takeAt(0).toDouble(); + qreal eoy = eoyArr.takeAt(0).toDouble(); + + QPointF c1 = QPointF(eox, eoy); + QPointF c2 = QPointF(eix, eiy); + + easingCurve.easing.addCubicBezierSegment(c1, c2, QPointF(1.0, 1.0)); + } + } else { + qreal eix = easingIn.value(QLatin1String("x")).toDouble(); + qreal eiy = easingIn.value(QLatin1String("y")).toDouble(); + + qreal eox = easingOut.value(QLatin1String("x")).toDouble(); + qreal eoy = easingOut.value(QLatin1String("y")).toDouble(); + + QPointF c1 = QPointF(eox, eoy); + QPointF c2 = QPointF(eix, eiy); + + easingCurve.easing.addCubicBezierSegment(c1, c2, QPointF(1.0, 1.0)); + } + + easingCurve.complete = true; + return easingCurve; + } + + EasingSegment<T> parseKeyframe(const QJsonObject keyframe, const QJsonObject nextKeyframe, + bool fromExpression) override + { + QJsonArray startValues = keyframe.value(QLatin1String("s")).toArray(); + QJsonArray endValues = nextKeyframe.value(QLatin1String("s")).toArray(); + int startTime = keyframe.value(QLatin1String("t")).toVariant().toInt(); + + EasingSegment<T> easingCurve; + easingCurve.startFrame = startTime; + + if (this->m_startFrame > startTime) + this->m_startFrame = startTime; + + qreal xs, ys, xe, ye; + // Keyframes originating from an expression use only scalar values. + // They must be expanded for both x and y coordinates + if (fromExpression) { + xs = startValues.at(0).toDouble(); + ys = startValues.at(0).toDouble(); + xe = endValues.at(0).toDouble(); + ye = endValues.at(0).toDouble(); + } else { + xs = startValues.at(0).toDouble(); + ys = startValues.at(1).toDouble(); + xe = endValues.at(0).toDouble(); + ye = endValues.at(1).toDouble(); + } + T s(xs, ys); + T e(xe, ye); + + QJsonObject easingIn = keyframe.value(QLatin1String("i")).toObject(); + QJsonObject easingOut = keyframe.value(QLatin1String("o")).toObject(); + + easingCurve.startFrame = startTime; + easingCurve.startValue = s; + easingCurve.endValue = e; + + if (easingIn.value(QLatin1String("x")).isArray()) { + QJsonArray eixArr = easingIn.value(QLatin1String("x")).toArray(); + QJsonArray eiyArr = easingIn.value(QLatin1String("y")).toArray(); + + QJsonArray eoxArr = easingOut.value(QLatin1String("x")).toArray(); + QJsonArray eoyArr = easingOut.value(QLatin1String("y")).toArray(); + + while (!eixArr.isEmpty() && !eiyArr.isEmpty()) { + qreal eix = eixArr.takeAt(0).toDouble(); + qreal eiy = eiyArr.takeAt(0).toDouble(); + qreal eox =eoxArr.takeAt(0).toDouble(); qreal eoy = eoyArr.takeAt(0).toDouble(); diff --git a/src/bodymovin/bmrect.cpp b/src/bodymovin/bmrect.cpp index 0deed01..754c5b8 100644 --- a/src/bodymovin/bmrect.cpp +++ b/src/bodymovin/bmrect.cpp @@ -21,7 +21,7 @@ BMRect::BMRect(const BMRect &other) m_roundness = other.m_roundness; } -BMRect::BMRect(const QJsonObject &definition, BMBase *parent) +BMRect::BMRect(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) { setParent(parent); BMBase::parse(definition); @@ -32,15 +32,15 @@ BMRect::BMRect(const QJsonObject &definition, BMBase *parent) QJsonObject position = definition.value(QLatin1String("p")).toObject(); position = resolveExpression(position); - m_position.construct(position); + m_position.construct(position, version); QJsonObject size = definition.value(QLatin1String("s")).toObject(); size = resolveExpression(size); - m_size.construct(size); + m_size.construct(size, version); QJsonObject roundness = definition.value(QLatin1String("r")).toObject(); roundness = resolveExpression(roundness); - m_roundness.construct(roundness); + m_roundness.construct(roundness, version); m_direction = definition.value(QLatin1String("d")).toInt(); } diff --git a/src/bodymovin/bmrect_p.h b/src/bodymovin/bmrect_p.h index 4a77485..6b32e31 100644 --- a/src/bodymovin/bmrect_p.h +++ b/src/bodymovin/bmrect_p.h @@ -33,11 +33,11 @@ class BODYMOVIN_EXPORT BMRect : public BMShape public: BMRect() = default; explicit BMRect(const BMRect &other); - BMRect(const QJsonObject &definition, BMBase *parent = nullptr); + BMRect(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent = nullptr); BMBase *clone() const override; - void construct(const QJsonObject &definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); bool setProperty(BMLiteral::PropertyType propertyType, QVariant value) override; diff --git a/src/bodymovin/bmrepeater.cpp b/src/bodymovin/bmrepeater.cpp index 087702b..da47ab0 100644 --- a/src/bodymovin/bmrepeater.cpp +++ b/src/bodymovin/bmrepeater.cpp @@ -3,11 +3,11 @@ #include "bmrepeater_p.h" -BMRepeater::BMRepeater(const QJsonObject &definition, BMBase *parent) +BMRepeater::BMRepeater(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) { setParent(parent); m_transform.setParent(this); - construct(definition); + construct(definition, version); } BMBase *BMRepeater::clone() const @@ -15,7 +15,7 @@ BMBase *BMRepeater::clone() const return new BMRepeater(*this); } -void BMRepeater::construct(const QJsonObject &definition) +void BMRepeater::construct(const QJsonObject &definition, const QVersionNumber &version) { qCDebug(lcLottieQtBodymovinParser) << "BMRepeater::construct():" << m_name; @@ -25,13 +25,13 @@ void BMRepeater::construct(const QJsonObject &definition) QJsonObject copies = definition.value(QLatin1String("c")).toObject(); copies = resolveExpression(copies); - m_copies.construct(copies); + m_copies.construct(copies, version); QJsonObject offset = definition.value(QLatin1String("o")).toObject(); offset = resolveExpression(offset); - m_offset.construct(offset); + m_offset.construct(offset, version); - m_transform.construct(definition.value(QLatin1String("tr")).toObject()); + m_transform.construct(definition.value(QLatin1String("tr")).toObject(), version); } void BMRepeater::updateProperties(int frame) diff --git a/src/bodymovin/bmrepeater_p.h b/src/bodymovin/bmrepeater_p.h index f30cb37..52b4ad3 100644 --- a/src/bodymovin/bmrepeater_p.h +++ b/src/bodymovin/bmrepeater_p.h @@ -29,11 +29,12 @@ class BODYMOVIN_EXPORT BMRepeater : public BMShape public: BMRepeater() = default; explicit BMRepeater(const BMRepeater &other) = default; - BMRepeater(const QJsonObject &definition, BMBase *parent = nullptr); + BMRepeater(const QJsonObject &definition, const QVersionNumber &version, + BMBase *parent = nullptr); BMBase *clone() const override; - void construct(const QJsonObject& definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/bodymovin/bmrepeatertransform.cpp b/src/bodymovin/bmrepeatertransform.cpp index 344427d..f6c137c 100644 --- a/src/bodymovin/bmrepeatertransform.cpp +++ b/src/bodymovin/bmrepeatertransform.cpp @@ -13,10 +13,11 @@ BMRepeaterTransform::BMRepeaterTransform(const BMRepeaterTransform &other) m_opacities = other.m_opacities; } -BMRepeaterTransform::BMRepeaterTransform(const QJsonObject &definition, BMBase *parent) +BMRepeaterTransform::BMRepeaterTransform(const QJsonObject &definition, + const QVersionNumber &version, BMBase *parent) { setParent(parent); - construct(definition); + construct(definition, version); } BMBase *BMRepeaterTransform::clone() const @@ -24,21 +25,21 @@ BMBase *BMRepeaterTransform::clone() const return new BMRepeaterTransform(*this); } -void BMRepeaterTransform::construct(const QJsonObject &definition) +void BMRepeaterTransform::construct(const QJsonObject &definition, const QVersionNumber &version) { qCDebug(lcLottieQtBodymovinParser) << "BMRepeaterTransform::construct():" << name(); - BMBasicTransform::construct(definition); + BMBasicTransform::construct(definition, version); if (m_hidden) return; QJsonObject startOpacity = definition.value(QLatin1String("so")).toObject(); startOpacity = resolveExpression(startOpacity); - m_startOpacity.construct(startOpacity); + m_startOpacity.construct(startOpacity, version); QJsonObject endOpacity = definition.value(QLatin1String("eo")).toObject(); endOpacity = resolveExpression(endOpacity); - m_endOpacity.construct(endOpacity); + m_endOpacity.construct(endOpacity, version); } void BMRepeaterTransform::updateProperties(int frame) diff --git a/src/bodymovin/bmrepeatertransform_p.h b/src/bodymovin/bmrepeatertransform_p.h index 1d29768..456e32c 100644 --- a/src/bodymovin/bmrepeatertransform_p.h +++ b/src/bodymovin/bmrepeatertransform_p.h @@ -26,11 +26,12 @@ class BODYMOVIN_EXPORT BMRepeaterTransform : public BMBasicTransform public: BMRepeaterTransform() = default; explicit BMRepeaterTransform(const BMRepeaterTransform &other); - BMRepeaterTransform(const QJsonObject &definition, BMBase *parent); + BMRepeaterTransform(const QJsonObject &definition, const QVersionNumber &version, + BMBase *parent); BMBase *clone() const override; - void construct(const QJsonObject &definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/bodymovin/bmround.cpp b/src/bodymovin/bmround.cpp index 3e6a5ec..46bb860 100644 --- a/src/bodymovin/bmround.cpp +++ b/src/bodymovin/bmround.cpp @@ -16,10 +16,10 @@ BMRound::BMRound(const BMRound &other) m_radius = other.m_radius; } -BMRound::BMRound(const QJsonObject &definition, BMBase *parent) +BMRound::BMRound(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) { setParent(parent); - construct(definition); + construct(definition, version); } BMBase *BMRound::clone() const @@ -27,7 +27,7 @@ BMBase *BMRound::clone() const return new BMRound(*this); } -void BMRound::construct(const QJsonObject &definition) +void BMRound::construct(const QJsonObject &definition, const QVersionNumber &version) { BMBase::parse(definition); if (m_hidden) @@ -37,11 +37,11 @@ void BMRound::construct(const QJsonObject &definition) QJsonObject position = definition.value(QLatin1String("p")).toObject(); position = resolveExpression(position); - m_position.construct(position); + m_position.construct(position, version); QJsonObject radius = definition.value(QLatin1String("r")).toObject(); radius = resolveExpression(radius); - m_radius.construct(radius); + m_radius.construct(radius, version); } void BMRound::updateProperties(int frame) diff --git a/src/bodymovin/bmround_p.h b/src/bodymovin/bmround_p.h index 952d7c8..8ebe9a3 100644 --- a/src/bodymovin/bmround_p.h +++ b/src/bodymovin/bmround_p.h @@ -35,11 +35,11 @@ class BODYMOVIN_EXPORT BMRound : public BMShape public: BMRound() = default; explicit BMRound(const BMRound &other); - BMRound(const QJsonObject &definition, BMBase *parent = nullptr); + BMRound(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent = nullptr); BMBase *clone() const override; - void construct(const QJsonObject &definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/bodymovin/bmshape.cpp b/src/bodymovin/bmshape.cpp index a81a46e..4e9014d 100644 --- a/src/bodymovin/bmshape.cpp +++ b/src/bodymovin/bmshape.cpp @@ -35,7 +35,7 @@ BMBase *BMShape::clone() const return new BMShape(*this); } -BMShape *BMShape::construct(QJsonObject definition, BMBase *parent) +BMShape *BMShape::construct(QJsonObject definition, const QVersionNumber &version, BMBase *parent) { qCDebug(lcLottieQtBodymovinParser) << "BMShape::construct()"; @@ -56,77 +56,77 @@ BMShape *BMShape::construct(QJsonObject definition, BMBase *parent) case BM_SHAPE_TAG('g', 'r'): { qCDebug(lcLottieQtBodymovinParser) << "Parse group"; - shape = new BMGroup(definition, parent); + shape = new BMGroup(definition, version, parent); shape->setType(BM_SHAPE_GROUP_IX); break; } case BM_SHAPE_TAG('r', 'c'): { qCDebug(lcLottieQtBodymovinParser) << "Parse m_rect"; - shape = new BMRect(definition, parent); + shape = new BMRect(definition, version, parent); shape->setType(BM_SHAPE_RECT_IX); break; } case BM_SHAPE_TAG('f', 'l'): { qCDebug(lcLottieQtBodymovinParser) << "Parse fill"; - shape = new BMFill(definition, parent); + shape = new BMFill(definition, version, parent); shape->setType(BM_SHAPE_FILL_IX); break; } case BM_SHAPE_TAG('g', 'f'): { qCDebug(lcLottieQtBodymovinParser) << "Parse group fill"; - shape = new BMGFill(definition, parent); + shape = new BMGFill(definition, version, parent); shape->setType(BM_SHAPE_GFILL_IX); break; } case BM_SHAPE_TAG('s', 't'): { qCDebug(lcLottieQtBodymovinParser) << "Parse stroke"; - shape = new BMStroke(definition, parent); + shape = new BMStroke(definition, version, parent); shape->setType(BM_SHAPE_STROKE_IX); break; } case BM_SHAPE_TAG('t', 'r'): { qCDebug(lcLottieQtBodymovinParser) << "Parse shape transform"; - shape = new BMShapeTransform(definition, parent); + shape = new BMShapeTransform(definition, version, parent); shape->setType(BM_SHAPE_TRANS_IX); break; } case BM_SHAPE_TAG('e', 'l'): { qCDebug(lcLottieQtBodymovinParser) << "Parse ellipse"; - shape = new BMEllipse(definition, parent); + shape = new BMEllipse(definition, version, parent); shape->setType(BM_SHAPE_ELLIPSE_IX); break; } case BM_SHAPE_TAG('r', 'd'): { qCDebug(lcLottieQtBodymovinParser) << "Parse round"; - shape = new BMRound(definition, parent); + shape = new BMRound(definition, version, parent); shape->setType(BM_SHAPE_ROUND_IX); break; } case BM_SHAPE_TAG('s', 'h'): { qCDebug(lcLottieQtBodymovinParser) << "Parse shape"; - shape = new BMFreeFormShape(definition, parent); + shape = new BMFreeFormShape(definition, version, parent); shape->setType(BM_SHAPE_SHAPE_IX); break; } case BM_SHAPE_TAG('t', 'm'): { qCDebug(lcLottieQtBodymovinParser) << "Parse trim path"; - shape = new BMTrimPath(definition, parent); + shape = new BMTrimPath(definition, version, parent); shape->setType(BM_SHAPE_TRIM_IX); break; } case BM_SHAPE_TAG('r', 'p'): { qCDebug(lcLottieQtBodymovinParser) << "Parse trim path"; - shape = new BMRepeater(definition, parent); + shape = new BMRepeater(definition, version, parent); shape->setType(BM_SHAPE_REPEATER_IX); break; } diff --git a/src/bodymovin/bmshape_p.h b/src/bodymovin/bmshape_p.h index 698dc59..a41bb18 100644 --- a/src/bodymovin/bmshape_p.h +++ b/src/bodymovin/bmshape_p.h @@ -49,7 +49,8 @@ public: BMBase *clone() const override; - static BMShape *construct(QJsonObject definition, BMBase *parent = nullptr); + static BMShape *construct(QJsonObject definition, const QVersionNumber &version, + BMBase *parent = nullptr); virtual const QPainterPath &path() const; virtual bool acceptsTrim() const; diff --git a/src/bodymovin/bmshapelayer.cpp b/src/bodymovin/bmshapelayer.cpp index 71d7e42..a753d2e 100644 --- a/src/bodymovin/bmshapelayer.cpp +++ b/src/bodymovin/bmshapelayer.cpp @@ -25,9 +25,10 @@ BMShapeLayer::BMShapeLayer(const BMShapeLayer &other) m_appliedTrim = other.m_appliedTrim; } -BMShapeLayer::BMShapeLayer(const QJsonObject &definition) +BMShapeLayer::BMShapeLayer(const QJsonObject &definition, const QVersionNumber &version) { m_type = BM_LAYER_SHAPE_IX; + m_version = version; BMLayer::parse(definition); if (m_hidden) @@ -44,13 +45,13 @@ BMShapeLayer::BMShapeLayer(const QJsonObject &definition) } QJsonObject trans = definition.value(QLatin1String("ks")).toObject(); - m_layerTransform = new BMBasicTransform(trans, this); + m_layerTransform = new BMBasicTransform(trans, version, this); QJsonArray items = definition.value(QLatin1String("shapes")).toArray(); QJsonArray::const_iterator itemIt = items.constEnd(); while (itemIt != items.constBegin()) { itemIt--; - BMShape *shape = BMShape::construct((*itemIt).toObject(), this); + BMShape *shape = BMShape::construct((*itemIt).toObject(), version, this); if (shape) appendChild(shape); } diff --git a/src/bodymovin/bmshapelayer_p.h b/src/bodymovin/bmshapelayer_p.h index e905b6b..c23535f 100644 --- a/src/bodymovin/bmshapelayer_p.h +++ b/src/bodymovin/bmshapelayer_p.h @@ -31,7 +31,7 @@ class BODYMOVIN_EXPORT BMShapeLayer : public BMLayer public: BMShapeLayer() = default; explicit BMShapeLayer(const BMShapeLayer &other); - BMShapeLayer(const QJsonObject &definition); + BMShapeLayer(const QJsonObject &definition, const QVersionNumber &version); ~BMShapeLayer() override; BMBase *clone() const override; diff --git a/src/bodymovin/bmshapetransform.cpp b/src/bodymovin/bmshapetransform.cpp index 3370a0e..b5cb523 100644 --- a/src/bodymovin/bmshapetransform.cpp +++ b/src/bodymovin/bmshapetransform.cpp @@ -19,10 +19,11 @@ BMShapeTransform::BMShapeTransform(const BMShapeTransform &other) m_shearAngle = other.m_shearAngle; } -BMShapeTransform::BMShapeTransform(const QJsonObject &definition, BMBase *parent) +BMShapeTransform::BMShapeTransform(const QJsonObject &definition, const QVersionNumber &version, + BMBase *parent) { setParent(parent); - construct(definition); + construct(definition, version); } BMBase *BMShapeTransform::clone() const @@ -30,19 +31,19 @@ BMBase *BMShapeTransform::clone() const return new BMShapeTransform(*this); } -void BMShapeTransform::construct(const QJsonObject &definition) +void BMShapeTransform::construct(const QJsonObject &definition, const QVersionNumber &version) { - BMBasicTransform::construct(definition); + BMBasicTransform::construct(definition, version); qCDebug(lcLottieQtBodymovinParser) << "BMShapeTransform::construct():" << BMShape::name(); QJsonObject skew = definition.value(QLatin1String("sk")).toObject(); skew = resolveExpression(skew); - m_skew.construct(skew); + m_skew.construct(skew, version); QJsonObject skewAxis = definition.value(QLatin1String("sa")).toObject(); skewAxis = resolveExpression(skewAxis); - m_skewAxis.construct(skewAxis); + m_skewAxis.construct(skewAxis, version); } void BMShapeTransform::updateProperties(int frame) diff --git a/src/bodymovin/bmshapetransform_p.h b/src/bodymovin/bmshapetransform_p.h index b0c52d2..9b9d120 100644 --- a/src/bodymovin/bmshapetransform_p.h +++ b/src/bodymovin/bmshapetransform_p.h @@ -29,11 +29,11 @@ class BODYMOVIN_EXPORT BMShapeTransform : public BMBasicTransform { public: explicit BMShapeTransform(const BMShapeTransform &other); - BMShapeTransform(const QJsonObject &definition, BMBase *parent); + BMShapeTransform(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent); BMBase *clone() const override; - void construct(const QJsonObject &definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/bodymovin/bmspatialproperty_p.h b/src/bodymovin/bmspatialproperty_p.h index e857720..7d2432b 100644 --- a/src/bodymovin/bmspatialproperty_p.h +++ b/src/bodymovin/bmspatialproperty_p.h @@ -25,15 +25,68 @@ QT_BEGIN_NAMESPACE class BMSpatialProperty : public BMProperty2D<QPointF> { public: - virtual void construct(const QJsonObject &definition) override + virtual void construct(const QJsonObject &definition, const QVersionNumber &version) override { qCDebug(lcLottieQtBodymovinParser) << "BMSpatialProperty::construct()"; - BMProperty2D<QPointF>::construct(definition); + BMProperty2D<QPointF>::construct(definition, version); } - virtual EasingSegment<QPointF> parseKeyframe(const QJsonObject keyframe, bool fromExpression) override + virtual EasingSegment<QPointF> parseKeyframe(const QJsonObject keyframe, + bool fromExpression) override { - EasingSegment<QPointF> easing = BMProperty2D<QPointF>::parseKeyframe(keyframe, fromExpression); + EasingSegment<QPointF> easing = + BMProperty2D<QPointF>::parseKeyframe(keyframe, fromExpression); + + // No need to parse further incomplete keyframes (i.e. last keyframes) + if (!easing.complete) { + return easing; + } + + qreal tix = 0, tiy = 0, tox = 0, toy = 0; + if (fromExpression) { + // If spatial property definition originates from + // an expression (specifically Slider), it contains scalar + // property. It must be expanded to both x and y coordinates + QJsonArray iArr = keyframe.value(QLatin1String("i")).toArray(); + QJsonArray oArr = keyframe.value(QLatin1String("o")).toArray(); + + if (iArr.count() && oArr.count()) { + tix = iArr.at(0).toDouble(); + tiy = tix; + tox = oArr.at(0).toDouble(); + toy = tox; + } + } else { + QJsonArray tiArr = keyframe.value(QLatin1String("ti")).toArray(); + QJsonArray toArr = keyframe.value(QLatin1String("to")).toArray(); + + if (tiArr.count() && toArr.count()) { + tix = tiArr.at(0).toDouble(); + tiy = tiArr.at(1).toDouble(); + tox = toArr.at(0).toDouble(); + toy = toArr.at(1).toDouble(); + } + } + QPointF s(easing.startValue); + QPointF e(easing.endValue); + QPointF c1(tox, toy); + QPointF c2(tix, tiy); + + c1 += s; + c2 += e; + + m_bezierPath.moveTo(s); + m_bezierPath.cubicTo(c1, c2, e); + + return easing; + } + + virtual EasingSegment<QPointF> parseKeyframe(const QJsonObject keyframe, + const QJsonObject nextKeyframe, + bool fromExpression) override + { + EasingSegment<QPointF> easing = + BMProperty2D<QPointF>::parseKeyframe(keyframe, nextKeyframe, fromExpression); // No need to parse further incomplete keyframes (i.e. last keyframes) if (!easing.complete) { diff --git a/src/bodymovin/bmstroke.cpp b/src/bodymovin/bmstroke.cpp index e596a86..86a5f20 100644 --- a/src/bodymovin/bmstroke.cpp +++ b/src/bodymovin/bmstroke.cpp @@ -20,7 +20,7 @@ BMStroke::BMStroke(const BMStroke &other) m_miterLimit = other.m_miterLimit; } -BMStroke::BMStroke(const QJsonObject &definition, BMBase *parent) +BMStroke::BMStroke(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) { setParent(parent); @@ -63,15 +63,15 @@ BMStroke::BMStroke(const QJsonObject &definition, BMBase *parent) QJsonObject opacity = definition.value(QLatin1String("o")).toObject(); opacity = resolveExpression(opacity); - m_opacity.construct(opacity); + m_opacity.construct(opacity, version); QJsonObject width = definition.value(QLatin1String("w")).toObject(); width = resolveExpression(width); - m_width.construct(width); + m_width.construct(width, version); QJsonObject color = definition.value(QLatin1String("c")).toObject(); color = resolveExpression(color); - m_color.construct(color); + m_color.construct(color, version); } BMBase *BMStroke::clone() const diff --git a/src/bodymovin/bmstroke_p.h b/src/bodymovin/bmstroke_p.h index 6a811ab..cc3b838 100644 --- a/src/bodymovin/bmstroke_p.h +++ b/src/bodymovin/bmstroke_p.h @@ -28,7 +28,8 @@ class BODYMOVIN_EXPORT BMStroke : public BMShape public: BMStroke() = default; explicit BMStroke(const BMStroke &other); - BMStroke(const QJsonObject &definition, BMBase *parent = nullptr); + BMStroke(const QJsonObject &definition, const QVersionNumber &version, + BMBase *parent = nullptr); BMBase *clone() const override; diff --git a/src/bodymovin/bmtrimpath.cpp b/src/bodymovin/bmtrimpath.cpp index dea1b7b..62a5f7a 100644 --- a/src/bodymovin/bmtrimpath.cpp +++ b/src/bodymovin/bmtrimpath.cpp @@ -15,12 +15,12 @@ BMTrimPath::BMTrimPath() m_appliedTrim = this; } -BMTrimPath::BMTrimPath(const QJsonObject &definition, BMBase *parent) +BMTrimPath::BMTrimPath(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent) { m_appliedTrim = this; setParent(parent); - construct(definition); + construct(definition, version); } BMTrimPath::BMTrimPath(const BMTrimPath &other) @@ -37,7 +37,7 @@ BMBase *BMTrimPath::clone() const return new BMTrimPath(*this); } -void BMTrimPath::construct(const QJsonObject &definition) +void BMTrimPath::construct(const QJsonObject &definition, const QVersionNumber &version) { BMBase::parse(definition); if (m_hidden) @@ -47,15 +47,15 @@ void BMTrimPath::construct(const QJsonObject &definition) QJsonObject start = definition.value(QLatin1String("s")).toObject(); start = resolveExpression(start); - m_start.construct(start); + m_start.construct(start, version); QJsonObject end = definition.value(QLatin1String("e")).toObject(); end = resolveExpression(end); - m_end.construct(end); + m_end.construct(end, version); QJsonObject offset = definition.value(QLatin1String("o")).toObject(); offset = resolveExpression(offset); - m_offset.construct(offset); + m_offset.construct(offset, version); int simultaneous = true; if (definition.contains(QLatin1String("m"))) { diff --git a/src/bodymovin/bmtrimpath_p.h b/src/bodymovin/bmtrimpath_p.h index fdcdad2..ea653c0 100644 --- a/src/bodymovin/bmtrimpath_p.h +++ b/src/bodymovin/bmtrimpath_p.h @@ -27,14 +27,15 @@ class BODYMOVIN_EXPORT BMTrimPath : public BMShape { public: BMTrimPath(); - BMTrimPath(const QJsonObject &definition, BMBase *parent = nullptr); + BMTrimPath(const QJsonObject &definition, const QVersionNumber &version, + BMBase *parent = nullptr); explicit BMTrimPath(const BMTrimPath &other); void inherit(const BMTrimPath &other); BMBase *clone() const override; - void construct(const QJsonObject &definition); + void construct(const QJsonObject &definition, const QVersionNumber &version); void updateProperties(int frame) override; void render(LottieRenderer &renderer) const override; diff --git a/src/imports/lottieanimation.cpp b/src/imports/lottieanimation.cpp index 1334c76..4d60ed6 100644 --- a/src/imports/lottieanimation.cpp +++ b/src/imports/lottieanimation.cpp @@ -315,6 +315,11 @@ int LottieAnimation::currentFrame() const return m_currentFrame; } +QVersionNumber LottieAnimation::version() const +{ + return m_version; +} + /*! \qmlproperty int LottieAnimation::frameRate @@ -655,6 +660,12 @@ int LottieAnimation::parse(QByteArray jsonSource) if (Q_UNLIKELY(rootObj.empty())) return -1; + QStringList versionString = rootObj.value(QLatin1String("v")).toString().split(u'.'); + QList<int> version; + foreach (QString v, versionString) + version.append(v.toInt()); + m_version = QVersionNumber(version); + int startFrame = rootObj.value(QLatin1String("ip")).toVariant().toInt(); int endFrame = rootObj.value(QLatin1String("op")).toVariant().toInt(); m_animFrameRate = rootObj.value(QLatin1String("fr")).toVariant().toInt(); diff --git a/src/imports/lottieanimation.h b/src/imports/lottieanimation.h index 88c9dde..cce6d5e 100644 --- a/src/imports/lottieanimation.h +++ b/src/imports/lottieanimation.h @@ -74,6 +74,8 @@ public: int endFrame() const; int currentFrame() const; + QVersionNumber version() const; + Q_INVOKABLE void start(); Q_INVOKABLE void play(); @@ -122,6 +124,7 @@ protected: QMetaObject::Connection m_waitForFrameConn; Status m_status = Null; + QVersionNumber m_version = QVersionNumber(); int m_startFrame = 0; int m_endFrame = 0; int m_currentFrame = 0; diff --git a/src/imports/rasterrenderer/batchrenderer.cpp b/src/imports/rasterrenderer/batchrenderer.cpp index d83eb70..1d11074 100644 --- a/src/imports/rasterrenderer/batchrenderer.cpp +++ b/src/imports/rasterrenderer/batchrenderer.cpp @@ -86,7 +86,7 @@ void BatchRenderer::registerAnimator(LottieAnimation *animator) entry->currentFrame = animator->startFrame(); entry->animDir = animator->direction(); entry->bmTreeBlueprint = new BMBase; - parse(entry->bmTreeBlueprint, animator->jsonSource()); + parse(entry->bmTreeBlueprint, animator->jsonSource(), animator->version()); m_waitCondition.wakeAll(); } @@ -210,7 +210,8 @@ void BatchRenderer::run() } } -int BatchRenderer::parse(BMBase *rootElement, const QByteArray &jsonSource) const +int BatchRenderer::parse(BMBase *rootElement, const QByteArray &jsonSource, + const QVersionNumber &version) const { QJsonDocument doc = QJsonDocument::fromJson(jsonSource); QJsonObject rootObj = doc.object(); @@ -239,7 +240,7 @@ int BatchRenderer::parse(BMBase *rootElement, const QByteArray &jsonSource) cons QString refId = jsonLayer.value("refId").toString(); jsonLayer.insert("asset", assets.value(refId)); } - BMLayer *layer = BMLayer::construct(jsonLayer); + BMLayer *layer = BMLayer::construct(jsonLayer, version); if (layer) { layer->setParent(rootElement); // Mask layers must be rendered before the layers they affect to diff --git a/src/imports/rasterrenderer/batchrenderer.h b/src/imports/rasterrenderer/batchrenderer.h index 619f84e..7d86edc 100644 --- a/src/imports/rasterrenderer/batchrenderer.h +++ b/src/imports/rasterrenderer/batchrenderer.h @@ -13,6 +13,7 @@ QT_BEGIN_NAMESPACE class BMBase; class QImage; +class QVersionNumber; class LottieAnimation; class BatchRenderer : public QThread @@ -55,7 +56,8 @@ public slots: protected: void run() override; - int parse(BMBase *rootElement, const QByteArray &jsonSource) const; + int parse(BMBase *rootElement, const QByteArray &jsonSource, + const QVersionNumber &version) const; void prerender(Entry *animEntry); |