| /* | |
| * 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 "AnimTimer.h" | |
| #include "Sample.h" | |
| #include "SkBlurMask.h" | |
| #include "SkBlurMaskFilter.h" | |
| #include "SkCamera.h" | |
| #include "SkCanvas.h" | |
| #include "SkColorFilter.h" | |
| #include "SkPath.h" | |
| #include "SkPathOps.h" | |
| #include "SkPoint3.h" | |
| #include "SkShadowUtils.h" | |
| #include "SkUTF.h" | |
| #include "ToolUtils.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; | |
| SkScalar fAnimTranslate; | |
| SkScalar fAnimAngle; | |
| SkScalar fAnimAlpha; | |
| bool fShowAmbient; | |
| bool fShowSpot; | |
| bool fUseAlt; | |
| bool fShowObject; | |
| bool fIgnoreShadowAlpha; | |
| bool fDoAlphaAnimation; | |
| public: | |
| ShadowsView() | |
| : fZDelta(0) | |
| , fAnimTranslate(0) | |
| , fAnimAngle(0) | |
| , fAnimAlpha(1) | |
| , fShowAmbient(true) | |
| , fShowSpot(true) | |
| , fUseAlt(false) | |
| , fShowObject(true) | |
| , fIgnoreShadowAlpha(false) | |
| , fDoAlphaAnimation(false) {} | |
| protected: | |
| 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, | |
| SkPath::kCW_Direction); | |
| 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); | |
| } | |
| bool onQuery(Sample::Event* evt) override { | |
| if (Sample::TitleQ(*evt)) { | |
| Sample::TitleR(evt, "AndroidShadows"); | |
| return true; | |
| } | |
| SkUnichar uni; | |
| if (Sample::CharQ(*evt, &uni)) { | |
| 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 '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 this->INHERITED::onQuery(evt); | |
| } | |
| void drawBG(SkCanvas* canvas) { | |
| canvas->drawColor(0xFFDDDDDD); | |
| } | |
| 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; | |
| } | |
| 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 { | |
| this->drawBG(canvas); | |
| 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 = SkTMax(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 = SkTMax(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 = SkTMax(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 = SkTMax(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 = SkTMax(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 = SkTMax(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 = SkTMax(1.0f, 8 + fZDelta); | |
| this->drawShadowedPath(canvas, fStarPath, zPlaneParams, paint, | |
| kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); | |
| paint.setColor(SK_ColorWHITE); | |
| canvas->translate(150, 0); | |
| zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta); | |
| this->drawShadowedPath(canvas, fNotchPath, zPlaneParams, paint, | |
| kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); | |
| paint.setColor(SK_ColorWHITE); | |
| canvas->translate(200, 0); | |
| zPlaneParams.fZ = SkTMax(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 = SkTMax(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 = SkTMax(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), | |
| SkTMax(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, | |
| SkTMax(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, | |
| SkTMax(1.0f, 8 + fZDelta) + SkScalarSin(radians)*pivot.fX); | |
| this->drawShadowedPath(canvas, fStarPath, zPlaneParams, paint, .1f, | |
| lightPos, kLightWidth, .5f); | |
| } | |
| bool onAnimate(const AnimTimer& timer) override { | |
| fAnimTranslate = timer.pingPong(30, 0, 125, -125); | |
| fAnimAngle = timer.pingPong(15, 0, 0, 20); | |
| if (fDoAlphaAnimation) { | |
| fAnimAlpha = timer.pingPong(5, 0, 1, 0); | |
| } | |
| return true; | |
| } | |
| private: | |
| typedef Sample INHERITED; | |
| }; | |
| ////////////////////////////////////////////////////////////////////////////// | |
| DEF_SAMPLE( return new ShadowsView(); ) |