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