1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2019 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottiePriv.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottieValue.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/animator/Animator.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/effects/Effects.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGGradient.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGRenderEffect.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGRenderNode.h"
19*c8dee2aaSAndroid Build Coastguard Worker
20*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
21*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
22*c8dee2aaSAndroid Build Coastguard Worker
23*c8dee2aaSAndroid Build Coastguard Worker namespace skjson {
24*c8dee2aaSAndroid Build Coastguard Worker class ArrayValue;
25*c8dee2aaSAndroid Build Coastguard Worker }
26*c8dee2aaSAndroid Build Coastguard Worker
27*c8dee2aaSAndroid Build Coastguard Worker namespace skottie {
28*c8dee2aaSAndroid Build Coastguard Worker namespace internal {
29*c8dee2aaSAndroid Build Coastguard Worker
30*c8dee2aaSAndroid Build Coastguard Worker namespace {
31*c8dee2aaSAndroid Build Coastguard Worker
32*c8dee2aaSAndroid Build Coastguard Worker class GradientRampEffectAdapter final : public AnimatablePropertyContainer {
33*c8dee2aaSAndroid Build Coastguard Worker public:
Make(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer,const AnimationBuilder * abuilder)34*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<GradientRampEffectAdapter> Make(const skjson::ArrayValue& jprops,
35*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> layer,
36*c8dee2aaSAndroid Build Coastguard Worker const AnimationBuilder* abuilder) {
37*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<GradientRampEffectAdapter>(new GradientRampEffectAdapter(jprops,
38*c8dee2aaSAndroid Build Coastguard Worker std::move(layer),
39*c8dee2aaSAndroid Build Coastguard Worker abuilder));
40*c8dee2aaSAndroid Build Coastguard Worker }
41*c8dee2aaSAndroid Build Coastguard Worker
node() const42*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> node() const { return fShaderEffect; }
43*c8dee2aaSAndroid Build Coastguard Worker
44*c8dee2aaSAndroid Build Coastguard Worker private:
GradientRampEffectAdapter(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer,const AnimationBuilder * abuilder)45*c8dee2aaSAndroid Build Coastguard Worker GradientRampEffectAdapter(const skjson::ArrayValue& jprops,
46*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> layer,
47*c8dee2aaSAndroid Build Coastguard Worker const AnimationBuilder* abuilder)
48*c8dee2aaSAndroid Build Coastguard Worker : fShaderEffect(sksg::ShaderEffect::Make(std::move(layer))) {
49*c8dee2aaSAndroid Build Coastguard Worker enum : size_t {
50*c8dee2aaSAndroid Build Coastguard Worker kStartPoint_Index = 0,
51*c8dee2aaSAndroid Build Coastguard Worker kStartColor_Index = 1,
52*c8dee2aaSAndroid Build Coastguard Worker kEndPoint_Index = 2,
53*c8dee2aaSAndroid Build Coastguard Worker kEndColor_Index = 3,
54*c8dee2aaSAndroid Build Coastguard Worker kRampShape_Index = 4,
55*c8dee2aaSAndroid Build Coastguard Worker kRampScatter_Index = 5,
56*c8dee2aaSAndroid Build Coastguard Worker kBlendRatio_Index = 6,
57*c8dee2aaSAndroid Build Coastguard Worker };
58*c8dee2aaSAndroid Build Coastguard Worker
59*c8dee2aaSAndroid Build Coastguard Worker EffectBinder(jprops, *abuilder, this)
60*c8dee2aaSAndroid Build Coastguard Worker .bind( kStartPoint_Index, fStartPoint)
61*c8dee2aaSAndroid Build Coastguard Worker .bind( kStartColor_Index, fStartColor)
62*c8dee2aaSAndroid Build Coastguard Worker .bind( kEndPoint_Index, fEndPoint )
63*c8dee2aaSAndroid Build Coastguard Worker .bind( kEndColor_Index, fEndColor )
64*c8dee2aaSAndroid Build Coastguard Worker .bind( kRampShape_Index, fShape )
65*c8dee2aaSAndroid Build Coastguard Worker .bind(kRampScatter_Index, fScatter )
66*c8dee2aaSAndroid Build Coastguard Worker .bind( kBlendRatio_Index, fBlend );
67*c8dee2aaSAndroid Build Coastguard Worker }
68*c8dee2aaSAndroid Build Coastguard Worker
69*c8dee2aaSAndroid Build Coastguard Worker enum class InstanceType {
70*c8dee2aaSAndroid Build Coastguard Worker kNone,
71*c8dee2aaSAndroid Build Coastguard Worker kLinear,
72*c8dee2aaSAndroid Build Coastguard Worker kRadial,
73*c8dee2aaSAndroid Build Coastguard Worker };
74*c8dee2aaSAndroid Build Coastguard Worker
onSync()75*c8dee2aaSAndroid Build Coastguard Worker void onSync() override {
76*c8dee2aaSAndroid Build Coastguard Worker // This adapter manages a SG fragment with the following structure:
77*c8dee2aaSAndroid Build Coastguard Worker //
78*c8dee2aaSAndroid Build Coastguard Worker // - ShaderEffect [fRoot]
79*c8dee2aaSAndroid Build Coastguard Worker // \ GradientShader [fGradient]
80*c8dee2aaSAndroid Build Coastguard Worker // \ child/wrapped fragment
81*c8dee2aaSAndroid Build Coastguard Worker //
82*c8dee2aaSAndroid Build Coastguard Worker // The gradient shader is updated based on the (animatable) instance type (linear/radial).
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker auto update_gradient = [this] (InstanceType new_type) {
85*c8dee2aaSAndroid Build Coastguard Worker if (new_type != fInstanceType) {
86*c8dee2aaSAndroid Build Coastguard Worker fGradient = new_type == InstanceType::kLinear
87*c8dee2aaSAndroid Build Coastguard Worker ? sk_sp<sksg::Gradient>(sksg::LinearGradient::Make())
88*c8dee2aaSAndroid Build Coastguard Worker : sk_sp<sksg::Gradient>(sksg::RadialGradient::Make());
89*c8dee2aaSAndroid Build Coastguard Worker
90*c8dee2aaSAndroid Build Coastguard Worker fShaderEffect->setShader(fGradient);
91*c8dee2aaSAndroid Build Coastguard Worker fInstanceType = new_type;
92*c8dee2aaSAndroid Build Coastguard Worker }
93*c8dee2aaSAndroid Build Coastguard Worker
94*c8dee2aaSAndroid Build Coastguard Worker fGradient->setColorStops({{0, fStartColor},
95*c8dee2aaSAndroid Build Coastguard Worker {1, fEndColor}});
96*c8dee2aaSAndroid Build Coastguard Worker };
97*c8dee2aaSAndroid Build Coastguard Worker
98*c8dee2aaSAndroid Build Coastguard Worker static constexpr int kLinearShapeValue = 1;
99*c8dee2aaSAndroid Build Coastguard Worker const auto instance_type = (SkScalarRoundToInt(fShape) == kLinearShapeValue)
100*c8dee2aaSAndroid Build Coastguard Worker ? InstanceType::kLinear
101*c8dee2aaSAndroid Build Coastguard Worker : InstanceType::kRadial;
102*c8dee2aaSAndroid Build Coastguard Worker
103*c8dee2aaSAndroid Build Coastguard Worker // Sync the gradient shader instance if needed.
104*c8dee2aaSAndroid Build Coastguard Worker update_gradient(instance_type);
105*c8dee2aaSAndroid Build Coastguard Worker
106*c8dee2aaSAndroid Build Coastguard Worker // Sync instance-dependent gradient params.
107*c8dee2aaSAndroid Build Coastguard Worker const auto start_point = SkPoint{fStartPoint.x, fStartPoint.y},
108*c8dee2aaSAndroid Build Coastguard Worker end_point = SkPoint{ fEndPoint.x, fEndPoint.y};
109*c8dee2aaSAndroid Build Coastguard Worker if (instance_type == InstanceType::kLinear) {
110*c8dee2aaSAndroid Build Coastguard Worker auto* lg = static_cast<sksg::LinearGradient*>(fGradient.get());
111*c8dee2aaSAndroid Build Coastguard Worker lg->setStartPoint(start_point);
112*c8dee2aaSAndroid Build Coastguard Worker lg->setEndPoint(end_point);
113*c8dee2aaSAndroid Build Coastguard Worker } else {
114*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(instance_type == InstanceType::kRadial);
115*c8dee2aaSAndroid Build Coastguard Worker
116*c8dee2aaSAndroid Build Coastguard Worker auto* rg = static_cast<sksg::RadialGradient*>(fGradient.get());
117*c8dee2aaSAndroid Build Coastguard Worker rg->setStartCenter(start_point);
118*c8dee2aaSAndroid Build Coastguard Worker rg->setEndCenter(start_point);
119*c8dee2aaSAndroid Build Coastguard Worker rg->setEndRadius(SkPoint::Distance(start_point, end_point));
120*c8dee2aaSAndroid Build Coastguard Worker }
121*c8dee2aaSAndroid Build Coastguard Worker
122*c8dee2aaSAndroid Build Coastguard Worker // TODO: blend, scatter
123*c8dee2aaSAndroid Build Coastguard Worker }
124*c8dee2aaSAndroid Build Coastguard Worker
125*c8dee2aaSAndroid Build Coastguard Worker const sk_sp<sksg::ShaderEffect> fShaderEffect;
126*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::Gradient> fGradient;
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker InstanceType fInstanceType = InstanceType::kNone;
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker ColorValue fStartColor,
131*c8dee2aaSAndroid Build Coastguard Worker fEndColor;
132*c8dee2aaSAndroid Build Coastguard Worker Vec2Value fStartPoint = {0,0},
133*c8dee2aaSAndroid Build Coastguard Worker fEndPoint = {0,0};
134*c8dee2aaSAndroid Build Coastguard Worker ScalarValue fBlend = 0,
135*c8dee2aaSAndroid Build Coastguard Worker fScatter = 0,
136*c8dee2aaSAndroid Build Coastguard Worker fShape = 0; // 1 -> linear, 7 -> radial (?!)
137*c8dee2aaSAndroid Build Coastguard Worker };
138*c8dee2aaSAndroid Build Coastguard Worker
139*c8dee2aaSAndroid Build Coastguard Worker } // namespace
140*c8dee2aaSAndroid Build Coastguard Worker
attachGradientEffect(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer) const141*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> EffectBuilder::attachGradientEffect(const skjson::ArrayValue& jprops,
142*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> layer) const {
143*c8dee2aaSAndroid Build Coastguard Worker return fBuilder->attachDiscardableAdapter<GradientRampEffectAdapter>(jprops,
144*c8dee2aaSAndroid Build Coastguard Worker std::move(layer),
145*c8dee2aaSAndroid Build Coastguard Worker fBuilder);
146*c8dee2aaSAndroid Build Coastguard Worker }
147*c8dee2aaSAndroid Build Coastguard Worker
148*c8dee2aaSAndroid Build Coastguard Worker } // namespace internal
149*c8dee2aaSAndroid Build Coastguard Worker } // namespace skottie
150