blob: 5186e2c2f875ec9bd36d9d365ad2e69875f5226d [file] [log] [blame]
Florin Malitaa6e30f72018-03-23 13:41:58 -04001/*
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 "SkottieAdapter.h"
9
10#include "SkMatrix.h"
11#include "SkottieValue.h"
12#include "SkPath.h"
13#include "SkRRect.h"
14#include "SkSGGradient.h"
15#include "SkSGPath.h"
16#include "SkSGRect.h"
17#include "SkSGTransform.h"
18#include "SkSGTrimEffect.h"
19
20#include <cmath>
21
22namespace skottie {
23
24RRectAdapter::RRectAdapter(sk_sp<sksg::RRect> wrapped_node)
25 : fRRectNode(std::move(wrapped_node)) {}
26
27void RRectAdapter::apply() {
28 // BM "position" == "center position"
29 auto rr = SkRRect::MakeRectXY(SkRect::MakeXYWH(fPosition.x() - fSize.width() / 2,
30 fPosition.y() - fSize.height() / 2,
31 fSize.width(), fSize.height()),
32 fRadius.width(),
33 fRadius.height());
34 fRRectNode->setRRect(rr);
35}
36
37TransformAdapter::TransformAdapter(sk_sp<sksg::Matrix> matrix)
38 : fMatrixNode(std::move(matrix)) {}
39
40void TransformAdapter::apply() {
41 SkMatrix t = SkMatrix::MakeTrans(-fAnchorPoint.x(), -fAnchorPoint.y());
42
43 t.postScale(fScale.x() / 100, fScale.y() / 100); // 100% based
44 t.postRotate(fRotation);
45 t.postTranslate(fPosition.x(), fPosition.y());
46 // TODO: skew
47
48 fMatrixNode->setMatrix(t);
49}
50
51PolyStarAdapter::PolyStarAdapter(sk_sp<sksg::Path> wrapped_node, Type t)
52 : fPathNode(std::move(wrapped_node))
53 , fType(t) {}
54
55void PolyStarAdapter::apply() {
56 const auto count = SkScalarTruncToInt(fPointCount);
57 const auto arc = SK_ScalarPI * 2 / count;
58
59 const auto pt_on_circle = [](const SkPoint& c, SkScalar r, SkScalar a) {
60 return SkPoint::Make(c.x() + r * std::cos(a),
61 c.y() + r * std::sin(a));
62 };
63
64 // TODO: inner/outer "roundness"?
65
66 SkPath poly;
67
68 auto angle = SkDegreesToRadians(fRotation);
69 poly.moveTo(pt_on_circle(fPosition, fOuterRadius, angle));
70
71 for (int i = 0; i < count; ++i) {
72 if (fType == Type::kStar) {
73 poly.lineTo(pt_on_circle(fPosition, fInnerRadius, angle + arc * 0.5f));
74 }
75 angle += arc;
76 poly.lineTo(pt_on_circle(fPosition, fOuterRadius, angle));
77 }
78
79 poly.close();
80 fPathNode->setPath(poly);
81}
82
83GradientAdapter::GradientAdapter(sk_sp<sksg::Gradient> grad, size_t stopCount)
84 : fGradient(std::move(grad))
85 , fStopCount(stopCount) {}
86
87void GradientAdapter::apply() {
88 this->onApply();
89
90 // |fColorStops| holds |fStopCount| x [ pos, r, g, g ] + ? x [ pos, alpha ]
91
92 if (fColorStops.size() < fStopCount * 4 || ((fColorStops.size() - fStopCount * 4) % 2)) {
93 SkDebugf("!! Invalid gradient stop array size: %zu", fColorStops.size());
94 return;
95 }
96
97 std::vector<sksg::Gradient::ColorStop> stops;
98
99 // TODO: merge/lerp opacity stops
100 const auto csEnd = fColorStops.cbegin() + fStopCount * 4;
101 for (auto cs = fColorStops.cbegin(); cs != csEnd; cs += 4) {
102 const auto pos = cs[0];
103 const VectorValue rgb({ cs[1], cs[2], cs[3] });
104
105 stops.push_back({ pos, ValueTraits<VectorValue>::As<SkColor>(rgb) });
106 }
107
108 fGradient->setColorStops(std::move(stops));
109}
110
111LinearGradientAdapter::LinearGradientAdapter(sk_sp<sksg::LinearGradient> grad, size_t stopCount)
112 : INHERITED(std::move(grad), stopCount) {}
113
114void LinearGradientAdapter::onApply() {
115 auto* grad = static_cast<sksg::LinearGradient*>(fGradient.get());
116 grad->setStartPoint(this->startPoint());
117 grad->setEndPoint(this->endPoint());
118}
119
120RadialGradientAdapter::RadialGradientAdapter(sk_sp<sksg::RadialGradient> grad, size_t stopCount)
121 : INHERITED(std::move(grad), stopCount) {}
122
123void RadialGradientAdapter::onApply() {
124 auto* grad = static_cast<sksg::RadialGradient*>(fGradient.get());
125 grad->setStartCenter(this->startPoint());
126 grad->setEndCenter(this->startPoint());
127 grad->setStartRadius(0);
128 grad->setEndRadius(SkPoint::Distance(this->startPoint(), this->endPoint()));
129}
130
131TrimEffectAdapter::TrimEffectAdapter(sk_sp<sksg::TrimEffect> trimEffect)
132 : fTrimEffect(std::move(trimEffect)) {
133 SkASSERT(fTrimEffect);
134}
135
136void TrimEffectAdapter::apply() {
137 // BM semantics: start/end are percentages, offset is "degrees" (?!).
138 const auto start = fStart / 100,
139 end = fEnd / 100,
140 offset = fOffset / 360;
141
142 auto startT = SkTMin(start, end) + offset,
143 stopT = SkTMax(start, end) + offset;
144 auto mode = SkTrimPathEffect::Mode::kNormal;
145
146 if (stopT - startT < 1) {
147 startT -= SkScalarFloorToScalar(startT);
148 stopT -= SkScalarFloorToScalar(stopT);
149
150 if (startT > stopT) {
151 SkTSwap(startT, stopT);
152 mode = SkTrimPathEffect::Mode::kInverted;
153 }
154 } else {
155 startT = 0;
156 stopT = 1;
157 }
158
159 fTrimEffect->setStart(startT);
160 fTrimEffect->setStop(stopT);
161 fTrimEffect->setMode(mode);
162}
163
164} // namespace skottie