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 "Sample.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 "SkUTF.h" 20 #include "sk_tool_utils.h" 21 22 //////////////////////////////////////////////////////////////////////////// 23 24 class ShadowsView : public Sample { 25 SkPath fRectPath; 26 SkPath fRRPath; 27 SkPath fCirclePath; 28 SkPath fFunkyRRPath; 29 SkPath fCubicPath; 30 SkPath fStarPath; 31 SkPath fSquareRRectPath; 32 SkPath fWideRectPath; 33 SkPath fWideOvalPath; 34 SkPath fNotchPath; 35 SkPath fTabPath; 36 37 SkPoint3 fLightPos; 38 SkScalar fZDelta; 39 SkScalar fAnimTranslate; 40 SkScalar fAnimAngle; 41 SkScalar fAnimAlpha; 42 43 bool fShowAmbient; 44 bool fShowSpot; 45 bool fUseAlt; 46 bool fShowObject; 47 bool fIgnoreShadowAlpha; 48 bool fDoAlphaAnimation; 49 50 public: ShadowsView()51 ShadowsView() 52 : fZDelta(0) 53 , fAnimTranslate(0) 54 , fAnimAngle(0) 55 , fAnimAlpha(1) 56 , fShowAmbient(true) 57 , fShowSpot(true) 58 , fUseAlt(false) 59 , fShowObject(true) 60 , fIgnoreShadowAlpha(false) 61 , fDoAlphaAnimation(false) {} 62 63 protected: onOnceBeforeDraw()64 void onOnceBeforeDraw() override { 65 fCirclePath.addCircle(0, 0, 50); 66 fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100)); 67 fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4)); 68 fFunkyRRPath.addRoundRect(SkRect::MakeXYWH(-50, -50, SK_Scalar1 * 100, SK_Scalar1 * 100), 69 40 * SK_Scalar1, 20 * SK_Scalar1, 70 SkPath::kCW_Direction); 71 fCubicPath.cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1, 72 20 * SK_Scalar1, 100 * SK_Scalar1, 73 0 * SK_Scalar1, 0 * SK_Scalar1); 74 fStarPath.moveTo(0.0f, -50.0f); 75 fStarPath.lineTo(14.43f, -25.0f); 76 fStarPath.lineTo(43.30f, -25.0f); 77 fStarPath.lineTo(28.86f, 0.0f); 78 fStarPath.lineTo(43.30f, 25.0f); 79 fStarPath.lineTo(14.43f, 25.0f); 80 fStarPath.lineTo(0.0f, 50.0f); 81 fStarPath.lineTo(-14.43f, 25.0f); 82 fStarPath.lineTo(-43.30f, 25.0f); 83 fStarPath.lineTo(-28.86f, 0.0f); 84 fStarPath.lineTo(-43.30f, -25.0f); 85 fStarPath.lineTo(-14.43f, -25.0f); 86 fSquareRRectPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-50, -50, 100, 100), 87 10, 10)); 88 fWideRectPath.addRect(SkRect::MakeXYWH(0, 0, 630, 70)); 89 fWideOvalPath.addOval(SkRect::MakeXYWH(0, 0, 630, 70)); 90 91 fNotchPath.moveTo(0, 80); 92 fNotchPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), -90, -90, false); 93 fNotchPath.lineTo(-75, 100); 94 fNotchPath.lineTo(-75, -100); 95 fNotchPath.lineTo(75, -100); 96 fNotchPath.lineTo(75, 100); 97 fNotchPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 0, -90, false); 98 99 fTabPath.moveTo(-75, -100); 100 fTabPath.lineTo(75, -100); 101 fTabPath.lineTo(75, 100); 102 fTabPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 0, 90, false); 103 fTabPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 90, 90, false); 104 fTabPath.lineTo(-75, 100); 105 106 fLightPos = SkPoint3::Make(350, 0, 600); 107 } 108 onQuery(Sample::Event * evt)109 bool onQuery(Sample::Event* evt) override { 110 if (Sample::TitleQ(*evt)) { 111 Sample::TitleR(evt, "AndroidShadows"); 112 return true; 113 } 114 115 SkUnichar uni; 116 if (Sample::CharQ(*evt, &uni)) { 117 bool handled = false; 118 switch (uni) { 119 case 'W': 120 fShowAmbient = !fShowAmbient; 121 handled = true; 122 break; 123 case 'S': 124 fShowSpot = !fShowSpot; 125 handled = true; 126 break; 127 case 'T': 128 fUseAlt = !fUseAlt; 129 handled = true; 130 break; 131 case 'O': 132 fShowObject = !fShowObject; 133 handled = true; 134 break; 135 case 'N': 136 fDoAlphaAnimation = !fDoAlphaAnimation; 137 if (!fDoAlphaAnimation) { 138 fAnimAlpha = 1; 139 } 140 handled = true; 141 break; 142 case '>': 143 fZDelta += 0.5f; 144 handled = true; 145 break; 146 case '<': 147 fZDelta -= 0.5f; 148 handled = true; 149 break; 150 case '?': 151 fIgnoreShadowAlpha = !fIgnoreShadowAlpha; 152 handled = true; 153 break; 154 default: 155 break; 156 } 157 if (handled) { 158 return true; 159 } 160 } 161 return this->INHERITED::onQuery(evt); 162 } 163 drawBG(SkCanvas * canvas)164 void drawBG(SkCanvas* canvas) { 165 canvas->drawColor(0xFFDDDDDD); 166 } 167 drawShadowedPath(SkCanvas * canvas,const SkPath & path,const SkPoint3 & zPlaneParams,const SkPaint & paint,SkScalar ambientAlpha,const SkPoint3 & lightPos,SkScalar lightWidth,SkScalar spotAlpha)168 void drawShadowedPath(SkCanvas* canvas, const SkPath& path, 169 const SkPoint3& zPlaneParams, 170 const SkPaint& paint, SkScalar ambientAlpha, 171 const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) { 172 if (fIgnoreShadowAlpha) { 173 ambientAlpha = 1; 174 spotAlpha = 1; 175 } 176 if (!fShowAmbient) { 177 ambientAlpha = 0; 178 } 179 if (!fShowSpot) { 180 spotAlpha = 0; 181 } 182 uint32_t flags = 0; 183 if (fUseAlt) { 184 flags |= SkShadowFlags::kGeometricOnly_ShadowFlag; 185 } 186 187 SkColor ambientColor = SkColorSetARGB(ambientAlpha * 255, 0, 0, 0); 188 SkColor spotColor = SkColorSetARGB(spotAlpha * 255, 0, 0, 0); 189 SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, lightPos, lightWidth, 190 ambientColor, spotColor, flags); 191 192 if (fShowObject) { 193 canvas->drawPath(path, paint); 194 } else { 195 SkPaint strokePaint; 196 197 strokePaint.setColor(paint.getColor()); 198 strokePaint.setStyle(SkPaint::kStroke_Style); 199 200 canvas->drawPath(path, strokePaint); 201 } 202 } 203 onDrawContent(SkCanvas * canvas)204 void onDrawContent(SkCanvas* canvas) override { 205 this->drawBG(canvas); 206 const SkScalar kLightWidth = 800; 207 const SkScalar kAmbientAlpha = 0.039f; 208 const SkScalar kSpotAlpha = 0.19f; 209 210 SkPaint paint; 211 paint.setAntiAlias(true); 212 213 SkPoint3 lightPos = fLightPos; 214 SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, 0); 215 216 paint.setColor(SK_ColorWHITE); 217 canvas->translate(200, 90); 218 zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta); 219 this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, 220 lightPos, kLightWidth, fAnimAlpha*kSpotAlpha); 221 222 paint.setColor(SK_ColorRED); 223 canvas->translate(250, 0); 224 zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); 225 this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, 226 lightPos, kLightWidth, fAnimAlpha*kSpotAlpha); 227 228 paint.setColor(SK_ColorBLUE); 229 canvas->translate(-250, 110); 230 zPlaneParams.fZ = SkTMax(1.0f, 12 + fZDelta); 231 this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, 232 lightPos, kLightWidth, fAnimAlpha*0.5f); 233 234 paint.setColor(SK_ColorGREEN); 235 canvas->translate(250, 0); 236 zPlaneParams.fZ = SkTMax(1.0f, 64 + fZDelta); 237 this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, 238 lightPos, kLightWidth, fAnimAlpha*kSpotAlpha); 239 240 paint.setColor(SK_ColorYELLOW); 241 canvas->translate(-250, 110); 242 zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); 243 this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, 244 lightPos, kLightWidth, fAnimAlpha*kSpotAlpha); 245 246 paint.setColor(SK_ColorCYAN); 247 canvas->translate(250, 0); 248 zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta); 249 this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha, 250 lightPos, kLightWidth, fAnimAlpha*kSpotAlpha); 251 252 paint.setColor(SK_ColorWHITE); 253 canvas->translate(250, -180); 254 zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta); 255 this->drawShadowedPath(canvas, fStarPath, zPlaneParams, paint, 256 kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); 257 258 paint.setColor(SK_ColorWHITE); 259 canvas->translate(150, 0); 260 zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta); 261 this->drawShadowedPath(canvas, fNotchPath, zPlaneParams, paint, 262 kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); 263 264 paint.setColor(SK_ColorWHITE); 265 canvas->translate(200, 0); 266 zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta); 267 this->drawShadowedPath(canvas, fTabPath, zPlaneParams, paint, 268 kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha); 269 270 // circular reveal 271 SkPath tmpPath; 272 SkPath tmpClipPath; 273 tmpClipPath.addCircle(fAnimTranslate, 0, 60); 274 Op(fSquareRRectPath, tmpClipPath, kIntersect_SkPathOp, &tmpPath); 275 276 paint.setColor(SK_ColorMAGENTA); 277 canvas->translate(-725, 240); 278 zPlaneParams.fZ = SkTMax(1.0f, 32 + fZDelta); 279 this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f, 280 lightPos, kLightWidth, .5f); 281 282 // path ops bug 283 SkPath tmpClipPathBug; 284 tmpClipPathBug.addCircle(88.0344925f, 0, 60); 285 Op(fSquareRRectPath, tmpClipPathBug, kIntersect_SkPathOp, &tmpPath); 286 287 canvas->translate(250, 0); 288 zPlaneParams.fZ = SkTMax(1.0f, 32 + fZDelta); 289 this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f, 290 lightPos, kLightWidth, .5f); 291 292 // perspective paths 293 SkPoint pivot = SkPoint::Make(fWideRectPath.getBounds().width()/2, 294 fWideRectPath.getBounds().height()/2); 295 SkPoint translate = SkPoint::Make(100, 450); 296 paint.setColor(SK_ColorWHITE); 297 Sk3DView view; 298 view.save(); 299 view.rotateX(fAnimAngle); 300 SkMatrix persp; 301 view.getMatrix(&persp); 302 persp.preTranslate(-pivot.fX, -pivot.fY); 303 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); 304 canvas->setMatrix(persp); 305 SkScalar radians = SkDegreesToRadians(fAnimAngle); 306 zPlaneParams = SkPoint3::Make(0, 307 SkScalarSin(radians), 308 SkTMax(1.0f, 16 + fZDelta) - SkScalarSin(radians)*pivot.fY); 309 this->drawShadowedPath(canvas, fWideRectPath, zPlaneParams, paint, .1f, 310 lightPos, kLightWidth, .5f); 311 312 pivot = SkPoint::Make(fWideOvalPath.getBounds().width() / 2, 313 fWideOvalPath.getBounds().height() / 2); 314 translate = SkPoint::Make(100, 600); 315 view.restore(); 316 view.save(); 317 view.rotateY(fAnimAngle); 318 view.getMatrix(&persp); 319 persp.preTranslate(-pivot.fX, -pivot.fY); 320 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); 321 canvas->setMatrix(persp); 322 zPlaneParams = SkPoint3::Make(-SkScalarSin(radians), 323 0, 324 SkTMax(1.0f, 32 + fZDelta) + SkScalarSin(radians)*pivot.fX); 325 this->drawShadowedPath(canvas, fWideOvalPath, zPlaneParams, paint, .1f, 326 lightPos, kLightWidth, .5f); 327 328 pivot = SkPoint::Make(fStarPath.getBounds().width() / 2, 329 fStarPath.getBounds().height() / 2); 330 translate = SkPoint::Make(700, 250); 331 view.restore(); 332 view.rotateY(fAnimAngle); 333 view.getMatrix(&persp); 334 persp.preTranslate(-pivot.fX, -pivot.fY); 335 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY); 336 canvas->setMatrix(persp); 337 zPlaneParams = SkPoint3::Make(-SkScalarSin(radians), 338 0, 339 SkTMax(1.0f, 8 + fZDelta) + SkScalarSin(radians)*pivot.fX); 340 this->drawShadowedPath(canvas, fStarPath, zPlaneParams, paint, .1f, 341 lightPos, kLightWidth, .5f); 342 } 343 onAnimate(const SkAnimTimer & timer)344 bool onAnimate(const SkAnimTimer& timer) override { 345 fAnimTranslate = timer.pingPong(30, 0, 125, -125); 346 fAnimAngle = timer.pingPong(15, 0, 0, 20); 347 if (fDoAlphaAnimation) { 348 fAnimAlpha = timer.pingPong(5, 0, 1, 0); 349 } 350 return true; 351 } 352 353 private: 354 typedef Sample INHERITED; 355 }; 356 357 ////////////////////////////////////////////////////////////////////////////// 358 359 DEF_SAMPLE( return new ShadowsView(); ) 360