1 2 /* 3 * Copyright 2016 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 #include "SampleCode.h" 9 #include "SkAnimTimer.h" 10 #include "SkBlurMask.h" 11 #include "SkBlurMaskFilter.h" 12 #include "SkColorFilter.h" 13 #include "SkCamera.h" 14 #include "SkCanvas.h" 15 #include "SkPath.h" 16 #include "SkPathOps.h" 17 #include "SkPoint3.h" 18 #include "SkShadowUtils.h" 19 #include "SkUtils.h" 20 #include "SkView.h" 21 #include "sk_tool_utils.h" 22 23 //////////////////////////////////////////////////////////////////////////// 24 25 class ShadowsView : public SampleView { 26 SkPath fRectPath; 27 SkPath fRRPath; 28 SkPath fCirclePath; 29 SkPath fFunkyRRPath; 30 SkPath fCubicPath; 31 SkPath fSquareRRectPath; 32 SkPath fWideRectPath; 33 SkPath fWideOvalPath; 34 SkPoint3 fLightPos; 35 SkScalar fZDelta; 36 SkScalar fAnimTranslate; 37 SkScalar fAnimAngle; 38 39 bool fShowAmbient; 40 bool fShowSpot; 41 bool fUseAlt; 42 bool fShowObject; 43 bool fIgnoreShadowAlpha; 44 45 public: 46 ShadowsView() 47 : fZDelta(0) 48 , fAnimTranslate(0) 49 , fAnimAngle(0) 50 , fShowAmbient(true) 51 , fShowSpot(true) 52 , fUseAlt(false) 53 , fShowObject(true) 54 , fIgnoreShadowAlpha(false) {} 55 56 protected: 57 void onOnceBeforeDraw() override { 58 fCirclePath.addCircle(0, 0, 50); 59 fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100)); 60 fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4)); 61 fFunkyRRPath.addRoundRect(SkRect::MakeXYWH(-50, -50, SK_Scalar1 * 100, SK_Scalar1 * 100), 62 40 * SK_Scalar1, 20 * SK_Scalar1, 63 SkPath::kCW_Direction); 64 fCubicPath.cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1, 65 20 * SK_Scalar1, 100 * SK_Scalar1, 66 0 * SK_Scalar1, 0 * SK_Scalar1); 67 fSquareRRectPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-50, -50, 100, 100), 68 10, 10)); 69 fWideRectPath.addRect(SkRect::MakeXYWH(0, 0, 630, 70)); 70 fWideOvalPath.addOval(SkRect::MakeXYWH(0, 0, 630, 70)); 71 72 fLightPos = SkPoint3::Make(350, 0, 600); 73 } 74 75 // overrides from SkEventSink 76 bool onQuery(SkEvent* evt) override { 77 if (SampleCode::TitleQ(*evt)) { 78 SampleCode::TitleR(evt, "AndroidShadows"); 79 return true; 80 } 81 82 SkUnichar uni; 83 if (SampleCode::CharQ(*evt, &uni)) { 84 bool handled = false; 85 switch (uni) { 86 case 'W': 87 fShowAmbient = !fShowAmbient; 88 handled = true; 89 break; 90 case 'S': 91 fShowSpot = !fShowSpot; 92 handled = true; 93 break; 94 case 'T': 95 fUseAlt = !fUseAlt; 96 handled = true; 97 break; 98 case 'O': 99 fShowObject = !fShowObject; 100 handled = true; 101 break; 102 case '>': 103 fZDelta += 0.5f; 104 handled = true; 105 break; 106 case '<': 107 fZDelta -= 0.5f; 108 handled = true; 109 break; 110 case '?': 111 fIgnoreShadowAlpha = !fIgnoreShadowAlpha; 112 handled = true; 113 break; 114 default: 115 break; 116 } 117 if (handled) { 118 this->inval(nullptr); 119 return true; 120 } 121 } 122 return this->INHERITED::onQuery(evt); 123 } 124 125 void drawBG(SkCanvas* canvas) { 126 canvas->drawColor(0xFFDDDDDD); 127 } 128 129 void drawShadowedPath(SkCanvas* canvas, const SkPath& path, 130 const SkPoint3& zPlaneParams, 131 const SkPaint& paint, SkScalar ambientAlpha, 132 const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) { 133 if (fIgnoreShadowAlpha) { 134 ambientAlpha = 255; 135 spotAlpha = 255; 136 } 137 if (!fShowAmbient) { 138 ambientAlpha = 0; 139 } 140 if (!fShowSpot) { 141 spotAlpha = 0; 142 } 143 uint32_t flags = 0; 144 if (fUseAlt) { 145 flags |= SkShadowFlags::kGeometricOnly_ShadowFlag; 146 } 147 148 SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, 149 lightPos, lightWidth, 150 ambientAlpha, spotAlpha, SK_ColorBLACK, flags); 151 152 if (fShowObject) { 153 canvas->drawPath(path, paint); 154 } else { 155 SkPaint strokePaint; 156 157 strokePaint.setColor(paint.getColor()); 158 strokePaint.setStyle(SkPaint::kStroke_Style); 159 160 canvas->drawPath(path, strokePaint); 161 } 162 } 163 164 void onDrawContent(SkCanvas* canvas) override { 165 this->drawBG(canvas); 166 const SkScalar kLightWidth = 800; 167 const SkScalar kAmbientAlpha = 0.1f; 168 const SkScalar kSpotAlpha = 0.25f; 169 170 SkPaint paint; 171 paint.setAntiAlias(true); 172 173 SkPoint3 lightPos = fLightPos; 174 SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, 0); 175 176 paint.setColor(SK_ColorWHITE); 177 canvas->translate(200, 90); 178 zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta); 179 this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha, 180 lightPos, kLightWidth, kSpotAlpha); 181 182 paint.setColor(SK_ColorRED); 183 canvas->translate(250, 0); 184 zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); 185 this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, kAmbientAlpha, 186 lightPos, kLightWidth, kSpotAlpha); 187 188 paint.setColor(SK_ColorBLUE); 189 canvas->translate(-250, 110); 190 zPlaneParams.fZ = SkTMax(1.0f, 12 + fZDelta); 191 this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, kAmbientAlpha, 192 lightPos, kLightWidth, 0.5f); 193 194 paint.setColor(SK_ColorGREEN); 195 canvas->translate(250, 0); 196 zPlaneParams.fZ = SkTMax(1.0f, 64 + fZDelta); 197 this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, kAmbientAlpha, 198 lightPos, kLightWidth, kSpotAlpha); 199 200 paint.setColor(SK_ColorYELLOW); 201 canvas->translate(-250, 110); 202 zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); 203 this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, kAmbientAlpha, 204 lightPos, kLightWidth, kSpotAlpha); 205 206 paint.setColor(SK_ColorCYAN); 207 canvas->translate(250, 0); 208 zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta); 209 this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, 210 kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); 211 212 // circular reveal 213 SkPath tmpPath; 214 SkPath tmpClipPath; 215 tmpClipPath.addCircle(fAnimTranslate, 0, 60); 216 Op(fSquareRRectPath, tmpClipPath, kIntersect_SkPathOp, &tmpPath); 217 218 paint.setColor(SK_ColorMAGENTA); 219 canvas->translate(-125, 60); 220 zPlaneParams.fZ = SkTMax(1.0f, 32 + fZDelta); 221 this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f, 222 lightPos, kLightWidth, .5f); 223 224 // perspective paths 225 SkPoint pivot = SkPoint::Make(fWideRectPath.getBounds().width()/2, 226 fWideRectPath.getBounds().height()/2); 227 SkPoint translate = SkPoint::Make(100, 450); 228 paint.setColor(SK_ColorWHITE); 229 Sk3DView view; 230 view.save(); 231 view.rotateX(fAnimAngle); 232 SkMatrix persp; 233 view.getMatrix(&persp); 234 persp.preTranslate(-pivot.fX, -pivot.fY); 235 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); 236 canvas->setMatrix(persp); 237 SkScalar radians = SkDegreesToRadians(fAnimAngle); 238 zPlaneParams = SkPoint3::Make(0, 239 SkScalarSin(-radians), 240 SkTMax(1.0f, 16 + fZDelta) - SkScalarSin(-radians)*pivot.fY); 241 this->drawShadowedPath(canvas, fWideRectPath, zPlaneParams, paint, .1f, 242 lightPos, kLightWidth, .5f); 243 244 pivot = SkPoint::Make(fWideOvalPath.getBounds().width() / 2, 245 fWideOvalPath.getBounds().height() / 2); 246 translate = SkPoint::Make(100, 600); 247 view.restore(); 248 view.rotateY(fAnimAngle); 249 view.getMatrix(&persp); 250 persp.preTranslate(-pivot.fX, -pivot.fY); 251 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); 252 canvas->setMatrix(persp); 253 zPlaneParams = SkPoint3::Make(-SkScalarSin(radians), 254 0, 255 SkTMax(1.0f, 32 + fZDelta) + SkScalarSin(radians)*pivot.fX); 256 this->drawShadowedPath(canvas, fWideOvalPath, zPlaneParams, paint, .1f, 257 lightPos, kLightWidth, .5f); 258 } 259 260 bool onAnimate(const SkAnimTimer& timer) override { 261 fAnimTranslate = timer.pingPong(30, 0, 200, -200); 262 fAnimAngle = timer.pingPong(15, 0, 0, 20); 263 264 return true; 265 } 266 267 private: 268 typedef SampleView INHERITED; 269 }; 270 271 ////////////////////////////////////////////////////////////////////////////// 272 273 static SkView* MyFactory() { return new ShadowsView; } 274 static SkViewRegister reg(MyFactory); 275