e8199af1d9
The geometric method for concave shadows seems to be failing in certain cases. See: https://github.com/flutter/flutter/issues/84262. I've never been satisfied with this solution and I've been thinking of removing it. This flag allows for Flutter to disable it for the time being until I can determine if anyone else is using it. Change-Id: Ia0a3f57002d94928f2baa655c88dc4d10b9edef8 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/533881 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Jim Van Verth <jvanverth@google.com>
344 lines
13 KiB
C++
344 lines
13 KiB
C++
|
|
/*
|
|
* Copyright 2016 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
#include "include/core/SkCanvas.h"
|
|
#include "include/core/SkColorFilter.h"
|
|
#include "include/core/SkPath.h"
|
|
#include "include/core/SkPoint3.h"
|
|
#include "include/pathops/SkPathOps.h"
|
|
#include "include/utils/SkCamera.h"
|
|
#include "include/utils/SkShadowUtils.h"
|
|
#include "samplecode/Sample.h"
|
|
#include "src/core/SkBlurMask.h"
|
|
#include "src/utils/SkUTF.h"
|
|
#include "tools/ToolUtils.h"
|
|
#include "tools/timer/TimeUtils.h"
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
class ShadowsView : public Sample {
|
|
SkPath fRectPath;
|
|
SkPath fRRPath;
|
|
SkPath fCirclePath;
|
|
SkPath fFunkyRRPath;
|
|
SkPath fCubicPath;
|
|
SkPath fStarPath;
|
|
SkPath fSquareRRectPath;
|
|
SkPath fWideRectPath;
|
|
SkPath fWideOvalPath;
|
|
SkPath fNotchPath;
|
|
SkPath fTabPath;
|
|
|
|
SkPoint3 fLightPos;
|
|
SkScalar fZDelta = 0;
|
|
SkScalar fAnimTranslate = 0;
|
|
SkScalar fAnimAngle = 0;
|
|
SkScalar fAnimAlpha = 1;
|
|
|
|
bool fShowAmbient = true;
|
|
bool fShowSpot = true;
|
|
bool fUseAlt = false;
|
|
bool fUseBlur = true;
|
|
bool fShowObject = true;
|
|
bool fIgnoreShadowAlpha = false;
|
|
bool fDoAlphaAnimation = false;
|
|
|
|
void onOnceBeforeDraw() override {
|
|
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));
|
|
fFunkyRRPath.addRoundRect(SkRect::MakeXYWH(-50, -50, SK_Scalar1 * 100, SK_Scalar1 * 100),
|
|
40 * SK_Scalar1, 20 * SK_Scalar1,
|
|
SkPathDirection::kCW);
|
|
fCubicPath.cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1,
|
|
20 * SK_Scalar1, 100 * SK_Scalar1,
|
|
0 * SK_Scalar1, 0 * SK_Scalar1);
|
|
fStarPath.moveTo(0.0f, -50.0f);
|
|
fStarPath.lineTo(14.43f, -25.0f);
|
|
fStarPath.lineTo(43.30f, -25.0f);
|
|
fStarPath.lineTo(28.86f, 0.0f);
|
|
fStarPath.lineTo(43.30f, 25.0f);
|
|
fStarPath.lineTo(14.43f, 25.0f);
|
|
fStarPath.lineTo(0.0f, 50.0f);
|
|
fStarPath.lineTo(-14.43f, 25.0f);
|
|
fStarPath.lineTo(-43.30f, 25.0f);
|
|
fStarPath.lineTo(-28.86f, 0.0f);
|
|
fStarPath.lineTo(-43.30f, -25.0f);
|
|
fStarPath.lineTo(-14.43f, -25.0f);
|
|
fSquareRRectPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-50, -50, 100, 100),
|
|
10, 10));
|
|
fWideRectPath.addRect(SkRect::MakeXYWH(0, 0, 630, 70));
|
|
fWideOvalPath.addOval(SkRect::MakeXYWH(0, 0, 630, 70));
|
|
|
|
fNotchPath.moveTo(0, 80);
|
|
fNotchPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), -90, -90, false);
|
|
fNotchPath.lineTo(-75, 100);
|
|
fNotchPath.lineTo(-75, -100);
|
|
fNotchPath.lineTo(75, -100);
|
|
fNotchPath.lineTo(75, 100);
|
|
fNotchPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 0, -90, false);
|
|
|
|
fTabPath.moveTo(-75, -100);
|
|
fTabPath.lineTo(75, -100);
|
|
fTabPath.lineTo(75, 100);
|
|
fTabPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 0, 90, false);
|
|
fTabPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 90, 90, false);
|
|
fTabPath.lineTo(-75, 100);
|
|
|
|
fLightPos = SkPoint3::Make(350, 0, 600);
|
|
}
|
|
|
|
SkString name() override { return SkString("AndroidShadows"); }
|
|
|
|
bool onChar(SkUnichar uni) override {
|
|
bool handled = false;
|
|
switch (uni) {
|
|
case 'W':
|
|
fShowAmbient = !fShowAmbient;
|
|
handled = true;
|
|
break;
|
|
case 'S':
|
|
fShowSpot = !fShowSpot;
|
|
handled = true;
|
|
break;
|
|
case 'T':
|
|
fUseAlt = !fUseAlt;
|
|
handled = true;
|
|
break;
|
|
case 'B':
|
|
fUseBlur = !fUseBlur;
|
|
handled = true;
|
|
break;
|
|
case 'O':
|
|
fShowObject = !fShowObject;
|
|
handled = true;
|
|
break;
|
|
case 'N':
|
|
fDoAlphaAnimation = !fDoAlphaAnimation;
|
|
if (!fDoAlphaAnimation) {
|
|
fAnimAlpha = 1;
|
|
}
|
|
handled = true;
|
|
break;
|
|
case '>':
|
|
fZDelta += 0.5f;
|
|
handled = true;
|
|
break;
|
|
case '<':
|
|
fZDelta -= 0.5f;
|
|
handled = true;
|
|
break;
|
|
case '?':
|
|
fIgnoreShadowAlpha = !fIgnoreShadowAlpha;
|
|
handled = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (handled) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
|
|
const SkPoint3& zPlaneParams,
|
|
const SkPaint& paint, SkScalar ambientAlpha,
|
|
const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
|
|
if (fIgnoreShadowAlpha) {
|
|
ambientAlpha = 1;
|
|
spotAlpha = 1;
|
|
}
|
|
if (!fShowAmbient) {
|
|
ambientAlpha = 0;
|
|
}
|
|
if (!fShowSpot) {
|
|
spotAlpha = 0;
|
|
}
|
|
uint32_t flags = 0;
|
|
if (fUseAlt) {
|
|
flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
|
|
}
|
|
if (fUseBlur) {
|
|
flags |= SkShadowFlags::kConcaveBlurOnly_ShadowFlag;
|
|
}
|
|
|
|
SkColor ambientColor = SkColorSetARGB(ambientAlpha * 255, 0, 0, 0);
|
|
SkColor spotColor = SkColorSetARGB(spotAlpha * 255, 0, 0, 0);
|
|
SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, lightPos, lightWidth,
|
|
ambientColor, spotColor, flags);
|
|
|
|
if (fShowObject) {
|
|
canvas->drawPath(path, paint);
|
|
} else {
|
|
SkPaint strokePaint;
|
|
|
|
strokePaint.setColor(paint.getColor());
|
|
strokePaint.setStyle(SkPaint::kStroke_Style);
|
|
|
|
canvas->drawPath(path, strokePaint);
|
|
}
|
|
}
|
|
|
|
void onDrawContent(SkCanvas* canvas) override {
|
|
canvas->drawColor(0xFFDDDDDD);
|
|
|
|
const SkScalar kLightWidth = 800;
|
|
const SkScalar kAmbientAlpha = 0.039f;
|
|
const SkScalar kSpotAlpha = 0.19f;
|
|
|
|
SkPaint paint;
|
|
paint.setAntiAlias(true);
|
|
|
|
SkPoint3 lightPos = fLightPos;
|
|
SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, 0);
|
|
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->translate(200, 90);
|
|
zPlaneParams.fZ = std::max(1.0f, 2 + fZDelta);
|
|
this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
|
|
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
|
|
|
|
paint.setColor(SK_ColorRED);
|
|
canvas->translate(250, 0);
|
|
zPlaneParams.fZ = std::max(1.0f, 8 + fZDelta);
|
|
this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
|
|
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
|
|
|
|
paint.setColor(SK_ColorBLUE);
|
|
canvas->translate(-250, 110);
|
|
zPlaneParams.fZ = std::max(1.0f, 12 + fZDelta);
|
|
this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
|
|
lightPos, kLightWidth, fAnimAlpha*0.5f);
|
|
|
|
paint.setColor(SK_ColorGREEN);
|
|
canvas->translate(250, 0);
|
|
zPlaneParams.fZ = std::max(1.0f, 64 + fZDelta);
|
|
this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
|
|
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
|
|
|
|
paint.setColor(SK_ColorYELLOW);
|
|
canvas->translate(-250, 110);
|
|
zPlaneParams.fZ = std::max(1.0f, 8 + fZDelta);
|
|
this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
|
|
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
|
|
|
|
paint.setColor(SK_ColorCYAN);
|
|
canvas->translate(250, 0);
|
|
zPlaneParams.fZ = std::max(1.0f, 16 + fZDelta);
|
|
this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
|
|
lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
|
|
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->translate(250, -180);
|
|
zPlaneParams.fZ = std::max(1.0f, 8 + fZDelta);
|
|
this->drawShadowedPath(canvas, fStarPath, zPlaneParams, paint,
|
|
kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha);
|
|
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->translate(150, 0);
|
|
zPlaneParams.fZ = std::max(1.0f, 2 + fZDelta);
|
|
this->drawShadowedPath(canvas, fNotchPath, zPlaneParams, paint,
|
|
kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha);
|
|
|
|
paint.setColor(SK_ColorWHITE);
|
|
canvas->translate(200, 0);
|
|
zPlaneParams.fZ = std::max(1.0f, 16 + fZDelta);
|
|
this->drawShadowedPath(canvas, fTabPath, zPlaneParams, paint,
|
|
kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha);
|
|
|
|
// circular reveal
|
|
SkPath tmpPath;
|
|
SkPath tmpClipPath;
|
|
tmpClipPath.addCircle(fAnimTranslate, 0, 60);
|
|
Op(fSquareRRectPath, tmpClipPath, kIntersect_SkPathOp, &tmpPath);
|
|
|
|
paint.setColor(SK_ColorMAGENTA);
|
|
canvas->translate(-725, 240);
|
|
zPlaneParams.fZ = std::max(1.0f, 32 + fZDelta);
|
|
this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f,
|
|
lightPos, kLightWidth, .5f);
|
|
|
|
// path ops bug
|
|
SkPath tmpClipPathBug;
|
|
tmpClipPathBug.addCircle(88.0344925f, 0, 60);
|
|
Op(fSquareRRectPath, tmpClipPathBug, kIntersect_SkPathOp, &tmpPath);
|
|
|
|
canvas->translate(250, 0);
|
|
zPlaneParams.fZ = std::max(1.0f, 32 + fZDelta);
|
|
this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f,
|
|
lightPos, kLightWidth, .5f);
|
|
|
|
// perspective paths
|
|
SkPoint pivot = SkPoint::Make(fWideRectPath.getBounds().width()/2,
|
|
fWideRectPath.getBounds().height()/2);
|
|
SkPoint translate = SkPoint::Make(100, 450);
|
|
paint.setColor(SK_ColorWHITE);
|
|
Sk3DView view;
|
|
view.save();
|
|
view.rotateX(fAnimAngle);
|
|
SkMatrix persp;
|
|
view.getMatrix(&persp);
|
|
persp.preTranslate(-pivot.fX, -pivot.fY);
|
|
persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
|
|
canvas->setMatrix(persp);
|
|
SkScalar radians = SkDegreesToRadians(fAnimAngle);
|
|
zPlaneParams = SkPoint3::Make(0,
|
|
SkScalarSin(radians),
|
|
std::max(1.0f, 16 + fZDelta) - SkScalarSin(radians)*pivot.fY);
|
|
this->drawShadowedPath(canvas, fWideRectPath, zPlaneParams, paint, .1f,
|
|
lightPos, kLightWidth, .5f);
|
|
|
|
pivot = SkPoint::Make(fWideOvalPath.getBounds().width() / 2,
|
|
fWideOvalPath.getBounds().height() / 2);
|
|
translate = SkPoint::Make(100, 600);
|
|
view.restore();
|
|
view.save();
|
|
view.rotateY(fAnimAngle);
|
|
view.getMatrix(&persp);
|
|
persp.preTranslate(-pivot.fX, -pivot.fY);
|
|
persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
|
|
canvas->setMatrix(persp);
|
|
zPlaneParams = SkPoint3::Make(-SkScalarSin(radians),
|
|
0,
|
|
std::max(1.0f, 32 + fZDelta) + SkScalarSin(radians)*pivot.fX);
|
|
this->drawShadowedPath(canvas, fWideOvalPath, zPlaneParams, paint, .1f,
|
|
lightPos, kLightWidth, .5f);
|
|
|
|
pivot = SkPoint::Make(fStarPath.getBounds().width() / 2,
|
|
fStarPath.getBounds().height() / 2);
|
|
translate = SkPoint::Make(700, 250);
|
|
view.restore();
|
|
view.rotateY(fAnimAngle);
|
|
view.getMatrix(&persp);
|
|
persp.preTranslate(-pivot.fX, -pivot.fY);
|
|
persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
|
|
canvas->setMatrix(persp);
|
|
zPlaneParams = SkPoint3::Make(-SkScalarSin(radians),
|
|
0,
|
|
std::max(1.0f, 8 + fZDelta) + SkScalarSin(radians)*pivot.fX);
|
|
this->drawShadowedPath(canvas, fStarPath, zPlaneParams, paint, .1f,
|
|
lightPos, kLightWidth, .5f);
|
|
}
|
|
|
|
bool onAnimate(double nanos) override {
|
|
fAnimTranslate = TimeUtils::PingPong(1e-9 * nanos, 30, 0, 125, -125);
|
|
fAnimAngle = TimeUtils::PingPong(1e-9 * nanos, 15, 0, 0, 20);
|
|
if (fDoAlphaAnimation) {
|
|
fAnimAlpha = TimeUtils::PingPong(1e-9 * nanos, 5, 0, 1, 0);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
using INHERITED = Sample;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
DEF_SAMPLE( return new ShadowsView(); )
|