• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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