1 2 /* 3 * Copyright 2017 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 ShadowUtilsView : public Sample { 25 SkTArray<SkPath> fConvexPaths; 26 SkTArray<SkPath> fConcavePaths; 27 SkScalar fZDelta; 28 29 bool fShowAmbient; 30 bool fShowSpot; 31 bool fUseAlt; 32 bool fShowObject; 33 bool fIgnoreShadowAlpha; 34 35 public: ShadowUtilsView()36 ShadowUtilsView() 37 : fZDelta(0) 38 , fShowAmbient(true) 39 , fShowSpot(true) 40 , fUseAlt(false) 41 , fShowObject(false) 42 , fIgnoreShadowAlpha(false) {} 43 44 protected: onOnceBeforeDraw()45 void onOnceBeforeDraw() override { 46 fConvexPaths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10); 47 SkRRect oddRRect; 48 oddRRect.setNinePatch(SkRect::MakeWH(50, 50), 9, 13, 6, 16); 49 fConvexPaths.push_back().addRRect(oddRRect); 50 fConvexPaths.push_back().addRect(SkRect::MakeWH(50, 50)); 51 fConvexPaths.push_back().addCircle(25, 25, 25); 52 fConvexPaths.push_back().cubicTo(100, 50, 20, 100, 0, 0); 53 fConvexPaths.push_back().addOval(SkRect::MakeWH(20, 60)); 54 55 // star 56 fConcavePaths.push_back().moveTo(0.0f, -33.3333f); 57 fConcavePaths.back().lineTo(9.62f, -16.6667f); 58 fConcavePaths.back().lineTo(28.867f, -16.6667f); 59 fConcavePaths.back().lineTo(19.24f, 0.0f); 60 fConcavePaths.back().lineTo(28.867f, 16.6667f); 61 fConcavePaths.back().lineTo(9.62f, 16.6667f); 62 fConcavePaths.back().lineTo(0.0f, 33.3333f); 63 fConcavePaths.back().lineTo(-9.62f, 16.6667f); 64 fConcavePaths.back().lineTo(-28.867f, 16.6667f); 65 fConcavePaths.back().lineTo(-19.24f, 0.0f); 66 fConcavePaths.back().lineTo(-28.867f, -16.6667f); 67 fConcavePaths.back().lineTo(-9.62f, -16.6667f); 68 fConcavePaths.back().close(); 69 70 // dumbbell 71 fConcavePaths.push_back().moveTo(50, 0); 72 fConcavePaths.back().cubicTo(100, 25, 60, 50, 50, 0); 73 fConcavePaths.back().cubicTo(0, -25, 40, -50, 50, 0); 74 } 75 onQuery(Sample::Event * evt)76 bool onQuery(Sample::Event* evt) override { 77 if (Sample::TitleQ(*evt)) { 78 Sample::TitleR(evt, "ShadowUtils"); 79 return true; 80 } 81 82 SkUnichar uni; 83 if (Sample::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 return true; 119 } 120 } 121 return this->INHERITED::onQuery(evt); 122 } 123 drawBG(SkCanvas * canvas)124 void drawBG(SkCanvas* canvas) { 125 canvas->drawColor(0xFFFFFFFF); 126 } 127 drawShadowedPath(SkCanvas * canvas,const SkPath & path,const SkPoint3 & zPlaneParams,const SkPaint & paint,SkScalar ambientAlpha,const SkPoint3 & lightPos,SkScalar lightWidth,SkScalar spotAlpha,uint32_t flags)128 void drawShadowedPath(SkCanvas* canvas, const SkPath& path, 129 const SkPoint3& zPlaneParams, 130 const SkPaint& paint, SkScalar ambientAlpha, 131 const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha, 132 uint32_t flags) { 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 if (fUseAlt) { 144 flags |= SkShadowFlags::kGeometricOnly_ShadowFlag; 145 } 146 147 SkColor ambientColor = SkColorSetARGB(ambientAlpha * 255, 255, 0, 0); 148 SkColor spotColor = SkColorSetARGB(spotAlpha * 255, 0, 0, 255); 149 SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, 150 lightPos, lightWidth, 151 ambientColor, spotColor, flags); 152 153 if (fShowObject) { 154 canvas->drawPath(path, paint); 155 } else { 156 SkPaint strokePaint; 157 158 strokePaint.setColor(paint.getColor()); 159 strokePaint.setStyle(SkPaint::kStroke_Style); 160 161 canvas->drawPath(path, strokePaint); 162 } 163 } 164 onDrawContent(SkCanvas * canvas)165 void onDrawContent(SkCanvas* canvas) override { 166 this->drawBG(canvas); 167 168 static constexpr int kW = 800; 169 static constexpr SkScalar kPad = 15.f; 170 static constexpr SkScalar kLightR = 100.f; 171 static constexpr SkScalar kHeight = 50.f; 172 static constexpr SkScalar kAmbientAlpha = 0.5f; 173 static constexpr SkScalar kSpotAlpha = 0.5f; 174 static constexpr SkPoint3 lightPos = { 250, 400, 500 }; 175 176 canvas->translate(3 * kPad, 3 * kPad); 177 canvas->save(); 178 SkScalar x = 0; 179 SkScalar dy = 0; 180 SkTDArray<SkMatrix> matrices; 181 matrices.push()->reset(); 182 SkMatrix* m = matrices.push(); 183 m->setRotate(33.f, 25.f, 25.f); 184 m->postScale(1.2f, 0.8f, 25.f, 25.f); 185 SkPaint paint; 186 paint.setColor(SK_ColorGREEN); 187 paint.setAntiAlias(true); 188 SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, SkTMax(1.0f, kHeight + fZDelta)); 189 190 // convex paths 191 for (auto& m : matrices) { 192 for (auto flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) { 193 for (const auto& path : fConvexPaths) { 194 SkRect postMBounds = path.getBounds(); 195 m.mapRect(&postMBounds); 196 SkScalar w = postMBounds.width() + kHeight; 197 SkScalar dx = w + kPad; 198 if (x + dx > kW - 3 * kPad) { 199 canvas->restore(); 200 canvas->translate(0, dy); 201 canvas->save(); 202 x = 0; 203 dy = 0; 204 } 205 206 canvas->save(); 207 canvas->concat(m); 208 this->drawShadowedPath(canvas, path, zPlaneParams, paint, kAmbientAlpha, 209 lightPos, kLightR, kSpotAlpha, flags); 210 canvas->restore(); 211 212 canvas->translate(dx, 0); 213 x += dx; 214 dy = SkTMax(dy, postMBounds.height() + kPad + kHeight); 215 } 216 } 217 } 218 219 // concave paths 220 canvas->restore(); 221 canvas->translate(kPad, dy); 222 canvas->save(); 223 x = kPad; 224 dy = 0; 225 for (auto& m : matrices) { 226 for (const auto& path : fConcavePaths) { 227 SkRect postMBounds = path.getBounds(); 228 m.mapRect(&postMBounds); 229 SkScalar w = postMBounds.width(); 230 SkScalar dx = w + kPad; 231 232 canvas->save(); 233 canvas->concat(m); 234 this->drawShadowedPath(canvas, path, zPlaneParams, paint, kAmbientAlpha, lightPos, 235 kLightR, kSpotAlpha, kNone_ShadowFlag); 236 canvas->restore(); 237 238 canvas->translate(dx, 0); 239 x += dx; 240 dy = SkTMax(dy, postMBounds.height() + kPad + kHeight); 241 } 242 } 243 244 // Show where the light is in x,y as a circle (specified in device space). 245 SkMatrix invCanvasM = canvas->getTotalMatrix(); 246 if (invCanvasM.invert(&invCanvasM)) { 247 canvas->save(); 248 canvas->concat(invCanvasM); 249 SkPaint paint; 250 paint.setColor(SK_ColorBLACK); 251 paint.setAntiAlias(true); 252 canvas->drawCircle(lightPos.fX, lightPos.fY, kLightR / 10.f, paint); 253 canvas->restore(); 254 } 255 } 256 257 private: 258 typedef Sample INHERITED; 259 }; 260 261 ////////////////////////////////////////////////////////////////////////////// 262 263 DEF_SAMPLE( return new ShadowUtilsView(); ) 264