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/SkColor.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkShader.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSize.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTileMode.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkGradientShader.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTPin.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottiePriv.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/SkottieValue.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "modules/skottie/src/effects/Effects.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "modules/sksg/include/SkSGRenderNode.h"
21*c8dee2aaSAndroid Build Coastguard Worker
22*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
23*c8dee2aaSAndroid Build Coastguard Worker #include <cmath>
24*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
25*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
26*c8dee2aaSAndroid Build Coastguard Worker
27*c8dee2aaSAndroid Build Coastguard Worker namespace skjson {
28*c8dee2aaSAndroid Build Coastguard Worker class ArrayValue;
29*c8dee2aaSAndroid Build Coastguard Worker }
30*c8dee2aaSAndroid Build Coastguard Worker
31*c8dee2aaSAndroid Build Coastguard Worker namespace skottie {
32*c8dee2aaSAndroid Build Coastguard Worker namespace internal {
33*c8dee2aaSAndroid Build Coastguard Worker
34*c8dee2aaSAndroid Build Coastguard Worker namespace {
35*c8dee2aaSAndroid Build Coastguard Worker
36*c8dee2aaSAndroid Build Coastguard Worker class LinearWipeAdapter final : public MaskShaderEffectBase {
37*c8dee2aaSAndroid Build Coastguard Worker public:
Make(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer,const SkSize & layer_size,const AnimationBuilder * abuilder)38*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<LinearWipeAdapter> Make(const skjson::ArrayValue& jprops,
39*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> layer,
40*c8dee2aaSAndroid Build Coastguard Worker const SkSize& layer_size,
41*c8dee2aaSAndroid Build Coastguard Worker const AnimationBuilder* abuilder) {
42*c8dee2aaSAndroid Build Coastguard Worker return sk_sp<LinearWipeAdapter>(new LinearWipeAdapter(jprops,
43*c8dee2aaSAndroid Build Coastguard Worker std::move(layer),
44*c8dee2aaSAndroid Build Coastguard Worker layer_size,
45*c8dee2aaSAndroid Build Coastguard Worker abuilder));
46*c8dee2aaSAndroid Build Coastguard Worker }
47*c8dee2aaSAndroid Build Coastguard Worker
48*c8dee2aaSAndroid Build Coastguard Worker private:
LinearWipeAdapter(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer,const SkSize & layer_size,const AnimationBuilder * abuilder)49*c8dee2aaSAndroid Build Coastguard Worker LinearWipeAdapter(const skjson::ArrayValue& jprops,
50*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> layer,
51*c8dee2aaSAndroid Build Coastguard Worker const SkSize& layer_size,
52*c8dee2aaSAndroid Build Coastguard Worker const AnimationBuilder* abuilder)
53*c8dee2aaSAndroid Build Coastguard Worker : INHERITED(std::move(layer), layer_size) {
54*c8dee2aaSAndroid Build Coastguard Worker enum : size_t {
55*c8dee2aaSAndroid Build Coastguard Worker kCompletion_Index = 0,
56*c8dee2aaSAndroid Build Coastguard Worker kAngle_Index = 1,
57*c8dee2aaSAndroid Build Coastguard Worker kFeather_Index = 2,
58*c8dee2aaSAndroid Build Coastguard Worker };
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker EffectBinder(jprops, *abuilder, this)
61*c8dee2aaSAndroid Build Coastguard Worker .bind(kCompletion_Index, fCompletion)
62*c8dee2aaSAndroid Build Coastguard Worker .bind( kAngle_Index, fAngle )
63*c8dee2aaSAndroid Build Coastguard Worker .bind( kFeather_Index, fFeather );
64*c8dee2aaSAndroid Build Coastguard Worker }
65*c8dee2aaSAndroid Build Coastguard Worker
onMakeMask() const66*c8dee2aaSAndroid Build Coastguard Worker MaskInfo onMakeMask() const override {
67*c8dee2aaSAndroid Build Coastguard Worker if (fCompletion >= 100) {
68*c8dee2aaSAndroid Build Coastguard Worker // The layer is fully disabled.
69*c8dee2aaSAndroid Build Coastguard Worker // TODO: fix layer controller visibility clash and pass a null shader instead.
70*c8dee2aaSAndroid Build Coastguard Worker return { SkShaders::Color(SK_ColorTRANSPARENT), false };
71*c8dee2aaSAndroid Build Coastguard Worker }
72*c8dee2aaSAndroid Build Coastguard Worker
73*c8dee2aaSAndroid Build Coastguard Worker if (fCompletion <= 0) {
74*c8dee2aaSAndroid Build Coastguard Worker // The layer is fully visible (no mask).
75*c8dee2aaSAndroid Build Coastguard Worker return { nullptr, true };
76*c8dee2aaSAndroid Build Coastguard Worker }
77*c8dee2aaSAndroid Build Coastguard Worker
78*c8dee2aaSAndroid Build Coastguard Worker const auto t = SkTPin(fCompletion * 0.01f, 0.0f, 1.0f),
79*c8dee2aaSAndroid Build Coastguard Worker feather = std::max(fFeather, 0.0f),
80*c8dee2aaSAndroid Build Coastguard Worker angle = SkDegreesToRadians(90 - fAngle),
81*c8dee2aaSAndroid Build Coastguard Worker cos_ = std::cos(angle),
82*c8dee2aaSAndroid Build Coastguard Worker sin_ = std::sin(angle);
83*c8dee2aaSAndroid Build Coastguard Worker
84*c8dee2aaSAndroid Build Coastguard Worker // Select the correct diagonal vector depending on quadrant.
85*c8dee2aaSAndroid Build Coastguard Worker const SkVector angle_v = {cos_, sin_},
86*c8dee2aaSAndroid Build Coastguard Worker diag_v = {std::copysign(this->layerSize().width() , cos_),
87*c8dee2aaSAndroid Build Coastguard Worker std::copysign(this->layerSize().height(), sin_)};
88*c8dee2aaSAndroid Build Coastguard Worker
89*c8dee2aaSAndroid Build Coastguard Worker // The transition length is the projection of the diagonal onto the angle vector.
90*c8dee2aaSAndroid Build Coastguard Worker const auto len = SkVector::DotProduct(diag_v, angle_v);
91*c8dee2aaSAndroid Build Coastguard Worker
92*c8dee2aaSAndroid Build Coastguard Worker // Pad the gradient segment to accommodate optional feather ramps at both extremities.
93*c8dee2aaSAndroid Build Coastguard Worker const auto grad_len = len + feather * 2;
94*c8dee2aaSAndroid Build Coastguard Worker const SkVector grad_v = angle_v * grad_len,
95*c8dee2aaSAndroid Build Coastguard Worker adjusted_grad_v = { grad_v.fX, -grad_v.fY }, // Y flipped for drawing space.
96*c8dee2aaSAndroid Build Coastguard Worker center_v = {0.5f * this->layerSize().width(),
97*c8dee2aaSAndroid Build Coastguard Worker 0.5f * this->layerSize().height()};
98*c8dee2aaSAndroid Build Coastguard Worker
99*c8dee2aaSAndroid Build Coastguard Worker // Gradient start/end points:
100*c8dee2aaSAndroid Build Coastguard Worker const SkPoint pts[] = {
101*c8dee2aaSAndroid Build Coastguard Worker center_v - adjusted_grad_v * 0.5f,
102*c8dee2aaSAndroid Build Coastguard Worker center_v + adjusted_grad_v * 0.5f,
103*c8dee2aaSAndroid Build Coastguard Worker };
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkColor colors[] = { 0x00000000,
106*c8dee2aaSAndroid Build Coastguard Worker 0xffffffff };
107*c8dee2aaSAndroid Build Coastguard Worker
108*c8dee2aaSAndroid Build Coastguard Worker // To emulate the feather effect, we distance the color stops to generate
109*c8dee2aaSAndroid Build Coastguard Worker // a linear transition/ramp. For t == 0 the ramp should be completely outside/before
110*c8dee2aaSAndroid Build Coastguard Worker // the transition domain, and for t == 1 it should be completely outside/after.
111*c8dee2aaSAndroid Build Coastguard Worker //
112*c8dee2aaSAndroid Build Coastguard Worker // [0 ................... |len|]
113*c8dee2aaSAndroid Build Coastguard Worker //
114*c8dee2aaSAndroid Build Coastguard Worker // [0 <feather_ramp> [ ] <feather_ramp> |grad_len|]
115*c8dee2aaSAndroid Build Coastguard Worker const auto adjusted_t = t * (len + feather) / grad_len;
116*c8dee2aaSAndroid Build Coastguard Worker const SkScalar pos[] = { adjusted_t,
117*c8dee2aaSAndroid Build Coastguard Worker adjusted_t + feather / grad_len };
118*c8dee2aaSAndroid Build Coastguard Worker
119*c8dee2aaSAndroid Build Coastguard Worker return { SkGradientShader::MakeLinear(pts, colors, pos, 2, SkTileMode::kClamp), true };
120*c8dee2aaSAndroid Build Coastguard Worker }
121*c8dee2aaSAndroid Build Coastguard Worker
122*c8dee2aaSAndroid Build Coastguard Worker ScalarValue fCompletion = 0,
123*c8dee2aaSAndroid Build Coastguard Worker fAngle = 0,
124*c8dee2aaSAndroid Build Coastguard Worker fFeather = 0;
125*c8dee2aaSAndroid Build Coastguard Worker
126*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = MaskShaderEffectBase;
127*c8dee2aaSAndroid Build Coastguard Worker };
128*c8dee2aaSAndroid Build Coastguard Worker
129*c8dee2aaSAndroid Build Coastguard Worker } // namespace
130*c8dee2aaSAndroid Build Coastguard Worker
attachLinearWipeEffect(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer) const131*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> EffectBuilder::attachLinearWipeEffect(const skjson::ArrayValue& jprops,
132*c8dee2aaSAndroid Build Coastguard Worker sk_sp<sksg::RenderNode> layer) const {
133*c8dee2aaSAndroid Build Coastguard Worker return fBuilder->attachDiscardableAdapter<LinearWipeAdapter>(jprops,
134*c8dee2aaSAndroid Build Coastguard Worker std::move(layer),
135*c8dee2aaSAndroid Build Coastguard Worker fLayerSize,
136*c8dee2aaSAndroid Build Coastguard Worker fBuilder);
137*c8dee2aaSAndroid Build Coastguard Worker }
138*c8dee2aaSAndroid Build Coastguard Worker
139*c8dee2aaSAndroid Build Coastguard Worker } // namespace internal
140*c8dee2aaSAndroid Build Coastguard Worker } // namespace skottie
141*c8dee2aaSAndroid Build Coastguard Worker
142