aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects/SkGaussianEdgeShader.cpp
blob: d73bfadbd77bead16a7c33f836186fd313a2bde1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
 * Copyright 2016 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkGaussianEdgeShader.h"
#include "SkReadBuffer.h"
#include "SkWriteBuffer.h"

 /** \class SkGaussianEdgeShaderImpl
 This subclass of shader applies a Gaussian to shadow edge

 The radius of the Gaussian blur is specified by the g value of the color, in 6.2 fixed point.
 For spot shadows, we increase the stroke width to set the shadow against the shape. This pad
 is specified by b, also in 6.2 fixed point. The r value represents the max final alpha.
 The incoming alpha should be 1.
 */
class SkGaussianEdgeShaderImpl : public SkShader {
public:
    SkGaussianEdgeShaderImpl() {}

    bool isOpaque() const override;

#if SK_SUPPORT_GPU
    sk_sp<GrFragmentProcessor> asFragmentProcessor(const AsFPArgs&) const override;
#endif

    SK_TO_STRING_OVERRIDE()
    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkGaussianEdgeShaderImpl)

protected:
    void flatten(SkWriteBuffer&) const override;

private:
    friend class SkGaussianEdgeShader;

    typedef SkShader INHERITED;
};

////////////////////////////////////////////////////////////////////////////

#if SK_SUPPORT_GPU

#include "GrCoordTransform.h"
#include "GrFragmentProcessor.h"
#include "GrInvariantOutput.h"
#include "glsl/GrGLSLFragmentProcessor.h"
#include "glsl/GrGLSLFragmentShaderBuilder.h"
#include "glsl/GrGLSLProgramDataManager.h"
#include "glsl/GrGLSLUniformHandler.h"
#include "SkGr.h"
#include "SkGrPriv.h"

class GaussianEdgeFP : public GrFragmentProcessor {
public:
    GaussianEdgeFP() {
        this->initClassID<GaussianEdgeFP>();

        // enable output of distance information for shape
        fUsesDistanceVectorField = true;
    }

    class GLSLGaussianEdgeFP : public GrGLSLFragmentProcessor {
    public:
        GLSLGaussianEdgeFP() {}

        void emitCode(EmitArgs& args) override {

            GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;

            fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
            fragBuilder->codeAppend("float radius = color.g*64.0;");
            fragBuilder->codeAppend("float pad = color.b*64.0;");

            fragBuilder->codeAppendf("float factor = 1.0 - clamp((%s.z - pad)/radius, 0.0, 1.0);",
                                     fragBuilder->distanceVectorName());
            fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
            fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.r);", args.fOutputColor);
        }

        static void GenKey(const GrProcessor& proc, const GrGLSLCaps&,
                           GrProcessorKeyBuilder* b) {
            // only one shader generated currently
            b->add32(0x0);
        }

    protected:
        void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {}
    };

    void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override {
        GLSLGaussianEdgeFP::GenKey(*this, caps, b);
    }

    const char* name() const override { return "GaussianEdgeFP"; }

    void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
        inout->mulByUnknownFourComponents();
    }

private:
    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override { return new GLSLGaussianEdgeFP; }

    bool onIsEqual(const GrFragmentProcessor& proc) const override { return true; }
};

////////////////////////////////////////////////////////////////////////////

sk_sp<GrFragmentProcessor> SkGaussianEdgeShaderImpl::asFragmentProcessor(const AsFPArgs& args) const {
    return sk_make_sp<GaussianEdgeFP>();
}

#endif

////////////////////////////////////////////////////////////////////////////

bool SkGaussianEdgeShaderImpl::isOpaque() const {
    return false;
}

////////////////////////////////////////////////////////////////////////////

#ifndef SK_IGNORE_TO_STRING
void SkGaussianEdgeShaderImpl::toString(SkString* str) const {
    str->appendf("GaussianEdgeShader: ()");
}
#endif

sk_sp<SkFlattenable> SkGaussianEdgeShaderImpl::CreateProc(SkReadBuffer& buf) {
    return sk_make_sp<SkGaussianEdgeShaderImpl>();
}

void SkGaussianEdgeShaderImpl::flatten(SkWriteBuffer& buf) const {
    this->INHERITED::flatten(buf);
}

///////////////////////////////////////////////////////////////////////////////

sk_sp<SkShader> SkGaussianEdgeShader::Make() {
    return sk_make_sp<SkGaussianEdgeShaderImpl>();
}

///////////////////////////////////////////////////////////////////////////////

SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGaussianEdgeShader)
SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkGaussianEdgeShaderImpl)
SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END

///////////////////////////////////////////////////////////////////////////////