/* * 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 If largerBlur is false: 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. If largerBlur is true: The radius of the Gaussian blur is specified by the r & g values of the color in 14.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 a value represents the max final alpha. LargerBlur will be removed once Android is migrated to the updated shader. */ class SkGaussianEdgeShaderImpl : public SkShader { public: SkGaussianEdgeShaderImpl() {} bool isOpaque() const override; #if SK_SUPPORT_GPU sk_sp 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(); // enable output of distance information for shape fUsesDistanceVectorField = true; } class GLSLGaussianEdgeFP : public GrGLSLFragmentProcessor { public: GLSLGaussianEdgeFP() {} void emitCode(EmitArgs& args) override { GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder; if (!args.fGpImplementsDistanceVector) { fragBuilder->codeAppendf("// GP does not implement fsDistanceVector - " " returning grey in GLSLGaussianEdgeFP\n"); fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor); fragBuilder->codeAppendf("%s = vec4(0.0, 0.0, 0.0, color.r);", args.fOutputColor); } else { fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor); fragBuilder->codeAppend("float radius = color.r*256.0*64.0 + 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.a);", args.fOutputColor); } } static void GenKey(const GrProcessor& proc, const GrShaderCaps&, GrProcessorKeyBuilder* b) { // only one shader generated currently b->add32(0x0); } protected: void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {} bool fLargerBlur; }; void onGetGLSLProcessorKey(const GrShaderCaps& 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 SkGaussianEdgeShaderImpl::asFragmentProcessor(const AsFPArgs&) const { return sk_make_sp(); } #endif //////////////////////////////////////////////////////////////////////////// bool SkGaussianEdgeShaderImpl::isOpaque() const { return false; } //////////////////////////////////////////////////////////////////////////// #ifndef SK_IGNORE_TO_STRING void SkGaussianEdgeShaderImpl::toString(SkString* str) const { str->appendf("GaussianEdgeShader: ()"); } #endif sk_sp SkGaussianEdgeShaderImpl::CreateProc(SkReadBuffer& buf) { return sk_make_sp(); } void SkGaussianEdgeShaderImpl::flatten(SkWriteBuffer& buf) const { } /////////////////////////////////////////////////////////////////////////////// sk_sp SkGaussianEdgeShader::Make() { return sk_make_sp(); } /////////////////////////////////////////////////////////////////////////////// SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGaussianEdgeShader) SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkGaussianEdgeShaderImpl) SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END ///////////////////////////////////////////////////////////////////////////////