diff options
-rw-r--r-- | include/utils/SkShadowUtils.h | 72 | ||||
-rw-r--r-- | samplecode/SampleAndroidShadows.cpp | 61 | ||||
-rwxr-xr-x | samplecode/SampleShadowUtils.cpp | 14 | ||||
-rwxr-xr-x | src/utils/SkShadowTessellator.cpp | 88 | ||||
-rw-r--r-- | src/utils/SkShadowTessellator.h | 4 | ||||
-rw-r--r-- | src/utils/SkShadowUtils.cpp | 19 | ||||
-rw-r--r-- | tests/ShadowUtilsTest.cpp | 10 |
7 files changed, 146 insertions, 122 deletions
diff --git a/include/utils/SkShadowUtils.h b/include/utils/SkShadowUtils.h index 01514a46ff..4a497bb397 100644 --- a/include/utils/SkShadowUtils.h +++ b/include/utils/SkShadowUtils.h @@ -43,29 +43,65 @@ public: uint32_t flags = SkShadowFlags::kNone_ShadowFlag, SkResourceCache* cache = nullptr); - /** - * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc - * light. Takes a function to vary the z value based on the transformed x and y position. - * This shadow will not be cached, as the assumption is that this will be used for animation. - * - * @param canvas The canvas on which to draw the shadows. - * @param path The occluder used to generate the shadows. - * @param heightFunc A function which returns the vertical offset of the occluder from the - * canvas based on local x and y values (the current matrix is not applied). - * @param lightPos The 3D position of the light relative to the canvas plane. This is - * independent of the canvas's current matrix. - * @param lightRadius The radius of the disc light. - * @param ambientAlpha The maximum alpha of the ambient shadow. - * @param spotAlpha The maxium alpha of the spot shadow. - * @param color The shadow color. - * @param flags Options controlling opaque occluder optimizations and shadow appearance. See - * SkShadowFlags. - */ + /** + * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc + * light. Takes a function to vary the z value based on the local x and y position. + * This shadow will not be cached, as the assumption is that this will be used for animation. + * + * Deprecated version with height functor (to be removed when Android is updated). + * + * @param canvas The canvas on which to draw the shadows. + * @param path The occluder used to generate the shadows. + * @param heightFunc A function which returns the vertical offset of the occluder from the + * canvas based on local x and y values (the current matrix is not applied). + * @param lightPos The 3D position of the light relative to the canvas plane. This is + * independent of the canvas's current matrix. + * @param lightRadius The radius of the disc light. + * @param ambientAlpha The maximum alpha of the ambient shadow. + * @param spotAlpha The maxium alpha of the spot shadow. + * @param color The shadow color. + * @param flags Options controlling opaque occluder optimizations and shadow appearance. See + * SkShadowFlags. + */ static void DrawUncachedShadow(SkCanvas* canvas, const SkPath& path, std::function<SkScalar(SkScalar, SkScalar)> heightFunc, const SkPoint3& lightPos, SkScalar lightRadius, SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color, + uint32_t flags = SkShadowFlags::kNone_ShadowFlag) { + SkPoint3 zPlane; + zPlane.fZ = heightFunc(0, 0); + zPlane.fX = heightFunc(1, 0) - zPlane.fZ; + zPlane.fY = heightFunc(0, 1) - zPlane.fZ; + + DrawUncachedShadow(canvas, path, zPlane, lightPos, lightRadius, ambientAlpha, spotAlpha, + color, flags); + } + + /** + * Draw an offset spot shadow and outlining ambient shadow for the given path using a disc + * light. Uses a plane function to vary the z value based on the local x and y position. + * This shadow will not be cached, as the assumption is that this will be used for animation. + * + * @param canvas The canvas on which to draw the shadows. + * @param path The occluder used to generate the shadows. + * @param zPlaneParams Values for the plane function which returns the Z offset of the + * occluder from the canvas based on local x and y values (the current matrix is not applied). + * @param lightPos The 3D position of the light relative to the canvas plane. This is + * independent of the canvas's current matrix. + * @param lightRadius The radius of the disc light. + * @param ambientAlpha The maximum alpha of the ambient shadow. + * @param spotAlpha The maxium alpha of the spot shadow. + * @param color The shadow color. + * @param flags Options controlling opaque occluder optimizations and shadow appearance. See + * SkShadowFlags. + */ + static void DrawUncachedShadow(SkCanvas* canvas, const SkPath& path, + const SkPoint3& zPlaneParams, + const SkPoint3& lightPos, SkScalar lightRadius, + SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color, uint32_t flags = SkShadowFlags::kNone_ShadowFlag); + + }; #endif diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp index c8ce14c8d5..81dc0cc2b6 100644 --- a/samplecode/SampleAndroidShadows.cpp +++ b/samplecode/SampleAndroidShadows.cpp @@ -128,7 +128,7 @@ protected: } void drawShadowedPath(SkCanvas* canvas, const SkPath& path, - std::function<SkScalar(SkScalar, SkScalar)> zFunc, + const SkPoint3& zPlaneParams, const SkPaint& paint, SkScalar ambientAlpha, const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) { if (fIgnoreShadowAlpha) { @@ -149,7 +149,7 @@ protected: // zValue, // lightPos, lightWidth, // ambientAlpha, spotAlpha, SK_ColorBLACK, flags); - SkShadowUtils::DrawUncachedShadow(canvas, path, zFunc, + SkShadowUtils::DrawUncachedShadow(canvas, path, zPlaneParams, lightPos, lightWidth, ambientAlpha, spotAlpha, SK_ColorBLACK, flags); @@ -175,48 +175,42 @@ protected: paint.setAntiAlias(true); SkPoint3 lightPos = fLightPos; + SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, 0); paint.setColor(SK_ColorWHITE); canvas->translate(200, 90); - SkScalar zValue = SkTMax(1.0f, 2 + fZDelta); - std::function<SkScalar(SkScalar, SkScalar)> zFunc = - [zValue](SkScalar, SkScalar) { return zValue; }; - this->drawShadowedPath(canvas, fRRPath, zFunc, paint, kAmbientAlpha, + zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta); + this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); paint.setColor(SK_ColorRED); canvas->translate(250, 0); - zValue = SkTMax(1.0f, 8 + fZDelta); - zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; - this->drawShadowedPath(canvas, fRectPath, zFunc, paint, kAmbientAlpha, + zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); + this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); paint.setColor(SK_ColorBLUE); canvas->translate(-250, 110); - zValue = SkTMax(1.0f, 12 + fZDelta); - zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; - this->drawShadowedPath(canvas, fCirclePath, zFunc, paint, kAmbientAlpha, + zPlaneParams.fZ = SkTMax(1.0f, 12 + fZDelta); + this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, kAmbientAlpha, lightPos, kLightWidth, 0.5f); paint.setColor(SK_ColorGREEN); canvas->translate(250, 0); - zValue = SkTMax(1.0f, 64 + fZDelta); - zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; - this->drawShadowedPath(canvas, fRRPath, zFunc, paint, kAmbientAlpha, + zPlaneParams.fZ = SkTMax(1.0f, 64 + fZDelta); + this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); paint.setColor(SK_ColorYELLOW); canvas->translate(-250, 110); - zValue = SkTMax(1.0f, 8 + fZDelta); - zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; - this->drawShadowedPath(canvas, fFunkyRRPath, zFunc, paint, kAmbientAlpha, + zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); + this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); paint.setColor(SK_ColorCYAN); canvas->translate(250, 0); - zValue = SkTMax(1.0f, 16 + fZDelta); - zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; - this->drawShadowedPath(canvas, fCubicPath, zFunc, paint, + zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta); + this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); // circular reveal @@ -227,9 +221,8 @@ protected: paint.setColor(SK_ColorMAGENTA); canvas->translate(-125, 60); - zValue = SkTMax(1.0f, 32 + fZDelta); - zFunc = [zValue](SkScalar, SkScalar) { return zValue; }; - this->drawShadowedPath(canvas, tmpPath, zFunc, paint, .1f, + zPlaneParams.fZ = SkTMax(1.0f, 32 + fZDelta); + this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f, lightPos, kLightWidth, .5f); // perspective paths @@ -245,13 +238,11 @@ protected: persp.preTranslate(-pivot.fX, -pivot.fY); persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); canvas->setMatrix(persp); - zValue = SkTMax(1.0f, 16 + fZDelta); SkScalar radians = SkDegreesToRadians(fAnimAngle); - zFunc = [zValue, pivot, radians](SkScalar x, SkScalar y) { - return SkScalarSin(-radians)*y + - zValue - SkScalarSin(-radians)*pivot.fY; - }; - this->drawShadowedPath(canvas, fWideRectPath, zFunc, paint, .1f, + zPlaneParams = SkPoint3::Make(0, + SkScalarSin(-radians), + SkTMax(1.0f, 16 + fZDelta) - SkScalarSin(-radians)*pivot.fY); + this->drawShadowedPath(canvas, fWideRectPath, zPlaneParams, paint, .1f, lightPos, kLightWidth, .5f); pivot = SkPoint::Make(fWideOvalPath.getBounds().width() / 2, @@ -263,12 +254,10 @@ protected: persp.preTranslate(-pivot.fX, -pivot.fY); persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); canvas->setMatrix(persp); - zValue = SkTMax(1.0f, 32 + fZDelta); - zFunc = [zValue, pivot, radians](SkScalar x, SkScalar y) { - return -SkScalarSin(radians)*x + - zValue + SkScalarSin(radians)*pivot.fX; - }; - this->drawShadowedPath(canvas, fWideOvalPath, zFunc, paint, .1f, + zPlaneParams = SkPoint3::Make(-SkScalarSin(radians), + 0, + SkTMax(1.0f, 32 + fZDelta) + SkScalarSin(radians)*pivot.fX); + this->drawShadowedPath(canvas, fWideOvalPath, zPlaneParams, paint, .1f, lightPos, kLightWidth, .5f); } diff --git a/samplecode/SampleShadowUtils.cpp b/samplecode/SampleShadowUtils.cpp index f5b6635886..6d047be93d 100755 --- a/samplecode/SampleShadowUtils.cpp +++ b/samplecode/SampleShadowUtils.cpp @@ -109,7 +109,7 @@ protected: } void drawShadowedPath(SkCanvas* canvas, const SkPath& path, - std::function<SkScalar(SkScalar, SkScalar)> zFunc, + const SkPoint3& zPlaneParams, const SkPaint& paint, SkScalar ambientAlpha, const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha, uint32_t flags) { @@ -130,10 +130,10 @@ protected: // zValue, // lightPos, lightWidth, // ambientAlpha, spotAlpha, SK_ColorBLACK, flags); - SkShadowUtils::DrawUncachedShadow(canvas, path, zFunc, + SkShadowUtils::DrawUncachedShadow(canvas, path, zPlaneParams, lightPos, lightWidth, ambientAlpha, 0, SK_ColorRED, flags); - SkShadowUtils::DrawUncachedShadow(canvas, path, zFunc, + SkShadowUtils::DrawUncachedShadow(canvas, path, zPlaneParams, lightPos, lightWidth, 0, spotAlpha, SK_ColorBLUE, flags); @@ -172,9 +172,7 @@ protected: SkPaint paint; paint.setColor(SK_ColorGREEN); paint.setAntiAlias(true); - SkScalar zValue = SkTMax(1.0f, kHeight + fZDelta); - std::function<SkScalar(SkScalar, SkScalar)> zFunc = - [zValue](SkScalar, SkScalar) { return zValue; }; + SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, SkTMax(1.0f, kHeight + fZDelta)); for (auto& m : matrices) { for (auto flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) { for (const auto& path : fPaths) { @@ -192,8 +190,8 @@ protected: canvas->save(); canvas->concat(m); - drawShadowedPath(canvas, path, zFunc, paint, kAmbientAlpha, kLightPos, kLightR, - kSpotAlpha, flags); + drawShadowedPath(canvas, path, zPlaneParams, paint, kAmbientAlpha, kLightPos, + kLightR, kSpotAlpha, flags); canvas->restore(); canvas->translate(dx, 0); diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp index 32a114253a..9a82ec3bfa 100755 --- a/src/utils/SkShadowTessellator.cpp +++ b/src/utils/SkShadowTessellator.cpp @@ -22,7 +22,7 @@ */ class SkBaseShadowTessellator { public: - SkBaseShadowTessellator(SkShadowTessellator::HeightFunc, bool transparent); + SkBaseShadowTessellator(const SkPoint3& zPlaneParams, bool transparent); virtual ~SkBaseShadowTessellator() {} sk_sp<SkVertices> releaseVertices() { @@ -56,11 +56,15 @@ protected: bool addArc(const SkVector& nextNormal, bool finishArc); - SkShadowTessellator::HeightFunc fHeightFunc; + SkScalar heightFunc(SkScalar x, SkScalar y) { + return fZPlaneParams.fX*x + fZPlaneParams.fY*y + fZPlaneParams.fZ; + } + + SkPoint3 fZPlaneParams; std::function<SkScalar(const SkPoint&)> fTransformedHeightFunc; SkScalar fZOffset; // members for perspective height function - SkScalar fZParams[3]; + SkPoint3 fPerspZParams; SkScalar fPartialDeterminants[3]; // first two points @@ -118,9 +122,8 @@ static void compute_radial_steps(const SkVector& v1, const SkVector& v2, SkScala *n = steps; } -SkBaseShadowTessellator::SkBaseShadowTessellator(SkShadowTessellator::HeightFunc heightFunc, - bool transparent) - : fHeightFunc(heightFunc) +SkBaseShadowTessellator::SkBaseShadowTessellator(const SkPoint3& zPlaneParams, bool transparent) + : fZPlaneParams(zPlaneParams) , fZOffset(0) , fFirstVertex(-1) , fSucceeded(false) @@ -133,17 +136,17 @@ SkBaseShadowTessellator::SkBaseShadowTessellator(SkShadowTessellator::HeightFunc } bool SkBaseShadowTessellator::setZOffset(const SkRect& bounds, bool perspective) { - SkScalar minZ = fHeightFunc(bounds.fLeft, bounds.fTop); + SkScalar minZ = this->heightFunc(bounds.fLeft, bounds.fTop); if (perspective) { - SkScalar z = fHeightFunc(bounds.fLeft, bounds.fBottom); + SkScalar z = this->heightFunc(bounds.fLeft, bounds.fBottom); if (z < minZ) { minZ = z; } - z = fHeightFunc(bounds.fRight, bounds.fTop); + z = this->heightFunc(bounds.fRight, bounds.fTop); if (z < minZ) { minZ = z; } - z = fHeightFunc(bounds.fRight, bounds.fBottom); + z = this->heightFunc(bounds.fRight, bounds.fBottom); if (z < minZ) { minZ = z; } @@ -267,27 +270,28 @@ bool SkBaseShadowTessellator::addArc(const SkVector& nextNormal, bool finishArc) bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) { if (!ctm.hasPerspective()) { fTransformedHeightFunc = [this](const SkPoint& p) { - return this->fHeightFunc(0, 0); + return fZPlaneParams.fZ; }; } else { SkMatrix ctmInverse; if (!ctm.invert(&ctmInverse)) { return false; } - SkScalar C = fHeightFunc(0, 0); - SkScalar A = fHeightFunc(1, 0) - C; - SkScalar B = fHeightFunc(0, 1) - C; // multiply by transpose - fZParams[0] = ctmInverse[SkMatrix::kMScaleX] * A + - ctmInverse[SkMatrix::kMSkewY] * B + - ctmInverse[SkMatrix::kMPersp0] * C; - fZParams[1] = ctmInverse[SkMatrix::kMSkewX] * A + - ctmInverse[SkMatrix::kMScaleY] * B + - ctmInverse[SkMatrix::kMPersp1] * C; - fZParams[2] = ctmInverse[SkMatrix::kMTransX] * A + - ctmInverse[SkMatrix::kMTransY] * B + - ctmInverse[SkMatrix::kMPersp2] * C; + fPerspZParams = SkPoint3::Make( + ctmInverse[SkMatrix::kMScaleX] * fZPlaneParams.fX + + ctmInverse[SkMatrix::kMSkewY] * fZPlaneParams.fY + + ctmInverse[SkMatrix::kMPersp0] * fZPlaneParams.fZ, + + ctmInverse[SkMatrix::kMSkewX] * fZPlaneParams.fX + + ctmInverse[SkMatrix::kMScaleY] * fZPlaneParams.fY + + ctmInverse[SkMatrix::kMPersp1] * fZPlaneParams.fZ, + + ctmInverse[SkMatrix::kMTransX] * fZPlaneParams.fX + + ctmInverse[SkMatrix::kMTransY] * fZPlaneParams.fY + + ctmInverse[SkMatrix::kMPersp2] * fZPlaneParams.fZ + ); // We use Cramer's rule to solve for the W value for a given post-divide X and Y, // so pre-compute those values that are independent of X and Y. @@ -304,17 +308,17 @@ bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) { // Pre-bake the numerator of Cramer's rule into the zParams to avoid another multiply. // TODO: this may introduce numerical instability, but I haven't seen any issues yet. - fZParams[0] *= ctmDeterminant; - fZParams[1] *= ctmDeterminant; - fZParams[2] *= ctmDeterminant; + fPerspZParams.fX *= ctmDeterminant; + fPerspZParams.fY *= ctmDeterminant; + fPerspZParams.fZ *= ctmDeterminant; fTransformedHeightFunc = [this](const SkPoint& p) { - SkScalar denom = p.fX * this->fPartialDeterminants[0] + - p.fY * this->fPartialDeterminants[1] + - this->fPartialDeterminants[2]; + SkScalar denom = p.fX * fPartialDeterminants[0] + + p.fY * fPartialDeterminants[1] + + fPartialDeterminants[2]; SkScalar w = SkScalarFastInvert(denom); - return (this->fZParams[0] * p.fX + this->fZParams[1] * p.fY + this->fZParams[2])*w + - this->fZOffset; + return (fPerspZParams.fX * p.fX + fPerspZParams.fY * p.fY + fPerspZParams.fZ)*w + + fZOffset; }; } @@ -327,7 +331,7 @@ bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) { class SkAmbientShadowTessellator : public SkBaseShadowTessellator { public: SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm, - SkShadowTessellator::HeightFunc heightFunc, bool transparent); + const SkPoint3& zPlaneParams, bool transparent); private: void handleLine(const SkPoint& p) override; @@ -352,9 +356,9 @@ private: SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm, - SkShadowTessellator::HeightFunc heightFunc, + const SkPoint3& zPlaneParams, bool transparent) - : INHERITED(heightFunc, transparent) { + : INHERITED(zPlaneParams, transparent) { // Set base colors SkScalar occluderHeight = heightFunc(0, 0); SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(occluderHeight*kHeightFactor, 0.0f))); @@ -650,7 +654,7 @@ void SkAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVecto class SkSpotShadowTessellator : public SkBaseShadowTessellator { public: SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm, - SkShadowTessellator::HeightFunc heightFunc, const SkPoint3& lightPos, + const SkPoint3& zPlaneParams, const SkPoint3& lightPos, SkScalar lightRadius, bool transparent); private: @@ -693,10 +697,10 @@ private: }; SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm, - SkShadowTessellator::HeightFunc heightFunc, + const SkPoint3& zPlaneParams, const SkPoint3& lightPos, SkScalar lightRadius, bool transparent) - : INHERITED(heightFunc, transparent) + : INHERITED(zPlaneParams, transparent) , fLightZ(lightPos.fZ) , fLightRadius(lightRadius) , fOffsetAdjust(0) @@ -714,7 +718,7 @@ SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMat // Set radius and colors SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY()); - SkScalar occluderHeight = heightFunc(center.fX, center.fY) + fZOffset; + SkScalar occluderHeight = this->heightFunc(center.fX, center.fY) + fZOffset; float zRatio = SkTPin(occluderHeight / (fLightZ - occluderHeight), 0.0f, 0.95f); SkScalar radius = lightRadius * zRatio; fRadius = radius; @@ -1287,14 +1291,14 @@ void SkSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& /////////////////////////////////////////////////////////////////////////////////////////////////// sk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm, - HeightFunc heightFunc, bool transparent) { - SkAmbientShadowTessellator ambientTess(path, ctm, heightFunc, transparent); + const SkPoint3& zPlane, bool transparent) { + SkAmbientShadowTessellator ambientTess(path, ctm, zPlane, transparent); return ambientTess.releaseVertices(); } sk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm, - HeightFunc heightFunc, const SkPoint3& lightPos, + const SkPoint3& zPlane, const SkPoint3& lightPos, SkScalar lightRadius, bool transparent) { - SkSpotShadowTessellator spotTess(path, ctm, heightFunc, lightPos, lightRadius, transparent); + SkSpotShadowTessellator spotTess(path, ctm, zPlane, lightPos, lightRadius, transparent); return spotTess.releaseVertices(); } diff --git a/src/utils/SkShadowTessellator.h b/src/utils/SkShadowTessellator.h index d6e784ee45..351beee29d 100644 --- a/src/utils/SkShadowTessellator.h +++ b/src/utils/SkShadowTessellator.h @@ -26,14 +26,14 @@ typedef std::function<SkScalar(SkScalar, SkScalar)> HeightFunc; * If transparent is true, then the center of the ambient shadow will be filled in. */ sk_sp<SkVertices> MakeAmbient(const SkPath& path, const SkMatrix& ctm, - HeightFunc heightFunc, bool transparent); + const SkPoint3& zPlane, bool transparent); /** * This function generates a spot shadow mesh 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. */ -sk_sp<SkVertices> MakeSpot(const SkPath& path, const SkMatrix& ctm, HeightFunc heightFunc, +sk_sp<SkVertices> MakeSpot(const SkPath& path, const SkMatrix& ctm, const SkPoint3& zPlane, const SkPoint3& lightPos, SkScalar lightRadius, bool transparent); } diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp index 19b2c2d403..7295e48fd5 100644 --- a/src/utils/SkShadowUtils.cpp +++ b/src/utils/SkShadowUtils.cpp @@ -170,10 +170,8 @@ struct AmbientVerticesFactory { } sk_sp<SkVertices> makeVertices(const SkPath& path, const SkMatrix& ctm) const { - SkScalar z = fOccluderHeight; - return SkShadowTessellator::MakeAmbient(path, ctm, - [z](SkScalar, SkScalar) { return z; }, - fTransparent); + SkPoint3 zParams = SkPoint3::Make(0, 0, fOccluderHeight); + return SkShadowTessellator::MakeAmbient(path, ctm, zParams, fTransparent); } }; @@ -221,9 +219,8 @@ struct SpotVerticesFactory { sk_sp<SkVertices> makeVertices(const SkPath& path, const SkMatrix& ctm) const { bool transparent = OccluderType::kTransparent == fOccluderType; - SkScalar z = fOccluderHeight; - return SkShadowTessellator::MakeSpot(path, ctm, - [z](SkScalar, SkScalar) -> SkScalar { return z; }, + SkPoint3 zParams = SkPoint3::Make(0, 0, fOccluderHeight); + return SkShadowTessellator::MakeSpot(path, ctm, zParams, fDevLightPos, fLightRadius, transparent); } }; @@ -680,13 +677,13 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc // Draw an offset spot shadow and outlining ambient shadow for the given path, // without caching and using a function based on local position to compute the height. void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path, - std::function<SkScalar(SkScalar, SkScalar)> heightFunc, + const SkPoint3& zPlaneParams, const SkPoint3& lightPos, SkScalar lightRadius, SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color, uint32_t flags) { // try fast paths bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag); - if (!skipAnalytic && draw_analytic_shadows(canvas, path, heightFunc(0, 0), lightPos, + if (!skipAnalytic && draw_analytic_shadows(canvas, path, zPlaneParams.fZ, lightPos, lightRadius, ambientAlpha, spotAlpha, color, flags)) { return; @@ -701,7 +698,7 @@ void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path, if (ambientAlpha > 0) { ambientAlpha = SkTMin(ambientAlpha, 1.f); sk_sp<SkVertices> vertices = SkShadowTessellator::MakeAmbient(path, viewMatrix, - heightFunc, transparent); + zPlaneParams, transparent); SkColor renderColor = compute_render_color(color, ambientAlpha); SkPaint paint; // Run the vertex color through a GaussianColorFilter and then modulate the grayscale @@ -714,7 +711,7 @@ void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path, if (spotAlpha > 0) { spotAlpha = SkTMin(spotAlpha, 1.f); - sk_sp<SkVertices> vertices = SkShadowTessellator::MakeSpot(path, viewMatrix, heightFunc, + sk_sp<SkVertices> vertices = SkShadowTessellator::MakeSpot(path, viewMatrix, zPlaneParams, lightPos, lightRadius, transparent); SkColor renderColor = compute_render_color(color, spotAlpha); diff --git a/tests/ShadowUtilsTest.cpp b/tests/ShadowUtilsTest.cpp index f83e44a1fc..c0e20d57e4 100644 --- a/tests/ShadowUtilsTest.cpp +++ b/tests/ShadowUtilsTest.cpp @@ -15,24 +15,24 @@ void tessellate_shadow(skiatest::Reporter* reporter, const SkPath& path, const SkMatrix& ctm, bool expectSuccess) { - auto heightFunc = [] (SkScalar, SkScalar) { return 4; }; + auto heightParams = SkPoint3::Make(0, 0, 4); - auto verts = SkShadowTessellator::MakeAmbient(path, ctm, heightFunc, true); + auto verts = SkShadowTessellator::MakeAmbient(path, ctm, heightParams, true); if (expectSuccess != SkToBool(verts)) { ERRORF(reporter, "Expected shadow tessellation to %s but it did not.", expectSuccess ? "succeed" : "fail"); } - verts = SkShadowTessellator::MakeAmbient(path, ctm, heightFunc, false); + verts = SkShadowTessellator::MakeAmbient(path, ctm, heightParams, false); if (expectSuccess != SkToBool(verts)) { ERRORF(reporter, "Expected shadow tessellation to %s but it did not.", expectSuccess ? "succeed" : "fail"); } - verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {0, 0, 128}, 128.f, false); + verts = SkShadowTessellator::MakeSpot(path, ctm, heightParams, {0, 0, 128}, 128.f, false); if (expectSuccess != SkToBool(verts)) { ERRORF(reporter, "Expected shadow tessellation to %s but it did not.", expectSuccess ? "succeed" : "fail"); } - verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {0, 0, 128}, 128.f, false); + verts = SkShadowTessellator::MakeSpot(path, ctm, heightParams, {0, 0, 128}, 128.f, false); if (expectSuccess != SkToBool(verts)) { ERRORF(reporter, "Expected shadow tessellation to %s but it did not.", expectSuccess ? "succeed" : "fail"); |