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/effects/SkRuntimeEffect.h"
11 #include "modules/skottie/src/Adapter.h"
12 #include "modules/skottie/src/SkottieJson.h"
13 #include "modules/skottie/src/SkottieValue.h"
14 #include "modules/sksg/include/SkSGColorFilter.h"
15 
16 namespace skottie::internal {
17 
18 namespace  {
19 
20 // Convert to black & white, based on input luminance and a threshold uniform.
21 static constexpr char gThresholdSkSL[] = R"(
22     uniform half   t;
23 
24     half4 main(half4 color) {
25         half4 c = unpremul(color);
26 
27         half lum = dot(c.rgb, half3(0.2126, 0.7152, 0.0722)),
28               bw = step(t, lum);
29 
30         return bw.xxx1 * c.a;
31     }
32 )";
33 
threshold_effect()34 static sk_sp<SkRuntimeEffect> threshold_effect() {
35     static const SkRuntimeEffect* effect =
36         SkRuntimeEffect::MakeForColorFilter(SkString(gThresholdSkSL), {}).effect.release();
37     SkASSERT(effect);
38 
39     return sk_ref_sp(effect);
40 }
41 
42 class ThresholdAdapter final : public DiscardableAdapterBase<ThresholdAdapter,
43                                                              sksg::ExternalColorFilter> {
44 public:
ThresholdAdapter(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer,const AnimationBuilder & abuilder)45     ThresholdAdapter(const skjson::ArrayValue& jprops,
46                      sk_sp<sksg::RenderNode> layer,
47                      const AnimationBuilder& abuilder)
48         : INHERITED(sksg::ExternalColorFilter::Make(std::move(layer)))
49     {
50         enum : size_t {
51             kLevel_Index = 0,
52         };
53 
54         EffectBinder(jprops, abuilder, this).bind(kLevel_Index, fLevel);
55     }
56 
57 private:
onSync()58     void onSync() override {
59         auto cf =
60                 threshold_effect()->makeColorFilter(SkData::MakeWithCopy(&fLevel, sizeof(fLevel)));
61 
62         this->node()->setColorFilter(std::move(cf));
63     }
64 
65     ScalarValue fLevel = 0;
66 
67     using INHERITED = DiscardableAdapterBase<ThresholdAdapter, sksg::ExternalColorFilter>;
68 };
69 
70 } // namespace
71 
attachThresholdEffect(const skjson::ArrayValue & jprops,sk_sp<sksg::RenderNode> layer) const72 sk_sp<sksg::RenderNode> EffectBuilder::attachThresholdEffect(const skjson::ArrayValue& jprops,
73                                                              sk_sp<sksg::RenderNode> layer) const {
74     return fBuilder->attachDiscardableAdapter<ThresholdAdapter>(jprops,
75                                                                 std::move(layer),
76                                                                 *fBuilder);
77 }
78 
79 } // namespace skottie::internal
80