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