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