aboutsummaryrefslogtreecommitdiffhomepage
path: root/samplecode/SampleAndroidShadows.cpp
diff options
context:
space:
mode:
authorGravatar jvanverth <jvanverth@google.com>2016-09-12 07:51:04 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-09-12 07:51:05 -0700
commitd99858ad46ca2c3b5c38061be8b006b25d24c6e0 (patch)
tree28272af51aae2efa6e8b825a71903b3bdbf8ed2f /samplecode/SampleAndroidShadows.cpp
parent2a78fca05416a13bad1b680b52d0ed4fc7f84762 (diff)
Update SampleAndroidShadows to use algorithm closer to Android OpenGL
Includes: * Update light position to be at a similar distance to Android OS * Scale spot shadows correctly * Compute stroke shapes and radii correctly * Allow for larger blur radius for shadows GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2319003003 TBR=reed@google.com NOTRY=true NOTREECHECKS=true Review-Url: https://codereview.chromium.org/2319003003
Diffstat (limited to 'samplecode/SampleAndroidShadows.cpp')
-rwxr-xr-xsamplecode/SampleAndroidShadows.cpp188
1 files changed, 88 insertions, 100 deletions
diff --git a/samplecode/SampleAndroidShadows.cpp b/samplecode/SampleAndroidShadows.cpp
index f411e5c9b3..e14c571ecd 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(&center, 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(&center, 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);
}