/src/skia/modules/skottie/src/layers/shapelayer/Repeater.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2020 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 "include/core/SkCanvas.h" |
9 | | #include "include/core/SkM44.h" |
10 | | #include "include/core/SkMatrix.h" |
11 | | #include "include/core/SkRect.h" |
12 | | #include "include/core/SkRefCnt.h" |
13 | | #include "include/core/SkScalar.h" |
14 | | #include "include/private/base/SkTPin.h" |
15 | | #include "modules/skottie/src/Adapter.h" |
16 | | #include "modules/skottie/src/SkottieJson.h" |
17 | | #include "modules/skottie/src/SkottiePriv.h" |
18 | | #include "modules/skottie/src/SkottieValue.h" |
19 | | #include "modules/skottie/src/layers/shapelayer/ShapeLayer.h" |
20 | | #include "modules/sksg/include/SkSGNode.h" |
21 | | #include "modules/sksg/include/SkSGRenderNode.h" |
22 | | #include "src/utils/SkJSON.h" |
23 | | |
24 | | #include <algorithm> |
25 | | #include <cmath> |
26 | | #include <cstddef> |
27 | | #include <utility> |
28 | | #include <vector> |
29 | | |
30 | | struct SkPoint; |
31 | | |
32 | | namespace sksg { |
33 | | class InvalidationController; |
34 | | } |
35 | | |
36 | | namespace skottie { |
37 | | namespace internal { |
38 | | |
39 | | namespace { |
40 | | |
41 | | class RepeaterRenderNode final : public sksg::CustomRenderNode { |
42 | | public: |
43 | | enum class CompositeMode { kBelow, kAbove }; |
44 | | |
45 | | RepeaterRenderNode(std::vector<sk_sp<RenderNode>>&& children, CompositeMode mode) |
46 | | : INHERITED(std::move(children)) |
47 | 0 | , fMode(mode) {} |
48 | | |
49 | | SG_ATTRIBUTE(Count , size_t, fCount ) |
50 | | SG_ATTRIBUTE(Offset , float , fOffset ) |
51 | | SG_ATTRIBUTE(AnchorPoint , SkV2 , fAnchorPoint ) |
52 | | SG_ATTRIBUTE(Position , SkV2 , fPosition ) |
53 | | SG_ATTRIBUTE(Scale , SkV2 , fScale ) |
54 | | SG_ATTRIBUTE(Rotation , float , fRotation ) |
55 | | SG_ATTRIBUTE(StartOpacity, float , fStartOpacity) |
56 | | SG_ATTRIBUTE(EndOpacity , float , fEndOpacity ) |
57 | | |
58 | | private: |
59 | 0 | const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing |
60 | | |
61 | 0 | SkMatrix instanceTransform(size_t i) const { |
62 | 0 | const auto t = fOffset + i; |
63 | | |
64 | | // Position, scale & rotation are "scaled" by index/offset. |
65 | 0 | return SkMatrix::Translate(t * fPosition.x + fAnchorPoint.x, |
66 | 0 | t * fPosition.y + fAnchorPoint.y) |
67 | 0 | * SkMatrix::RotateDeg(t * fRotation) |
68 | 0 | * SkMatrix::Scale(std::pow(fScale.x, t), |
69 | 0 | std::pow(fScale.y, t)) |
70 | 0 | * SkMatrix::Translate(-fAnchorPoint.x, |
71 | 0 | -fAnchorPoint.y); |
72 | 0 | } |
73 | | |
74 | 0 | SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override { |
75 | 0 | fChildrenBounds = SkRect::MakeEmpty(); |
76 | 0 | for (const auto& child : this->children()) { |
77 | 0 | fChildrenBounds.join(child->revalidate(ic, ctm)); |
78 | 0 | } |
79 | |
|
80 | 0 | auto bounds = SkRect::MakeEmpty(); |
81 | 0 | for (size_t i = 0; i < fCount; ++i) { |
82 | 0 | bounds.join(this->instanceTransform(i).mapRect(fChildrenBounds)); |
83 | 0 | } |
84 | |
|
85 | 0 | return bounds; |
86 | 0 | } |
87 | | |
88 | 0 | void onRender(SkCanvas* canvas, const RenderContext* ctx) const override { |
89 | | // To cover the full opacity range, the denominator below should be (fCount - 1). |
90 | | // Interstingly, that's not what AE does. Off-by-one bug? |
91 | 0 | const auto dOpacity = fCount > 1 ? (fEndOpacity - fStartOpacity) / fCount : 0.0f; |
92 | |
|
93 | 0 | for (size_t i = 0; i < fCount; ++i) { |
94 | 0 | const auto render_index = fMode == CompositeMode::kAbove ? i : fCount - i - 1; |
95 | 0 | const auto opacity = fStartOpacity + dOpacity * render_index; |
96 | |
|
97 | 0 | if (opacity <= 0) { |
98 | 0 | continue; |
99 | 0 | } |
100 | | |
101 | 0 | SkAutoCanvasRestore acr(canvas, true); |
102 | 0 | canvas->concat(this->instanceTransform(render_index)); |
103 | |
|
104 | 0 | const auto& children = this->children(); |
105 | 0 | const auto local_ctx = ScopedRenderContext(canvas, ctx) |
106 | 0 | .modulateOpacity(opacity) |
107 | 0 | .setIsolation(fChildrenBounds, |
108 | 0 | canvas->getTotalMatrix(), |
109 | 0 | children.size() > 1); |
110 | 0 | for (const auto& child : children) { |
111 | 0 | child->render(canvas, local_ctx); |
112 | 0 | } |
113 | 0 | } |
114 | 0 | } |
115 | | |
116 | | const CompositeMode fMode; |
117 | | |
118 | | SkRect fChildrenBounds = SkRect::MakeEmpty(); // cached |
119 | | |
120 | | size_t fCount = 0; |
121 | | float fOffset = 0, |
122 | | fRotation = 0, |
123 | | fStartOpacity = 1, |
124 | | fEndOpacity = 1; |
125 | | SkV2 fAnchorPoint = {0,0}, |
126 | | fPosition = {0,0}, |
127 | | fScale = {1,1}; |
128 | | |
129 | | using INHERITED = sksg::CustomRenderNode; |
130 | | }; |
131 | | |
132 | | class RepeaterAdapter final : public DiscardableAdapterBase<RepeaterAdapter, RepeaterRenderNode> { |
133 | | public: |
134 | | RepeaterAdapter(const skjson::ObjectValue& jrepeater, |
135 | | const skjson::ObjectValue& jtransform, |
136 | | const AnimationBuilder& abuilder, |
137 | | std::vector<sk_sp<sksg::RenderNode>>&& draws) |
138 | | : INHERITED(sk_make_sp<RepeaterRenderNode>(std::move(draws), |
139 | | (ParseDefault(jrepeater["m"], 1) == 1) |
140 | | ? RepeaterRenderNode::CompositeMode::kBelow |
141 | | : RepeaterRenderNode::CompositeMode::kAbove)) |
142 | 0 | { |
143 | 0 | this->bind(abuilder, jrepeater["c"], fCount); |
144 | 0 | this->bind(abuilder, jrepeater["o"], fOffset); |
145 | |
|
146 | 0 | this->bind(abuilder, jtransform["a" ], fAnchorPoint); |
147 | 0 | this->bind(abuilder, jtransform["p" ], fPosition); |
148 | 0 | this->bind(abuilder, jtransform["s" ], fScale); |
149 | 0 | this->bind(abuilder, jtransform["r" ], fRotation); |
150 | 0 | this->bind(abuilder, jtransform["so"], fStartOpacity); |
151 | 0 | this->bind(abuilder, jtransform["eo"], fEndOpacity); |
152 | 0 | } |
153 | | |
154 | | private: |
155 | 0 | void onSync() override { |
156 | 0 | static constexpr SkScalar kMaxCount = 1024; |
157 | 0 | this->node()->setCount(static_cast<size_t>(SkTPin(fCount, 0.0f, kMaxCount) + 0.5f)); |
158 | 0 | this->node()->setOffset(fOffset); |
159 | 0 | this->node()->setAnchorPoint(fAnchorPoint); |
160 | 0 | this->node()->setPosition(fPosition); |
161 | 0 | this->node()->setScale(fScale * 0.01f); |
162 | 0 | this->node()->setRotation(fRotation); |
163 | 0 | this->node()->setStartOpacity(SkTPin(fStartOpacity * 0.01f, 0.0f, 1.0f)); |
164 | 0 | this->node()->setEndOpacity (SkTPin(fEndOpacity * 0.01f, 0.0f, 1.0f)); |
165 | 0 | } |
166 | | |
167 | | // Repeater props |
168 | | ScalarValue fCount = 0, |
169 | | fOffset = 0; |
170 | | |
171 | | // Transform props |
172 | | Vec2Value fAnchorPoint = { 0, 0 }, |
173 | | fPosition = { 0, 0 }, |
174 | | fScale = { 100, 100 }; |
175 | | ScalarValue fRotation = 0, |
176 | | fStartOpacity = 100, |
177 | | fEndOpacity = 100; |
178 | | |
179 | | using INHERITED = DiscardableAdapterBase<RepeaterAdapter, RepeaterRenderNode>; |
180 | | }; |
181 | | |
182 | | } // namespace |
183 | | |
184 | | std::vector<sk_sp<sksg::RenderNode>> ShapeBuilder::AttachRepeaterDrawEffect( |
185 | | const skjson::ObjectValue& jrepeater, |
186 | | const AnimationBuilder* abuilder, |
187 | 2.03k | std::vector<sk_sp<sksg::RenderNode>>&& draws) { |
188 | 2.03k | std::vector<sk_sp<sksg::RenderNode>> repeater_draws; |
189 | | |
190 | 2.03k | if (const skjson::ObjectValue* jtransform = jrepeater["tr"]) { |
191 | | // input draws are in top->bottom order - reverse for paint order |
192 | 0 | std::reverse(draws.begin(), draws.end()); |
193 | |
|
194 | 0 | repeater_draws.reserve(1); |
195 | 0 | repeater_draws.push_back( |
196 | 0 | abuilder->attachDiscardableAdapter<RepeaterAdapter>(jrepeater, |
197 | 0 | *jtransform, |
198 | 0 | *abuilder, |
199 | 0 | std::move(draws))); |
200 | 2.03k | } else { |
201 | 2.03k | repeater_draws = std::move(draws); |
202 | 2.03k | } |
203 | | |
204 | 2.03k | return repeater_draws; |
205 | 2.03k | } |
206 | | |
207 | | } // namespace internal |
208 | | } // namespace skottie |