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