Chromium Code Reviews| Index: samplecode/SampleAndroidShadows.cpp |
| diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp |
| index 38fcd204d985af6700b01811be53375886b1dbc0..f603118e69622b84f457c14b4b94a28eefbd79d2 100755 |
| --- a/samplecode/SampleAndroidShadows.cpp |
| +++ b/samplecode/SampleAndroidShadows.cpp |
| @@ -25,15 +25,15 @@ class ShadowsView : public SampleView { |
| SkPoint3 fLightPos; |
| bool fShowAmbient; |
| - bool fUseAltAmbient; |
| bool fShowSpot; |
| + bool fUseAlt; |
| bool fShowObject; |
| public: |
| ShadowsView() |
| : fShowAmbient(true) |
| - , fUseAltAmbient(true) |
| , fShowSpot(true) |
| + , fUseAlt(true) |
| , fShowObject(true) {} |
| protected: |
| @@ -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(-220, -330, 150); |
| + fLightPos = SkPoint3::Make(-2, -2, 6); |
| } |
| // overrides from SkEventSink |
| @@ -57,12 +57,12 @@ protected: |
| case 'B': |
| fShowAmbient = !fShowAmbient; |
| break; |
| - case 'T': |
| - fUseAltAmbient = !fUseAltAmbient; |
| - break; |
| case 'S': |
| fShowSpot = !fShowSpot; |
| break; |
| + case 'T': |
| + fUseAlt = !fUseAlt; |
| + break; |
| case 'O': |
| fShowObject = !fShowObject; |
| break; |
| @@ -143,64 +143,44 @@ protected: |
| return; |
| } |
| + SkRect pathRect; |
| + SkRRect pathRRect; |
| + if ((!path.isOval(&pathRect) || pathRect.width() != pathRect.height()) && |
| + (!path.isRRect(&pathRRect) || !pathRRect.allCornersCircular()) && |
| + !path.isRect(&pathRect)) { |
|
robertphillips
2016/08/17 15:44:40
this-> ?
jvanverth1
2016/08/17 16:19:27
Done.
|
| + drawAmbientShadow(canvas, path, zValue, ambientAlpha); |
| + 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; |
|
robertphillips
2016/08/17 15:44:39
stroke shape -> "coverage" RRect ?
jvanverth1
2016/08/17 16:19:28
Done. And thanks -- there was a bug here.
|
| - // fast path |
| - SkRect pathRect; |
| - SkRRect pathRRect; |
| - if ((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) || |
| - (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) || |
| - path.isRect(&pathRect)) { |
| - |
| - // For all of these, we outset the rect by half the radius to get our stroke shape. |
| - if (path.isOval(nullptr)) { |
| - pathRect.outset(0.5f*radius, 0.5f*radius); |
| - pathRRect = SkRRect::MakeOval(pathRect); |
| - } else if (path.isRect(nullptr)) { |
| - pathRect.outset(0.5f*radius, 0.5f*radius); |
| - pathRRect = SkRRect::MakeRectXY(pathRect, 0.5f*radius, 0.5f*radius); |
| - } else { |
| - pathRRect.outset(0.5f*radius, 0.5f*radius); |
| - } |
| - |
| - SkPaint paint; |
| - paint.setAntiAlias(true); |
| - paint.setColor(SkColorSetARGB((unsigned char)(ambientAlpha*umbraAlpha*255.999f), |
| - 0, 0, 0)); |
| - paint.setStrokeWidth(radius); |
| - paint.setStyle(SkPaint::kStroke_Style); |
| - |
| - paint.setShader(SkGaussianEdgeShader::Make()); |
| - canvas->drawRRect(pathRRect, paint); |
| + // For all of these, we outset the rect by half the radius to get our stroke shape. |
| + if (path.isOval(nullptr)) { |
| + pathRect.outset(0.5f*radius, 0.5f*radius); |
| + pathRRect = SkRRect::MakeOval(pathRect); |
| + } else if (path.isRect(nullptr)) { |
| + pathRect.outset(0.5f*radius, 0.5f*radius); |
| + pathRRect = SkRRect::MakeRectXY(pathRect, 0.5f*radius, 0.5f*radius); |
| } else { |
| - // occlude blur |
| - SkRect occlRect; |
| - GetOcclRect(path, &occlRect); |
| - sk_sp<SkMaskFilter> f = SkBlurMaskFilter::Make(kNormal_SkBlurStyle, |
| - SkBlurMask::ConvertRadiusToSigma(radius), |
| - occlRect, |
| - SkBlurMaskFilter::kNone_BlurFlag); |
| - |
| - SkPaint paint; |
| - paint.setAntiAlias(true); |
| - paint.setMaskFilter(std::move(f)); |
| - paint.setColor(SkColorSetARGB((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 |
| + pathRRect.outset(0.5f*radius, 0.5f*radius); |
| } |
| + SkPaint paint; |
|
robertphillips
2016/08/17 15:44:40
Can this be BW ? Does that give us any advantage ?
jvanverth1
2016/08/17 16:19:27
No, it can't. We need the anti-aliased rrect rende
|
| + paint.setAntiAlias(true); |
| + // TODO: handle scale of radius due to CTM |
| + unsigned char gray = (unsigned char)(ambientAlpha*umbraAlpha*255.999f); |
|
robertphillips
2016/08/17 15:44:39
// convert the radius to fixed point 8.8 & place i
jvanverth1
2016/08/17 16:19:28
Done.
|
| + SkASSERT(radius < 256); |
| + unsigned char intPart = (unsigned char)radius; |
| + SkScalar fracPart = radius - intPart; |
| + paint.setColor(SkColorSetARGB(1, gray, intPart, (unsigned char)(fracPart*256.f))); |
| + |
| + sk_sp<SkShader> gaussShader = std::move(SkGaussianEdgeShader::Make()); |
| + paint.setShader(gaussShader); |
| + canvas->drawRRect(pathRRect, paint); |
| } |
| void drawSpotShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue, |
| @@ -235,10 +215,19 @@ protected: |
| 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, |
| @@ -251,7 +240,10 @@ protected: |
| // 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->drawPath(path, paint); |
| // draw occlusion rect |
| @@ -263,21 +255,89 @@ protected: |
| #endif |
| } |
| - void drawShadowedPath(SkCanvas* canvas, const SkPath& path, SkScalar zValue, |
| - const SkPaint& paint) { |
| - const SkScalar kLightWidth = 3; |
| - const SkScalar kAmbientAlpha = 0.25f; |
| - const SkScalar kSpotAlpha = 0.25f; |
| + void drawSpotShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue, |
| + SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) { |
| + if (spotAlpha <= 0) { |
| + return; |
| + } |
| + SkRect pathRect; |
| + SkRRect pathRRect; |
| + if ((!path.isOval(&pathRect) || pathRect.width() != pathRect.height()) && |
| + (!path.isRRect(&pathRRect) || !pathRRect.allCornersCircular()) && |
| + !path.isRect(&pathRect)) { |
|
robertphillips
2016/08/17 15:44:39
this->
jvanverth1
2016/08/17 16:19:28
Done.
|
| + drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha); |
| + return; |
| + } |
| + |
| + SkScalar zRatio = zValue / (lightPos.fZ - zValue); |
| + if (zRatio < 0.0f) { |
| + zRatio = 0.0f; |
| + } else if (zRatio > 0.95f) { |
| + zRatio = 0.95f; |
| + } |
| + SkScalar radius = lightWidth*zRatio; |
| + |
| + // For all of these, we outset the rect by half the radius to get our stroke shape. |
| + if (path.isOval(nullptr)) { |
| + pathRect.outset(0.5f*radius, 0.5f*radius); |
| + pathRRect = SkRRect::MakeOval(pathRect); |
| + } else if (path.isRect(nullptr)) { |
| + pathRect.outset(0.5f*radius, 0.5f*radius); |
| + pathRRect = SkRRect::MakeRectXY(pathRect, 0.5f*radius, 0.5f*radius); |
| + } else { |
| + pathRRect.outset(0.5f*radius, 0.5f*radius); |
| + } |
| + |
| + // 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)); |
| + SkAutoCanvasRestore acr(canvas, true); |
| + |
| + SkPaint paint; |
|
robertphillips
2016/08/17 15:44:40
same Q here
jvanverth1
2016/08/17 16:19:28
Same answer. :-)
|
| + paint.setAntiAlias(true); |
| + sk_sp<SkShader> gaussShader = std::move(SkGaussianEdgeShader::Make()); |
| + paint.setShader(gaussShader); |
|
robertphillips
2016/08/17 15:44:40
Maybe make_super_color(grey, radius) ?
jvanverth1
2016/08/17 16:19:27
Good idea, I'll add something like that to SkGauss
|
| + // TODO: handle scale of radius due to CTM |
| + unsigned char gray = (unsigned char)(spotAlpha*255.999f); |
| + SkASSERT(radius < 256); |
| + unsigned char intPart = (unsigned char)radius; |
| + SkScalar fracPart = radius - intPart; |
| + paint.setColor(SkColorSetARGB(1, gray, intPart, (unsigned char)(fracPart*256.f))); |
| + |
| + // 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); |
| + } |
| + |
| + void drawShadowedPath(SkCanvas* canvas, const SkPath& path, SkScalar zValue, |
| + const SkPaint& paint, SkScalar ambientAlpha, |
| + const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) { |
| if (fShowAmbient) { |
| - if (fUseAltAmbient) { |
| - this->drawAmbientShadowAlt(canvas, path, zValue, kAmbientAlpha); |
| + if (fUseAlt) { |
| + this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha); |
| } else { |
| - this->drawAmbientShadow(canvas, path, zValue, kAmbientAlpha); |
| + this->drawAmbientShadow(canvas, path, zValue, ambientAlpha); |
| } |
| } |
| if (fShowSpot) { |
| - this->drawSpotShadow(canvas, path, zValue, fLightPos, kLightWidth, kSpotAlpha); |
| + if (fUseAlt) { |
| + this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha); |
| + } else { |
| + this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha); |
| + } |
| } |
| if (fShowObject) { |
| canvas->drawPath(path, paint); |
| @@ -286,25 +346,40 @@ protected: |
| void onDrawContent(SkCanvas* canvas) override { |
| this->drawBG(canvas); |
| + const SkScalar kLightWidth = 6; |
| + const SkScalar kAmbientAlpha = 0.25f; |
| + const SkScalar kSpotAlpha = 0.25f; |
| SkPaint paint; |
| paint.setAntiAlias(true); |
| + SkPoint3 lightPos = fLightPos; |
| + |
| paint.setColor(SK_ColorWHITE); |
| canvas->translate(200, 90); |
| - this->drawShadowedPath(canvas, fRectPath, 5, paint); |
| + lightPos.fX += 200; |
| + lightPos.fY += 90; |
| + this->drawShadowedPath(canvas, fRectPath, 5, paint, kAmbientAlpha, |
| + lightPos, kLightWidth, kSpotAlpha); |
| paint.setColor(SK_ColorRED); |
| canvas->translate(250, 0); |
| - this->drawShadowedPath(canvas, fRRPath, 5, paint); |
| + lightPos.fX += 250; |
| + this->drawShadowedPath(canvas, fRRPath, 5, paint, kAmbientAlpha, |
| + lightPos, kLightWidth, kSpotAlpha); |
| paint.setColor(SK_ColorBLUE); |
| canvas->translate(-250, 110); |
| - this->drawShadowedPath(canvas, fCirclePath, 5, paint); |
| + lightPos.fX -= 250; |
| + lightPos.fY += 110; |
| + this->drawShadowedPath(canvas, fCirclePath, 5, paint, 0.0f, |
| + lightPos, kLightWidth, 0.5f); |
| paint.setColor(SK_ColorGREEN); |
| canvas->translate(250, 0); |
| - this->drawShadowedPath(canvas, fRRPath, 5, paint); |
| + lightPos.fX += 250; |
| + this->drawShadowedPath(canvas, fRRPath, 5, paint, kAmbientAlpha, |
| + lightPos, kLightWidth, kSpotAlpha); |
| } |
| protected: |