• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "modules/skottie/src/SkottieAdapter.h"
9 
10 #include "include/core/SkFont.h"
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkMatrix44.h"
13 #include "include/core/SkPath.h"
14 #include "include/core/SkRRect.h"
15 #include "include/private/SkTo.h"
16 #include "include/utils/Sk3D.h"
17 #include "modules/skottie/src/SkottieValue.h"
18 #include "modules/sksg/include/SkSGDraw.h"
19 #include "modules/sksg/include/SkSGGradient.h"
20 #include "modules/sksg/include/SkSGGroup.h"
21 #include "modules/sksg/include/SkSGPaint.h"
22 #include "modules/sksg/include/SkSGPath.h"
23 #include "modules/sksg/include/SkSGRect.h"
24 #include "modules/sksg/include/SkSGTransform.h"
25 #include "modules/sksg/include/SkSGTrimEffect.h"
26 
27 #include <cmath>
28 #include <utility>
29 
30 namespace skottie {
31 
32 namespace internal {
33 
34 DiscardableAdaptorBase::DiscardableAdaptorBase() = default;
35 
setAnimators(sksg::AnimatorList && animators)36 void DiscardableAdaptorBase::setAnimators(sksg::AnimatorList&& animators) {
37     fAnimators = std::move(animators);
38 }
39 
onTick(float t)40 void DiscardableAdaptorBase::onTick(float t) {
41     for (auto& animator : fAnimators) {
42         animator->tick(t);
43     }
44 
45     this->onSync();
46 }
47 
48 } // namespace internal
49 
RRectAdapter(sk_sp<sksg::RRect> wrapped_node)50 RRectAdapter::RRectAdapter(sk_sp<sksg::RRect> wrapped_node)
51     : fRRectNode(std::move(wrapped_node)) {}
52 
53 RRectAdapter::~RRectAdapter() = default;
54 
apply()55 void RRectAdapter::apply() {
56     // BM "position" == "center position"
57     auto rr = SkRRect::MakeRectXY(SkRect::MakeXYWH(fPosition.x() - fSize.width() / 2,
58                                                    fPosition.y() - fSize.height() / 2,
59                                                    fSize.width(), fSize.height()),
60                                   fRadius.width(),
61                                   fRadius.height());
62    fRRectNode->setRRect(rr);
63 }
64 
TransformAdapter2D(sk_sp<sksg::Matrix<SkMatrix>> matrix)65 TransformAdapter2D::TransformAdapter2D(sk_sp<sksg::Matrix<SkMatrix>> matrix)
66     : fMatrixNode(std::move(matrix)) {}
67 
68 TransformAdapter2D::~TransformAdapter2D() = default;
69 
totalMatrix() const70 SkMatrix TransformAdapter2D::totalMatrix() const {
71     SkMatrix t = SkMatrix::MakeTrans(-fAnchorPoint.x(), -fAnchorPoint.y());
72 
73     t.postScale(fScale.x() / 100, fScale.y() / 100); // 100% based
74     t.postRotate(fRotation);
75     t.postTranslate(fPosition.x(), fPosition.y());
76     // TODO: skew
77 
78     return t;
79 }
80 
apply()81 void TransformAdapter2D::apply() {
82     fMatrixNode->setMatrix(this->totalMatrix());
83 }
84 
Vec3(const VectorValue & v)85 TransformAdapter3D::Vec3::Vec3(const VectorValue& v) {
86     fX = v.size() > 0 ? v[0] : 0;
87     fY = v.size() > 1 ? v[1] : 0;
88     fZ = v.size() > 2 ? v[2] : 0;
89 }
90 
TransformAdapter3D()91 TransformAdapter3D::TransformAdapter3D()
92     : fMatrixNode(sksg::Matrix<SkMatrix44>::Make(SkMatrix::I())) {}
93 
94 TransformAdapter3D::~TransformAdapter3D() = default;
95 
refTransform() const96 sk_sp<sksg::Transform> TransformAdapter3D::refTransform() const {
97     return fMatrixNode;
98 }
99 
totalMatrix() const100 SkMatrix44 TransformAdapter3D::totalMatrix() const {
101     SkMatrix44 t;
102 
103     t.setTranslate(-fAnchorPoint.fX, -fAnchorPoint.fY, -fAnchorPoint.fZ);
104     t.postScale(fScale.fX / 100, fScale.fY / 100, fScale.fZ / 100);
105 
106     SkMatrix44 r;
107     r.setRotateDegreesAbout(0, 0, 1, fRotation.fZ);
108     t.postConcat(r);
109     r.setRotateDegreesAbout(0, 1, 0, fRotation.fY);
110     t.postConcat(r);
111     r.setRotateDegreesAbout(1, 0, 0, fRotation.fX);
112     t.postConcat(r);
113 
114     t.postTranslate(fPosition.fX, fPosition.fY, fPosition.fZ);
115 
116     return t;
117 }
118 
apply()119 void TransformAdapter3D::apply() {
120     fMatrixNode->setMatrix(this->totalMatrix());
121 }
122 
CameraAdapter(const SkSize & viewport_size)123 CameraAdapter:: CameraAdapter(const SkSize& viewport_size)
124     : fViewportSize(viewport_size) {}
125 
126 CameraAdapter::~CameraAdapter() = default;
127 
totalMatrix() const128 SkMatrix44 CameraAdapter::totalMatrix() const {
129     // Camera parameters:
130     //
131     //   * location          -> position attribute
132     //   * point of interest -> anchor point attribute
133     //   * orientation       -> rotation attribute
134     //
135     SkPoint3 pos = { this->getPosition().fX,
136                      this->getPosition().fY,
137                     -this->getPosition().fZ },
138              poi = { this->getAnchorPoint().fX,
139                      this->getAnchorPoint().fY,
140                     -this->getAnchorPoint().fZ },
141               up = { 0, 1, 0 };
142 
143     // Initial camera vector.
144     SkMatrix44 cam_t;
145     Sk3LookAt(&cam_t, pos, poi, up);
146 
147     // Rotation origin is camera position.
148     {
149         SkMatrix44 rot;
150         rot.setRotateDegreesAbout(1, 0, 0,  this->getRotation().fX);
151         cam_t.postConcat(rot);
152         rot.setRotateDegreesAbout(0, 1, 0,  this->getRotation().fY);
153         cam_t.postConcat(rot);
154         rot.setRotateDegreesAbout(0, 0, 1, -this->getRotation().fZ);
155         cam_t.postConcat(rot);
156     }
157 
158     // Flip world Z, as it is opposite of what Sk3D expects.
159     cam_t.preScale(1, 1, -1);
160 
161     // View parameters:
162     //
163     //   * size     -> composition size (TODO: AE seems to base it on width only?)
164     //   * distance -> "zoom" camera attribute
165     //
166     const auto view_size     = SkTMax(fViewportSize.width(), fViewportSize.height()),
167                view_distance = this->getZoom(),
168                view_angle    = std::atan(sk_ieee_float_divide(view_size * 0.5f, view_distance));
169 
170     SkMatrix44 persp_t;
171     Sk3Perspective(&persp_t, 0, view_distance, 2 * view_angle);
172     persp_t.postScale(view_size * 0.5f, view_size * 0.5f, 1);
173 
174     SkMatrix44 t;
175     t.setTranslate(fViewportSize.width() * 0.5f, fViewportSize.height() * 0.5f, 0);
176     t.preConcat(persp_t);
177     t.preConcat(cam_t);
178 
179     return t;
180 }
181 
RepeaterAdapter(sk_sp<sksg::RenderNode> repeater_node,Composite composite)182 RepeaterAdapter::RepeaterAdapter(sk_sp<sksg::RenderNode> repeater_node, Composite composite)
183     : fRepeaterNode(repeater_node)
184     , fComposite(composite)
185     , fRoot(sksg::Group::Make()) {}
186 
187 RepeaterAdapter::~RepeaterAdapter() = default;
188 
apply()189 void RepeaterAdapter::apply() {
190     static constexpr SkScalar kMaxCount = 512;
191     const auto count = static_cast<size_t>(SkTPin(fCount, 0.0f, kMaxCount) + 0.5f);
192 
193     const auto& compute_transform = [this] (size_t index) {
194         const auto t = fOffset + index;
195 
196         // Position, scale & rotation are "scaled" by index/offset.
197         SkMatrix m = SkMatrix::MakeTrans(-fAnchorPoint.x(),
198                                          -fAnchorPoint.y());
199         m.postScale(std::pow(fScale.x() * .01f, fOffset),
200                     std::pow(fScale.y() * .01f, fOffset));
201         m.postRotate(t * fRotation);
202         m.postTranslate(t * fPosition.x() + fAnchorPoint.x(),
203                         t * fPosition.y() + fAnchorPoint.y());
204 
205         return m;
206     };
207 
208     // TODO: start/end opacity support.
209 
210     // TODO: we can avoid rebuilding all the fragments in most cases.
211     fRoot->clear();
212     for (size_t i = 0; i < count; ++i) {
213         const auto insert_index = (fComposite == Composite::kAbove) ? i : count - i - 1;
214         fRoot->addChild(sksg::TransformEffect::Make(fRepeaterNode,
215                                                     compute_transform(insert_index)));
216     }
217 }
218 
PolyStarAdapter(sk_sp<sksg::Path> wrapped_node,Type t)219 PolyStarAdapter::PolyStarAdapter(sk_sp<sksg::Path> wrapped_node, Type t)
220     : fPathNode(std::move(wrapped_node))
221     , fType(t) {}
222 
223 PolyStarAdapter::~PolyStarAdapter() = default;
224 
apply()225 void PolyStarAdapter::apply() {
226     static constexpr int kMaxPointCount = 100000;
227     const auto count = SkToUInt(SkTPin(SkScalarRoundToInt(fPointCount), 0, kMaxPointCount));
228     const auto arc   = sk_ieee_float_divide(SK_ScalarPI * 2, count);
229 
230     const auto pt_on_circle = [](const SkPoint& c, SkScalar r, SkScalar a) {
231         return SkPoint::Make(c.x() + r * std::cos(a),
232                              c.y() + r * std::sin(a));
233     };
234 
235     // TODO: inner/outer "roundness"?
236 
237     SkPath poly;
238 
239     auto angle = SkDegreesToRadians(fRotation - 90);
240     poly.moveTo(pt_on_circle(fPosition, fOuterRadius, angle));
241     poly.incReserve(fType == Type::kStar ? count * 2 : count);
242 
243     for (unsigned i = 0; i < count; ++i) {
244         if (fType == Type::kStar) {
245             poly.lineTo(pt_on_circle(fPosition, fInnerRadius, angle + arc * 0.5f));
246         }
247         angle += arc;
248         poly.lineTo(pt_on_circle(fPosition, fOuterRadius, angle));
249     }
250 
251     poly.close();
252     fPathNode->setPath(poly);
253 }
254 
GradientAdapter(sk_sp<sksg::Gradient> grad,size_t stopCount)255 GradientAdapter::GradientAdapter(sk_sp<sksg::Gradient> grad, size_t stopCount)
256     : fGradient(std::move(grad))
257     , fStopCount(stopCount) {}
258 
apply()259 void GradientAdapter::apply() {
260     this->onApply();
261 
262     // |fColorStops| holds |fStopCount| x [ pos, r, g, g ] + ? x [ pos, alpha ]
263 
264     if (fColorStops.size() < fStopCount * 4 || ((fColorStops.size() - fStopCount * 4) % 2)) {
265         // apply() may get called before the stops are set, so only log when we have some stops.
266         if (!fColorStops.empty()) {
267             SkDebugf("!! Invalid gradient stop array size: %zu\n", fColorStops.size());
268         }
269         return;
270     }
271 
272     std::vector<sksg::Gradient::ColorStop> stops;
273 
274     // TODO: merge/lerp opacity stops
275     const auto csEnd = fColorStops.cbegin() + fStopCount * 4;
276     for (auto cs = fColorStops.cbegin(); cs != csEnd; cs += 4) {
277         const auto pos = cs[0];
278         const VectorValue rgb({ cs[1], cs[2], cs[3] });
279 
280         stops.push_back({ pos, ValueTraits<VectorValue>::As<SkColor>(rgb) });
281     }
282 
283     fGradient->setColorStops(std::move(stops));
284 }
285 
LinearGradientAdapter(sk_sp<sksg::LinearGradient> grad,size_t stopCount)286 LinearGradientAdapter::LinearGradientAdapter(sk_sp<sksg::LinearGradient> grad, size_t stopCount)
287     : INHERITED(std::move(grad), stopCount) {}
288 
onApply()289 void LinearGradientAdapter::onApply() {
290     auto* grad = static_cast<sksg::LinearGradient*>(fGradient.get());
291     grad->setStartPoint(this->startPoint());
292     grad->setEndPoint(this->endPoint());
293 }
294 
RadialGradientAdapter(sk_sp<sksg::RadialGradient> grad,size_t stopCount)295 RadialGradientAdapter::RadialGradientAdapter(sk_sp<sksg::RadialGradient> grad, size_t stopCount)
296     : INHERITED(std::move(grad), stopCount) {}
297 
onApply()298 void RadialGradientAdapter::onApply() {
299     auto* grad = static_cast<sksg::RadialGradient*>(fGradient.get());
300     grad->setStartCenter(this->startPoint());
301     grad->setEndCenter(this->startPoint());
302     grad->setStartRadius(0);
303     grad->setEndRadius(SkPoint::Distance(this->startPoint(), this->endPoint()));
304 }
305 
TrimEffectAdapter(sk_sp<sksg::TrimEffect> trimEffect)306 TrimEffectAdapter::TrimEffectAdapter(sk_sp<sksg::TrimEffect> trimEffect)
307     : fTrimEffect(std::move(trimEffect)) {
308     SkASSERT(fTrimEffect);
309 }
310 
311 TrimEffectAdapter::~TrimEffectAdapter() = default;
312 
apply()313 void TrimEffectAdapter::apply() {
314     // BM semantics: start/end are percentages, offset is "degrees" (?!).
315     const auto  start = fStart  / 100,
316                   end = fEnd    / 100,
317                offset = fOffset / 360;
318 
319     auto startT = SkTMin(start, end) + offset,
320           stopT = SkTMax(start, end) + offset;
321     auto   mode = SkTrimPathEffect::Mode::kNormal;
322 
323     if (stopT - startT < 1) {
324         startT -= SkScalarFloorToScalar(startT);
325         stopT  -= SkScalarFloorToScalar(stopT);
326 
327         if (startT > stopT) {
328             using std::swap;
329             swap(startT, stopT);
330             mode = SkTrimPathEffect::Mode::kInverted;
331         }
332     } else {
333         startT = 0;
334         stopT  = 1;
335     }
336 
337     fTrimEffect->setStart(startT);
338     fTrimEffect->setStop(stopT);
339     fTrimEffect->setMode(mode);
340 }
341 
342 } // namespace skottie
343