aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/private/SkShadowFlags.h4
-rw-r--r--samplecode/SampleAndroidShadows.cpp351
-rw-r--r--src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp10
-rwxr-xr-xsrc/utils/SkShadowTessellator.cpp38
-rw-r--r--src/utils/SkShadowTessellator.h5
-rw-r--r--src/utils/SkShadowUtils.cpp124
-rw-r--r--tests/ShadowUtilsTest.cpp12
7 files changed, 106 insertions, 438 deletions
diff --git a/include/private/SkShadowFlags.h b/include/private/SkShadowFlags.h
index 23b0f54095..8caf632988 100644
--- a/include/private/SkShadowFlags.h
+++ b/include/private/SkShadowFlags.h
@@ -14,8 +14,10 @@ enum SkShadowFlags {
/** The occluding object is not opaque. Knowing that the occluder is opaque allows
* us to cull shadow geometry behind it and improve performance. */
kTransparentOccluder_ShadowFlag = 0x01,
+ /** Don't try to use analytic shadows. */
+ kGeometricOnly_ShadowFlag = 0x02,
/** mask for all shadow flags */
- kAll_ShadowFlag = 0x01
+ kAll_ShadowFlag = 0x03
};
#endif
diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp
index 02b494ff20..99e5ff4556 100644
--- a/samplecode/SampleAndroidShadows.cpp
+++ b/samplecode/SampleAndroidShadows.cpp
@@ -21,8 +21,6 @@
#include "SkView.h"
#include "sk_tool_utils.h"
-#define USE_SHADOW_UTILS
-
////////////////////////////////////////////////////////////////////////////
class ShadowsView : public SampleView {
@@ -129,327 +127,27 @@ protected:
canvas->drawColor(0xFFDDDDDD);
}
- static void GetOcclRect(const SkPath& path, SkRect* occlRect) {
- SkRect pathRect;
- SkRRect pathRRect;
- if (path.isOval(&pathRect)) {
- *occlRect = sk_tool_utils::compute_central_occluder(SkRRect::MakeOval(pathRect));
- } else if (path.isRRect(&pathRRect)) {
- *occlRect = sk_tool_utils::compute_central_occluder(pathRRect);
- } else if (path.isRect(occlRect)) {
- // the inverse transform for the spot shadow occluder doesn't always get us
- // back to exactly the same position, so deducting a little slop
- occlRect->inset(1, 1);
- } else {
- *occlRect = SkRect::MakeEmpty();
- }
- }
-
- void drawAmbientShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
- SkScalar ambientAlpha) {
-
- if (ambientAlpha <= 0) {
- return;
- }
-
- const SkScalar kHeightFactor = 1.f / 128.f;
- const SkScalar kGeomFactor = 64;
-
- SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
- SkScalar radius = zValue*kHeightFactor*kGeomFactor;
-
- // occlude blur
- SkRect occlRect;
- GetOcclRect(path, &occlRect);
- sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
- SkBlurMask::ConvertRadiusToSigma(radius),
- occlRect,
- SkBlurMaskFilter::kNone_BlurFlag);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setMaskFilter(std::move(mf));
- paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
- ? 255
- : (unsigned char)(ambientAlpha*umbraAlpha*255.999f), 0, 0, 0));
- canvas->drawPath(path, paint);
-
- // draw occlusion rect
-#if DRAW_OCCL_RECT
- SkPaint stroke;
- stroke.setStyle(SkPaint::kStroke_Style);
- stroke.setColor(SK_ColorBLUE);
- canvas->drawRect(occlRect, stroke);
-#endif
- }
-
- void drawAmbientShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
- SkScalar ambientAlpha) {
-
- if (ambientAlpha <= 0) {
- return;
- }
-
- const SkScalar kHeightFactor = 1.f / 128.f;
- const SkScalar kGeomFactor = 64;
-
- SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
- SkScalar radius = zValue*kHeightFactor*kGeomFactor;
- // distance to outer of edge of geometry from original shape edge
- SkScalar offset = radius*umbraAlpha;
-
- SkRect pathRect;
- SkRRect pathRRect;
- SkScalar scaleFactors[2];
- if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
- return;
- }
- if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 64 ||
- !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
- (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
- path.isRect(&pathRect))) {
- this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
- return;
- }
-
- // For all of these, we inset the offset rect by half the radius to get our stroke shape.
- SkScalar strokeOutset = offset - SK_ScalarHalf*radius;
- // Make sure we'll have a radius of at least 0.5 after xform
- if (strokeOutset*scaleFactors[0] < 0.5f) {
- strokeOutset = 0.5f / scaleFactors[0];
- }
- if (path.isOval(nullptr)) {
- pathRect.outset(strokeOutset, strokeOutset);
- pathRRect = SkRRect::MakeOval(pathRect);
- } else if (path.isRect(nullptr)) {
- pathRect.outset(strokeOutset, strokeOutset);
- pathRRect = SkRRect::MakeRectXY(pathRect, strokeOutset, strokeOutset);
- } else {
- pathRRect.outset(strokeOutset, strokeOutset);
- }
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kStroke_Style);
- // we outset the stroke a little to cover up AA on the interior edge
- SkScalar pad = 0.5f;
- paint.setStrokeWidth(radius + 2*pad);
- // handle scale of radius and pad due to CTM
- radius *= scaleFactors[0];
- pad *= scaleFactors[0];
- SkASSERT(radius < 16384);
- SkASSERT(pad < 64);
- // Convert radius to 14.2 fixed point and place in the R & G components.
- // Convert pad to 6.2 fixed point and place in the B component.
- uint16_t iRadius = (uint16_t)(radius*4.0f);
- unsigned char alpha = (unsigned char)(ambientAlpha*255.999f);
- paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
- iRadius >> 8, iRadius & 0xff,
- (unsigned char)(4.0f*pad)));
-
- paint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorBLACK, SkBlendMode::kModulate));
- paint.setShader(SkGaussianEdgeShader::Make());
- canvas->drawRRect(pathRRect, paint);
- }
-
- void drawSpotShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
- SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
- if (spotAlpha <= 0) {
- return;
- }
-
- SkScalar zRatio = zValue / (lightPos.fZ - zValue);
- if (zRatio < 0.0f) {
- zRatio = 0.0f;
- } else if (zRatio > 0.95f) {
- zRatio = 0.95f;
- }
- SkScalar blurRadius = lightWidth*zRatio;
-
- // compute the transformation params
- SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
- SkMatrix ctmInverse;
- if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
- return;
- }
- SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
- ctmInverse.mapPoints(&lightPos2D, 1);
- SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
- zRatio*(center.fY - lightPos2D.fY));
- SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
-
- SkAutoCanvasRestore acr(canvas, true);
-
- sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
- SkBlurMask::ConvertRadiusToSigma(blurRadius),
- SkBlurMaskFilter::kNone_BlurFlag);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setMaskFilter(std::move(mf));
- paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
- ? 255
- : (unsigned char)(spotAlpha*255.999f), 0, 0, 0));
-
- // apply transformation to shadow
- canvas->scale(scale, scale);
- canvas->translate(offset.fX, offset.fY);
- canvas->drawPath(path, paint);
- }
-
- void drawSpotShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
- SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
- if (spotAlpha <= 0) {
- return;
- }
-
- SkScalar zRatio = zValue / (lightPos.fZ - zValue);
- if (zRatio < 0.0f) {
- zRatio = 0.0f;
- } else if (zRatio > 0.95f) {
- zRatio = 0.95f;
- }
- SkScalar radius = 2.0f*lightWidth*zRatio;
-
- SkRect pathRect;
- SkRRect pathRRect;
- SkScalar scaleFactors[2];
- if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
- return;
- }
- if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 16384 ||
- !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
- (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
- path.isRect(&pathRect))) {
- this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
- return;
- }
-
- // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space
- const SkScalar minRadius = SK_ScalarHalf/scaleFactors[0];
- if (path.isOval(nullptr)) {
- pathRRect = SkRRect::MakeOval(pathRect);
- } else if (path.isRect(nullptr)) {
- pathRRect = SkRRect::MakeRectXY(pathRect, minRadius, minRadius);
- } else {
- if (pathRRect.getSimpleRadii().fX < minRadius) {
- pathRRect.setRectXY(pathRRect.rect(), minRadius, minRadius);
- }
- }
-
- // compute the scale and translation for the shadow
- SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
- SkRRect shadowRRect;
- pathRRect.transform(SkMatrix::MakeScale(scale, scale), &shadowRRect);
- SkPoint center = SkPoint::Make(shadowRRect.rect().centerX(), shadowRRect.rect().centerY());
- SkMatrix ctmInverse;
- if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
- return;
- }
- SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
- ctmInverse.mapPoints(&lightPos2D, 1);
- SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
- zRatio*(center.fY - lightPos2D.fY));
- SkAutoCanvasRestore acr(canvas, true);
-
- SkPaint paint;
- paint.setAntiAlias(true);
- // We want to extend the stroked area in so that it meets up with the caster
- // geometry. The stroked geometry will, by definition already be inset half the
- // stroke width but we also have to account for the scaling.
- // We also add 1/2 to cover up AA on the interior edge.
- SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(pathRect.fLeft),
- SkTAbs(pathRect.fRight)),
- SkTMax(SkTAbs(pathRect.fTop),
- SkTAbs(pathRect.fBottom)));
- SkScalar insetAmount = offset.length() - (0.5f * radius) + scaleOffset + 0.5f;
-
- // compute area
- SkScalar strokeWidth = radius + insetAmount;
- SkScalar strokedArea = 2.0f*strokeWidth*(shadowRRect.width() + shadowRRect.height());
- SkScalar filledArea = (shadowRRect.height() + radius)*(shadowRRect.width() + radius);
- // If the area of the stroked geometry is larger than the fill geometry, or
- // if our pad is too big to convert to 6.2 fixed point, just fill it.
- if (strokedArea > filledArea) {
- paint.setStyle(SkPaint::kStrokeAndFill_Style);
- paint.setStrokeWidth(radius);
- } else {
- // Since we can't have unequal strokes, inset the shadow rect so the inner
- // and outer edges of the stroke will land where we want.
- SkRect insetRect = shadowRRect.rect().makeInset(insetAmount/2.0f, insetAmount/2.0f);
- SkScalar insetRad = SkTMax(shadowRRect.getSimpleRadii().fX - insetAmount/2.0f,
- minRadius);
-
- shadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad);
- paint.setStyle(SkPaint::kStroke_Style);
- paint.setStrokeWidth(strokeWidth);
- }
- paint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorBLACK, SkBlendMode::kModulate));
- paint.setShader(SkGaussianEdgeShader::Make());
- // handle scale of radius due to CTM
- radius *= scaleFactors[0];
- // don't need to scale pad as it was computed from the transformed offset
- SkASSERT(radius < 16384);
- SkScalar pad = 0;
- SkASSERT(pad < 64);
- // Convert radius to 14.2 fixed point and place in the R & G components.
- // Convert pad to 6.2 fixed point and place in the B component.
- uint16_t iRadius = (uint16_t)(radius*4.0f);
- unsigned char alpha = (unsigned char)(spotAlpha*255.999f);
- paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
- iRadius >> 8, iRadius & 0xff,
- (unsigned char)(4.0f*pad)));
-
- // apply transformation to shadow
- canvas->translate(offset.fX, offset.fY);
- canvas->drawRRect(shadowRRect, paint);
- }
-
void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
std::function<SkScalar(SkScalar, SkScalar)> zFunc,
const SkPaint& paint, SkScalar ambientAlpha,
const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
-#ifdef USE_SHADOW_UTILS
- SkScalar zValue = zFunc(0, 0);
- if (fUseAlt) {
- if (fShowAmbient) {
- this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
- }
- if (fShowSpot) {
- this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
- }
- } else {
- if (!fShowAmbient) {
- ambientAlpha = 0;
- }
- if (!fShowSpot) {
- spotAlpha = 0;
- }
-
- //SkShadowUtils::DrawShadow(canvas, path,
- // zValue,
- // lightPos, lightWidth,
- // ambientAlpha, spotAlpha, SK_ColorBLACK);
- SkShadowUtils::DrawUncachedShadow(canvas, path, zFunc,
- lightPos, lightWidth,
- ambientAlpha, spotAlpha, SK_ColorBLACK);
+ if (!fShowAmbient) {
+ ambientAlpha = 0;
}
-#else
- if (fShowAmbient) {
- if (fUseAlt) {
- this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
- } else {
- this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
- }
+ if (!fShowSpot) {
+ spotAlpha = 0;
}
- if (fShowSpot) {
- if (fUseAlt) {
- this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
- } else {
- this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
- }
+ uint32_t flags = 0;
+ if (fUseAlt) {
+ flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
}
-#endif
+ //SkShadowUtils::DrawShadow(canvas, path,
+ // zValue,
+ // lightPos, lightWidth,
+ // ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
+ SkShadowUtils::DrawUncachedShadow(canvas, path, zFunc,
+ lightPos, lightWidth,
+ ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
if (fShowObject) {
canvas->drawPath(path, paint);
@@ -577,27 +275,6 @@ protected:
return true;
}
-protected:
- SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
- return new SkView::Click(this);
- }
-
- bool onClick(Click *click) override {
- SkScalar x = click->fCurr.fX;
- SkScalar y = click->fCurr.fY;
-
- SkScalar dx = x - click->fPrev.fX;
- SkScalar dy = y - click->fPrev.fY;
-
- if (dx != 0 || dy != 0) {
- fLightPos.fX += dx;
- fLightPos.fY += dy;
- this->inval(nullptr);
- }
-
- return true;
- }
-
private:
typedef SampleView INHERITED;
};
diff --git a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
index 95b08d2f0d..a37c173c0b 100644
--- a/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
+++ b/src/gpu/effects/GrBlurredEdgeFragmentProcessor.cpp
@@ -23,7 +23,7 @@ public:
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;");
+ fragBuilder->codeAppendf("float factor = 1.0 - color.a;");
} 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;");
@@ -37,14 +37,10 @@ public:
fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
break;
case GrBlurredEdgeFP::kSmoothstep_Mode:
- fragBuilder->codeAppend("factor = smoothstep(factor, 0.0, 1.0);");
+ fragBuilder->codeAppend("factor = smoothstep(1.0, 0.0, factor);");
break;
}
- if (!args.fGpImplementsDistanceVector) {
- fragBuilder->codeAppendf("%s = vec4(factor*color.g);", args.fOutputColor);
- } else {
- fragBuilder->codeAppendf("%s = vec4(factor*color.a);", args.fOutputColor);
- }
+ fragBuilder->codeAppendf("%s = vec4(factor);", args.fOutputColor);
}
protected:
diff --git a/src/utils/SkShadowTessellator.cpp b/src/utils/SkShadowTessellator.cpp
index 36df514534..32a114253a 100755
--- a/src/utils/SkShadowTessellator.cpp
+++ b/src/utils/SkShadowTessellator.cpp
@@ -327,8 +327,7 @@ bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) {
class SkAmbientShadowTessellator : public SkBaseShadowTessellator {
public:
SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm,
- SkShadowTessellator::HeightFunc heightFunc,
- SkScalar ambientAlpha, bool transparent);
+ SkShadowTessellator::HeightFunc heightFunc, bool transparent);
private:
void handleLine(const SkPoint& p) override;
@@ -343,10 +342,9 @@ private:
}
SkColor umbraColor(SkScalar z) {
SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(z*kHeightFactor, 0.0f)));
- return SkColorSetARGB(255, 0, fAmbientAlpha * 255.9999f, umbraAlpha * 255.9999f);
+ return SkColorSetARGB(umbraAlpha * 255.9999f, 0, 0, 0);
}
- SkScalar fAmbientAlpha;
int fCentroidCount;
typedef SkBaseShadowTessellator INHERITED;
@@ -355,10 +353,8 @@ private:
SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
const SkMatrix& ctm,
SkShadowTessellator::HeightFunc heightFunc,
- SkScalar ambientAlpha,
bool transparent)
- : INHERITED(heightFunc, transparent)
- , fAmbientAlpha(ambientAlpha) {
+ : INHERITED(heightFunc, transparent) {
// Set base colors
SkScalar occluderHeight = heightFunc(0, 0);
SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(occluderHeight*kHeightFactor, 0.0f)));
@@ -366,8 +362,8 @@ SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
// 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.
- fUmbraColor = SkColorSetARGB(255, 0, ambientAlpha * 255.9999f, umbraAlpha * 255.9999f);
- fPenumbraColor = SkColorSetARGB(255, 0, ambientAlpha * 255.9999f, 0);
+ fUmbraColor = SkColorSetARGB(umbraAlpha * 255.9999f, 0, 0, 0);
+ fPenumbraColor = SkColorSetARGB(0, 0, 0, 0);
// make sure we're not below the canvas plane
this->setZOffset(path.getBounds(), ctm.hasPerspective());
@@ -654,9 +650,8 @@ 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, SkScalar lightRadius,
- SkScalar spotAlpha, bool transparent);
+ SkShadowTessellator::HeightFunc heightFunc, const SkPoint3& lightPos,
+ SkScalar lightRadius, bool transparent);
private:
void computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm,
@@ -700,7 +695,7 @@ private:
SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
SkShadowTessellator::HeightFunc heightFunc,
const SkPoint3& lightPos, SkScalar lightRadius,
- SkScalar spotAlpha, bool transparent)
+ bool transparent)
: INHERITED(heightFunc, transparent)
, fLightZ(lightPos.fZ)
, fLightRadius(lightRadius)
@@ -723,8 +718,8 @@ SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMat
float zRatio = SkTPin(occluderHeight / (fLightZ - occluderHeight), 0.0f, 0.95f);
SkScalar radius = lightRadius * zRatio;
fRadius = radius;
- fUmbraColor = SkColorSetARGB(255, 0, spotAlpha * 255.9999f, 255);
- fPenumbraColor = SkColorSetARGB(255, 0, spotAlpha * 255.9999f, 0);
+ fUmbraColor = SkColorSetARGB(255, 0, 0, 0);
+ fPenumbraColor = SkColorSetARGB(0, 0, 0, 0);
// Compute the scale and translation for the spot shadow.
SkMatrix shadowTransform;
@@ -1292,17 +1287,14 @@ void SkSpotShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector&
///////////////////////////////////////////////////////////////////////////////////////////////////
sk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
- HeightFunc heightFunc, SkScalar ambientAlpha,
- bool transparent) {
- SkAmbientShadowTessellator ambientTess(path, ctm, heightFunc, ambientAlpha, transparent);
+ HeightFunc heightFunc, bool transparent) {
+ SkAmbientShadowTessellator ambientTess(path, ctm, heightFunc, transparent);
return ambientTess.releaseVertices();
}
sk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm,
- HeightFunc heightFunc,
- const SkPoint3& lightPos, SkScalar lightRadius,
- SkScalar spotAlpha, bool transparent) {
- SkSpotShadowTessellator spotTess(path, ctm, heightFunc, lightPos, lightRadius,
- spotAlpha, transparent);
+ HeightFunc heightFunc, const SkPoint3& lightPos,
+ SkScalar lightRadius, bool transparent) {
+ SkSpotShadowTessellator spotTess(path, ctm, heightFunc, lightPos, lightRadius, transparent);
return spotTess.releaseVertices();
}
diff --git a/src/utils/SkShadowTessellator.h b/src/utils/SkShadowTessellator.h
index f9f4a144c9..d6e784ee45 100644
--- a/src/utils/SkShadowTessellator.h
+++ b/src/utils/SkShadowTessellator.h
@@ -26,7 +26,7 @@ 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, SkScalar ambientAlpha, bool transparent);
+ HeightFunc heightFunc, bool transparent);
/**
* This function generates a spot shadow mesh for a path by walking the transformed path,
@@ -34,8 +34,7 @@ sk_sp<SkVertices> MakeAmbient(const SkPath& path, const SkMatrix& ctm,
* 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,
- const SkPoint3& lightPos, SkScalar lightRadius,
- SkScalar spotAlpha, bool transparent);
+ const SkPoint3& lightPos, SkScalar lightRadius, bool transparent);
}
#endif
diff --git a/src/utils/SkShadowUtils.cpp b/src/utils/SkShadowUtils.cpp
index 279ca7338c..430ea2c3b1 100644
--- a/src/utils/SkShadowUtils.cpp
+++ b/src/utils/SkShadowUtils.cpp
@@ -54,52 +54,52 @@ private:
};
static void build_table() {
- SkDebugf("const uint16_t gByteExpU16Table[256] = {");
+ SkDebugf("const uint8_t gByteExpU8Table[256] = {");
for (int i = 0; i <= 255; ++i) {
if (!(i % 8)) {
SkDebugf("\n");
}
SkScalar factor = SK_Scalar1 - i / 255.f;
factor = SkScalarExp(-factor * factor * 4) - 0.018f;
- int v = (int)(factor * 65536);
- SkDebugf(" 0x%04X,", v);
+ int v = (int)(factor * 255.9f);
+ SkDebugf(" 0x%02X,", v);
}
SkDebugf("\n};\n");
}
-const uint16_t gByteExpU16Table[256] = {
- 0x0014, 0x003A, 0x0062, 0x008A, 0x00B3, 0x00DE, 0x010A, 0x0136,
- 0x0165, 0x0194, 0x01C4, 0x01F6, 0x0229, 0x025E, 0x0294, 0x02CB,
- 0x0304, 0x033E, 0x0379, 0x03B7, 0x03F5, 0x0435, 0x0477, 0x04BB,
- 0x0500, 0x0546, 0x058F, 0x05D9, 0x0625, 0x0673, 0x06C3, 0x0714,
- 0x0768, 0x07BD, 0x0814, 0x086E, 0x08C9, 0x0926, 0x0986, 0x09E8,
- 0x0A4B, 0x0AB1, 0x0B1A, 0x0B84, 0x0BF1, 0x0C60, 0x0CD2, 0x0D46,
- 0x0DBC, 0x0E35, 0x0EB0, 0x0F2E, 0x0FAF, 0x1032, 0x10B7, 0x1140,
- 0x11CB, 0x1258, 0x12E9, 0x137C, 0x1412, 0x14AB, 0x1547, 0x15E6,
- 0x1688, 0x172D, 0x17D5, 0x187F, 0x192D, 0x19DE, 0x1A92, 0x1B4A,
- 0x1C04, 0x1CC2, 0x1D83, 0x1E47, 0x1F0E, 0x1FD9, 0x20A7, 0x2178,
- 0x224D, 0x2325, 0x2401, 0x24E0, 0x25C2, 0x26A8, 0x2792, 0x287F,
- 0x296F, 0x2A63, 0x2B5A, 0x2C56, 0x2D54, 0x2E56, 0x2F5C, 0x3065,
- 0x3172, 0x3283, 0x3397, 0x34AE, 0x35CA, 0x36E9, 0x380B, 0x3931,
- 0x3A5B, 0x3B88, 0x3CB9, 0x3DED, 0x3F25, 0x4061, 0x41A0, 0x42E2,
- 0x4428, 0x4572, 0x46BF, 0x480F, 0x4963, 0x4ABA, 0x4C14, 0x4D72,
- 0x4ED3, 0x5038, 0x519F, 0x530A, 0x5478, 0x55E9, 0x575D, 0x58D4,
- 0x5A4F, 0x5BCC, 0x5D4C, 0x5ECF, 0x6054, 0x61DD, 0x6368, 0x64F6,
- 0x6686, 0x6819, 0x69AE, 0x6B45, 0x6CDF, 0x6E7B, 0x701A, 0x71BA,
- 0x735D, 0x7501, 0x76A7, 0x784F, 0x79F9, 0x7BA4, 0x7D51, 0x7F00,
- 0x80AF, 0x8260, 0x8413, 0x85C6, 0x877A, 0x8930, 0x8AE6, 0x8C9C,
- 0x8E54, 0x900C, 0x91C4, 0x937D, 0x9535, 0x96EE, 0x98A7, 0x9A60,
- 0x9C18, 0x9DD1, 0x9F88, 0xA13F, 0xA2F6, 0xA4AB, 0xA660, 0xA814,
- 0xA9C6, 0xAB78, 0xAD27, 0xAED6, 0xB082, 0xB22D, 0xB3D6, 0xB57D,
- 0xB722, 0xB8C5, 0xBA65, 0xBC03, 0xBD9E, 0xBF37, 0xC0CD, 0xC25F,
- 0xC3EF, 0xC57B, 0xC704, 0xC889, 0xCA0B, 0xCB89, 0xCD04, 0xCE7A,
- 0xCFEC, 0xD15A, 0xD2C4, 0xD429, 0xD58A, 0xD6E6, 0xD83D, 0xD990,
- 0xDADD, 0xDC25, 0xDD68, 0xDEA6, 0xDFDE, 0xE111, 0xE23E, 0xE365,
- 0xE486, 0xE5A2, 0xE6B7, 0xE7C6, 0xE8CF, 0xE9D1, 0xEACD, 0xEBC3,
- 0xECB2, 0xED9A, 0xEE7C, 0xEF56, 0xF02A, 0xF0F6, 0xF1BC, 0xF27A,
- 0xF332, 0xF3E1, 0xF48A, 0xF52B, 0xF5C5, 0xF657, 0xF6E1, 0xF764,
- 0xF7DF, 0xF852, 0xF8BE, 0xF922, 0xF97E, 0xF9D2, 0xFA1E, 0xFA62,
- 0xFA9F, 0xFAD3, 0xFAFF, 0xFB23, 0xFB40, 0xFB54, 0xFB60, 0xFB64,
+const uint8_t gByteExpU8Table[256] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04,
+ 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07,
+ 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09,
+ 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0D,
+ 0x0D, 0x0E, 0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x11,
+ 0x11, 0x12, 0x12, 0x13, 0x14, 0x14, 0x15, 0x15,
+ 0x16, 0x17, 0x17, 0x18, 0x19, 0x19, 0x1A, 0x1B,
+ 0x1C, 0x1C, 0x1D, 0x1E, 0x1F, 0x1F, 0x20, 0x21,
+ 0x22, 0x23, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
+ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39,
+ 0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42,
+ 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4C, 0x4D,
+ 0x4E, 0x50, 0x51, 0x53, 0x54, 0x55, 0x57, 0x58,
+ 0x5A, 0x5B, 0x5D, 0x5E, 0x60, 0x61, 0x63, 0x64,
+ 0x66, 0x68, 0x69, 0x6B, 0x6C, 0x6E, 0x70, 0x71,
+ 0x73, 0x74, 0x76, 0x78, 0x79, 0x7B, 0x7D, 0x7E,
+ 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8A, 0x8C,
+ 0x8E, 0x8F, 0x91, 0x93, 0x95, 0x96, 0x98, 0x9A,
+ 0x9C, 0x9D, 0x9F, 0xA1, 0xA2, 0xA4, 0xA6, 0xA8,
+ 0xA9, 0xAB, 0xAD, 0xAE, 0xB0, 0xB2, 0xB3, 0xB5,
+ 0xB7, 0xB8, 0xBA, 0xBB, 0xBD, 0xBF, 0xC0, 0xC2,
+ 0xC3, 0xC5, 0xC6, 0xC8, 0xC9, 0xCB, 0xCC, 0xCE,
+ 0xCF, 0xD1, 0xD2, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9,
+ 0xDA, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE2, 0xE3,
+ 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB,
+ 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF0, 0xF1, 0xF2,
+ 0xF3, 0xF3, 0xF4, 0xF5, 0xF5, 0xF6, 0xF6, 0xF7,
+ 0xF7, 0xF8, 0xF8, 0xF9, 0xF9, 0xF9, 0xFA, 0xFA,
+ 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB,
};
void SkGaussianColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
@@ -109,7 +109,7 @@ void SkGaussianColorFilter::filterSpan(const SkPMColor src[], int count, SkPMCol
}
for (int i = 0; i < count; ++i) {
SkPMColor c = src[i];
- uint8_t a = gByteExpU16Table[SkGetPackedB32(c)] * SkGetPackedG32(c) >> 16;
+ uint8_t a = gByteExpU8Table[SkGetPackedA32(c)];
dst[i] = SkPackARGB32(a, a, a, a);
}
}
@@ -143,12 +143,10 @@ uint64_t resource_cache_shared_id() {
/** Factory for an ambient shadow mesh with particular shadow properties. */
struct AmbientVerticesFactory {
SkScalar fOccluderHeight = SK_ScalarNaN; // NaN so that isCompatible will fail until init'ed.
- SkScalar fAmbientAlpha;
bool fTransparent;
bool isCompatible(const AmbientVerticesFactory& that, SkVector* translate) const {
- if (fOccluderHeight != that.fOccluderHeight || fAmbientAlpha != that.fAmbientAlpha ||
- fTransparent != that.fTransparent) {
+ if (fOccluderHeight != that.fOccluderHeight || fTransparent != that.fTransparent) {
return false;
}
translate->set(0, 0);
@@ -159,7 +157,7 @@ struct AmbientVerticesFactory {
SkScalar z = fOccluderHeight;
return SkShadowTessellator::MakeAmbient(path, ctm,
[z](SkScalar, SkScalar) { return z; },
- fAmbientAlpha, fTransparent);
+ fTransparent);
}
};
@@ -178,13 +176,11 @@ struct SpotVerticesFactory {
SkScalar fOccluderHeight = SK_ScalarNaN; // NaN so that isCompatible will fail until init'ed.
SkPoint3 fDevLightPos;
SkScalar fLightRadius;
- SkScalar fSpotAlpha;
OccluderType fOccluderType;
bool isCompatible(const SpotVerticesFactory& that, SkVector* translate) const {
if (fOccluderHeight != that.fOccluderHeight || fDevLightPos.fZ != that.fDevLightPos.fZ ||
- fLightRadius != that.fLightRadius || fSpotAlpha != that.fSpotAlpha ||
- fOccluderType != that.fOccluderType) {
+ fLightRadius != that.fLightRadius || fOccluderType != that.fOccluderType) {
return false;
}
switch (fOccluderType) {
@@ -212,8 +208,7 @@ struct SpotVerticesFactory {
SkScalar z = fOccluderHeight;
return SkShadowTessellator::MakeSpot(path, ctm,
[z](SkScalar, SkScalar) -> SkScalar { return z; },
- fDevLightPos, fLightRadius,
- fSpotAlpha, transparent);
+ fDevLightPos, fLightRadius, transparent);
}
};
@@ -569,14 +564,21 @@ static bool draw_analytic_shadows(SkCanvas* canvas, const SkPath& path, SkScalar
return false;
}
+static SkColor compute_render_color(SkColor color, float alpha) {
+ return SkColorSetARGB(alpha*SkColorGetA(color), SkColorGetR(color),
+ SkColorGetG(color), SkColorGetB(color));
+}
+
// 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& devLightPos, SkScalar lightRadius,
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
uint32_t flags, SkResourceCache* cache) {
// try fast paths
- if (draw_analytic_shadows(canvas, path, occluderHeight, devLightPos, lightRadius,
- ambientAlpha, spotAlpha, color, flags)) {
+ bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag);
+ if (!skipAnalytic && draw_analytic_shadows(canvas, path, occluderHeight, devLightPos,
+ lightRadius, ambientAlpha, spotAlpha, color,
+ flags)) {
return;
}
@@ -592,10 +594,10 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
ambientAlpha = SkTMin(ambientAlpha, 1.f);
AmbientVerticesFactory factory;
factory.fOccluderHeight = occluderHeight;
- factory.fAmbientAlpha = ambientAlpha;
factory.fTransparent = transparent;
- draw_shadow(factory, canvas, shadowedPath, color, cache);
+ SkColor renderColor = compute_render_color(color, ambientAlpha);
+ draw_shadow(factory, canvas, shadowedPath, renderColor, cache);
}
if (spotAlpha > 0) {
@@ -614,7 +616,6 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
factory.fOccluderHeight = occluderHeight;
factory.fDevLightPos = devLightPos;
factory.fLightRadius = lightRadius;
- factory.fSpotAlpha = spotAlpha;
SkRRect rrect;
if (transparent) {
@@ -653,7 +654,9 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
if (factory.fOccluderType == SpotVerticesFactory::OccluderType::kOpaque) {
factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent;
}
- draw_shadow(factory, canvas, shadowedPath, color, cache);
+
+ SkColor renderColor = compute_render_color(color, spotAlpha);
+ draw_shadow(factory, canvas, shadowedPath, renderColor, cache);
}
}
@@ -665,8 +668,10 @@ void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path,
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
uint32_t flags) {
// try fast paths
- if (draw_analytic_shadows(canvas, path, heightFunc(0, 0), lightPos, lightRadius,
- ambientAlpha, spotAlpha, color, flags)) {
+ bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag);
+ if (!skipAnalytic && draw_analytic_shadows(canvas, path, heightFunc(0, 0), lightPos,
+ lightRadius, ambientAlpha, spotAlpha, color,
+ flags)) {
return;
}
@@ -679,13 +684,13 @@ 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, ambientAlpha,
- transparent);
+ heightFunc, transparent);
+ SkColor renderColor = compute_render_color(color, ambientAlpha);
SkPaint paint;
// Run the vertex color through a GaussianColorFilter and then modulate the grayscale
// result of that against our 'color' param.
paint.setColorFilter(SkColorFilter::MakeComposeFilter(
- SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate),
+ SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
SkGaussianColorFilter::Make()));
canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
}
@@ -694,12 +699,13 @@ void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path,
spotAlpha = SkTMin(spotAlpha, 1.f);
sk_sp<SkVertices> vertices = SkShadowTessellator::MakeSpot(path, viewMatrix, heightFunc,
lightPos, lightRadius,
- spotAlpha, transparent);
+ transparent);
+ SkColor renderColor = compute_render_color(color, spotAlpha);
SkPaint paint;
// Run the vertex color through a GaussianColorFilter and then modulate the grayscale
// result of that against our 'color' param.
paint.setColorFilter(SkColorFilter::MakeComposeFilter(
- SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate),
+ SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
SkGaussianColorFilter::Make()));
canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
}
diff --git a/tests/ShadowUtilsTest.cpp b/tests/ShadowUtilsTest.cpp
index 56990146f0..f83e44a1fc 100644
--- a/tests/ShadowUtilsTest.cpp
+++ b/tests/ShadowUtilsTest.cpp
@@ -14,29 +14,25 @@
void tessellate_shadow(skiatest::Reporter* reporter, const SkPath& path, const SkMatrix& ctm,
bool expectSuccess) {
- static constexpr SkScalar kAmbientAlpha = 0.25f;
- static constexpr SkScalar kSpotAlpha = 0.25f;
auto heightFunc = [] (SkScalar, SkScalar) { return 4; };
- auto verts = SkShadowTessellator::MakeAmbient(path, ctm, heightFunc, kAmbientAlpha, true);
+ auto verts = SkShadowTessellator::MakeAmbient(path, ctm, heightFunc, 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, kAmbientAlpha, false);
+ verts = SkShadowTessellator::MakeAmbient(path, ctm, heightFunc, 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,
- kSpotAlpha, false);
+ verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {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,
- kSpotAlpha, false);
+ verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {0, 0, 128}, 128.f, false);
if (expectSuccess != SkToBool(verts)) {
ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
expectSuccess ? "succeed" : "fail");