blob: 3a7e16301737100342ac4dc486e81eb1baf047ca [file] [log] [blame]
Florin Malita45dc1f02019-07-01 13:57:43 -04001/*
2 * Copyright 2019 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
Florin Malitac6fbedc2019-10-28 13:57:12 -04008#include "modules/skottie/src/Layer.h"
Florin Malita45dc1f02019-07-01 13:57:43 -04009
Florin Malitaa3936c82020-01-06 12:17:27 -050010#include "modules/skottie/src/Camera.h"
Florin Malitac6fbedc2019-10-28 13:57:12 -040011#include "modules/skottie/src/Composition.h"
Florin Malita45dc1f02019-07-01 13:57:43 -040012#include "modules/skottie/src/SkottieJson.h"
13#include "modules/skottie/src/effects/Effects.h"
Florin Malita5f1108c2019-07-03 10:09:31 -040014#include "modules/skottie/src/effects/MotionBlurEffect.h"
Florin Malita45dc1f02019-07-01 13:57:43 -040015#include "modules/sksg/include/SkSGClipEffect.h"
16#include "modules/sksg/include/SkSGDraw.h"
17#include "modules/sksg/include/SkSGGroup.h"
18#include "modules/sksg/include/SkSGMaskEffect.h"
19#include "modules/sksg/include/SkSGMerge.h"
20#include "modules/sksg/include/SkSGPaint.h"
21#include "modules/sksg/include/SkSGPath.h"
22#include "modules/sksg/include/SkSGRect.h"
23#include "modules/sksg/include/SkSGRenderEffect.h"
24#include "modules/sksg/include/SkSGRenderNode.h"
25#include "modules/sksg/include/SkSGTransform.h"
26
Florin Malita45dc1f02019-07-01 13:57:43 -040027namespace skottie {
28namespace internal {
29
30namespace {
31
Florin Malita8b70f4d2020-04-23 18:58:21 -040032static constexpr size_t kNullLayerType = 3;
Florin Malita45dc1f02019-07-01 13:57:43 -040033
34struct MaskInfo {
35 SkBlendMode fBlendMode; // used when masking with layers/blending
36 sksg::Merge::Mode fMergeMode; // used when clipping
37 bool fInvertGeometry;
38};
39
40const MaskInfo* GetMaskInfo(char mode) {
41 static constexpr MaskInfo k_add_info =
42 { SkBlendMode::kSrcOver , sksg::Merge::Mode::kUnion , false };
43 static constexpr MaskInfo k_int_info =
44 { SkBlendMode::kSrcIn , sksg::Merge::Mode::kIntersect , false };
45 // AE 'subtract' is the same as 'intersect' + inverted geometry
46 // (draws the opacity-adjusted paint *outside* the shape).
47 static constexpr MaskInfo k_sub_info =
48 { SkBlendMode::kSrcIn , sksg::Merge::Mode::kIntersect , true };
49 static constexpr MaskInfo k_dif_info =
50 { SkBlendMode::kDifference, sksg::Merge::Mode::kDifference, false };
51
52 switch (mode) {
53 case 'a': return &k_add_info;
54 case 'f': return &k_dif_info;
55 case 'i': return &k_int_info;
56 case 's': return &k_sub_info;
57 default: break;
58 }
59
60 return nullptr;
61}
62
Florin Malitaaf99f3e2020-02-03 12:09:15 -050063class MaskAdapter final : public AnimatablePropertyContainer {
64public:
65 MaskAdapter(const skjson::ObjectValue& jmask, const AnimationBuilder& abuilder, SkBlendMode bm)
66 : fMaskPaint(sksg::Color::Make(SK_ColorBLACK)) {
67 fMaskPaint->setAntiAlias(true);
68 fMaskPaint->setBlendMode(bm);
69
70 this->bind(abuilder, jmask["o"], fOpacity);
71
72 if (this->bind(abuilder, jmask["f"], fFeather)) {
73 fMaskFilter = sksg::BlurImageFilter::Make();
74 }
75 }
76
77 bool hasEffect() const {
78 return !this->isStatic()
79 || fOpacity < 100
Florin Malita6509bc72020-03-12 11:11:26 -040080 || fFeather != SkV2{0,0};
Florin Malitaaf99f3e2020-02-03 12:09:15 -050081 }
82
83 sk_sp<sksg::RenderNode> makeMask(sk_sp<sksg::Path> mask_path) const {
84 auto mask = sksg::Draw::Make(std::move(mask_path), fMaskPaint);
85
86 // Optional mask blur (feather).
87 return sksg::ImageFilterEffect::Make(std::move(mask), fMaskFilter);
88 }
89
90private:
91 void onSync() override {
92 fMaskPaint->setOpacity(fOpacity * 0.01f);
93 if (fMaskFilter) {
Florin Malitaaf99f3e2020-02-03 12:09:15 -050094 // Close enough to AE.
95 static constexpr SkScalar kFeatherToSigma = 0.38f;
Florin Malita6509bc72020-03-12 11:11:26 -040096 fMaskFilter->setSigma({fFeather.x * kFeatherToSigma,
97 fFeather.y * kFeatherToSigma});
Florin Malitaaf99f3e2020-02-03 12:09:15 -050098 }
99 }
100
101 const sk_sp<sksg::PaintNode> fMaskPaint;
102 sk_sp<sksg::BlurImageFilter> fMaskFilter; // optional "feather"
103
Florin Malita6509bc72020-03-12 11:11:26 -0400104 Vec2Value fFeather = {0,0};
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500105 ScalarValue fOpacity = 100;
106};
107
Florin Malita45dc1f02019-07-01 13:57:43 -0400108sk_sp<sksg::RenderNode> AttachMask(const skjson::ArrayValue* jmask,
109 const AnimationBuilder* abuilder,
Florin Malita45dc1f02019-07-01 13:57:43 -0400110 sk_sp<sksg::RenderNode> childNode) {
111 if (!jmask) return childNode;
112
113 struct MaskRecord {
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500114 sk_sp<sksg::Path> mask_path; // for clipping and masking
115 sk_sp<MaskAdapter> mask_adapter; // for masking
116 sksg::Merge::Mode merge_mode; // for clipping
Florin Malita45dc1f02019-07-01 13:57:43 -0400117 };
118
119 SkSTArray<4, MaskRecord, true> mask_stack;
Florin Malita45dc1f02019-07-01 13:57:43 -0400120 bool has_effect = false;
Florin Malita45dc1f02019-07-01 13:57:43 -0400121
122 for (const skjson::ObjectValue* m : *jmask) {
123 if (!m) continue;
124
125 const skjson::StringValue* jmode = (*m)["mode"];
126 if (!jmode || jmode->size() != 1) {
127 abuilder->log(Logger::Level::kError, &(*m)["mode"], "Invalid mask mode.");
128 continue;
129 }
130
131 const auto mode = *jmode->begin();
132 if (mode == 'n') {
133 // "None" masks have no effect.
134 continue;
135 }
136
137 const auto* mask_info = GetMaskInfo(mode);
138 if (!mask_info) {
139 abuilder->log(Logger::Level::kWarning, nullptr, "Unsupported mask mode: '%c'.", mode);
140 continue;
141 }
142
Florin Malitafd91f6d2019-07-25 11:41:07 -0400143 auto mask_path = abuilder->attachPath((*m)["pt"]);
Florin Malita45dc1f02019-07-01 13:57:43 -0400144 if (!mask_path) {
145 abuilder->log(Logger::Level::kError, m, "Could not parse mask path.");
146 continue;
147 }
148
149 // "inv" is cumulative with mask info fInvertGeometry
150 const auto inverted =
151 (mask_info->fInvertGeometry != ParseDefault<bool>((*m)["inv"], false));
Mike Reed7d34dc72019-11-26 12:17:17 -0500152 mask_path->setFillType(inverted ? SkPathFillType::kInverseWinding
153 : SkPathFillType::kWinding);
Florin Malita45dc1f02019-07-01 13:57:43 -0400154
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500155 const auto blend_mode = mask_stack.empty() ? SkBlendMode::kSrc
156 : mask_info->fBlendMode;
Florin Malita45dc1f02019-07-01 13:57:43 -0400157
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500158 auto mask_adapter = sk_make_sp<MaskAdapter>(*m, *abuilder, blend_mode);
159 abuilder->attachDiscardableAdapter(mask_adapter);
Florin Malita45dc1f02019-07-01 13:57:43 -0400160
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500161 has_effect |= mask_adapter->hasEffect();
Florin Malita45dc1f02019-07-01 13:57:43 -0400162
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500163
164 mask_stack.push_back({ std::move(mask_path),
165 std::move(mask_adapter),
166 mask_info->fMergeMode });
Florin Malita45dc1f02019-07-01 13:57:43 -0400167 }
168
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500169
Florin Malita45dc1f02019-07-01 13:57:43 -0400170 if (mask_stack.empty())
171 return childNode;
172
173 // If the masks are fully opaque, we can clip.
174 if (!has_effect) {
175 sk_sp<sksg::GeometryNode> clip_node;
176
177 if (mask_stack.count() == 1) {
178 // Single path -> just clip.
179 clip_node = std::move(mask_stack.front().mask_path);
180 } else {
181 // Multiple clip paths -> merge.
182 std::vector<sksg::Merge::Rec> merge_recs;
183 merge_recs.reserve(SkToSizeT(mask_stack.count()));
184
185 for (auto& mask : mask_stack) {
186 const auto mode = merge_recs.empty() ? sksg::Merge::Mode::kMerge : mask.merge_mode;
187 merge_recs.push_back({std::move(mask.mask_path), mode});
188 }
189 clip_node = sksg::Merge::Make(std::move(merge_recs));
190 }
191
192 return sksg::ClipEffect::Make(std::move(childNode), std::move(clip_node), true);
193 }
194
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500195 // Complex masks (non-opaque or blurred) turn into a mask node stack.
Florin Malita45dc1f02019-07-01 13:57:43 -0400196 sk_sp<sksg::RenderNode> maskNode;
197 if (mask_stack.count() == 1) {
198 // no group needed for single mask
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500199 const auto rec = mask_stack.front();
200 maskNode = rec.mask_adapter->makeMask(std::move(rec.mask_path));
Florin Malita45dc1f02019-07-01 13:57:43 -0400201 } else {
202 std::vector<sk_sp<sksg::RenderNode>> masks;
203 masks.reserve(SkToSizeT(mask_stack.count()));
204 for (auto& rec : mask_stack) {
Florin Malitaaf99f3e2020-02-03 12:09:15 -0500205 masks.push_back(rec.mask_adapter->makeMask(std::move(rec.mask_path)));
Florin Malita45dc1f02019-07-01 13:57:43 -0400206 }
207
208 maskNode = sksg::Group::Make(std::move(masks));
209 }
210
211 return sksg::MaskEffect::Make(std::move(childNode), std::move(maskNode));
212}
213
Florin Malitabb7d95f2020-03-26 15:58:56 -0400214class LayerController final : public Animator {
Florin Malita5f1108c2019-07-03 10:09:31 -0400215public:
Florin Malitabb7d95f2020-03-26 15:58:56 -0400216 LayerController(AnimatorScope&& layer_animators,
Florin Malita5f1108c2019-07-03 10:09:31 -0400217 sk_sp<sksg::RenderNode> layer,
218 size_t tanim_count, float in, float out)
219 : fLayerAnimators(std::move(layer_animators))
220 , fLayerNode(std::move(layer))
221 , fTransformAnimatorsCount(tanim_count)
222 , fIn(in)
223 , fOut(out) {}
224
225protected:
Florin Malita01f2ce02020-03-31 05:44:28 -0400226 StateChanged onSeek(float t) override {
Florin Malitac4fae742020-02-27 15:50:04 -0500227 // in/out may be inverted for time-reversed layers
228 const auto active = (t >= fIn && t < fOut) || (t > fOut && t <= fIn);
Florin Malita5f1108c2019-07-03 10:09:31 -0400229
Florin Malita01f2ce02020-03-31 05:44:28 -0400230 bool changed = false;
Florin Malita5f1108c2019-07-03 10:09:31 -0400231 if (fLayerNode) {
Florin Malita01f2ce02020-03-31 05:44:28 -0400232 changed |= (fLayerNode->isVisible() != active);
Florin Malita5f1108c2019-07-03 10:09:31 -0400233 fLayerNode->setVisible(active);
234 }
235
236 // When active, dispatch ticks to all layer animators.
237 // When inactive, we must still dispatch ticks to the layer transform animators
238 // (active child layers depend on transforms being updated).
239 const auto dispatch_count = active ? fLayerAnimators.size()
240 : fTransformAnimatorsCount;
241 for (size_t i = 0; i < dispatch_count; ++i) {
Florin Malita01f2ce02020-03-31 05:44:28 -0400242 changed |= fLayerAnimators[i]->seek(t);
Florin Malita5f1108c2019-07-03 10:09:31 -0400243 }
Florin Malita0147de42020-03-27 09:49:03 -0400244
Florin Malita01f2ce02020-03-31 05:44:28 -0400245 return changed;
Florin Malita5f1108c2019-07-03 10:09:31 -0400246 }
247
248private:
Florin Malitabb7d95f2020-03-26 15:58:56 -0400249 const AnimatorScope fLayerAnimators;
Florin Malita5f1108c2019-07-03 10:09:31 -0400250 const sk_sp<sksg::RenderNode> fLayerNode;
251 const size_t fTransformAnimatorsCount;
252 const float fIn,
253 fOut;
254};
255
Florin Malitabb7d95f2020-03-26 15:58:56 -0400256class MotionBlurController final : public Animator {
Florin Malita5f1108c2019-07-03 10:09:31 -0400257public:
258 explicit MotionBlurController(sk_sp<MotionBlurEffect> mbe)
259 : fMotionBlurEffect(std::move(mbe)) {}
260
261protected:
262 // When motion blur is present, time ticks are not passed to layer animators
263 // but to the motion blur effect. The effect then drives the animators/scene-graph
264 // during reval and render phases.
Florin Malita01f2ce02020-03-31 05:44:28 -0400265 StateChanged onSeek(float t) override {
Florin Malita5f1108c2019-07-03 10:09:31 -0400266 fMotionBlurEffect->setT(t);
Florin Malita0147de42020-03-27 09:49:03 -0400267 return true;
Florin Malita5f1108c2019-07-03 10:09:31 -0400268 }
269
270private:
271 const sk_sp<MotionBlurEffect> fMotionBlurEffect;
272};
273
Florin Malita45dc1f02019-07-01 13:57:43 -0400274} // namespace
275
Florin Malitac6fbedc2019-10-28 13:57:12 -0400276LayerBuilder::LayerBuilder(const skjson::ObjectValue& jlayer)
277 : fJlayer(jlayer)
278 , fIndex(ParseDefault<int>(jlayer["ind"], -1))
279 , fParentIndex(ParseDefault<int>(jlayer["parent"], -1))
280 , fType(ParseDefault<int>(jlayer["ty"], -1)) {
Florin Malita45dc1f02019-07-01 13:57:43 -0400281
Florin Malitac6fbedc2019-10-28 13:57:12 -0400282 if (this->isCamera() || ParseDefault<int>(jlayer["ddd"], 0)) {
283 fFlags |= Flags::kIs3D;
Florin Malita60c84fd2019-07-02 18:02:54 -0400284 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400285}
286
Florin Malitac6fbedc2019-10-28 13:57:12 -0400287LayerBuilder::~LayerBuilder() = default;
288
289bool LayerBuilder::isCamera() const {
290 static constexpr int kCameraLayerType = 13;
291
292 return fType == kCameraLayerType;
293}
294
295sk_sp<sksg::Transform> LayerBuilder::buildTransform(const AnimationBuilder& abuilder,
296 CompositionBuilder* cbuilder) {
297 // Depending on the leaf node type, we treat the whole transform chain as either 2D or 3D.
298 const auto transform_chain_type = this->is3D() ? TransformType::k3D
299 : TransformType::k2D;
300 fLayerTransform = this->getTransform(abuilder, cbuilder, transform_chain_type);
301
302 return fLayerTransform;
303}
304
305sk_sp<sksg::Transform> LayerBuilder::getTransform(const AnimationBuilder& abuilder,
306 CompositionBuilder* cbuilder,
307 TransformType ttype) {
308 const auto cache_valid_mask = (1ul << ttype);
309 if (!(fFlags & cache_valid_mask)) {
310 // Set valid flag upfront to break cycles.
311 fFlags |= cache_valid_mask;
312
313 const AnimationBuilder::AutoPropertyTracker apt(&abuilder, fJlayer);
314 AnimationBuilder::AutoScope ascope(&abuilder, std::move(fLayerScope));
315 fTransformCache[ttype] = this->doAttachTransform(abuilder, cbuilder, ttype);
316 fLayerScope = ascope.release();
317 fTransformAnimatorCount = fLayerScope.size();
Florin Malitad9e85862019-10-17 13:46:33 -0400318 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400319
Florin Malitac6fbedc2019-10-28 13:57:12 -0400320 return fTransformCache[ttype];
321}
Florin Malita45dc1f02019-07-01 13:57:43 -0400322
Florin Malitac6fbedc2019-10-28 13:57:12 -0400323sk_sp<sksg::Transform> LayerBuilder::getParentTransform(const AnimationBuilder& abuilder,
324 CompositionBuilder* cbuilder,
325 TransformType ttype) {
326 if (auto* parent_builder = cbuilder->layerBuilder(fParentIndex)) {
327 // Explicit parent layer.
328 return parent_builder->getTransform(abuilder, cbuilder, ttype);
329 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400330
Florin Malitac6fbedc2019-10-28 13:57:12 -0400331 if (ttype == TransformType::k3D) {
332 // During camera transform attachment, cbuilder->getCameraTransform() is null.
333 // This prevents camera->camera transform chain cycles.
334 SkASSERT(!this->isCamera() || !cbuilder->getCameraTransform());
335
336 // 3D transform chains are implicitly rooted onto the camera.
337 return cbuilder->getCameraTransform();
Florin Malita45dc1f02019-07-01 13:57:43 -0400338 }
339
340 return nullptr;
341}
342
Florin Malitac6fbedc2019-10-28 13:57:12 -0400343sk_sp<sksg::Transform> LayerBuilder::doAttachTransform(const AnimationBuilder& abuilder,
344 CompositionBuilder* cbuilder,
345 TransformType ttype) {
346 const skjson::ObjectValue* jtransform = fJlayer["ks"];
Florin Malita45dc1f02019-07-01 13:57:43 -0400347 if (!jtransform) {
348 return nullptr;
349 }
350
Florin Malitac6fbedc2019-10-28 13:57:12 -0400351 auto parent_transform = this->getParentTransform(abuilder, cbuilder, ttype);
Florin Malita45dc1f02019-07-01 13:57:43 -0400352
Florin Malitac6fbedc2019-10-28 13:57:12 -0400353 if (this->isCamera()) {
Florin Malita45dc1f02019-07-01 13:57:43 -0400354 // parent_transform applies to the camera itself => it pre-composes inverted to the
355 // camera/view/adapter transform.
356 //
357 // T_camera' = T_camera x Inv(parent_transform)
358 //
Florin Malitae7bd58f2020-01-27 11:58:49 -0500359 return abuilder.attachCamera(fJlayer,
360 *jtransform,
361 sksg::Transform::MakeInverse(std::move(parent_transform)),
362 cbuilder->fSize);
Florin Malita45dc1f02019-07-01 13:57:43 -0400363 }
364
Florin Malitac6fbedc2019-10-28 13:57:12 -0400365 return this->is3D()
366 ? abuilder.attachMatrix3D(*jtransform, std::move(parent_transform))
367 : abuilder.attachMatrix2D(*jtransform, std::move(parent_transform));
Florin Malita45dc1f02019-07-01 13:57:43 -0400368}
369
Florin Malitac6fbedc2019-10-28 13:57:12 -0400370bool LayerBuilder::hasMotionBlur(const CompositionBuilder* cbuilder) const {
371 return cbuilder->fMotionBlurSamples > 1
372 && cbuilder->fMotionBlurAngle > 0
373 && ParseDefault(fJlayer["mb"], false);
Florin Malita45dc1f02019-07-01 13:57:43 -0400374}
375
Florin Malitac6fbedc2019-10-28 13:57:12 -0400376sk_sp<sksg::RenderNode> LayerBuilder::buildRenderTree(const AnimationBuilder& abuilder,
Florin Malita46a331b2019-12-12 15:43:53 -0500377 CompositionBuilder* cbuilder,
378 const LayerBuilder* prev_layer) {
Florin Malitac6fbedc2019-10-28 13:57:12 -0400379 AnimationBuilder::LayerInfo layer_info = {
Florin Malita6cc49532019-12-05 09:06:22 -0500380 cbuilder->fSize,
Florin Malitac6fbedc2019-10-28 13:57:12 -0400381 ParseDefault<float>(fJlayer["ip"], 0.0f),
382 ParseDefault<float>(fJlayer["op"], 0.0f),
Florin Malita45dc1f02019-07-01 13:57:43 -0400383 };
Florin Malitac4fae742020-02-27 15:50:04 -0500384 if (SkScalarNearlyEqual(layer_info.fInPoint, layer_info.fOutPoint)) {
Florin Malitac6fbedc2019-10-28 13:57:12 -0400385 abuilder.log(Logger::Level::kError, nullptr,
386 "Invalid layer in/out points: %f/%f.",
387 layer_info.fInPoint, layer_info.fOutPoint);
Florin Malita45dc1f02019-07-01 13:57:43 -0400388 return nullptr;
389 }
390
Florin Malitac6fbedc2019-10-28 13:57:12 -0400391 const AnimationBuilder::AutoPropertyTracker apt(&abuilder, fJlayer);
Florin Malita45dc1f02019-07-01 13:57:43 -0400392
Florin Malitac6fbedc2019-10-28 13:57:12 -0400393 using LayerBuilder =
394 sk_sp<sksg::RenderNode> (AnimationBuilder::*)(const skjson::ObjectValue&,
395 AnimationBuilder::LayerInfo*) const;
Florin Malita45dc1f02019-07-01 13:57:43 -0400396
397 // AE is annoyingly inconsistent in how effects interact with layer transforms: depending on
398 // the layer type, effects are applied before or after the content is transformed.
399 //
400 // Empirically, pre-rendered layers (for some loose meaning of "pre-rendered") are in the
401 // former category (effects are subject to transformation), while the remaining types are in
402 // the latter.
403 enum : uint32_t {
404 kTransformEffects = 1, // The layer transform also applies to its effects.
405 };
406
407 static constexpr struct {
Florin Malita60c84fd2019-07-02 18:02:54 -0400408 LayerBuilder fBuilder;
409 uint32_t fFlags;
Florin Malita45dc1f02019-07-01 13:57:43 -0400410 } gLayerBuildInfo[] = {
Florin Malita8b70f4d2020-04-23 18:58:21 -0400411 { &AnimationBuilder::attachPrecompLayer, kTransformEffects }, // 'ty': 0 -> precomp
412 { &AnimationBuilder::attachSolidLayer , kTransformEffects }, // 'ty': 1 -> solid
Florin Malita71c31412020-05-07 16:44:18 -0400413 { &AnimationBuilder::attachFootageLayer, kTransformEffects }, // 'ty': 2 -> image
Florin Malita8b70f4d2020-04-23 18:58:21 -0400414 { &AnimationBuilder::attachNullLayer , 0 }, // 'ty': 3 -> null
415 { &AnimationBuilder::attachShapeLayer , 0 }, // 'ty': 4 -> shape
416 { &AnimationBuilder::attachTextLayer , 0 }, // 'ty': 5 -> text
417 { nullptr , 0 }, // 'ty': 6 -> audio
418 { nullptr , 0 }, // 'ty': 7 -> pholderVideo
419 { nullptr , 0 }, // 'ty': 8 -> imageSeq
Florin Malita71c31412020-05-07 16:44:18 -0400420 { &AnimationBuilder::attachFootageLayer, kTransformEffects }, // 'ty': 9 -> video
Florin Malita8b70f4d2020-04-23 18:58:21 -0400421 { nullptr , 0 }, // 'ty': 10 -> pholderStill
422 { nullptr , 0 }, // 'ty': 11 -> guide
423 { nullptr , 0 }, // 'ty': 12 -> adjustment
424 { &AnimationBuilder::attachNullLayer , 0 }, // 'ty': 13 -> camera
425 { nullptr , 0 }, // 'ty': 14 -> light
Florin Malita45dc1f02019-07-01 13:57:43 -0400426 };
427
Florin Malita8b70f4d2020-04-23 18:58:21 -0400428 // Treat all hidden layers as null.
429 const auto type = ParseDefault<bool>(fJlayer["hd"], false)
430 ? kNullLayerType
431 : SkToSizeT(fType);
432
433 if (type >= SK_ARRAY_COUNT(gLayerBuildInfo)) {
Florin Malita60c84fd2019-07-02 18:02:54 -0400434 return nullptr;
435 }
436
Florin Malita8b70f4d2020-04-23 18:58:21 -0400437 const auto& build_info = gLayerBuildInfo[type];
438
Florin Malitac6fbedc2019-10-28 13:57:12 -0400439 // Switch to the layer animator scope (which at this point holds transform-only animators).
440 AnimationBuilder::AutoScope ascope(&abuilder, std::move(fLayerScope));
Florin Malita45dc1f02019-07-01 13:57:43 -0400441
Florin Malita8b70f4d2020-04-23 18:58:21 -0400442 // Potentially null.
443 sk_sp<sksg::RenderNode> layer;
Florin Malita45dc1f02019-07-01 13:57:43 -0400444
445 // Build the layer content fragment.
Florin Malita8b70f4d2020-04-23 18:58:21 -0400446 if (build_info.fBuilder) {
447 layer = (abuilder.*(build_info.fBuilder))(fJlayer, &layer_info);
448 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400449
450 // Clip layers with explicit dimensions.
451 float w = 0, h = 0;
Florin Malitac6fbedc2019-10-28 13:57:12 -0400452 if (Parse<float>(fJlayer["w"], &w) && Parse<float>(fJlayer["h"], &h)) {
Florin Malita45dc1f02019-07-01 13:57:43 -0400453 layer = sksg::ClipEffect::Make(std::move(layer),
454 sksg::Rect::Make(SkRect::MakeWH(w, h)),
455 true);
456 }
457
458 // Optional layer mask.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400459 layer = AttachMask(fJlayer["masksProperties"], &abuilder, std::move(layer));
Florin Malita45dc1f02019-07-01 13:57:43 -0400460
Florin Malita45dc1f02019-07-01 13:57:43 -0400461 // Does the transform apply to effects also?
462 // (AE quirk: it doesn't - except for solid layers)
463 const auto transform_effects = (build_info.fFlags & kTransformEffects);
464
465 // Attach the transform before effects, when needed.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400466 if (fLayerTransform && !transform_effects) {
467 layer = sksg::TransformEffect::Make(std::move(layer), fLayerTransform);
Florin Malita45dc1f02019-07-01 13:57:43 -0400468 }
469
470 // Optional layer effects.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400471 if (const skjson::ArrayValue* jeffects = fJlayer["ef"]) {
472 layer = EffectBuilder(&abuilder, layer_info.fSize).attachEffects(*jeffects,
473 std::move(layer));
Florin Malita45dc1f02019-07-01 13:57:43 -0400474 }
475
476 // Attach the transform after effects, when needed.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400477 if (fLayerTransform && transform_effects) {
478 layer = sksg::TransformEffect::Make(std::move(layer), std::move(fLayerTransform));
Florin Malita45dc1f02019-07-01 13:57:43 -0400479 }
480
Florin Malitaae581992020-03-24 21:18:42 -0400481 // Optional layer styles.
482 if (const skjson::ArrayValue* jstyles = fJlayer["sy"]) {
483 layer = EffectBuilder(&abuilder, layer_info.fSize).attachStyles(*jstyles, std::move(layer));
484 }
485
Florin Malita45dc1f02019-07-01 13:57:43 -0400486 // Optional layer opacity.
487 // TODO: de-dupe this "ks" lookup with matrix above.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400488 if (const skjson::ObjectValue* jtransform = fJlayer["ks"]) {
489 layer = abuilder.attachOpacity(*jtransform, std::move(layer));
Florin Malita45dc1f02019-07-01 13:57:43 -0400490 }
491
Florin Malitac6fbedc2019-10-28 13:57:12 -0400492 const auto has_animators = !abuilder.fCurrentAnimatorScope->empty();
Florin Malita45dc1f02019-07-01 13:57:43 -0400493
Florin Malitabb7d95f2020-03-26 15:58:56 -0400494 sk_sp<Animator> controller = sk_make_sp<LayerController>(ascope.release(),
495 layer,
496 fTransformAnimatorCount,
497 layer_info.fInPoint,
498 layer_info.fOutPoint);
Florin Malita45dc1f02019-07-01 13:57:43 -0400499
Florin Malita5f1108c2019-07-03 10:09:31 -0400500 // Optional motion blur.
Florin Malitac6fbedc2019-10-28 13:57:12 -0400501 if (layer && has_animators && this->hasMotionBlur(cbuilder)) {
Florin Malita5f1108c2019-07-03 10:09:31 -0400502 // Wrap both the layer node and the controller.
503 auto motion_blur = MotionBlurEffect::Make(std::move(controller), std::move(layer),
Florin Malitac6fbedc2019-10-28 13:57:12 -0400504 cbuilder->fMotionBlurSamples,
505 cbuilder->fMotionBlurAngle,
506 cbuilder->fMotionBlurPhase);
Florin Malita5f240182019-07-23 17:28:53 -0400507 controller = sk_make_sp<MotionBlurController>(motion_blur);
Florin Malita5f1108c2019-07-03 10:09:31 -0400508 layer = std::move(motion_blur);
509 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400510
Florin Malitac6fbedc2019-10-28 13:57:12 -0400511 abuilder.fCurrentAnimatorScope->push_back(std::move(controller));
Florin Malita60c84fd2019-07-02 18:02:54 -0400512
Florin Malita46a331b2019-12-12 15:43:53 -0500513 // Stash the content tree in case it is needed for later mattes.
514 fContentTree = layer;
515
516 if (ParseDefault<bool>(fJlayer["td"], false)) {
517 // |layer| is a track matte. We apply it as a mask to the next layer.
Florin Malita60c84fd2019-07-02 18:02:54 -0400518 return nullptr;
519 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400520
Florin Malita46a331b2019-12-12 15:43:53 -0500521 // Optional matte.
522 size_t matte_mode;
523 if (prev_layer && Parse(fJlayer["tt"], &matte_mode)) {
524 static constexpr sksg::MaskEffect::Mode gMatteModes[] = {
Florin Malita59e72b72019-10-16 08:51:09 -0400525 sksg::MaskEffect::Mode::kAlphaNormal, // tt: 1
526 sksg::MaskEffect::Mode::kAlphaInvert, // tt: 2
527 sksg::MaskEffect::Mode::kLumaNormal, // tt: 3
528 sksg::MaskEffect::Mode::kLumaInvert, // tt: 4
Florin Malita45dc1f02019-07-01 13:57:43 -0400529 };
Florin Malita45dc1f02019-07-01 13:57:43 -0400530
Florin Malita46a331b2019-12-12 15:43:53 -0500531 if (matte_mode > 0 && matte_mode <= SK_ARRAY_COUNT(gMatteModes)) {
532 // The current layer is masked with the previous layer *content*.
Florin Malita512eb942019-10-28 21:22:42 -0400533 layer = sksg::MaskEffect::Make(std::move(layer),
Florin Malita46a331b2019-12-12 15:43:53 -0500534 prev_layer->fContentTree,
535 gMatteModes[matte_mode - 1]);
536 } else {
537 abuilder.log(Logger::Level::kError, nullptr,
538 "Unknown track matte mode: %zu\n", matte_mode);
Florin Malita45dc1f02019-07-01 13:57:43 -0400539 }
Florin Malita45dc1f02019-07-01 13:57:43 -0400540 }
541
Florin Malita46a331b2019-12-12 15:43:53 -0500542 // Finally, attach an optional blend mode.
543 // NB: blend modes are never applied to matte sources (layer content only).
544 return abuilder.attachBlendMode(fJlayer, std::move(layer));
Florin Malita45dc1f02019-07-01 13:57:43 -0400545}
546
547} // namespace internal
548} // namespace skottie