| /* | |
| * 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/SkPathBuilder.h" | |
| #include "include/core/SkPoint3.h" | |
| #include "include/core/SkRRect.h" | |
| #include "include/pathops/SkPathOps.h" | |
| #include "include/utils/SkCamera.h" | |
| #include "include/utils/SkShadowUtils.h" | |
| #include "src/core/SkBlurMask.h" | |
| #include "src/core/SkUTF.h" | |
| #include "tools/ToolUtils.h" | |
| #include "tools/timer/TimeUtils.h" | |
| #include "tools/viewer/Slide.h" | |
| //////////////////////////////////////////////////////////////////////////// | |
| class ShadowsSlide : public Slide { | |
| 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; | |
| public: | |
| ShadowsSlide() { fName = "AndroidShadows"; } | |
| void load(SkScalar w, SkScalar h) override { | |
| fCirclePath = SkPath::Circle(0, 0, 50); | |
| fRectPath = SkPath::Rect(SkRect::MakeXYWH(-100, -50, 200, 100)); | |
| fRRPath = SkPath::RRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4)); | |
| fFunkyRRPath = SkPath::RRect(SkRect::MakeXYWH(-50, -50, SK_Scalar1 * 100, SK_Scalar1 * 100), | |
| 40 * SK_Scalar1, 20 * SK_Scalar1, | |
| SkPathDirection::kCW); | |
| fCubicPath = SkPathBuilder() | |
| .cubicTo(100, 50, 20, 100, 0, 0) | |
| .detach(); | |
| fStarPath = SkPathBuilder() | |
| .moveTo(0.0f, -50.0f) | |
| .lineTo(14.43f, -25.0f) | |
| .lineTo(43.30f, -25.0f) | |
| .lineTo(28.86f, 0.0f) | |
| .lineTo(43.30f, 25.0f) | |
| .lineTo(14.43f, 25.0f) | |
| .lineTo(0.0f, 50.0f) | |
| .lineTo(-14.43f, 25.0f) | |
| .lineTo(-43.30f, 25.0f) | |
| .lineTo(-28.86f, 0.0f) | |
| .lineTo(-43.30f, -25.0f) | |
| .lineTo(-14.43f, -25.0f) | |
| .detach(); | |
| fSquareRRectPath = SkPath::RRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-50, -50, 100, 100), | |
| 10, 10)); | |
| fWideRectPath = SkPath::Rect(SkRect::MakeXYWH(0, 0, 630, 70)); | |
| fWideOvalPath = SkPath::Oval(SkRect::MakeXYWH(0, 0, 630, 70)); | |
| fNotchPath = SkPathBuilder() | |
| .moveTo(0, 80) | |
| .arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), -90, -90, false) | |
| .lineTo(-75, 100) | |
| .lineTo(-75, -100) | |
| .lineTo(75, -100) | |
| .lineTo(75, 100) | |
| .arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 0, -90, false) | |
| .detach(); | |
| fTabPath = SkPathBuilder() | |
| .moveTo(-75, -100) | |
| .lineTo(75, -100) | |
| .lineTo(75, 100) | |
| .arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 0, 90, false) | |
| .arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 90, 90, false) | |
| .lineTo(-75, 100) | |
| .detach(); | |
| fLightPos = SkPoint3::Make(350, 0, 600); | |
| } | |
| 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; | |
| } | |
| bool animate(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; | |
| } | |
| void draw(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 tmpClipPath = SkPath::Circle(fAnimTranslate, 0, 60); | |
| SkPath tmpPath = Op(fSquareRRectPath, tmpClipPath, kIntersect_SkPathOp).value_or(SkPath()); | |
| 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 = SkPath::Circle(88.0344925f, 0, 60); | |
| if (auto res = Op(fSquareRRectPath, tmpClipPathBug, kIntersect_SkPathOp)) { | |
| tmpPath = *res; | |
| } | |
| 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); | |
| } | |
| private: | |
| 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); | |
| } | |
| } | |
| }; | |
| ////////////////////////////////////////////////////////////////////////////// | |
| DEF_SLIDE( return new ShadowsSlide(); ) |