|  |  | 
|  | /* | 
|  | * 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(); ) |