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