blob: 1990fbf67b5674baeb8ddc0f172e8fe561d80072 [file] [log] [blame]
/*
* 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 and b values of the color,
where g is the integer component and b is the fractional component. The r value
represents the max final alpha.
*/
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*255.0 + color.b;");
fragBuilder->codeAppendf("float factor = 1.0 - clamp(%s.z/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
///////////////////////////////////////////////////////////////////////////////