1 /*
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
8 #include "modules/skottie/src/effects/Effects.h"
9
10 #include "modules/skottie/src/SkottieAdapter.h"
11 #include "modules/skottie/src/SkottieValue.h"
12 #include "modules/sksg/include/SkSGGradient.h"
13 #include "modules/sksg/include/SkSGRenderEffect.h"
14 #include "src/utils/SkJSON.h"
15
16 namespace skottie {
17 namespace internal {
18
19 namespace {
20
21 class GradientRampEffectAdapter final : public SkNVRefCnt<GradientRampEffectAdapter> {
22 public:
GradientRampEffectAdapter(sk_sp<sksg::RenderNode> child)23 explicit GradientRampEffectAdapter(sk_sp<sksg::RenderNode> child)
24 : fRoot(sksg::ShaderEffect::Make(std::move(child))) {}
25
26 ADAPTER_PROPERTY(StartPoint, SkPoint , SkPoint::Make(0, 0))
27 ADAPTER_PROPERTY(EndPoint , SkPoint , SkPoint::Make(0, 0))
ADAPTER_PROPERTY(StartColor,SkColor,SK_ColorBLACK)28 ADAPTER_PROPERTY(StartColor, SkColor , SK_ColorBLACK)
29 ADAPTER_PROPERTY(EndColor , SkColor , SK_ColorBLACK)
30 ADAPTER_PROPERTY(Blend , SkScalar, 0)
31 ADAPTER_PROPERTY(Scatter , SkScalar, 0)
32
33 // Really an enum: 1 -> linear, 7 -> radial (?!)
34 ADAPTER_PROPERTY(Shape , SkScalar, 0)
35
36 const sk_sp<sksg::ShaderEffect>& root() const { return fRoot; }
37
38 private:
39 enum class InstanceType {
40 kNone,
41 kLinear,
42 kRadial,
43 };
44
apply()45 void apply() {
46 // This adapter manages a SG fragment with the following structure:
47 //
48 // - ShaderEffect [fRoot]
49 // \ GradientShader [fGradient]
50 // \ child/wrapped fragment
51 //
52 // The gradient shader is updated based on the (animatable) instance type (linear/radial).
53
54 auto update_gradient = [this] (InstanceType new_type) {
55 if (new_type != fInstanceType) {
56 fGradient = new_type == InstanceType::kLinear
57 ? sk_sp<sksg::Gradient>(sksg::LinearGradient::Make())
58 : sk_sp<sksg::Gradient>(sksg::RadialGradient::Make());
59
60 fRoot->setShader(fGradient);
61 fInstanceType = new_type;
62 }
63
64 fGradient->setColorStops({ {0, fStartColor}, {1, fEndColor} });
65 };
66
67 static constexpr int kLinearShapeValue = 1;
68 const auto instance_type = (SkScalarRoundToInt(fShape) == kLinearShapeValue)
69 ? InstanceType::kLinear
70 : InstanceType::kRadial;
71
72 // Sync the gradient shader instance if needed.
73 update_gradient(instance_type);
74
75 // Sync instance-dependent gradient params.
76 if (instance_type == InstanceType::kLinear) {
77 auto* lg = static_cast<sksg::LinearGradient*>(fGradient.get());
78 lg->setStartPoint(fStartPoint);
79 lg->setEndPoint(fEndPoint);
80 } else {
81 SkASSERT(instance_type == InstanceType::kRadial);
82
83 auto* rg = static_cast<sksg::RadialGradient*>(fGradient.get());
84 rg->setStartCenter(fStartPoint);
85 rg->setEndCenter(fStartPoint);
86 rg->setEndRadius(SkPoint::Distance(fStartPoint, fEndPoint));
87 }
88
89 // TODO: blend, scatter
90 }
91
92 sk_sp<sksg::ShaderEffect> fRoot;
93 sk_sp<sksg::Gradient> fGradient;
94 InstanceType fInstanceType = InstanceType::kNone;
95 };
96
97 } // anonymous ns
98
attachGradientEffect(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer) const99 sk_sp<sksg::RenderNode> EffectBuilder::attachGradientEffect(const skjson::ArrayValue& jprops,
100 sk_sp<sksg::RenderNode> layer) const {
101 enum : size_t {
102 kStartPoint_Index = 0,
103 kStartColor_Index = 1,
104 kEndPoint_Index = 2,
105 kEndColor_Index = 3,
106 kRampShape_Index = 4,
107 kRampScatter_Index = 5,
108 kBlendRatio_Index = 6,
109 };
110
111 auto adapter = sk_make_sp<GradientRampEffectAdapter>(std::move(layer));
112
113 fBuilder->bindProperty<VectorValue>(GetPropValue(jprops, kStartPoint_Index),
114 [adapter](const VectorValue& p0) {
115 adapter->setStartPoint(ValueTraits<VectorValue>::As<SkPoint>(p0));
116 });
117 fBuilder->bindProperty<VectorValue>(GetPropValue(jprops, kEndPoint_Index),
118 [adapter](const VectorValue& p1) {
119 adapter->setEndPoint(ValueTraits<VectorValue>::As<SkPoint>(p1));
120 });
121 fBuilder->bindProperty<VectorValue>(GetPropValue(jprops, kStartColor_Index),
122 [adapter](const VectorValue& c0) {
123 adapter->setStartColor(ValueTraits<VectorValue>::As<SkColor>(c0));
124 });
125 fBuilder->bindProperty<VectorValue>(GetPropValue(jprops, kEndColor_Index),
126 [adapter](const VectorValue& c1) {
127 adapter->setEndColor(ValueTraits<VectorValue>::As<SkColor>(c1));
128 });
129 fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kRampShape_Index),
130 [adapter](const ScalarValue& shape) {
131 adapter->setShape(shape);
132 });
133 fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kBlendRatio_Index),
134 [adapter](const ScalarValue& blend) {
135 adapter->setBlend(blend);
136 });
137 fBuilder->bindProperty<ScalarValue>(GetPropValue(jprops, kRampScatter_Index),
138 [adapter](const ScalarValue& scatter) {
139 adapter->setScatter(scatter);
140 });
141
142 return adapter->root();
143 }
144
145 } // namespace internal
146 } // namespace skottie
147