Combine the ambient and spot alphas into the base color

for geometric shadows. 

This matches the analytic shadow approach better, and
is color space invariant.
Also includes cleanup in SampleAndroidShadows.

Bug: skia:6546
Change-Id: I7a7cd060420dae741f967334c8b19542a14f0bcf
Reviewed-on: https://skia-review.googlesource.com/15228
Commit-Queue: Jim Van Verth <jvanverth@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
This commit is contained in:
Jim Van Verth 2017-05-04 09:58:17 -04:00 committed by Skia Commit-Bot
parent db711c982b
commit 060d982036
7 changed files with 107 additions and 439 deletions

View File

@ -14,8 +14,10 @@ enum SkShadowFlags {
/** The occluding object is not opaque. Knowing that the occluder is opaque allows /** The occluding object is not opaque. Knowing that the occluder is opaque allows
* us to cull shadow geometry behind it and improve performance. */ * us to cull shadow geometry behind it and improve performance. */
kTransparentOccluder_ShadowFlag = 0x01, kTransparentOccluder_ShadowFlag = 0x01,
/** Don't try to use analytic shadows. */
kGeometricOnly_ShadowFlag = 0x02,
/** mask for all shadow flags */ /** mask for all shadow flags */
kAll_ShadowFlag = 0x01 kAll_ShadowFlag = 0x03
}; };
#endif #endif

View File

@ -21,8 +21,6 @@
#include "SkView.h" #include "SkView.h"
#include "sk_tool_utils.h" #include "sk_tool_utils.h"
#define USE_SHADOW_UTILS
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
class ShadowsView : public SampleView { class ShadowsView : public SampleView {
@ -129,327 +127,27 @@ protected:
canvas->drawColor(0xFFDDDDDD); 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, void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
std::function<SkScalar(SkScalar, SkScalar)> zFunc, std::function<SkScalar(SkScalar, SkScalar)> zFunc,
const SkPaint& paint, SkScalar ambientAlpha, const SkPaint& paint, SkScalar ambientAlpha,
const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) { const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
#ifdef USE_SHADOW_UTILS if (!fShowAmbient) {
SkScalar zValue = zFunc(0, 0); ambientAlpha = 0;
}
if (!fShowSpot) {
spotAlpha = 0;
}
uint32_t flags = 0;
if (fUseAlt) { if (fUseAlt) {
if (fShowAmbient) { flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
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);
} }
#else //SkShadowUtils::DrawShadow(canvas, path,
if (fShowAmbient) { // zValue,
if (fUseAlt) { // lightPos, lightWidth,
this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha); // ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
} else { SkShadowUtils::DrawUncachedShadow(canvas, path, zFunc,
this->drawAmbientShadow(canvas, path, zValue, ambientAlpha); lightPos, lightWidth,
} ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
}
if (fShowSpot) {
if (fUseAlt) {
this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
} else {
this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
}
}
#endif
if (fShowObject) { if (fShowObject) {
canvas->drawPath(path, paint); canvas->drawPath(path, paint);
@ -577,27 +275,6 @@ protected:
return true; 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: private:
typedef SampleView INHERITED; typedef SampleView INHERITED;
}; };

View File

@ -23,7 +23,7 @@ public:
fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor); fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
if (!args.fGpImplementsDistanceVector) { if (!args.fGpImplementsDistanceVector) {
fragBuilder->codeAppendf("// assuming interpolant is set in vertex colors\n"); 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 { } else {
fragBuilder->codeAppendf("// using distance to edge to compute interpolant\n"); 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 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;"); fragBuilder->codeAppend("factor = exp(-factor * factor * 4.0) - 0.018;");
break; break;
case GrBlurredEdgeFP::kSmoothstep_Mode: case GrBlurredEdgeFP::kSmoothstep_Mode:
fragBuilder->codeAppend("factor = smoothstep(factor, 0.0, 1.0);"); fragBuilder->codeAppend("factor = smoothstep(1.0, 0.0, factor);");
break; break;
} }
if (!args.fGpImplementsDistanceVector) { fragBuilder->codeAppendf("%s = vec4(factor);", args.fOutputColor);
fragBuilder->codeAppendf("%s = vec4(factor*color.g);", args.fOutputColor);
} else {
fragBuilder->codeAppendf("%s = vec4(factor*color.a);", args.fOutputColor);
}
} }
protected: protected:

