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