Chromium Code Reviews| Index: samplecode/SampleAndroidShadows.cpp |
| diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp |
| index f411e5c9b3999301ce7ff9298f30e174c7648828..ae92ed989766c66ef98ad856e83f7098ecea7a91 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,30 +165,39 @@ 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)); |
| + 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); |
|
herb_g
2016/09/07 18:22:00
how about:
uint16_t iRadius = (uint16_t)(radius *
jvanverth1
2016/09/08 18:12:35
Done.
|
| + // 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. |
| + unsigned int red = (unsigned int)(radius*0.015625f); |
| + unsigned char alpha = (unsigned char)(ambientAlpha*255.999f); |
| + paint.setColor(SkColorSetARGB(alpha, red, (unsigned char)(4.0f*(radius - red)), |
| + (unsigned char)(4.0f*pad))); |
| sk_sp<SkShader> gaussShader = SkGaussianEdgeShader::Make(); |
| paint.setShader(gaussShader); |
| @@ -201,7 +216,7 @@ 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()); |
| @@ -209,34 +224,11 @@ protected: |
| 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; |
| - } |
| 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 +237,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 +254,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 +270,28 @@ 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()); |
| + // compute the scale and translation for the shadow |
| + SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue); |
| + SkMatrix shadowXform; |
| + shadowXform.setScale(scale, scale); |
| + SkRRect shadowRRect; |
| + pathRRect.transform(shadowXform, &shadowRRect); |
|
herb_g
2016/09/07 18:22:00
....transform(SkMatrix::MakeScale(scale, scale), &
jvanverth1
2016/09/08 18:12:35
Done.
|
| + SkPoint center = SkPoint::Make(shadowRRect.rect().centerX(), shadowRRect.rect().centerY()); |
| canvas->getTotalMatrix().mapPoints(¢er, 1); |
| - SkPoint offset = SkPoint::Make(-zRatio*(lightPos.fX - center.fX), |
| - -zRatio*(lightPos.fY - center.fY)); |
| + SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos.fX), |
| + zRatio*(center.fY - lightPos.fY)); |
| SkAutoCanvasRestore acr(canvas, true); |
| SkPaint paint; |
| @@ -310,9 +300,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) { |
| @@ -326,28 +316,20 @@ protected: |
| sk_sp<SkShader> gaussShader = SkGaussianEdgeShader::Make(); |
| paint.setShader(gaussShader); |
| // 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. |
| + unsigned int red = (unsigned int)(radius*0.015625f); |
| + unsigned char alpha = (unsigned char)(spotAlpha*255.999f); |
| + paint.setColor(SkColorSetARGB(alpha, red, (unsigned char)(4.0f*(radius - red)), |
| + (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 +356,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 +369,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, 16, paint, kAmbientAlpha, |
| lightPos, kLightWidth, kSpotAlpha); |
| } |