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