View File

@ -327,8 +327,7 @@ bool SkBaseShadowTessellator::setTransformedHeightFunc(const SkMatrix& ctm) {
class SkAmbientShadowTessellator : public SkBaseShadowTessellator { class SkAmbientShadowTessellator : public SkBaseShadowTessellator {
public: public:
SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm, SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm,
SkShadowTessellator::HeightFunc heightFunc, SkShadowTessellator::HeightFunc heightFunc, bool transparent);
SkScalar ambientAlpha, bool transparent);
private: private:
void handleLine(const SkPoint& p) override; void handleLine(const SkPoint& p) override;
@ -343,10 +342,9 @@ private:
} }
SkColor umbraColor(SkScalar z) { SkColor umbraColor(SkScalar z) {
SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(z*kHeightFactor, 0.0f))); 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; int fCentroidCount;
typedef SkBaseShadowTessellator INHERITED; typedef SkBaseShadowTessellator INHERITED;
@ -355,10 +353,8 @@ private:
SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path, SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
const SkMatrix& ctm, const SkMatrix& ctm,
SkShadowTessellator::HeightFunc heightFunc, SkShadowTessellator::HeightFunc heightFunc,
SkScalar ambientAlpha,
bool transparent) bool transparent)
: INHERITED(heightFunc, transparent) : INHERITED(heightFunc, transparent) {
, fAmbientAlpha(ambientAlpha) {
// Set base colors // Set base colors
SkScalar occluderHeight = heightFunc(0, 0); SkScalar occluderHeight = heightFunc(0, 0);
SkScalar umbraAlpha = SkScalarInvert((1.0f + SkTMax(occluderHeight*kHeightFactor, 0.0f))); 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 // 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 // then "blurred" by the GrBlurredEdgeFP. It is then multiplied by fAmbientAlpha to get
// the final alpha. // the final alpha.
fUmbraColor = SkColorSetARGB(255, 0, ambientAlpha * 255.9999f, umbraAlpha * 255.9999f); fUmbraColor = SkColorSetARGB(umbraAlpha * 255.9999f, 0, 0, 0);
fPenumbraColor = SkColorSetARGB(255, 0, ambientAlpha * 255.9999f, 0); fPenumbraColor = SkColorSetARGB(0, 0, 0, 0);
// make sure we're not below the canvas plane // make sure we're not below the canvas plane
this->setZOffset(path.getBounds(), ctm.hasPerspective()); this->setZOffset(path.getBounds(), ctm.hasPerspective());
@ -654,9 +650,8 @@ void SkAmbientShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVecto
class SkSpotShadowTessellator : public SkBaseShadowTessellator { class SkSpotShadowTessellator : public SkBaseShadowTessellator {
public: public:
SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm, SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
SkShadowTessellator::HeightFunc heightFunc, SkShadowTessellator::HeightFunc heightFunc, const SkPoint3& lightPos,
const SkPoint3& lightPos, SkScalar lightRadius, SkScalar lightRadius, bool transparent);
SkScalar spotAlpha, bool transparent);
private: private:
void computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm, void computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm,
@ -700,7 +695,7 @@ private:
SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm, SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
SkShadowTessellator::HeightFunc heightFunc, SkShadowTessellator::HeightFunc heightFunc,
const SkPoint3& lightPos, SkScalar lightRadius, const SkPoint3& lightPos, SkScalar lightRadius,
SkScalar spotAlpha, bool transparent) bool transparent)
: INHERITED(heightFunc, transparent) : INHERITED(heightFunc, transparent)
, fLightZ(lightPos.fZ) , fLightZ(lightPos.fZ)
, fLightRadius(lightRadius) , fLightRadius(lightRadius)
@ -723,8 +718,8 @@ SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMat
float zRatio = SkTPin(occluderHeight / (fLightZ - occluderHeight), 0.0f, 0.95f); float zRatio = SkTPin(occluderHeight / (fLightZ - occluderHeight), 0.0f, 0.95f);
SkScalar radius = lightRadius * zRatio; SkScalar radius = lightRadius * zRatio;
fRadius = radius; fRadius = radius;
fUmbraColor = SkColorSetARGB(255, 0, spotAlpha * 255.9999f, 255); fUmbraColor = SkColorSetARGB(255, 0, 0, 0);
fPenumbraColor = SkColorSetARGB(255, 0, spotAlpha * 255.9999f, 0); fPenumbraColor = SkColorSetARGB(0, 0, 0, 0);
// Compute the scale and translation for the spot shadow. // Compute the scale and translation for the spot shadow.
SkMatrix shadowTransform; 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, sk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
HeightFunc heightFunc, SkScalar ambientAlpha, HeightFunc heightFunc, bool transparent) {
bool transparent) { SkAmbientShadowTessellator ambientTess(path, ctm, heightFunc, transparent);
SkAmbientShadowTessellator ambientTess(path, ctm, heightFunc, ambientAlpha, transparent);
return ambientTess.releaseVertices(); return ambientTess.releaseVertices();
} }
sk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm, sk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm,
HeightFunc heightFunc, HeightFunc heightFunc, const SkPoint3& lightPos,
const SkPoint3& lightPos, SkScalar lightRadius, SkScalar lightRadius, bool transparent) {
SkScalar spotAlpha, bool transparent) { SkSpotShadowTessellator spotTess(path, ctm, heightFunc, lightPos, lightRadius, transparent);
SkSpotShadowTessellator spotTess(path, ctm, heightFunc, lightPos, lightRadius,
spotAlpha, transparent);
return spotTess.releaseVertices(); return spotTess.releaseVertices();
} }

