| Index: samplecode/SampleAndroidShadows.cpp
|
| diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp
|
| index f411e5c9b3999301ce7ff9298f30e174c7648828..e14c571ecd18febdbfc6abb470767f2021631e7b 100755
|
| --- a/samplecode/SampleAndroidShadows.cpp
|
| +++ b/samplecode/SampleAndroidShadows.cpp
|
| @@ -41,7 +41,7 @@ protected:
|
| fCirclePath.addCircle(0, 0, 50);
|
| fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100));
|
| fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4));
|
| - fLightPos = SkPoint3::Make(-2, -2, 6);
|
| + fLightPos = SkPoint3::Make(-700, -700, 2800);
|
| }
|
|
|
| // overrides from SkEventSink
|
| @@ -148,10 +148,16 @@ protected:
|
|
|
| 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;
|
| - if (radius >= 64 ||
|
| + 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))) {
|
| @@ -159,33 +165,41 @@ protected:
|
| return;
|
| }
|
|
|
| - // For all of these, we outset the rect by half the radius to get our stroke shape.
|
| - SkScalar halfRadius = SK_ScalarHalf*radius;
|
| + // 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(halfRadius, halfRadius);
|
| + pathRect.outset(strokeOutset, strokeOutset);
|
| pathRRect = SkRRect::MakeOval(pathRect);
|
| } else if (path.isRect(nullptr)) {
|
| - pathRect.outset(halfRadius, halfRadius);
|
| - pathRRect = SkRRect::MakeRectXY(pathRect, halfRadius, halfRadius);
|
| + pathRect.outset(strokeOutset, strokeOutset);
|
| + pathRRect = SkRRect::MakeRectXY(pathRect, strokeOutset, strokeOutset);
|
| } else {
|
| - pathRRect.outset(halfRadius, halfRadius);
|
| + 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
|
| - paint.setStrokeWidth(radius + 1);
|
| - // handle scale of radius due to CTM
|
| - SkScalar maxScale = canvas->getTotalMatrix().getMaxScale();
|
| - radius *= maxScale;
|
| - unsigned char gray = (unsigned char)(ambientAlpha*umbraAlpha*255.999f);
|
| - SkASSERT(radius < 64);
|
| - // Convert radius to 6.2 fixed point and place in the G component.
|
| - paint.setColor(SkColorSetARGB(1, gray, (unsigned char)(4.0f*radius), 0));
|
| -
|
| - sk_sp<SkShader> gaussShader = SkGaussianEdgeShader::Make();
|
| - paint.setShader(gaussShader);
|
| + 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(alpha, iRadius >> 8, iRadius & 0xff,
|
| + (unsigned char)(4.0f*pad)));
|
| +
|
| + paint.setShader(SkGaussianEdgeShader::Make(true));
|
| canvas->drawRRect(pathRRect, paint);
|
| }
|
|
|
| @@ -201,42 +215,24 @@ protected:
|
| } else if (zRatio > 0.95f) {
|
| zRatio = 0.95f;
|
| }
|
| - SkScalar radius = lightWidth*zRatio;
|
| + SkScalar blurRadius = lightWidth*zRatio;
|
|
|
| // compute the transformation params
|
| SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
|
| - canvas->getTotalMatrix().mapPoints(¢er, 1);
|
| - SkPoint offset = SkPoint::Make(-zRatio*(lightPos.fX - center.fX),
|
| - -zRatio*(lightPos.fY - center.fY));
|
| - SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
|
| - if (scale < 1.0f) {
|
| - scale = 1.0f;
|
| - } else if (scale > 1024.f) {
|
| - scale = 1024.f;
|
| + 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);
|
|
|
| - SkRect occlRect;
|
| - GetOcclRect(path, &occlRect);
|
| - // apply inverse transform
|
| - occlRect.offset(-offset);
|
| -#if 0
|
| - // It looks like the scale may be invalid
|
| - SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
|
| - if (scale < 1.0f) {
|
| - scale = 1.0f;
|
| - } else if (scale > 1024.f) {
|
| - scale = 1024.f;
|
| - }
|
| - occlRect.fLeft /= scale;
|
| - occlRect.fRight /= scale;
|
| - occlRect.fTop /= scale;
|
| - occlRect.fBottom /= scale;
|
| -#endif
|
| sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
|
| - SkBlurMask::ConvertRadiusToSigma(radius),
|
| - occlRect,
|
| + SkBlurMask::ConvertRadiusToSigma(blurRadius),
|
| SkBlurMaskFilter::kNone_BlurFlag);
|
|
|
| SkPaint paint;
|
| @@ -245,20 +241,9 @@ protected:
|
| paint.setColor(SkColorSetARGB((unsigned char)(spotAlpha*255.999f), 0, 0, 0));
|
|
|
| // apply transformation to shadow
|
| - canvas->translate(offset.fX, offset.fY);
|
| -#if 0
|
| - // It looks like the scale may be invalid
|
| canvas->scale(scale, scale);
|
| -#endif
|
| + canvas->translate(offset.fX, offset.fY);
|
| canvas->drawPath(path, paint);
|
| -
|
| - // draw occlusion rect
|
| -#if DRAW_OCCL_RECT
|
| - SkPaint stroke;
|
| - stroke.setStyle(SkPaint::kStroke_Style);
|
| - stroke.setColor(SK_ColorRED);
|
| - canvas->drawRect(occlRect, stroke)
|
| -#endif
|
| }
|
|
|
| void drawSpotShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
|
| @@ -273,11 +258,15 @@ protected:
|
| } else if (zRatio > 0.95f) {
|
| zRatio = 0.95f;
|
| }
|
| - SkScalar radius = lightWidth*zRatio;
|
| + SkScalar radius = 2.0f*lightWidth*zRatio;
|
|
|
| SkRect pathRect;
|
| SkRRect pathRRect;
|
| - if (radius >= 64 ||
|
| + 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))) {
|
| @@ -285,23 +274,31 @@ protected:
|
| return;
|
| }
|
|
|
| - // For all of these, we outset the rect by half the radius to get our stroke shape.
|
| - SkScalar halfRadius = SK_ScalarHalf*radius;
|
| + // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space
|
| + SkScalar minRadius = SK_ScalarHalf/scaleFactors[0];
|
| if (path.isOval(nullptr)) {
|
| - pathRect.outset(halfRadius, halfRadius);
|
| pathRRect = SkRRect::MakeOval(pathRect);
|
| } else if (path.isRect(nullptr)) {
|
| - pathRect.outset(halfRadius, halfRadius);
|
| - pathRRect = SkRRect::MakeRectXY(pathRect, halfRadius, halfRadius);
|
| + pathRRect = SkRRect::MakeRectXY(pathRect, minRadius, minRadius);
|
| } else {
|
| - pathRRect.outset(halfRadius, halfRadius);
|
| + if (pathRRect.getSimpleRadii().fX < minRadius) {
|
| + pathRRect.setRectXY(pathRRect.rect(), minRadius, minRadius);
|
| + }
|
| }
|
|
|
| - // compute the transformation params
|
| - SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
|
| - canvas->getTotalMatrix().mapPoints(¢er, 1);
|
| - SkPoint offset = SkPoint::Make(-zRatio*(lightPos.fX - center.fX),
|
| - -zRatio*(lightPos.fY - center.fY));
|
| + // 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;
|
| @@ -310,9 +307,9 @@ protected:
|
| // the edge of the shape. We also add 1/2 to cover up AA on the interior edge.
|
| SkScalar pad = offset.length() + 0.5f;
|
| // compute area
|
| - SkScalar strokeWidth = radius + 2.0f*pad;
|
| - SkScalar strokedArea = 2.0f*strokeWidth*(pathRRect.width() + pathRRect.height());
|
| - SkScalar filledArea = (pathRRect.height() + radius)*(pathRRect.width() + radius);
|
| + SkScalar strokeWidth = radius + 2.0f*pad/scaleFactors[0];
|
| + 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 || pad >= 64) {
|
| @@ -323,31 +320,22 @@ protected:
|
| paint.setStyle(SkPaint::kStroke_Style);
|
| paint.setStrokeWidth(strokeWidth);
|
| }
|
| - sk_sp<SkShader> gaussShader = SkGaussianEdgeShader::Make();
|
| - paint.setShader(gaussShader);
|
| + paint.setShader(SkGaussianEdgeShader::Make(true));
|
| // handle scale of radius due to CTM
|
| - SkScalar maxScale = canvas->getTotalMatrix().getMaxScale();
|
| - radius *= maxScale;
|
| - unsigned char gray = (unsigned char)(spotAlpha*255.999f);
|
| - SkASSERT(radius < 64);
|
| + radius *= scaleFactors[0];
|
| + // don't need to scale pad as it was computed from the transformed offset
|
| + SkASSERT(radius < 16384);
|
| SkASSERT(pad < 64);
|
| - // Convert radius and pad to 6.2 fixed point and place in the G & B components.
|
| - paint.setColor(SkColorSetARGB(1, gray, (unsigned char)(radius*4.0f),
|
| - (unsigned char)(pad*4.0f)));
|
| + // 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(alpha, iRadius >> 8, iRadius & 0xff,
|
| + (unsigned char)(4.0f*pad)));
|
|
|
| // apply transformation to shadow
|
| canvas->translate(offset.fX, offset.fY);
|
| -#if 0
|
| - // It looks like the scale may be invalid
|
| - SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
|
| - if (scale < 1.0f) {
|
| - scale = 1.0f;
|
| - } else if (scale > 1024.f) {
|
| - scale = 1024.f;
|
| - }
|
| - canvas->scale(scale, scale);
|
| -#endif
|
| - canvas->drawRRect(pathRRect, paint);
|
| + canvas->drawRRect(shadowRRect, paint);
|
| }
|
|
|
| void drawShadowedPath(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
|
| @@ -374,7 +362,7 @@ protected:
|
|
|
| void onDrawContent(SkCanvas* canvas) override {
|
| this->drawBG(canvas);
|
| - const SkScalar kLightWidth = 3;
|
| + const SkScalar kLightWidth = 2800;
|
| const SkScalar kAmbientAlpha = 0.25f;
|
| const SkScalar kSpotAlpha = 0.25f;
|
|
|
| @@ -387,26 +375,26 @@ protected:
|
| canvas->translate(200, 90);
|
| lightPos.fX += 200;
|
| lightPos.fY += 90;
|
| - this->drawShadowedPath(canvas, fRectPath, 5, paint, kAmbientAlpha,
|
| + this->drawShadowedPath(canvas, fRectPath, 2, paint, kAmbientAlpha,
|
| lightPos, kLightWidth, kSpotAlpha);
|
|
|
| paint.setColor(SK_ColorRED);
|
| canvas->translate(250, 0);
|
| lightPos.fX += 250;
|
| - this->drawShadowedPath(canvas, fRRPath, 5, paint, kAmbientAlpha,
|
| + this->drawShadowedPath(canvas, fRRPath, 4, paint, kAmbientAlpha,
|
| lightPos, kLightWidth, kSpotAlpha);
|
|
|
| paint.setColor(SK_ColorBLUE);
|
| canvas->translate(-250, 110);
|
| lightPos.fX -= 250;
|
| lightPos.fY += 110;
|
| - this->drawShadowedPath(canvas, fCirclePath, 5, paint, 0.0f,
|
| + this->drawShadowedPath(canvas, fCirclePath, 8, paint, 0.0f,
|
| lightPos, kLightWidth, 0.5f);
|
|
|
| paint.setColor(SK_ColorGREEN);
|
| canvas->translate(250, 0);
|
| lightPos.fX += 250;
|
| - this->drawShadowedPath(canvas, fRRPath, 5, paint, kAmbientAlpha,
|
| + this->drawShadowedPath(canvas, fRRPath, 64, paint, kAmbientAlpha,
|
| lightPos, kLightWidth, kSpotAlpha);
|
| }
|
|
|
|
|