1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#ifndef BMSPATIALPROPERTY_P_H
5#define BMSPATIALPROPERTY_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QPointF>
19#include <QPainterPath>
20
21#include <QtBodymovin/private/bmproperty_p.h>
22
23QT_BEGIN_NAMESPACE
24
25class BMSpatialProperty : public BMProperty2D<QPointF>
26{
27public:
28 virtual void construct(const QJsonObject &definition, const QVersionNumber &version) override
29 {
30 qCDebug(lcLottieQtBodymovinParser) << "BMSpatialProperty::construct()";
31 BMProperty2D<QPointF>::construct(definition, version);
32 }
33
34 virtual EasingSegment<QPointF> parseKeyframe(const QJsonObject keyframe,
35 bool fromExpression) override
36 {
37 EasingSegment<QPointF> easing =
38 BMProperty2D<QPointF>::parseKeyframe(keyframe, fromExpression);
39
40 // No need to parse further incomplete keyframes (i.e. last keyframes)
41 if (!easing.complete) {
42 return easing;
43 }
44
45 qreal tix = 0, tiy = 0, tox = 0, toy = 0;
46 if (fromExpression) {
47 // If spatial property definition originates from
48 // an expression (specifically Slider), it contains scalar
49 // property. It must be expanded to both x and y coordinates
50 QJsonArray iArr = keyframe.value(key: QLatin1String("i")).toArray();
51 QJsonArray oArr = keyframe.value(key: QLatin1String("o")).toArray();
52
53 if (iArr.count() && oArr.count()) {
54 tix = iArr.at(i: 0).toDouble();
55 tiy = tix;
56 tox = oArr.at(i: 0).toDouble();
57 toy = tox;
58 }
59 } else {
60 QJsonArray tiArr = keyframe.value(key: QLatin1String("ti")).toArray();
61 QJsonArray toArr = keyframe.value(key: QLatin1String("to")).toArray();
62
63 if (tiArr.count() && toArr.count()) {
64 tix = tiArr.at(i: 0).toDouble();
65 tiy = tiArr.at(i: 1).toDouble();
66 tox = toArr.at(i: 0).toDouble();
67 toy = toArr.at(i: 1).toDouble();
68 }
69 }
70 QPointF s(easing.startValue);
71 QPointF e(easing.endValue);
72 QPointF c1(tox, toy);
73 QPointF c2(tix, tiy);
74
75 c1 += s;
76 c2 += e;
77
78 m_bezierPath.moveTo(p: s);
79 m_bezierPath.cubicTo(ctrlPt1: c1, ctrlPt2: c2, endPt: e);
80
81 return easing;
82 }
83
84 virtual EasingSegment<QPointF> parseKeyframe(const QJsonObject keyframe,
85 const QJsonObject nextKeyframe,
86 bool fromExpression) override
87 {
88 EasingSegment<QPointF> easing =
89 BMProperty2D<QPointF>::parseKeyframe(keyframe, nextKeyframe, fromExpression);
90
91 // No need to parse further incomplete keyframes (i.e. last keyframes)
92 if (!easing.complete) {
93 return easing;
94 }
95
96 qreal tix = 0, tiy = 0, tox = 0, toy = 0;
97 if (fromExpression) {
98 // If spatial property definition originates from
99 // an expression (specifically Slider), it contains scalar
100 // property. It must be expanded to both x and y coordinates
101 QJsonArray iArr = keyframe.value(key: QLatin1String("i")).toArray();
102 QJsonArray oArr = keyframe.value(key: QLatin1String("o")).toArray();
103
104 if (iArr.count() && oArr.count()) {
105 tix = iArr.at(i: 0).toDouble();
106 tiy = tix;
107 tox = oArr.at(i: 0).toDouble();
108 toy = tox;
109 }
110 } else {
111 QJsonArray tiArr = keyframe.value(key: QLatin1String("ti")).toArray();
112 QJsonArray toArr = keyframe.value(key: QLatin1String("to")).toArray();
113
114 if (tiArr.count() && toArr.count()) {
115 tix = tiArr.at(i: 0).toDouble();
116 tiy = tiArr.at(i: 1).toDouble();
117 tox = toArr.at(i: 0).toDouble();
118 toy = toArr.at(i: 1).toDouble();
119 }
120 }
121 QPointF s(easing.startValue);
122 QPointF e(easing.endValue);
123 QPointF c1(tox, toy);
124 QPointF c2(tix, tiy);
125
126 c1 += s;
127 c2 += e;
128
129 m_bezierPath.moveTo(p: s);
130 m_bezierPath.cubicTo(ctrlPt1: c1, ctrlPt2: c2, endPt: e);
131
132 return easing;
133 }
134
135 virtual bool update(int frame) override
136 {
137 if (!m_animated)
138 return false;
139
140 int adjustedFrame = qBound(min: m_startFrame, val: frame, max: m_endFrame);
141 if (const EasingSegment<QPointF> *easing = getEasingSegment(frame: adjustedFrame)) {
142 qreal progress = ((adjustedFrame - m_startFrame) * 1.0) / (m_endFrame - m_startFrame);
143 qreal easedValue = easing->valueForProgress(progress);
144 m_value = m_bezierPath.pointAtPercent(t: easedValue);
145 }
146
147 return true;
148 }
149
150private:
151 QPainterPath m_bezierPath;
152};
153
154QT_END_NAMESPACE
155
156#endif // BMSPATIALPROPERTY_P_H
157

source code of qtlottie/src/bodymovin/bmspatialproperty_p.h