1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "bmgfill_p.h"
5
6#include <QLinearGradient>
7#include <QRadialGradient>
8#include <QtMath>
9#include <QColor>
10
11QT_BEGIN_NAMESPACE
12
13BMGFill::BMGFill(const BMGFill &other)
14 : BMShape(other)
15{
16 if (m_hidden)
17 return;
18
19 m_opacity = other.m_opacity;
20 m_startPoint = other.m_startPoint;
21 m_endPoint = other.m_endPoint;
22 m_highlightLength = other.m_highlightLength;
23 m_highlightAngle = other.m_highlightAngle;
24 m_colors = other.m_colors;
25 if (other.gradientType() == QGradient::LinearGradient)
26 m_gradient = new QLinearGradient;
27 else if (other.gradientType() == QGradient::RadialGradient)
28 m_gradient = new QRadialGradient;
29 else {
30 Q_UNREACHABLE();
31 }
32}
33
34BMGFill::~BMGFill()
35{
36 if (m_gradient)
37 delete m_gradient;
38}
39
40BMBase *BMGFill::clone() const
41{
42 return new BMGFill(*this);
43}
44
45BMGFill::BMGFill(const QJsonObject &definition, const QVersionNumber &version, BMBase *parent)
46{
47 setParent(parent);
48
49 BMBase::parse(definition);
50 if (m_hidden)
51 return;
52
53 qCDebug(lcLottieQtBodymovinParser) << "BMGFill::construct():" << m_name;
54
55 int type = definition.value(key: QLatin1String("t")).toVariant().toInt();
56 switch (type) {
57 case 1:
58 m_gradient = new QLinearGradient;
59 break;
60 case 2:
61 m_gradient = new QRadialGradient;
62 break;
63 default:
64 qCWarning(lcLottieQtBodymovinParser) << "Unknown gradient fill type";
65 }
66
67 QJsonObject color = definition.value(key: QLatin1String("g")).toObject();
68 QJsonArray colorArr = color.value(key: QLatin1String("k")).toObject().value(key: QLatin1String("k")).toArray();
69 int elementCount = color.value(key: QLatin1String("p")).toInt();
70 for (int i = 0; i < (elementCount) * 4; i += 4) {
71 // p denotes the color stop percentage
72 QVector4D colorVec;
73 colorVec[0] = colorArr[i + 1].toVariant().toFloat();
74 colorVec[1] = colorArr[i + 2].toVariant().toFloat();
75 colorVec[2] = colorArr[i + 3].toVariant().toFloat();
76 // Set gradient stop position into w of the vector
77 colorVec[3] = colorArr[i + 0].toVariant().toFloat();
78 BMProperty4D<QVector4D> colorPos;
79 colorPos.setValue(colorVec);
80 m_colors.push_back(t: colorPos);
81 }
82
83 QJsonObject opacity = definition.value(key: QLatin1String("o")).toObject();
84 opacity = resolveExpression(definition: opacity);
85 m_opacity.construct(definition: opacity, version);
86
87 QJsonObject startPoint = definition.value(key: QLatin1String("s")).toObject();
88 startPoint = resolveExpression(definition: startPoint);
89 m_startPoint.construct(definition: startPoint, version);
90
91 QJsonObject endPoint = definition.value(key: QLatin1String("e")).toObject();
92 endPoint = resolveExpression(definition: endPoint);
93 m_endPoint.construct(definition: endPoint, version);
94
95 QJsonObject highlight = definition.value(key: QLatin1String("h")).toObject();
96 m_highlightLength.construct(definition: highlight, version);
97
98 QJsonObject angle = definition.value(key: QLatin1String("a")).toObject();
99 angle = resolveExpression(definition: angle);
100 m_highlightAngle.construct(definition: angle, version);
101
102 m_highlightAngle.setValue(0.0);
103}
104
105void BMGFill::updateProperties(int frame)
106{
107 QGradient::Type type = gradientType();
108 if (type != QGradient::LinearGradient &&
109 type != QGradient::RadialGradient)
110 return;
111
112 m_startPoint.update(frame);
113 m_endPoint.update(frame);
114 m_highlightLength.update(frame);
115 m_highlightAngle.update(frame);
116 m_opacity.update(frame);
117 QList<BMProperty4D<QVector4D>>::iterator colorIt = m_colors.begin();
118 while (colorIt != m_colors.end()) {
119 (*colorIt).update(frame);
120 ++colorIt;
121 }
122
123 setGradient();
124}
125
126void BMGFill::render(LottieRenderer &renderer) const
127{
128 renderer.render(fill: *this);
129}
130
131QGradient *BMGFill::value() const
132{
133 return m_gradient;
134}
135
136QGradient::Type BMGFill::gradientType() const
137{
138 if (m_gradient)
139 return m_gradient->type();
140 else
141 return QGradient::NoGradient;
142}
143
144QPointF BMGFill::startPoint() const
145{
146 return m_startPoint.value();
147}
148
149QPointF BMGFill::endPoint() const
150{
151 return m_endPoint.value();
152}
153
154qreal BMGFill::highlightLength() const
155{
156 return m_highlightLength.value();
157}
158
159qreal BMGFill::highlightAngle() const
160{
161 return m_highlightAngle.value();
162}
163
164qreal BMGFill::opacity() const
165{
166 return m_opacity.value();
167}
168
169void BMGFill::setGradient()
170{
171 QList<BMProperty4D<QVector4D>>::iterator colorIt = m_colors.begin();
172 while (colorIt != m_colors.end()) {
173 QVector4D colorPos = (*colorIt).value();
174 QColor color;
175 color.setRedF(static_cast<qreal>(colorPos[0]));
176 color.setGreenF(static_cast<qreal>(colorPos[1]));
177 color.setBlueF(static_cast<qreal>(colorPos[2]));
178 color.setAlphaF(m_opacity.value() / 100.0);
179 m_gradient->setColorAt(pos: static_cast<qreal>(colorPos[3]),
180 color);
181 ++colorIt;
182 }
183
184 switch (gradientType()) {
185 case QGradient::LinearGradient:
186 {
187 QLinearGradient *g = static_cast<QLinearGradient*>(m_gradient);
188 g->setStart(m_startPoint.value());
189 g->setFinalStop(m_endPoint.value());
190 break;
191 }
192 case QGradient::RadialGradient:
193 {
194 QRadialGradient *g = static_cast<QRadialGradient*>(m_gradient);
195 qreal dx = qAbs(t: m_endPoint.value().x() + m_startPoint.value().x());
196 qreal dy = qAbs(t: m_endPoint.value().y() + m_startPoint.value().y());
197 qreal radius = qSqrt(v: dx * dx + dy * dy);
198 qreal angle = qAsin(v: dy / radius);
199 g->setCenter(m_startPoint.value());
200 g->setCenterRadius(radius);
201 qreal focusRadius = 2;
202 qreal x = (g->radius() - 2 * focusRadius) * qCos(v: angle + qDegreesToRadians(degrees: m_highlightAngle.value()));
203 qreal y = (g->radius() - 2 * focusRadius) * qSin(v: angle + qDegreesToRadians(degrees: m_highlightAngle.value()));
204 g->setFocalPoint(g->center() + QPointF(x, y));
205 g->setFocalRadius(focusRadius);
206 break;
207 }
208 default:
209 break;
210 }
211}
212
213QT_END_NAMESPACE
214

source code of qtlottie/src/bodymovin/bmgfill.cpp