diff options
author | Jim Van Verth <jvanverth@google.com> | 2017-01-30 13:11:45 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-01-30 18:44:38 +0000 |
commit | efe3dedbb3493b738abdb56041b093245e4e8711 (patch) | |
tree | 5f38ba81ebc59b48e4888a6e5779e6dbc049c5ad | |
parent | 08c5ec71303aa58d6f081914f3e868fa5cce9f4c (diff) |
Change shadow tessellators to use SkColor and move to util.
BUG=skia:6119
Change-Id: I4c4a8933c663ccc057596318a06c538175b9f16b
Reviewed-on: https://skia-review.googlesource.com/7726
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Jim Van Verth <jvanverth@google.com>
-rw-r--r-- | gn/gpu.gni | 2 | ||||
-rw-r--r-- | gn/utils.gni | 2 | ||||
-rwxr-xr-x | include/gpu/effects/GrBlurredEdgeFragmentProcessor.h | 4 | ||||
-rwxr-xr-x | src/effects/shadows/SkAmbientShadowMaskFilter.cpp | 36 | ||||
-rwxr-xr-x | src/effects/shadows/SkSpotShadowMaskFilter.cpp | 37 | ||||
-rwxr-xr-x | src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp | 9 | ||||
-rwxr-xr-x | src/utils/SkShadowTessellator.cpp (renamed from src/gpu/effects/GrShadowTessellator.cpp) | 62 | ||||
-rwxr-xr-x | src/utils/SkShadowTessellator.h (renamed from src/gpu/effects/GrShadowTessellator.h) | 36 | ||||
-rwxr-xr-x | src/utils/SkShadowUtils.cpp | 128 |
9 files changed, 193 insertions, 123 deletions
diff --git a/gn/gpu.gni b/gn/gpu.gni index b3ed69481e..001e6c1eeb 100644 --- a/gn/gpu.gni +++ b/gn/gpu.gni @@ -329,8 +329,6 @@ skia_gpu_sources = [ "$_src/gpu/effects/GrRRectEffect.h", "$_src/gpu/effects/GrShadowGeoProc.cpp", "$_src/gpu/effects/GrShadowGeoProc.h", - "$_src/gpu/effects/GrShadowTessellator.cpp", - "$_src/gpu/effects/GrShadowTessellator.h", "$_src/gpu/effects/GrSimpleTextureEffect.cpp", "$_src/gpu/effects/GrSimpleTextureEffect.h", "$_src/gpu/effects/GrSingleTextureEffect.cpp", diff --git a/gn/utils.gni b/gn/utils.gni index 068881f605..8d3f1c7a17 100644 --- a/gn/utils.gni +++ b/gn/utils.gni @@ -69,6 +69,8 @@ skia_utils_sources = [ "$_src/utils/SkRGBAToYUV.h", "$_src/utils/SkShadowPaintFilterCanvas.cpp", "$_src/utils/SkShadowPaintFilterCanvas.h", + "$_src/utils/SkShadowTessellator.cpp", + "$_src/utils/SkShadowTessellator.h", "$_src/utils/SkShadowUtils.cpp", "$_src/utils/SkTextBox.cpp", "$_src/utils/SkTextureCompressor.cpp", diff --git a/include/gpu/effects/GrBlurredEdgeFragmentProcessor.h b/include/gpu/effects/GrBlurredEdgeFragmentProcessor.h index 2e52485791..c9dd27679f 100755 --- a/include/gpu/effects/GrBlurredEdgeFragmentProcessor.h +++ b/include/gpu/effects/GrBlurredEdgeFragmentProcessor.h @@ -18,11 +18,11 @@ * 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. + * The a value represents the max final alpha. * * When not using implicit distance, then b in the input color represents the input to the - * blur function. + * blur function, and r the max final alpha. * - * In either case, the a value represents the max final alpha. */ class GrBlurredEdgeFP : public GrFragmentProcessor { public: diff --git a/src/effects/shadows/SkAmbientShadowMaskFilter.cpp b/src/effects/shadows/SkAmbientShadowMaskFilter.cpp index 0672020bcf..9db75c5acb 100755 --- a/src/effects/shadows/SkAmbientShadowMaskFilter.cpp +++ b/src/effects/shadows/SkAmbientShadowMaskFilter.cpp @@ -17,8 +17,6 @@ #include "GrStyle.h" #include "GrTexture.h" #include "GrTextureProxy.h" -#include "effects/GrBlurredEdgeFragmentProcessor.h" -#include "effects/GrShadowTessellator.h" #include "SkStrokeRec.h" #endif @@ -164,41 +162,21 @@ bool SkAmbientShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texPr return false; } -#ifdef SUPPORT_FAST_PATH // if circle // TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we // have our own GeometryProc. if (path.isOval(nullptr) && path.getBounds().width() == path.getBounds().height()) { SkRRect rrect = SkRRect::MakeOval(path.getBounds()); - return this->directFilterRRectMaskGPU(nullptr, drawContext, std::move(paint), clip, + return this->directFilterRRectMaskGPU(nullptr, rtContext, std::move(paint), clip, SkMatrix::I(), strokeRec, rrect, rrect); } else if (path.isRect(nullptr)) { SkRRect rrect = SkRRect::MakeRect(path.getBounds()); - return this->directFilterRRectMaskGPU(nullptr, drawContext, std::move(paint), clip, + return this->directFilterRRectMaskGPU(nullptr, rtContext, std::move(paint), clip, SkMatrix::I(), strokeRec, rrect, rrect); } -#endif - - SkScalar radius = fOccluderHeight * kHeightFactor * kGeomFactor; - 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 GrBlurredEdgeFP. It is then multiplied by fAmbientAlpha to get - // the final alpha. - GrColor umbraColor = GrColorPackRGBA(0, 0, umbraAlpha*255.9999f, fAmbientAlpha*255.9999f); - GrColor penumbraColor = GrColorPackRGBA(0, 0, 0, fAmbientAlpha*255.9999f); - - GrAmbientShadowTessellator tess(path, 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; + // TODO + return false; } bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*, @@ -209,10 +187,6 @@ bool SkAmbientShadowMaskFilterImpl::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 @@ -246,7 +220,7 @@ bool SkAmbientShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*, if (fAmbientAlpha > 0.0f) { SkScalar srcSpaceAmbientRadius = fOccluderHeight * kHeightFactor * kGeomFactor; const float umbraAlpha = (1.0f + SkTMax(fOccluderHeight * kHeightFactor, 0.0f)); - const SkScalar ambientOffset = srcSpaceAmbientRadius * umbraAlpha; + const SkScalar ambientOffset = srcSpaceAmbientRadius / umbraAlpha; // For the ambient rrect, we inset the offset rect by half the srcSpaceAmbientRadius // to get our stroke shape. diff --git a/src/effects/shadows/SkSpotShadowMaskFilter.cpp b/src/effects/shadows/SkSpotShadowMaskFilter.cpp index 7a1f3117eb..99a03db091 100755 --- a/src/effects/shadows/SkSpotShadowMaskFilter.cpp +++ b/src/effects/shadows/SkSpotShadowMaskFilter.cpp @@ -17,8 +17,6 @@ #include "GrStyle.h" #include "GrTexture.h" #include "GrTextureProxy.h" -#include "effects/GrBlurredEdgeFragmentProcessor.h" -#include "effects/GrShadowTessellator.h" #include "SkStrokeRec.h" #endif @@ -181,45 +179,20 @@ bool SkSpotShadowMaskFilterImpl::directFilterMaskGPU(GrTextureProvider* texProvi return false; } -#ifdef SUPPORT_FAST_PATH // if circle // TODO: switch to SkScalarNearlyEqual when either oval renderer is updated or we // have our own GeometryProc. if (path.isOval(nullptr) && path.getBounds().width() == path.getBounds().height()) { SkRRect rrect = SkRRect::MakeOval(path.getBounds()); - return this->directFilterRRectMaskGPU(nullptr, drawContext, std::move(paint), clip, + return this->directFilterRRectMaskGPU(nullptr, rtContext, std::move(paint), clip, SkMatrix::I(), strokeRec, rrect, rrect); } else if (path.isRect(nullptr)) { SkRRect rrect = SkRRect::MakeRect(path.getBounds()); - return this->directFilterRRectMaskGPU(nullptr, drawContext, std::move(paint), clip, + return this->directFilterRRectMaskGPU(nullptr, rtContext, std::move(paint), clip, SkMatrix::I(), strokeRec, rrect, rrect); } -#endif - - 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; + return false; } bool SkSpotShadowMaskFilterImpl::directFilterRRectMaskGPU(GrContext*, @@ -230,10 +203,6 @@ 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 diff --git a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp index 1441a752c8..502b6e5b95 100755 --- a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp +++ b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp @@ -41,8 +41,13 @@ public: 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); + if (!args.fGpImplementsDistanceVector) { + fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.g);", + args.fOutputColor); + } else { + fragBuilder->codeAppendf("%s = factor*vec4(0.0, 0.0, 0.0, color.a);", + args.fOutputColor); + } } protected: diff --git a/src/gpu/effects/GrShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp index a51a66addd..5ad5e4f758 100755 --- a/src/gpu/effects/GrShadowTessellator.cpp +++ b/src/utils/SkShadowTessellator.cpp @@ -5,7 +5,7 @@ * found in the LICENSE file. */ -#include "GrShadowTessellator.h" +#include "SkShadowTessellator.h" #include "GrPathUtils.h" #include "SkGeometry.h" @@ -39,10 +39,10 @@ static void compute_radial_steps(const SkVector& v1, const SkVector& v2, SkScala *n = SkScalarFloorToInt(steps); } -GrAmbientShadowTessellator::GrAmbientShadowTessellator(const SkPath& path, +SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path, SkScalar radius, - GrColor umbraColor, - GrColor penumbraColor, + SkColor umbraColor, + SkColor penumbraColor, bool transparent) : fRadius(radius) , fUmbraColor(umbraColor) @@ -142,7 +142,7 @@ static const SkScalar kQuadTolerance = 0.2f; static const SkScalar kCubicTolerance = 0.2f; static const SkScalar kConicTolerance = 0.5f; -void GrAmbientShadowTessellator::handleLine(const SkPoint& p) { +void SkAmbientShadowTessellator::handleLine(const SkPoint& p) { if (fInitPoints.count() < 2) { *fInitPoints.push() = p; return; @@ -195,7 +195,9 @@ void GrAmbientShadowTessellator::handleLine(const SkPoint& p) { } } -void GrAmbientShadowTessellator::handleQuad(const SkPoint pts[3]) { +void SkAmbientShadowTessellator::handleQuad(const SkPoint pts[3]) { +#if SK_SUPPORT_GPU + // TODO: Pull PathUtils out of Ganesh? int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance); fPointBuffer.setReserve(maxCount); SkPoint* target = fPointBuffer.begin(); @@ -205,9 +207,12 @@ void GrAmbientShadowTessellator::handleQuad(const SkPoint pts[3]) { for (int i = 0; i < count; i++) { this->handleLine(fPointBuffer[i]); } +#endif } -void GrAmbientShadowTessellator::handleCubic(SkPoint pts[4]) { +void SkAmbientShadowTessellator::handleCubic(SkPoint pts[4]) { +#if SK_SUPPORT_GPU + // TODO: Pull PathUtils out of Ganesh? int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance); fPointBuffer.setReserve(maxCount); SkPoint* target = fPointBuffer.begin(); @@ -217,9 +222,10 @@ void GrAmbientShadowTessellator::handleCubic(SkPoint pts[4]) { for (int i = 0; i < count; i++) { this->handleLine(fPointBuffer[i]); } +#endif } -void GrAmbientShadowTessellator::handleConic(SkPoint pts[3], SkScalar w) { +void SkAmbientShadowTessellator::handleConic(SkPoint pts[3], SkScalar w) { SkAutoConicToQuads quadder; const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance); SkPoint lastPoint = *(quads++); @@ -235,7 +241,7 @@ void GrAmbientShadowTessellator::handleConic(SkPoint pts[3], SkScalar w) { } } -void GrAmbientShadowTessellator::addArc(const SkVector& nextNormal) { +void SkAmbientShadowTessellator::addArc(const SkVector& nextNormal) { // fill in fan from previous quad SkScalar rotSin, rotCos; int numSteps; @@ -255,7 +261,7 @@ void GrAmbientShadowTessellator::addArc(const SkVector& nextNormal) { } } -void GrAmbientShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint, +void SkAmbientShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint, const SkVector& nextNormal) { // close out previous arc *fPositions.push() = fPositions[fPrevInnerIndex] + nextNormal; @@ -267,7 +273,7 @@ void GrAmbientShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint, this->addEdge(nextPoint, nextNormal); } -void GrAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) { +void SkAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) { // add next quad *fPositions.push() = nextPoint; *fColors.push() = fUmbraColor; @@ -298,10 +304,10 @@ void GrAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVecto /////////////////////////////////////////////////////////////////////////////////////////////////// -GrSpotShadowTessellator::GrSpotShadowTessellator(const SkPath& path, +SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, SkScalar scale, const SkVector& translate, SkScalar radius, - GrColor umbraColor, GrColor penumbraColor, + SkColor umbraColor, SkColor penumbraColor, bool /* transparent */) : fRadius(radius) , fUmbraColor(umbraColor) @@ -394,7 +400,7 @@ GrSpotShadowTessellator::GrSpotShadowTessellator(const SkPath& path, } } -void GrSpotShadowTessellator::computeClipBounds(const SkPath& path) { +void SkSpotShadowTessellator::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); @@ -443,7 +449,7 @@ void GrSpotShadowTessellator::computeClipBounds(const SkPath& path) { fCentroid *= SkScalarInvert(centroidCount); } -void GrSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate, +void SkSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate, SkPoint* pts, int count) { // TODO: vectorize for (int i = 0; i < count; ++i) { @@ -452,7 +458,7 @@ void GrSpotShadowTessellator::mapPoints(SkScalar scale, const SkVector& xlate, } } -void GrSpotShadowTessellator::handleLine(const SkPoint& p) { +void SkSpotShadowTessellator::handleLine(const SkPoint& p) { if (fInitPoints.count() < 2) { *fInitPoints.push() = p; return; @@ -503,12 +509,14 @@ void GrSpotShadowTessellator::handleLine(const SkPoint& p) { } } -void GrSpotShadowTessellator::handleLine(SkScalar scale, const SkVector& xlate, SkPoint p) { +void SkSpotShadowTessellator::handleLine(SkScalar scale, const SkVector& xlate, SkPoint p) { this->mapPoints(scale, xlate, &p, 1); this->handleLine(p); } -void GrSpotShadowTessellator::handleQuad(const SkPoint pts[3]) { +void SkSpotShadowTessellator::handleQuad(const SkPoint pts[3]) { +#if SK_SUPPORT_GPU + // TODO: Pull PathUtils out of Ganesh? int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance); fPointBuffer.setReserve(maxCount); SkPoint* target = fPointBuffer.begin(); @@ -518,14 +526,17 @@ void GrSpotShadowTessellator::handleQuad(const SkPoint pts[3]) { for (int i = 0; i < count; i++) { this->handleLine(fPointBuffer[i]); } +#endif } -void GrSpotShadowTessellator::handleQuad(SkScalar scale, const SkVector& xlate, SkPoint pts[3]) { +void SkSpotShadowTessellator::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]) { +void SkSpotShadowTessellator::handleCubic(SkScalar scale, const SkVector& xlate, SkPoint pts[4]) { +#if SK_SUPPORT_GPU + // TODO: Pull PathUtils out of Ganesh? this->mapPoints(scale, xlate, pts, 4); int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance); fPointBuffer.setReserve(maxCount); @@ -536,9 +547,10 @@ void GrSpotShadowTessellator::handleCubic(SkScalar scale, const SkVector& xlate, for (int i = 0; i < count; i++) { this->handleLine(fPointBuffer[i]); } +#endif } -void GrSpotShadowTessellator::handleConic(SkScalar scale, const SkVector& xlate, +void SkSpotShadowTessellator::handleConic(SkScalar scale, const SkVector& xlate, SkPoint pts[3], SkScalar w) { this->mapPoints(scale, xlate, pts, 3); SkAutoConicToQuads quadder; @@ -556,7 +568,7 @@ void GrSpotShadowTessellator::handleConic(SkScalar scale, const SkVector& xlate, } } -void GrSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint, GrColor umbraColor, +void SkSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor, SkScalar radius) { SkVector v = fCentroid - pathPoint; SkScalar distance = v.length(); @@ -574,7 +586,7 @@ void GrSpotShadowTessellator::addInnerPoint(const SkPoint& pathPoint, GrColor um fPrevPoint = pathPoint; } -void GrSpotShadowTessellator::addArc(const SkVector& nextNormal) { +void SkSpotShadowTessellator::addArc(const SkVector& nextNormal) { // fill in fan from previous quad SkScalar rotSin, rotCos; int numSteps; @@ -594,7 +606,7 @@ void GrSpotShadowTessellator::addArc(const SkVector& nextNormal) { } } -void GrSpotShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint, +void SkSpotShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint, const SkVector& nextNormal) { // close out previous arc SkPoint newPoint = fPrevPoint + nextNormal; @@ -607,7 +619,7 @@ void GrSpotShadowTessellator::finishArcAndAddEdge(const SkPoint& nextPoint, this->addEdge(nextPoint, nextNormal); } -void GrSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) { +void SkSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal) { // add next quad this->addInnerPoint(nextPoint, fUmbraColor, fRadius); SkPoint newPoint = nextPoint + nextNormal; diff --git a/src/gpu/effects/GrShadowTessellator.h b/src/utils/SkShadowTessellator.h index c2acde72f4..ababba74dd 100755 --- a/src/gpu/effects/GrShadowTessellator.h +++ b/src/utils/SkShadowTessellator.h @@ -5,13 +5,13 @@ * found in the LICENSE file. */ -#ifndef GrShadowTessellator_DEFINED -#define GrShadowTessellator_DEFINED +#ifndef SkShadowTessellator_DEFINED +#define SkShadowTessellator_DEFINED #include "SkTDArray.h" #include "SkPoint.h" -#include "GrColor.h" +#include "SkColor.h" class SkMatrix; class SkPath; @@ -23,14 +23,14 @@ class SkPath; * radius, and setting inner and outer colors to umbraColor and penumbraColor, respectively. * If transparent is true, then the center of the ambient shadow will be filled in. */ -class GrAmbientShadowTessellator { +class SkAmbientShadowTessellator { public: - GrAmbientShadowTessellator(const SkPath& path, SkScalar radius, GrColor umbraColor, - GrColor penumbraColor, bool transparent); + SkAmbientShadowTessellator(const SkPath& path, SkScalar radius, SkColor umbraColor, + SkColor penumbraColor, bool transparent); int vertexCount() { return fPositions.count(); } SkPoint* positions() { return fPositions.begin(); } - GrColor* colors() { return fColors.begin(); } + SkColor* colors() { return fColors.begin(); } int indexCount() { return fIndices.count(); } uint16_t* indices() { return fIndices.begin(); } @@ -48,12 +48,12 @@ private: void addEdge(const SkVector& nextPoint, const SkVector& nextNormal); SkScalar fRadius; - GrColor fUmbraColor; - GrColor fPenumbraColor; + SkColor fUmbraColor; + SkColor fPenumbraColor; bool fTransparent; SkTDArray<SkPoint> fPositions; - SkTDArray<GrColor> fColors; + SkTDArray<SkColor> fColors; SkTDArray<uint16_t> fIndices; int fPrevInnerIndex; @@ -74,15 +74,15 @@ private: * 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 { +class SkSpotShadowTessellator { public: - GrSpotShadowTessellator(const SkPath& path, SkScalar scale, const SkVector& translate, - SkScalar radius, GrColor umbraColor, GrColor penumbraColor, + SkSpotShadowTessellator(const SkPath& path, SkScalar scale, const SkVector& translate, + SkScalar radius, SkColor umbraColor, SkColor penumbraColor, bool transparent); int vertexCount() { return fPositions.count(); } SkPoint* positions() { return fPositions.begin(); } - GrColor* colors() { return fColors.begin(); } + SkColor* colors() { return fColors.begin(); } int indexCount() { return fIndices.count(); } uint16_t* indices() { return fIndices.begin(); } @@ -100,17 +100,17 @@ private: 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 addInnerPoint(const SkPoint& pathPoint, SkColor 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; + SkColor fUmbraColor; + SkColor fPenumbraColor; SkTDArray<SkPoint> fPositions; - SkTDArray<GrColor> fColors; + SkTDArray<SkColor> fColors; SkTDArray<uint16_t> fIndices; int fPrevInnerIndex; diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp index e93f778072..5c92d66845 100755 --- a/src/utils/SkShadowUtils.cpp +++ b/src/utils/SkShadowUtils.cpp @@ -7,19 +7,129 @@ #include "SkShadowUtils.h" #include "SkCanvas.h" -#include "../effects/shadows/SkAmbientShadowMaskFilter.h" -#include "../effects/shadows/SkSpotShadowMaskFilter.h" +#include "SkColorFilter.h" +#include "SkPath.h" +#include "SkShadowTessellator.h" + +/** +* Gaussian color filter -- produces a Gaussian ramp based on the color's B value, +* then blends with the color's G value. +* Final result is black with alpha of Gaussian(B)*G. +* The assumption is that the original color's alpha is 1. +*/ +class SK_API SkGaussianColorFilter : public SkColorFilter { +public: + static sk_sp<SkColorFilter> Make() { + return sk_sp<SkColorFilter>(new SkGaussianColorFilter); + } + + void filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const override; + +#if SK_SUPPORT_GPU + sk_sp<GrFragmentProcessor> asFragmentProcessor(GrContext*, SkColorSpace*) const override; +#endif + + SK_TO_STRING_OVERRIDE() + SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkGaussianColorFilter) + +protected: + void flatten(SkWriteBuffer&) const override {} + +private: + SkGaussianColorFilter() : INHERITED() {} + + typedef SkColorFilter INHERITED; +}; + +void SkGaussianColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const { + for (int i = 0; i < count; ++i) { + SkPMColor c = src[i]; + + SkScalar factor = SK_Scalar1 - SkGetPackedB32(c) / 255.f; + factor = SkScalarExp(-factor * factor * 4) - 0.018f; + + dst[i] = SkPackARGB32(factor*SkGetPackedG32(c), 0, 0, 0); + } +} + +sk_sp<SkFlattenable> SkGaussianColorFilter::CreateProc(SkReadBuffer&) { + return Make(); +} + +#ifndef SK_IGNORE_TO_STRING +void SkGaussianColorFilter::toString(SkString* str) const { + str->append("SkGaussianColorFilter "); +} +#endif + +#if SK_SUPPORT_GPU +#include "effects/GrBlurredEdgeFragmentProcessor.h" + +sk_sp<GrFragmentProcessor> SkGaussianColorFilter::asFragmentProcessor(GrContext*, + SkColorSpace*) const { + return GrBlurredEdgeFP::Make(GrBlurredEdgeFP::kGaussian_Mode); +} +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////// +static const float kHeightFactor = 1.0f / 128.0f; +static const float kGeomFactor = 64.0f; // Draw an offset spot shadow and outlining ambient shadow for the given path. void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight, const SkPoint3& lightPos, SkScalar lightRadius, SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color, uint32_t flags) { - SkPaint newPaint; - newPaint.setColor(color); - newPaint.setMaskFilter(SkAmbientShadowMaskFilter::Make(occluderHeight, ambientAlpha, flags)); - canvas->drawPath(path, newPaint); - newPaint.setMaskFilter(SkSpotShadowMaskFilter::Make(occluderHeight, lightPos, lightRadius, - spotAlpha, flags)); - canvas->drawPath(path, newPaint); + + SkPath xformedPath; + // TODO: handle transforming the path as part of the tessellator + path.transform(canvas->getTotalMatrix(), &xformedPath); + canvas->save(); + canvas->resetMatrix(); + + if (ambientAlpha > 0) { + SkScalar radius = occluderHeight * kHeightFactor * kGeomFactor; + SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(occluderHeight*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 GrBlurredEdgeFP. It is then multiplied by fAmbientAlpha to get + // the final alpha. + SkColor umbraColor = SkColorSetARGB(255, 0, ambientAlpha*255.9999f, umbraAlpha*255.9999f); + SkColor penumbraColor = SkColorSetARGB(255, 0, ambientAlpha*255.9999f, 0); + + SkAmbientShadowTessellator tess(xformedPath, radius, umbraColor, penumbraColor, + SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag)); + + SkPaint paint; + paint.setColor(color); + paint.setColorFilter(SkGaussianColorFilter::Make()); + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, tess.vertexCount(), tess.positions(), + nullptr, tess.colors(), tess.indices(), tess.indexCount(), paint); + } + + if (spotAlpha > 0) { + float zRatio = SkTPin(occluderHeight / (lightPos.fZ - occluderHeight), 0.0f, 0.95f); + SkScalar radius = lightRadius * zRatio; + + // Compute the scale and translation for the spot shadow. + const SkScalar scale = lightPos.fZ / (lightPos.fZ - occluderHeight); + + SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY()); + const SkVector spotOffset = SkVector::Make(zRatio*(center.fX - lightPos.fX), + zRatio*(center.fY - lightPos.fY)); + + SkColor umbraColor = SkColorSetARGB(255, 0, spotAlpha*255.9999f, 255); + SkColor penumbraColor = SkColorSetARGB(255, 0, spotAlpha*255.9999f, 0); + SkSpotShadowTessellator tess(xformedPath, scale, spotOffset, radius, + umbraColor, penumbraColor, + SkToBool(flags & SkShadowFlags::kTransparentOccluder_ShadowFlag)); + + SkPaint paint; + paint.setColor(color); + paint.setColorFilter(SkGaussianColorFilter::Make()); + canvas->drawVertices(SkCanvas::kTriangles_VertexMode, tess.vertexCount(), tess.positions(), + nullptr, tess.colors(), tess.indices(), tess.indexCount(), paint); + } + + canvas->restore(); } |