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 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 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 zFunc, const SkPaint& paint, SkScalar ambientAlpha, const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) { -#ifdef USE_SHADOW_UTILS - SkScalar zValue = zFunc(0, 0); + if (!fShowAmbient) { + ambientAlpha = 0; + } + if (!fShowSpot) { + spotAlpha = 0; + } + uint32_t flags = 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); + flags |= SkShadowFlags::kGeometricOnly_ShadowFlag; } -#else - if (fShowAmbient) { - if (fUseAlt) { - this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha); - } else { - this->drawAmbientShadow(canvas, path, zValue, ambientAlpha); - } - } - if (fShowSpot) { - if (fUseAlt) { - this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha); - } else { - this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha); - } - } -#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 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 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 HeightFunc; * If transparent is true, then the center of the ambient shadow will be filled in. */ sk_sp 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 MakeAmbient(const SkPath& path, const SkMatrix& ctm, * The center will be clipped against the original path unless transparent is true. */ sk_sp 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 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 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");