| Index: samplecode/SampleAndroidShadows.cpp
|
| diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp
|
| index 38fcd204d985af6700b01811be53375886b1dbc0..41af384e2e0e37e1b066b147202d91c1035cdd69 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,48 @@ protected:
|
| return;
|
| }
|
|
|
| + SkRect pathRect;
|
| + SkRRect pathRRect;
|
| + if ((!path.isOval(&pathRect) || pathRect.width() != pathRect.height()) &&
|
| + (!path.isRRect(&pathRRect) || !pathRRect.allCornersCircular()) &&
|
| + !path.isRect(&pathRect)) {
|
| + this->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;
|
|
|
| - // 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 the radius to get our coverage shape.
|
| + if (path.isOval(nullptr)) {
|
| + pathRect.outset(radius, radius);
|
| + pathRRect = SkRRect::MakeOval(pathRect);
|
| + } else if (path.isRect(nullptr)) {
|
| + pathRect.outset(radius, radius);
|
| + pathRRect = SkRRect::MakeRectXY(pathRect, radius, 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(radius, radius);
|
| }
|
|
|
| + SkPaint paint;
|
| + paint.setAntiAlias(true);
|
| + // 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 < 256);
|
| + // convert the radius to fixed point 8.8 and
|
| + // place it in the G,B components of the color
|
| + 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 +219,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 +244,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 +259,93 @@ 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)) {
|
| + this->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 the radius to get our coverage shape.
|
| + if (path.isOval(nullptr)) {
|
| + pathRect.outset(radius, radius);
|
| + pathRRect = SkRRect::MakeOval(pathRect);
|
| + } else if (path.isRect(nullptr)) {
|
| + pathRect.outset(radius, radius);
|
| + pathRRect = SkRRect::MakeRectXY(pathRect, radius, radius);
|
| + } else {
|
| + pathRRect.outset(radius, 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;
|
| + paint.setAntiAlias(true);
|
| + sk_sp<SkShader> gaussShader = std::move(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 < 256);
|
| + // convert the radius to fixed point 8.8 and
|
| + // place it in the G,B components of the color
|
| + 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 +354,40 @@ protected:
|
|
|
| void onDrawContent(SkCanvas* canvas) override {
|
| this->drawBG(canvas);
|
| + const SkScalar kLightWidth = 3;
|
| + 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:
|
|
|