Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / modules / skottie / src / effects / BuldgeEffect.cpp
1 /*
2  * Copyright 2021 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 "include/core/SkCanvas.h"
11 #include "include/core/SkPictureRecorder.h"
12 #include "include/effects/SkRuntimeEffect.h"
13 #include "modules/skottie/src/Adapter.h"
14 #include "modules/skottie/src/SkottieValue.h"
15 #include "modules/sksg/include/SkSGPaint.h"
16 #include "modules/sksg/include/SkSGRenderNode.h"
17 #include "src/utils/SkJSON.h"
18
19 namespace skottie::internal {
20
21 #ifdef SK_ENABLE_SKSL
22
23 namespace {
24
25 static constexpr char gBulgeDisplacementSkSL[] =
26     "uniform shader u_layer;"
27
28     "uniform float2 u_center;"
29     "uniform float2 u_radius;"
30     "uniform float  u_h;"
31     "uniform float  u_r;"
32     "uniform float  u_asinInverseR;"
33     "uniform float  u_rcpR;"
34     "uniform float  u_rcpAsinInvR;"
35     "uniform float  u_selector;"
36
37     // AE's bulge effect appears to be a combination of spherical displacement and
38     // exponential displacement along the radius.
39     // To simplify the math, we pre scale/translate such that the ellipse becomes a
40     // circle with radius == 1, centered on origin.
41     "float2 displace_sph(float2 v) {"
42         "float arc_ratio = asin(length(v)*u_rcpR)*u_rcpAsinInvR;"
43         "return normalize(v)*arc_ratio - v;"
44     "}"
45
46     "float2 displace_exp(float2 v) {"
47         "return v*pow(dot(v,v),u_h) - v;"
48     "}"
49
50     "half2 displace(float2 v) {"
51         "float t = dot(v, v);"
52         "if (t >= 1) {"
53             "return v;"
54         "}"
55         "float2 d = displace_sph(v) + displace_exp(v);"
56         "return v + (d * u_selector);"
57     "}"
58
59     "half4 main(float2 xy) {"
60         "xy = displace(xy);"
61         "xy = xy*u_radius + u_center;"
62         "return u_layer.eval(xy);"
63     "}";
64
65 static sk_sp<SkRuntimeEffect> bulge_effect() {
66     static const SkRuntimeEffect* effect =
67         SkRuntimeEffect::MakeForShader(SkString(gBulgeDisplacementSkSL), {}).effect.release();
68     SkASSERT(effect);
69
70     return sk_ref_sp(effect);
71 }
72
73 class BulgeNode final : public sksg::CustomRenderNode {
74 public:
75     explicit BulgeNode(sk_sp<RenderNode> child, const SkSize& child_size)
76         : INHERITED({std::move(child)})
77         , fChildSize(child_size) {}
78
79     SG_ATTRIBUTE(Center  , SkPoint   , fCenter)
80     SG_ATTRIBUTE(Radius  , SkVector  , fRadius)
81     SG_ATTRIBUTE(Height  , float     , fHeight)
82
83 private:
84     sk_sp<SkShader> contentShader() {
85         if (!fContentShader || this->hasChildrenInval()) {
86             const auto& child = this->children()[0];
87             child->revalidate(nullptr, SkMatrix::I());
88
89             SkPictureRecorder recorder;
90             child->render(recorder.beginRecording(SkRect::MakeSize(fChildSize)));
91
92             fContentShader = recorder.finishRecordingAsPicture()
93                     ->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat, SkFilterMode::kLinear,
94                                  nullptr, nullptr);
95         }
96
97         return fContentShader;
98     }
99
100     sk_sp<SkShader> buildEffectShader() {
101         if (fHeight == 0) {
102             return nullptr;
103         }
104
105         SkRuntimeShaderBuilder builder(bulge_effect());
106         float adjHeight = std::abs(fHeight)/4;
107         float r = (1 + adjHeight)/2/sqrt(adjHeight);
108         float h = std::pow(adjHeight, 3)*1.3;
109         builder.uniform("u_center")       = fCenter;
110         builder.uniform("u_radius")       = fRadius;
111         builder.uniform("u_h")            = h;
112         builder.uniform("u_r")            = r;
113         builder.uniform("u_asinInverseR") = std::asin(1/r);
114         builder.uniform("u_rcpR")            = 1.0f/r;
115         builder.uniform("u_rcpAsinInvR") = 1.0f/std::asin(1/r);
116         builder.uniform("u_selector")     = (fHeight > 0 ? 1.0f : -1.0f);
117
118         builder.child("u_layer") = this->contentShader();
119
120         const auto lm = SkMatrix::Translate(fCenter.x(), fCenter.y())
121                       * SkMatrix::Scale(fRadius.x(), fRadius.y());
122         return builder.makeShader(&lm);
123     }
124
125     SkRect onRevalidate(sksg::InvalidationController* ic, const SkMatrix& ctm) override {
126         const auto& child = this->children()[0];
127         fEffectShader = buildEffectShader();
128         return child->revalidate(ic, ctm);
129     }
130
131     void onRender(SkCanvas* canvas, const RenderContext* ctx) const override {
132         if (fHeight == 0) {
133             this->children()[0]->render(canvas, ctx);
134             return;
135         }
136         const auto& bounds = this->bounds();
137         const auto local_ctx = ScopedRenderContext(canvas, ctx)
138                 .setIsolation(bounds, canvas->getTotalMatrix(), true);
139
140         canvas->saveLayer(&bounds, nullptr);
141
142         SkPaint effect_paint;
143         effect_paint.setShader(fEffectShader);
144         effect_paint.setBlendMode(SkBlendMode::kSrcOver);
145
146         canvas->drawPaint(effect_paint);
147     }
148
149     const RenderNode* onNodeAt(const SkPoint&) const override { return nullptr; } // no hit-testing
150
151     sk_sp<SkShader> fEffectShader;
152     sk_sp<SkShader> fContentShader;
153     const SkSize fChildSize;
154
155     SkPoint  fCenter = {0,0};
156     SkVector fRadius = {0,0};
157     float   fHeight = 0;
158
159     using INHERITED = sksg::CustomRenderNode;
160 };
161
162 class BulgeEffectAdapter final : public DiscardableAdapterBase<BulgeEffectAdapter,
163                                                              BulgeNode> {
164 public:
165     BulgeEffectAdapter(const skjson::ArrayValue& jprops,
166                       const AnimationBuilder& abuilder,
167                       sk_sp<BulgeNode> node)
168         : INHERITED(std::move(node))
169     {
170         enum : size_t {
171             kHorizontalRadius_Index = 0,
172             kVerticalRadius_Index = 1,
173             kBulgeCenter_Index = 2,
174             kBulgeHeight_Index = 3,
175             // kTaper_Index = 4,
176             // kAA_Index = 5,
177             // kPinning_Index = 6,
178         };
179         EffectBinder(jprops, abuilder, this).bind(kHorizontalRadius_Index, fHorizontalRadius)
180                                             .bind(kVerticalRadius_Index, fVerticalRadius)
181                                             .bind(kBulgeCenter_Index, fCenter)
182                                             .bind(kBulgeHeight_Index, fBulgeHeight);
183     }
184
185 private:
186     void onSync() override {
187         // pre-shader math
188         auto n = this->node();
189         n->setCenter({fCenter.x, fCenter.y});
190         n->setRadius({fHorizontalRadius, fVerticalRadius});
191         n->setHeight(fBulgeHeight);
192     }
193
194     Vec2Value fCenter;
195     ScalarValue fHorizontalRadius,
196                 fVerticalRadius,
197                 fBulgeHeight;
198     using INHERITED = DiscardableAdapterBase<BulgeEffectAdapter, BulgeNode>;
199 };
200
201 } // namespace
202
203 #endif  // SK_ENABLE_SKSL
204
205 sk_sp<sksg::RenderNode> EffectBuilder::attachBulgeEffect(const skjson::ArrayValue& jprops,
206                                                              sk_sp<sksg::RenderNode> layer) const {
207 #ifdef SK_ENABLE_SKSL
208     auto shaderNode = sk_make_sp<BulgeNode>(std::move(layer), fLayerSize);
209     return fBuilder->attachDiscardableAdapter<BulgeEffectAdapter>(jprops, *fBuilder, std::move(shaderNode));
210 #else
211     return layer;
212 #endif
213 }
214
215 } // namespace skottie::internal