View File

@ -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. * 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, 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, * 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. * 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, HeightFunc heightFunc,
const SkPoint3& lightPos, SkScalar lightRadius, const SkPoint3& lightPos, SkScalar lightRadius, bool transparent);
SkScalar spotAlpha, bool transparent);
} }
#endif #endif

View File

@ -54,52 +54,52 @@ private:
}; };
static void build_table() { static void build_table() {
SkDebugf("const uint16_t gByteExpU16Table[256] = {"); SkDebugf("const uint8_t gByteExpU8Table[256] = {");
for (int i = 0; i <= 255; ++i) { for (int i = 0; i <= 255; ++i) {
if (!(i % 8)) { if (!(i % 8)) {
SkDebugf("\n"); SkDebugf("\n");
} }
SkScalar factor = SK_Scalar1 - i / 255.f; SkScalar factor = SK_Scalar1 - i / 255.f;
factor = SkScalarExp(-factor * factor * 4) - 0.018f; factor = SkScalarExp(-factor * factor * 4) - 0.018f;
int v = (int)(factor * 65536); int v = (int)(factor * 255.9f);
SkDebugf(" 0x%04X,", v); SkDebugf(" 0x%02X,", v);
} }
SkDebugf("\n};\n"); SkDebugf("\n};\n");
} }
const uint16_t gByteExpU16Table[256] = { const uint8_t gByteExpU8Table[256] = {
0x0014, 0x003A, 0x0062, 0x008A, 0x00B3, 0x00DE, 0x010A, 0x0136, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x0165, 0x0194, 0x01C4, 0x01F6, 0x0229, 0x025E, 0x0294, 0x02CB, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02,
0x0304, 0x033E, 0x0379, 0x03B7, 0x03F5, 0x0435, 0x0477, 0x04BB, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04,
0x0500, 0x0546, 0x058F, 0x05D9, 0x0625, 0x0673, 0x06C3, 0x0714, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07,
0x0768, 0x07BD, 0x0814, 0x086E, 0x08C9, 0x0926, 0x0986, 0x09E8, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09,
0x0A4B, 0x0AB1, 0x0B1A, 0x0B84, 0x0BF1, 0x0C60, 0x0CD2, 0x0D46, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0D,
0x0DBC, 0x0E35, 0x0EB0, 0x0F2E, 0x0FAF, 0x1032, 0x10B7, 0x1140, 0x0D, 0x0E, 0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x11,
0x11CB, 0x1258, 0x12E9, 0x137C, 0x1412, 0x14AB, 0x1547, 0x15E6, 0x11, 0x12, 0x12, 0x13, 0x14, 0x14, 0x15, 0x15,
0x1688, 0x172D, 0x17D5, 0x187F, 0x192D, 0x19DE, 0x1A92, 0x1B4A, 0x16, 0x17, 0x17, 0x18, 0x19, 0x19, 0x1A, 0x1B,
0x1C04, 0x1CC2, 0x1D83, 0x1E47, 0x1F0E, 0x1FD9, 0x20A7, 0x2178, 0x1C, 0x1C, 0x1D, 0x1E, 0x1F, 0x1F, 0x20, 0x21,
0x224D, 0x2325, 0x2401, 0x24E0, 0x25C2, 0x26A8, 0x2792, 0x287F, 0x22, 0x23, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x296F, 0x2A63, 0x2B5A, 0x2C56, 0x2D54, 0x2E56, 0x2F5C, 0x3065, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
0x3172, 0x3283, 0x3397, 0x34AE, 0x35CA, 0x36E9, 0x380B, 0x3931, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38, 0x39,
0x3A5B, 0x3B88, 0x3CB9, 0x3DED, 0x3F25, 0x4061, 0x41A0, 0x42E2, 0x3A, 0x3B, 0x3C, 0x3D, 0x3F, 0x40, 0x41, 0x42,
0x4428, 0x4572, 0x46BF, 0x480F, 0x4963, 0x4ABA, 0x4C14, 0x4D72, 0x44, 0x45, 0x46, 0x48, 0x49, 0x4A, 0x4C, 0x4D,
0x4ED3, 0x5038, 0x519F, 0x530A, 0x5478, 0x55E9, 0x575D, 0x58D4, 0x4E, 0x50, 0x51, 0x53, 0x54, 0x55, 0x57, 0x58,
0x5A4F, 0x5BCC, 0x5D4C, 0x5ECF, 0x6054, 0x61DD, 0x6368, 0x64F6, 0x5A, 0x5B, 0x5D, 0x5E, 0x60, 0x61, 0x63, 0x64,
0x6686, 0x6819, 0x69AE, 0x6B45, 0x6CDF, 0x6E7B, 0x701A, 0x71BA, 0x66, 0x68, 0x69, 0x6B, 0x6C, 0x6E, 0x70, 0x71,
0x735D, 0x7501, 0x76A7, 0x784F, 0x79F9, 0x7BA4, 0x7D51, 0x7F00, 0x73, 0x74, 0x76, 0x78, 0x79, 0x7B, 0x7D, 0x7E,
0x80AF, 0x8260, 0x8413, 0x85C6, 0x877A, 0x8930, 0x8AE6, 0x8C9C, 0x80, 0x82, 0x84, 0x85, 0x87, 0x89, 0x8A, 0x8C,
0x8E54, 0x900C, 0x91C4, 0x937D, 0x9535, 0x96EE, 0x98A7, 0x9A60, 0x8E, 0x8F, 0x91, 0x93, 0x95, 0x96, 0x98, 0x9A,
0x9C18, 0x9DD1, 0x9F88, 0xA13F, 0xA2F6, 0xA4AB, 0xA660, 0xA814, 0x9C, 0x9D, 0x9F, 0xA1, 0xA2, 0xA4, 0xA6, 0xA8,
0xA9C6, 0xAB78, 0xAD27, 0xAED6, 0xB082, 0xB22D, 0xB3D6, 0xB57D, 0xA9, 0xAB, 0xAD, 0xAE, 0xB0, 0xB2, 0xB3, 0xB5,
0xB722, 0xB8C5, 0xBA65, 0xBC03, 0xBD9E, 0xBF37, 0xC0CD, 0xC25F, 0xB7, 0xB8, 0xBA, 0xBB, 0xBD, 0xBF, 0xC0, 0xC2,
0xC3EF, 0xC57B, 0xC704, 0xC889, 0xCA0B, 0xCB89, 0xCD04, 0xCE7A, 0xC3, 0xC5, 0xC6, 0xC8, 0xC9, 0xCB, 0xCC, 0xCE,
0xCFEC, 0xD15A, 0xD2C4, 0xD429, 0xD58A, 0xD6E6, 0xD83D, 0xD990, 0xCF, 0xD1, 0xD2, 0xD4, 0xD5, 0xD6, 0xD8, 0xD9,
0xDADD, 0xDC25, 0xDD68, 0xDEA6, 0xDFDE, 0xE111, 0xE23E, 0xE365, 0xDA, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE2, 0xE3,
0xE486, 0xE5A2, 0xE6B7, 0xE7C6, 0xE8CF, 0xE9D1, 0xEACD, 0xEBC3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB,
0xECB2, 0xED9A, 0xEE7C, 0xEF56, 0xF02A, 0xF0F6, 0xF1BC, 0xF27A, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF0, 0xF1, 0xF2,
0xF332, 0xF3E1, 0xF48A, 0xF52B, 0xF5C5, 0xF657, 0xF6E1, 0xF764, 0xF3, 0xF3, 0xF4, 0xF5, 0xF5, 0xF6, 0xF6, 0xF7,
0xF7DF, 0xF852, 0xF8BE, 0xF922, 0xF97E, 0xF9D2, 0xFA1E, 0xFA62, 0xF7, 0xF8, 0xF8, 0xF9, 0xF9, 0xF9, 0xFA, 0xFA,
0xFA9F, 0xFAD3, 0xFAFF, 0xFB23, 0xFB40, 0xFB54, 0xFB60, 0xFB64, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFB, 0xFB,
}; };
void SkGaussianColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const { 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) { for (int i = 0; i < count; ++i) {
SkPMColor c = src[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); 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. */ /** Factory for an ambient shadow mesh with particular shadow properties. */
struct AmbientVerticesFactory { struct AmbientVerticesFactory {
SkScalar fOccluderHeight = SK_ScalarNaN; // NaN so that isCompatible will fail until init'ed. SkScalar fOccluderHeight = SK_ScalarNaN; // NaN so that isCompatible will fail until init'ed.
SkScalar fAmbientAlpha;
bool fTransparent; bool fTransparent;
bool isCompatible(const AmbientVerticesFactory& that, SkVector* translate) const { bool isCompatible(const AmbientVerticesFactory& that, SkVector* translate) const {
if (fOccluderHeight != that.fOccluderHeight || fAmbientAlpha != that.fAmbientAlpha || if (fOccluderHeight != that.fOccluderHeight || fTransparent != that.fTransparent) {
fTransparent != that.fTransparent) {
return false; return false;
} }
translate->set(0, 0); translate->set(0, 0);
@ -159,7 +157,7 @@ struct AmbientVerticesFactory {
SkScalar z = fOccluderHeight; SkScalar z = fOccluderHeight;
return SkShadowTessellator::MakeAmbient(path, ctm, return SkShadowTessellator::MakeAmbient(path, ctm,
[z](SkScalar, SkScalar) { return z; }, [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. SkScalar fOccluderHeight = SK_ScalarNaN; // NaN so that isCompatible will fail until init'ed.
SkPoint3 fDevLightPos; SkPoint3 fDevLightPos;
SkScalar fLightRadius; SkScalar fLightRadius;
SkScalar fSpotAlpha;
OccluderType fOccluderType; OccluderType fOccluderType;
bool isCompatible(const SpotVerticesFactory& that, SkVector* translate) const { bool isCompatible(const SpotVerticesFactory& that, SkVector* translate) const {
if (fOccluderHeight != that.fOccluderHeight || fDevLightPos.fZ != that.fDevLightPos.fZ || if (fOccluderHeight != that.fOccluderHeight || fDevLightPos.fZ != that.fDevLightPos.fZ ||
fLightRadius != that.fLightRadius || fSpotAlpha != that.fSpotAlpha || fLightRadius != that.fLightRadius || fOccluderType != that.fOccluderType) {
fOccluderType != that.fOccluderType) {
return false; return false;
} }
switch (fOccluderType) { switch (fOccluderType) {
@ -212,8 +208,7 @@ struct SpotVerticesFactory {
SkScalar z = fOccluderHeight; SkScalar z = fOccluderHeight;
return SkShadowTessellator::MakeSpot(path, ctm, return SkShadowTessellator::MakeSpot(path, ctm,
[z](SkScalar, SkScalar) -> SkScalar { return z; }, [z](SkScalar, SkScalar) -> SkScalar { return z; },
fDevLightPos, fLightRadius, fDevLightPos, fLightRadius, transparent);
fSpotAlpha, transparent);
} }
}; };
@ -569,14 +564,21 @@ static bool draw_analytic_shadows(SkCanvas* canvas, const SkPath& path, SkScalar
return false; 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. // Draw an offset spot shadow and outlining ambient shadow for the given path.
void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight, void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar occluderHeight,
const SkPoint3& devLightPos, SkScalar lightRadius, const SkPoint3& devLightPos, SkScalar lightRadius,
SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color, SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
uint32_t flags, SkResourceCache* cache) { uint32_t flags, SkResourceCache* cache) {
// try fast paths // try fast paths
if (draw_analytic_shadows(canvas, path, occluderHeight, devLightPos, lightRadius, bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag);
ambientAlpha, spotAlpha, color, flags)) { if (!skipAnalytic && draw_analytic_shadows(canvas, path, occluderHeight, devLightPos,
lightRadius, ambientAlpha, spotAlpha, color,
flags)) {
return; return;
} }
@ -592,10 +594,10 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
ambientAlpha = SkTMin(ambientAlpha, 1.f); ambientAlpha = SkTMin(ambientAlpha, 1.f);
AmbientVerticesFactory factory; AmbientVerticesFactory factory;
factory.fOccluderHeight = occluderHeight; factory.fOccluderHeight = occluderHeight;
factory.fAmbientAlpha = ambientAlpha;
factory.fTransparent = transparent; 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) { if (spotAlpha > 0) {
@ -614,7 +616,6 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
factory.fOccluderHeight = occluderHeight; factory.fOccluderHeight = occluderHeight;
factory.fDevLightPos = devLightPos; factory.fDevLightPos = devLightPos;
factory.fLightRadius = lightRadius; factory.fLightRadius = lightRadius;
factory.fSpotAlpha = spotAlpha;
SkRRect rrect; SkRRect rrect;
if (transparent) { if (transparent) {
@ -653,7 +654,9 @@ void SkShadowUtils::DrawShadow(SkCanvas* canvas, const SkPath& path, SkScalar oc
if (factory.fOccluderType == SpotVerticesFactory::OccluderType::kOpaque) { if (factory.fOccluderType == SpotVerticesFactory::OccluderType::kOpaque) {
factory.fOccluderType = SpotVerticesFactory::OccluderType::kTransparent; 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, SkScalar ambientAlpha, SkScalar spotAlpha, SkColor color,
uint32_t flags) { uint32_t flags) {
// try fast paths // try fast paths
if (draw_analytic_shadows(canvas, path, heightFunc(0, 0), lightPos, lightRadius, bool skipAnalytic = SkToBool(flags & SkShadowFlags::kGeometricOnly_ShadowFlag);
ambientAlpha, spotAlpha, color, flags)) { if (!skipAnalytic && draw_analytic_shadows(canvas, path, heightFunc(0, 0), lightPos,
lightRadius, ambientAlpha, spotAlpha, color,
flags)) {
return; return;
} }
@ -679,13 +684,13 @@ void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path,
if (ambientAlpha > 0) { if (ambientAlpha > 0) {
ambientAlpha = SkTMin(ambientAlpha, 1.f); ambientAlpha = SkTMin(ambientAlpha, 1.f);
sk_sp<SkVertices> vertices = SkShadowTessellator::MakeAmbient(path, viewMatrix, sk_sp<SkVertices> vertices = SkShadowTessellator::MakeAmbient(path, viewMatrix,
heightFunc, ambientAlpha, heightFunc, transparent);
transparent); SkColor renderColor = compute_render_color(color, ambientAlpha);
SkPaint paint; SkPaint paint;
// Run the vertex color through a GaussianColorFilter and then modulate the grayscale // Run the vertex color through a GaussianColorFilter and then modulate the grayscale
// result of that against our 'color' param. // result of that against our 'color' param.
paint.setColorFilter(SkColorFilter::MakeComposeFilter( paint.setColorFilter(SkColorFilter::MakeComposeFilter(
SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate), SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
SkGaussianColorFilter::Make())); SkGaussianColorFilter::Make()));
canvas->drawVertices(vertices, SkBlendMode::kModulate, paint); canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
} }
@ -694,12 +699,13 @@ void SkShadowUtils::DrawUncachedShadow(SkCanvas* canvas, const SkPath& path,
spotAlpha = SkTMin(spotAlpha, 1.f); spotAlpha = SkTMin(spotAlpha, 1.f);
sk_sp<SkVertices> vertices = SkShadowTessellator::MakeSpot(path, viewMatrix, heightFunc, sk_sp<SkVertices> vertices = SkShadowTessellator::MakeSpot(path, viewMatrix, heightFunc,
lightPos, lightRadius, lightPos, lightRadius,
spotAlpha, transparent); transparent);
SkColor renderColor = compute_render_color(color, spotAlpha);
SkPaint paint; SkPaint paint;
// Run the vertex color through a GaussianColorFilter and then modulate the grayscale // Run the vertex color through a GaussianColorFilter and then modulate the grayscale
// result of that against our 'color' param. // result of that against our 'color' param.
paint.setColorFilter(SkColorFilter::MakeComposeFilter( paint.setColorFilter(SkColorFilter::MakeComposeFilter(
SkColorFilter::MakeModeFilter(color, SkBlendMode::kModulate), SkColorFilter::MakeModeFilter(renderColor, SkBlendMode::kModulate),
SkGaussianColorFilter::Make())); SkGaussianColorFilter::Make()));
canvas->drawVertices(vertices, SkBlendMode::kModulate, paint); canvas->drawVertices(vertices, SkBlendMode::kModulate, paint);
} }

View File

@ -14,29 +14,25 @@
void tessellate_shadow(skiatest::Reporter* reporter, const SkPath& path, const SkMatrix& ctm, void tessellate_shadow(skiatest::Reporter* reporter, const SkPath& path, const SkMatrix& ctm,
bool expectSuccess) { bool expectSuccess) {
static constexpr SkScalar kAmbientAlpha = 0.25f;
static constexpr SkScalar kSpotAlpha = 0.25f;
auto heightFunc = [] (SkScalar, SkScalar) { return 4; }; 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)) { if (expectSuccess != SkToBool(verts)) {
ERRORF(reporter, "Expected shadow tessellation to %s but it did not.", ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
expectSuccess ? "succeed" : "fail"); expectSuccess ? "succeed" : "fail");
} }
verts = SkShadowTessellator::MakeAmbient(path, ctm, heightFunc, kAmbientAlpha, false); verts = SkShadowTessellator::MakeAmbient(path, ctm, heightFunc, false);
if (expectSuccess != SkToBool(verts)) { if (expectSuccess != SkToBool(verts)) {
ERRORF(reporter, "Expected shadow tessellation to %s but it did not.", ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
expectSuccess ? "succeed" : "fail"); expectSuccess ? "succeed" : "fail");
} }
verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {0, 0, 128}, 128.f, verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {0, 0, 128}, 128.f, false);
kSpotAlpha, false);
if (expectSuccess != SkToBool(verts)) { if (expectSuccess != SkToBool(verts)) {
ERRORF(reporter, "Expected shadow tessellation to %s but it did not.", ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
expectSuccess ? "succeed" : "fail"); expectSuccess ? "succeed" : "fail");
} }
verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {0, 0, 128}, 128.f, verts = SkShadowTessellator::MakeSpot(path, ctm, heightFunc, {0, 0, 128}, 128.f, false);
kSpotAlpha, false);
if (expectSuccess != SkToBool(verts)) { if (expectSuccess != SkToBool(verts)) {
ERRORF(reporter, "Expected shadow tessellation to %s but it did not.", ERRORF(reporter, "Expected shadow tessellation to %s but it did not.",
expectSuccess ? "succeed" : "fail"); expectSuccess ? "succeed" : "fail");