Add geometric version of spot shadow
BUG=skia:6119 Change-Id: Ib9770bd88f4eebd68f2d893c5788f966d89f193c Reviewed-on: https://skia-review.googlesource.com/7585 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
This commit is contained in:
parent
fe8225802d
commit
91af727038
@ -42,6 +42,7 @@ skia_gpu_sources = [
|
||||
"$_include/gpu/GrTypesPriv.h",
|
||||
"$_include/gpu/GrXferProcessor.h",
|
||||
|
||||
"$_include/gpu/effects/GrBlurredEdgeFragmentProcessor.h",
|
||||
"$_include/gpu/effects/GrConstColorProcessor.h",
|
||||
"$_include/gpu/effects/GrCoverageSetOpXP.h",
|
||||
"$_include/gpu/effects/GrCustomXfermode.h",
|
||||
@ -296,6 +297,7 @@ skia_gpu_sources = [
|
||||
"$_src/gpu/ops/GrTestMeshDrawOp.h",
|
||||
|
||||
"$_src/gpu/effects/Gr1DKernelEffect.h",
|
||||
"$_src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp",
|
||||
"$_src/gpu/effects/GrConfigConversionEffect.cpp",
|
||||
"$_src/gpu/effects/GrConfigConversionEffect.h",
|
||||
"$_src/gpu/effects/GrConstColorProcessor.cpp",
|
||||
|
70
include/gpu/effects/GrBlurredEdgeFragmentProcessor.h
Executable file
70
include/gpu/effects/GrBlurredEdgeFragmentProcessor.h
Executable file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef GrBlurredEdgeFragmentProcessor_DEFINED
|
||||
#define GrBlurredEdgeFragmentProcessor_DEFINED
|
||||
|
||||
#include "GrFragmentProcessor.h"
|
||||
|
||||
/**
|
||||
* Shader for managing a blurred edge for a shadow.
|
||||
*
|
||||
* There are two blurring modes supported: Gaussian blur function and smoothstep function.
|
||||
*
|
||||
* If the primitive supports an implicit distance to the edge, the radius of the blur is specified
|
||||
* by 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.
|
||||
*
|
||||
* When not using implicit distance, then b in the input color represents the input to the
|
||||
* blur function.
|
||||
*
|
||||
* In either case, the a value represents the max final alpha.
|
||||
*/
|
||||
class GrBlurredEdgeFP : public GrFragmentProcessor {
|
||||
public:
|
||||
enum Mode {
|
||||
kGaussian_Mode,
|
||||
kSmoothstep_Mode,
|
||||
|
||||
kLastMode = kSmoothstep_Mode
|
||||
};
|
||||
static const int kModeCnt = kLastMode + 1;
|
||||
|
||||
static sk_sp<GrFragmentProcessor> Make(Mode mode = kGaussian_Mode) {
|
||||
return sk_sp<GrFragmentProcessor>(new GrBlurredEdgeFP(mode));
|
||||
}
|
||||
|
||||
const char* name() const override { return "BlurredEdge"; }
|
||||
|
||||
Mode mode() const { return fMode; }
|
||||
|
||||
private:
|
||||
GrBlurredEdgeFP(Mode mode)
|
||||
: INHERITED(kNone_OptimizationFlags)
|
||||
, fMode(mode) {
|
||||
// enable output of distance information for shape
|
||||
this->setWillUseDistanceVectorField();
|
||||
|
||||
this->initClassID<GrBlurredEdgeFP>();
|
||||
}
|
||||
|
||||
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
|
||||
|
||||
void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
|
||||
|
||||
bool onIsEqual(const GrFragmentProcessor&) const override;
|
||||
|
||||
void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
|
||||
|
||||
GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
|
||||
|
||||
Mode fMode;
|
||||
|
||||
typedef GrFragmentProcessor INHERITED;
|
||||
};
|
||||
|
||||
#endif
|
@ -12,18 +12,12 @@
|
||||
/** \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 the primitive supports an implicit distance to the edge, the radius of the blur is specified
|
||||
by 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.
|
||||
|
||||
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.
|
||||
When not using implicit distance, then b in the input color represents the input to the
|
||||
blur function.
|
||||
*/
|
||||
class SkGaussianEdgeShaderImpl : public SkShader {
|
||||
public:
|
||||
@ -51,86 +45,12 @@ private:
|
||||
|
||||
#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() : INHERITED(kNone_OptimizationFlags) {
|
||||
this->initClassID<GaussianEdgeFP>();
|
||||
|
||||
// enable output of distance information for shape
|
||||
this->setWillUseDistanceVectorField();
|
||||
}
|
||||
|
||||
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 - "
|
||||
" using alpha as input to GLSLGaussianEdgeFP\n");
|
||||
fragBuilder->codeAppendf("float factor = 1.0 - %s.a;", args.fInputColor);
|
||||
fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
|
||||
fragBuilder->codeAppendf("%s = vec4(0.0, 0.0, 0.0, factor);", 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; }
|
||||
|
||||
typedef GrFragmentProcessor INHERITED;
|
||||
};
|
||||
#include "effects/GrBlurredEdgeFragmentProcessor.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
sk_sp<GrFragmentProcessor> SkGaussianEdgeShaderImpl::asFragmentProcessor(const AsFPArgs&) const {
|
||||
return sk_make_sp<GaussianEdgeFP>();
|
||||
return GrBlurredEdgeFP::Make(GrBlurredEdgeFP::kGaussian_Mode);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -14,15 +14,11 @@
|
||||
#include "GrContext.h"
|
||||
#include "GrRenderTargetContext.h"
|
||||
#include "GrFragmentProcessor.h"
|
||||
#include "GrInvariantOutput.h"
|
||||
#include "GrStyle.h"
|
||||
#include "GrTexture.h"
|
||||
#include "GrTextureProxy.h"
|
||||
#include "effects/GrBlurredEdgeFragmentProcessor.h"
|
||||
#include "effects/GrShadowTessellator.h"
|
||||
#include "glsl/GrGLSLFragmentProcessor.h"
|
||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "glsl/GrGLSLProgramDataManager.h"
|
||||
#include "glsl/GrGLSLUniformHandler.h"
|
||||
#include "SkStrokeRec.h"
|
||||
#endif
|
||||
|
||||
@ -133,56 +129,6 @@ void SkAmbientShadowMaskFilterImpl::flatten(SkWriteBuffer& buffer) const {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// Shader for managing the shadow's edge. a in the input color represents the initial
|
||||
// edge color, which is transformed by a Gaussian function. b represents the blend factor,
|
||||
// which is multiplied by this transformed value.
|
||||
//
|
||||
class ShadowEdgeFP : public GrFragmentProcessor {
|
||||
public:
|
||||
ShadowEdgeFP() : INHERITED(kNone_OptimizationFlags) { this->initClassID<ShadowEdgeFP>(); }
|
||||
|
||||
class GLSLShadowEdgeFP : public GrGLSLFragmentProcessor {
|
||||
public:
|
||||
GLSLShadowEdgeFP() {}
|
||||
|
||||
void emitCode(EmitArgs& args) override {
|
||||
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
|
||||
|
||||
fragBuilder->codeAppendf("float factor = 1.0 - %s.a;", args.fInputColor);
|
||||
fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
|
||||
fragBuilder->codeAppendf("%s = vec4(0.0, 0.0, 0.0, %s.b*factor);", args.fOutputColor,
|
||||
args.fInputColor);
|
||||
}
|
||||
|
||||
static void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*) {}
|
||||
|
||||
protected:
|
||||
void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {}
|
||||
};
|
||||
|
||||
void onGetGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
|
||||
GLSLShadowEdgeFP::GenKey(*this, caps, b);
|
||||
}
|
||||
|
||||
const char* name() const override { return "ShadowEdgeFP"; }
|
||||
|
||||
void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
|
||||
inout->mulByUnknownFourComponents();
|
||||
}
|
||||
|
||||
private:
|
||||
GrGLSLFragmentProcessor* onCreateGLSLInstance() const override {
|
||||
return new GLSLShadowEdgeFP();
|
||||
}
|
||||
|
||||
bool onIsEqual(const GrFragmentProcessor& proc) const override { return true; }
|
||||
|
||||
typedef GrFragmentProcessor INHERITED;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool SkAmbientShadowMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect,
|
||||
const SkIRect& clipBounds,
|
||||
const SkMatrix& ctm,
|
||||
@ -200,7 +146,7 @@ bool SkAmbientShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texPr
|
||||
GrPaint&& paint,
|
||||
const GrClip& clip,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkStrokeRec&,
|
||||
const SkStrokeRec& strokeRec,
|
||||
const SkPath& path) const {
|
||||
SkASSERT(rtContext);
|
||||
// TODO: this will not handle local coordinates properly
|
||||
@ -214,6 +160,10 @@ bool SkAmbientShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texPr
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strokeRec.getStyle() != SkStrokeRec::kFill_Style) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_FAST_PATH
|
||||
// if circle
|
||||
// TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we
|
||||
@ -233,16 +183,16 @@ bool SkAmbientShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texPr
|
||||
SkScalar umbraAlpha = SkScalarInvert((1.0f+SkTMax(fOccluderHeight * kHeightFactor, 0.0f)));
|
||||
// umbraColor is the interior value, penumbraColor the exterior value.
|
||||
// umbraAlpha is the factor that is linearly interpolated from outside to inside, and
|
||||
// then "blurred" by the ShadowEdgeFP. It is then multiplied by fAmbientAlpha to get
|
||||
// then "blurred" by the GrBlurredEdgeFP. It is then multiplied by fAmbientAlpha to get
|
||||
// the final alpha.
|
||||
GrColor umbraColor = GrColorPackRGBA(0, 0, fAmbientAlpha*255.9999f, umbraAlpha*255.9999f);
|
||||
GrColor penumbraColor = GrColorPackRGBA(0, 0, fAmbientAlpha*255.9999f, 0);
|
||||
GrColor umbraColor = GrColorPackRGBA(0, 0, umbraAlpha*255.9999f, fAmbientAlpha*255.9999f);
|
||||
GrColor penumbraColor = GrColorPackRGBA(0, 0, 0, fAmbientAlpha*255.9999f);
|
||||
|
||||
GrAmbientShadowTessellator tess(SkMatrix::I(), path, radius, umbraColor, penumbraColor,
|
||||
GrAmbientShadowTessellator tess(path, radius, umbraColor, penumbraColor,
|
||||
SkToBool(fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag));
|
||||
|
||||
sk_sp<ShadowEdgeFP> edgeFP(new ShadowEdgeFP);
|
||||
paint.addColorFragmentProcessor(edgeFP);
|
||||
sk_sp<GrFragmentProcessor> edgeFP = GrBlurredEdgeFP::Make(GrBlurredEdgeFP::kGaussian_Mode);
|
||||
paint.addColorFragmentProcessor(std::move(edgeFP));
|
||||
|
||||
rtContext->drawVertices(clip, std::move(paint), SkMatrix::I(), kTriangles_GrPrimitiveType,
|
||||
tess.vertexCount(), tess.positions(), nullptr,
|
||||
|
@ -14,14 +14,11 @@
|
||||
#include "GrContext.h"
|
||||
#include "GrRenderTargetContext.h"
|
||||
#include "GrFragmentProcessor.h"
|
||||
#include "GrInvariantOutput.h"
|
||||
#include "GrStyle.h"
|
||||
#include "GrTexture.h"
|
||||
#include "GrTextureProxy.h"
|
||||
#include "glsl/GrGLSLFragmentProcessor.h"
|
||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
#include "glsl/GrGLSLProgramDataManager.h"
|
||||
#include "glsl/GrGLSLUniformHandler.h"
|
||||
#include "effects/GrBlurredEdgeFragmentProcessor.h"
|
||||
#include "effects/GrShadowTessellator.h"
|
||||
#include "SkStrokeRec.h"
|
||||
#endif
|
||||
|
||||
@ -162,15 +159,29 @@ bool SkSpotShadowMaskFilterImpl::canFilterMaskGPU(const SkRRect& devRRect,
|
||||
}
|
||||
|
||||
bool SkSpotShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvider,
|
||||
GrRenderTargetContext* drawContext,
|
||||
GrRenderTargetContext* rtContext,
|
||||
GrPaint&& paint,
|
||||
const GrClip& clip,
|
||||
const SkMatrix& viewMatrix,
|
||||
const SkStrokeRec& strokeRec,
|
||||
const SkPath& path) const {
|
||||
SkASSERT(drawContext);
|
||||
SkASSERT(rtContext);
|
||||
// TODO: this will not handle local coordinates properly
|
||||
|
||||
if (fSpotAlpha <= 0.0f) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// only convex paths for now
|
||||
if (!path.isConvex()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strokeRec.getStyle() != SkStrokeRec::kFill_Style) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef SUPPORT_FAST_PATH
|
||||
// if circle
|
||||
// TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we
|
||||
// have our own GeometryProc.
|
||||
@ -183,9 +194,32 @@ bool SkSpotShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvi
|
||||
return this->directFilterRRectMaskGPU(nullptr, drawContext, std::move(paint), clip,
|
||||
SkMatrix::I(), strokeRec, rrect, rrect);
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO
|
||||
return false;
|
||||
float zRatio = SkTPin(fOccluderHeight / (fLightPos.fZ - fOccluderHeight), 0.0f, 0.95f);
|
||||
|
||||
SkScalar radius = fLightRadius * zRatio;
|
||||
|
||||
// Compute the scale and translation for the spot shadow.
|
||||
const SkScalar scale = fLightPos.fZ / (fLightPos.fZ - fOccluderHeight);
|
||||
|
||||
SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
|
||||
const SkVector spotOffset = SkVector::Make(zRatio*(center.fX - fLightPos.fX),
|
||||
zRatio*(center.fY - fLightPos.fY));
|
||||
|
||||
GrColor umbraColor = GrColorPackRGBA(0, 0, 255, fSpotAlpha*255.9999f);
|
||||
GrColor penumbraColor = GrColorPackRGBA(0, 0, 0, fSpotAlpha*255.9999f);
|
||||
GrSpotShadowTessellator tess(path, scale, spotOffset, radius, umbraColor, penumbraColor,
|
||||
SkToBool(fFlags & SkShadowFlags::kTransparentOccluder_ShadowFlag));
|
||||
|
||||
sk_sp<GrFragmentProcessor> edgeFP = GrBlurredEdgeFP::Make(GrBlurredEdgeFP::kGaussian_Mode);
|
||||
paint.addColorFragmentProcessor(std::move(edgeFP));
|
||||
|
||||
rtContext->drawVertices(clip, std::move(paint), SkMatrix::I(), kTriangles_GrPrimitiveType,
|
||||
tess.vertexCount(), tess.positions(), nullptr,
|
||||
tess.colors(), tess.indices(), tess.indexCount());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
|
||||
@ -196,6 +230,10 @@ bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*,
|
||||
const SkStrokeRec& strokeRec,
|
||||
const SkRRect& rrect,
|
||||
const SkRRect& devRRect) const {
|
||||
#ifndef SUPPORT_FAST_PATH
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// It's likely the caller has already done these checks, but we have to be sure.
|
||||
// TODO: support analytic blurring of general rrect
|
||||
|
||||
|
72
src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
Executable file
72
src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
Executable file
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2017 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "effects/GrBlurredEdgeFragmentProcessor.h"
|
||||
#include "GrInvariantOutput.h"
|
||||
|
||||
#include "glsl/GrGLSLFragmentProcessor.h"
|
||||
#include "glsl/GrGLSLFragmentShaderBuilder.h"
|
||||
|
||||
class GLSLBlurredEdgeFP : public GrGLSLFragmentProcessor {
|
||||
public:
|
||||
GLSLBlurredEdgeFP() {}
|
||||
|
||||
void emitCode(EmitArgs& args) override {
|
||||
|
||||
GrBlurredEdgeFP::Mode mode = args.fFp.cast<GrBlurredEdgeFP>().mode();
|
||||
|
||||
GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
|
||||
|
||||
fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
|
||||
if (!args.fGpImplementsDistanceVector) {
|
||||
fragBuilder->codeAppendf("// assuming interpolant is set in vertex colors\n");
|
||||
fragBuilder->codeAppendf("float factor = 1.0 - color.b;");
|
||||
} else {
|
||||
fragBuilder->codeAppendf("// using distance to edge to compute interpolant\n");
|
||||
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());
|
||||
}
|
||||
switch (mode) {
|
||||
case GrBlurredEdgeFP::kGaussian_Mode:
|
||||
fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
|
||||
break;
|
||||
case GrBlurredEdgeFP::kSmoothstep_Mode:
|
||||
fragBuilder->codeAppend("factor = smoothstep(factor, 0.0, 1.0);");
|
||||
break;
|
||||
}
|
||||
fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.a);",
|
||||
args.fOutputColor);
|
||||
}
|
||||
|
||||
protected:
|
||||
void onSetData(const GrGLSLProgramDataManager& pdman, const GrProcessor& proc) override {}
|
||||
|
||||
GrBlurredEdgeFP::Mode fMode;
|
||||
};
|
||||
|
||||
GrGLSLFragmentProcessor* GrBlurredEdgeFP::onCreateGLSLInstance() const {
|
||||
return new GLSLBlurredEdgeFP();
|
||||
}
|
||||
|
||||
void GrBlurredEdgeFP::onGetGLSLProcessorKey(const GrShaderCaps& caps,
|
||||
GrProcessorKeyBuilder* b) const {
|
||||
b->add32(fMode);
|
||||
}
|
||||
|
||||
bool GrBlurredEdgeFP::onIsEqual(const GrFragmentProcessor& other) const {
|
||||
const GrBlurredEdgeFP& that = other.cast<GrBlurredEdgeFP>();
|
||||
return that.fMode == fMode;
|
||||
}
|
||||
|
||||
void GrBlurredEdgeFP::onComputeInvariantOutput(GrInvariantOutput* inout) const {
|
||||
inout->mulByUnknownFourComponents();
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,7 @@ static void compute_radial_steps(const SkVector& v1, const SkVector& v2, SkScala
|
||||
*n = SkScalarFloorToInt(steps);
|
||||
}
|
||||
|
||||
GrAmbientShadowTessellator::GrAmbientShadowTessellator(const SkMatrix& viewMatrix,
|
||||
const SkPath& path,
|
||||
GrAmbientShadowTessellator::GrAmbientShadowTessellator(const SkPath& path,
|
||||
SkScalar radius,
|
||||
GrColor umbraColor,
|
||||
GrColor penumbraColor,
|
||||
@ -74,16 +73,16 @@ GrAmbientShadowTessellator::GrAmbientShadowTessellator(const SkMatrix& viewMatri
|
||||
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
|
||||
switch (verb) {
|
||||
case SkPath::kLine_Verb:
|
||||
this->handleLine(viewMatrix, pts[1]);
|
||||
this->handleLine(pts[1]);
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
this->handleQuad(viewMatrix, pts);
|
||||
this->handleQuad(pts);
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
this->handleCubic(viewMatrix, pts);
|
||||
this->handleCubic(pts);
|
||||
break;
|
||||
case SkPath::kConic_Verb:
|
||||
this->handleConic(viewMatrix, pts, iter.conicWeight());
|
||||
this->handleConic(pts, iter.conicWeight());
|
||||
break;
|
||||
case SkPath::kMove_Verb:
|
||||
case SkPath::kClose_Verb:
|
||||
@ -192,15 +191,10 @@ void GrAmbientShadowTessellator::handleLine(const SkPoint& p) {
|
||||
SkVector normal;
|
||||
if (compute_normal(fPositions[fPrevInnerIndex], p, fRadius, fDirection, &normal)) {
|
||||
this->addArc(normal);
|
||||
this->addEdge(p, normal);
|
||||
this->finishArcAndAddEdge(p, normal);
|
||||
}
|
||||
}
|
||||
|
||||
void GrAmbientShadowTessellator::handleLine(const SkMatrix& m, SkPoint p) {
|
||||
m.mapPoints(&p, 1);
|
||||
this->handleLine(p);
|
||||
}
|
||||
|
||||
void GrAmbientShadowTessellator::handleQuad(const SkPoint pts[3]) {
|
||||
int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
|
||||
fPointBuffer.setReserve(maxCount);
|
||||
@ -213,13 +207,7 @@ void GrAmbientShadowTessellator::handleQuad(const SkPoint pts[3]) {
|
||||
}
|
||||
}
|
||||
|
||||
void GrAmbientShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) {
|
||||
m.mapPoints(pts, 3);
|
||||
this->handleQuad(pts);
|
||||
}
|
||||
|
||||
void GrAmbientShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) {
|
||||
m.mapPoints(pts, 4);
|
||||
void GrAmbientShadowTessellator::handleCubic(SkPoint pts[4]) {
|
||||
int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
|
||||
fPointBuffer.setReserve(maxCount);
|
||||
SkPoint* target = fPointBuffer.begin();
|
||||
@ -231,8 +219,7 @@ void GrAmbientShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4])
|
||||
}
|
||||
}
|
||||
|
||||
void GrAmbientShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
|
||||
m.mapPoints(pts, 3);
|
||||
void GrAmbientShadowTessellator::handleConic(SkPoint pts[3], SkScalar w) {
|
||||
SkAutoConicToQuads quadder;
|
||||
const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
|
||||
SkPoint lastPoint = *(quads++);
|
||||
@ -268,7 +255,6 @@ void GrAmbientShadowTessellator::addArc(const SkVector& nextNormal) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GrAmbientShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
|
||||
const SkVector& nextNormal) {
|
||||
// close out previous arc
|
||||
@ -309,3 +295,338 @@ void GrAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVecto
|
||||
fPrevInnerIndex = fPositions.count() - 2;
|
||||
fPrevNormal = nextNormal;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
GrSpotShadowTessellator::GrSpotShadowTessellator(const SkPath& path,
|
||||
SkScalar scale, const SkVector& translate,
|
||||
SkScalar radius,
|
||||
GrColor umbraColor, GrColor penumbraColor,
|
||||
bool /* transparent */)
|
||||
: fRadius(radius)
|
||||
, fUmbraColor(umbraColor)
|
||||
, fPenumbraColor(penumbraColor)
|
||||
, fPrevInnerIndex(-1) {
|
||||
|
||||
// TODO: calculate these better
|
||||
// Outer ring: 3*numPts
|
||||
// Inner ring: numPts
|
||||
fPositions.setReserve(4 * path.countPoints());
|
||||
fColors.setReserve(4 * path.countPoints());
|
||||
// Outer ring: 12*numPts
|
||||
// Inner ring: 0
|
||||
fIndices.setReserve(12 * path.countPoints());
|
||||
|
||||
fInitPoints.setReserve(3);
|
||||
|
||||
fClipPolygon.setReserve(path.countPoints());
|
||||
this->computeClipBounds(path);
|
||||
fCentroid *= scale;
|
||||
fCentroid += translate;
|
||||
|
||||
// walk around the path, tessellate and generate inner and outer rings
|
||||
SkPath::Iter iter(path, true);
|
||||
SkPoint pts[4];
|
||||
SkPath::Verb verb;
|
||||
*fPositions.push() = fCentroid;
|
||||
*fColors.push() = fUmbraColor;
|
||||
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
|
||||
switch (verb) {
|
||||
case SkPath::kLine_Verb:
|
||||
this->handleLine(scale, translate, pts[1]);
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
this->handleQuad(scale, translate, pts);
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
this->handleCubic(scale, translate, pts);
|
||||
break;
|
||||
case SkPath::kConic_Verb:
|
||||
this->handleConic(scale, translate, pts, iter.conicWeight());
|
||||
break;
|
||||
case SkPath::kMove_Verb:
|
||||
case SkPath::kClose_Verb:
|
||||
case SkPath::kDone_Verb:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SkVector normal;
|
||||
if (compute_normal(fPrevPoint, fFirstPoint, fRadius, fDirection,
|
||||
&normal)) {
|
||||
this->addArc(normal);
|
||||
|
||||
// close out previous arc
|
||||
*fPositions.push() = fPrevPoint + normal;
|
||||
*fColors.push() = fPenumbraColor;
|
||||
*fIndices.push() = fPrevInnerIndex;
|
||||
*fIndices.push() = fPositions.count() - 2;
|
||||
*fIndices.push() = fPositions.count() - 1;
|
||||
|
||||
// add final edge
|
||||
*fPositions.push() = fFirstPoint + normal;
|
||||
*fColors.push() = fPenumbraColor;
|
||||
|
||||
*fIndices.push() = fPrevInnerIndex;
|
||||
*fIndices.push() = fPositions.count() - 2;
|
||||
*fIndices.push() = fFirstVertex;
|
||||
|
||||
*fIndices.push() = fPositions.count() - 2;
|
||||
*fIndices.push() = fPositions.count() - 1;
|
||||
*fIndices.push() = fFirstVertex;
|
||||
|
||||
// add to center fan
|
||||
*fIndices.push() = 0;
|
||||
*fIndices.push() = fPrevInnerIndex;
|
||||
*fIndices.push() = fFirstVertex;
|
||||
}
|
||||
|
||||
// final fan
|
||||
if (fPositions.count() >= 3) {
|
||||
fPrevInnerIndex = fFirstVertex;
|
||||
fPrevPoint = fFirstPoint;
|
||||
fPrevNormal = normal;
|
||||
this->addArc(fFirstNormal);
|
||||
|
||||
*fIndices.push() = fFirstVertex;
|
||||
*fIndices.push() = fPositions.count() - 1;
|
||||
*fIndices.push() = fFirstVertex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::computeClipBounds(const SkPath& path) {
|
||||
// walk around the path and compute clip polygon
|
||||
// if original path is transparent, will accumulate sum of points for centroid
|
||||
SkPath::Iter iter(path, true);
|
||||
SkPoint pts[4];
|
||||
SkPath::Verb verb;
|
||||
|
||||
fCentroid = SkPoint::Make(0, 0);
|
||||
int centroidCount = 0;
|
||||
fClipPolygon.reset();
|
||||
|
||||
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
|
||||
switch (verb) {
|
||||
case SkPath::kMove_Verb:
|
||||
break;
|
||||
case SkPath::kLine_Verb:
|
||||
fCentroid += pts[1];
|
||||
centroidCount++;
|
||||
*fClipPolygon.push() = pts[1];
|
||||
break;
|
||||
case SkPath::kQuad_Verb:
|
||||
fCentroid += pts[1];
|
||||
fCentroid += pts[2];
|
||||
centroidCount += 2;
|
||||
*fClipPolygon.push() = pts[2];
|
||||
break;
|
||||
case SkPath::kConic_Verb:
|
||||
fCentroid += pts[1];
|
||||
fCentroid += pts[2];
|
||||
centroidCount += 2;
|
||||
*fClipPolygon.push() = pts[2];
|
||||
break;
|
||||
case SkPath::kCubic_Verb:
|
||||
fCentroid += pts[1];
|
||||
fCentroid += pts[2];
|
||||
fCentroid += pts[3];
|
||||
centroidCount += 3;
|
||||
*fClipPolygon.push() = pts[3];
|
||||
break;
|
||||
case SkPath::kClose_Verb:
|
||||
break;
|
||||
default:
|
||||
SkDEBUGFAIL("unknown verb");
|
||||
}
|
||||
}
|
||||
|
||||
fCentroid *= SkScalarInvert(centroidCount);
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate,
|
||||
SkPoint* pts, int count) {
|
||||
// TODO: vectorize
|
||||
for (int i = 0; i < count; ++i) {
|
||||
pts[i] *= scale;
|
||||
pts[i] += xlate;
|
||||
}
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::handleLine(const SkPoint& p) {
|
||||
if (fInitPoints.count() < 2) {
|
||||
*fInitPoints.push() = p;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fInitPoints.count() == 2) {
|
||||
// determine if cw or ccw
|
||||
SkVector v0 = fInitPoints[1] - fInitPoints[0];
|
||||
SkVector v1 = p - fInitPoints[0];
|
||||
SkScalar perpDot = v0.fX*v1.fY - v0.fY*v1.fX;
|
||||
if (SkScalarNearlyZero(perpDot)) {
|
||||
// nearly parallel, just treat as straight line and continue
|
||||
fInitPoints[1] = p;
|
||||
return;
|
||||
}
|
||||
|
||||
// if perpDot > 0, winding is ccw
|
||||
fDirection = (perpDot > 0) ? -1 : 1;
|
||||
|
||||
// add first quad
|
||||
if (!compute_normal(fInitPoints[0], fInitPoints[1], fRadius, fDirection,
|
||||
&fFirstNormal)) {
|
||||
// first two points are incident, make the third point the second and continue
|
||||
fInitPoints[1] = p;
|
||||
return;
|
||||
}
|
||||
|
||||
fFirstPoint = fInitPoints[0];
|
||||
fFirstVertex = fPositions.count();
|
||||
fPrevNormal = fFirstNormal;
|
||||
fPrevPoint = fFirstPoint;
|
||||
fPrevInnerIndex = fFirstVertex;
|
||||
|
||||
this->addInnerPoint(fFirstPoint, fUmbraColor, fRadius);
|
||||
SkPoint newPoint = fFirstPoint + fFirstNormal;
|
||||
*fPositions.push() = newPoint;
|
||||
*fColors.push() = fPenumbraColor;
|
||||
this->addEdge(fInitPoints[1], fFirstNormal);
|
||||
|
||||
// to ensure we skip this block next time
|
||||
*fInitPoints.push() = p;
|
||||
}
|
||||
|
||||
SkVector normal;
|
||||
if (compute_normal(fPrevPoint, p, fRadius, fDirection, &normal)) {
|
||||
this->addArc(normal);
|
||||
this->finishArcAndAddEdge(p, normal);
|
||||
}
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::handleLine(SkScalar scale, const SkVector& xlate, SkPoint p) {
|
||||
this->mapPoints(scale, xlate, &p, 1);
|
||||
this->handleLine(p);
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::handleQuad(const SkPoint pts[3]) {
|
||||
int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
|
||||
fPointBuffer.setReserve(maxCount);
|
||||
SkPoint* target = fPointBuffer.begin();
|
||||
int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
|
||||
kQuadTolerance, &target, maxCount);
|
||||
fPointBuffer.setCount(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
this->handleLine(fPointBuffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::handleQuad(SkScalar scale, const SkVector& xlate, SkPoint pts[3]) {
|
||||
this->mapPoints(scale, xlate, pts, 3);
|
||||
this->handleQuad(pts);
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::handleCubic(SkScalar scale, const SkVector& xlate, SkPoint pts[4]) {
|
||||
this->mapPoints(scale, xlate, pts, 4);
|
||||
int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
|
||||
fPointBuffer.setReserve(maxCount);
|
||||
SkPoint* target = fPointBuffer.begin();
|
||||
int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
|
||||
kCubicTolerance, &target, maxCount);
|
||||
fPointBuffer.setCount(count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
this->handleLine(fPointBuffer[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::handleConic(SkScalar scale, const SkVector& xlate,
|
||||
SkPoint pts[3], SkScalar w) {
|
||||
this->mapPoints(scale, xlate, pts, 3);
|
||||
SkAutoConicToQuads quadder;
|
||||
const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
|
||||
SkPoint lastPoint = *(quads++);
|
||||
int count = quadder.countQuads();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
SkPoint quadPts[3];
|
||||
quadPts[0] = lastPoint;
|
||||
quadPts[1] = quads[0];
|
||||
quadPts[2] = i == count - 1 ? pts[2] : quads[1];
|
||||
this->handleQuad(quadPts);
|
||||
lastPoint = quadPts[2];
|
||||
quads += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint, GrColor umbraColor,
|
||||
SkScalar radius) {
|
||||
SkVector v = fCentroid - pathPoint;
|
||||
SkScalar distance = v.length();
|
||||
if (distance < radius) {
|
||||
*fPositions.push() = fCentroid;
|
||||
*fColors.push() = umbraColor; // fix this
|
||||
// TODO: deal with fanning from centroid
|
||||
} else {
|
||||
SkScalar t = radius / distance;
|
||||
v *= t;
|
||||
SkPoint innerPoint = pathPoint + v;
|
||||
*fPositions.push() = innerPoint;
|
||||
*fColors.push() = umbraColor;
|
||||
}
|
||||
fPrevPoint = pathPoint;
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::addArc(const SkVector& nextNormal) {
|
||||
// fill in fan from previous quad
|
||||
SkScalar rotSin, rotCos;
|
||||
int numSteps;
|
||||
compute_radial_steps(fPrevNormal, nextNormal, fRadius, &rotSin, &rotCos, &numSteps);
|
||||
SkVector prevNormal = fPrevNormal;
|
||||
for (int i = 0; i < numSteps; ++i) {
|
||||
SkVector nextNormal;
|
||||
nextNormal.fX = prevNormal.fX*rotCos - prevNormal.fY*rotSin;
|
||||
nextNormal.fY = prevNormal.fY*rotCos + prevNormal.fX*rotSin;
|
||||
*fPositions.push() = fPrevPoint + nextNormal;
|
||||
*fColors.push() = fPenumbraColor;
|
||||
*fIndices.push() = fPrevInnerIndex;
|
||||
*fIndices.push() = fPositions.count() - 2;
|
||||
*fIndices.push() = fPositions.count() - 1;
|
||||
|
||||
prevNormal = nextNormal;
|
||||
}
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint,
|
||||
const SkVector& nextNormal) {
|
||||
// close out previous arc
|
||||
SkPoint newPoint = fPrevPoint + nextNormal;
|
||||
*fPositions.push() = newPoint;
|
||||
*fColors.push() = fPenumbraColor;
|
||||
*fIndices.push() = fPrevInnerIndex;
|
||||
*fIndices.push() = fPositions.count() - 2;
|
||||
*fIndices.push() = fPositions.count() - 1;
|
||||
|
||||
this->addEdge(nextPoint, nextNormal);
|
||||
}
|
||||
|
||||
void GrSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) {
|
||||
// add next quad
|
||||
this->addInnerPoint(nextPoint, fUmbraColor, fRadius);
|
||||
SkPoint newPoint = nextPoint + nextNormal;
|
||||
*fPositions.push() = newPoint;
|
||||
*fColors.push() = fPenumbraColor;
|
||||
|
||||
*fIndices.push() = fPrevInnerIndex;
|
||||
*fIndices.push() = fPositions.count() - 3;
|
||||
*fIndices.push() = fPositions.count() - 2;
|
||||
|
||||
*fIndices.push() = fPositions.count() - 3;
|
||||
*fIndices.push() = fPositions.count() - 1;
|
||||
*fIndices.push() = fPositions.count() - 2;
|
||||
|
||||
// add to center fan
|
||||
*fIndices.push() = 0;
|
||||
*fIndices.push() = fPrevInnerIndex;
|
||||
*fIndices.push() = fPositions.count() - 2;
|
||||
|
||||
fPrevInnerIndex = fPositions.count() - 2;
|
||||
fPrevNormal = nextNormal;
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
class SkMatrix;
|
||||
class SkPath;
|
||||
|
||||
// TODO: derive these two classes from a base class containing common elements
|
||||
|
||||
/**
|
||||
* This class generates an ambient shadow for a path by walking the path, outsetting by the
|
||||
* radius, and setting inner and outer colors to umbraColor and penumbraColor, respectively.
|
||||
@ -23,8 +25,8 @@ class SkPath;
|
||||
*/
|
||||
class GrAmbientShadowTessellator {
|
||||
public:
|
||||
GrAmbientShadowTessellator(const SkMatrix& viewMatrix, const SkPath& path, SkScalar radius,
|
||||
GrColor umbraColor, GrColor penumbraColor, bool transparent);
|
||||
GrAmbientShadowTessellator(const SkPath& path, SkScalar radius, GrColor umbraColor,
|
||||
GrColor penumbraColor, bool transparent);
|
||||
|
||||
int vertexCount() { return fPositions.count(); }
|
||||
SkPoint* positions() { return fPositions.begin(); }
|
||||
@ -34,14 +36,12 @@ public:
|
||||
|
||||
private:
|
||||
void handleLine(const SkPoint& p);
|
||||
void handleLine(const SkMatrix& m, SkPoint p);
|
||||
|
||||
void handleQuad(const SkPoint pts[3]);
|
||||
void handleQuad(const SkMatrix& m, SkPoint pts[3]);
|
||||
|
||||
void handleCubic(const SkMatrix& m, SkPoint pts[4]);
|
||||
void handleCubic(SkPoint pts[4]);
|
||||
|
||||
void handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w);
|
||||
void handleConic(SkPoint pts[3], SkScalar w);
|
||||
|
||||
void addArc(const SkVector& nextNormal);
|
||||
void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal);
|
||||
@ -69,4 +69,65 @@ private:
|
||||
SkTDArray<SkPoint> fPointBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class generates an spot shadow for a path by walking the transformed path, further
|
||||
* transforming by the scale and translation, and outsetting and insetting by a radius.
|
||||
* The center will be clipped against the original path unless transparent is true.
|
||||
*/
|
||||
class GrSpotShadowTessellator {
|
||||
public:
|
||||
GrSpotShadowTessellator(const SkPath& path, SkScalar scale, const SkVector& translate,
|
||||
SkScalar radius, GrColor umbraColor, GrColor penumbraColor,
|
||||
bool transparent);
|
||||
|
||||
int vertexCount() { return fPositions.count(); }
|
||||
SkPoint* positions() { return fPositions.begin(); }
|
||||
GrColor* colors() { return fColors.begin(); }
|
||||
int indexCount() { return fIndices.count(); }
|
||||
uint16_t* indices() { return fIndices.begin(); }
|
||||
|
||||
private:
|
||||
void computeClipBounds(const SkPath& path);
|
||||
|
||||
void handleLine(const SkPoint& p);
|
||||
void handleLine(SkScalar scale, const SkVector& xlate, SkPoint p);
|
||||
|
||||
void handleQuad(const SkPoint pts[3]);
|
||||
void handleQuad(SkScalar scale, const SkVector& xlate, SkPoint pts[3]);
|
||||
|
||||
void handleCubic(SkScalar scale, const SkVector& xlate, SkPoint pts[4]);
|
||||
|
||||
void handleConic(SkScalar scale, const SkVector& xlate, SkPoint pts[3], SkScalar w);
|
||||
|
||||
void mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count);
|
||||
void addInnerPoint(const SkPoint& pathPoint, GrColor umbraColor, SkScalar radiusSqd);
|
||||
void addArc(const SkVector& nextNormal);
|
||||
void finishArcAndAddEdge(const SkVector& nextPoint, const SkVector& nextNormal);
|
||||
void addEdge(const SkVector& nextPoint, const SkVector& nextNormal);
|
||||
|
||||
SkScalar fRadius;
|
||||
GrColor fUmbraColor;
|
||||
GrColor fPenumbraColor;
|
||||
|
||||
SkTDArray<SkPoint> fPositions;
|
||||
SkTDArray<GrColor> fColors;
|
||||
SkTDArray<uint16_t> fIndices;
|
||||
|
||||
int fPrevInnerIndex;
|
||||
SkPoint fPrevPoint;
|
||||
SkVector fPrevNormal;
|
||||
int fFirstVertex;
|
||||
SkPoint fFirstPoint;
|
||||
SkVector fFirstNormal;
|
||||
SkScalar fDirection;
|
||||
|
||||
SkPoint fCentroid;
|
||||
SkTDArray<SkPoint> fClipPolygon;
|
||||
|
||||
// first three points
|
||||
SkTDArray<SkPoint> fInitPoints;
|
||||
// temporary buffer
|
||||
SkTDArray<SkPoint> fPointBuffer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user