1 /* 2 * Copyright 2017 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "gm.h" 9 #include "SkCanvas.h" 10 #include "SkPath.h" 11 #include "SkResourceCache.h" 12 #include "SkShadowUtils.h" 13 14 void draw_shadow(SkCanvas* canvas, const SkPath& path, int height, SkColor color, SkPoint3 lightPos, 15 SkScalar lightR, bool isAmbient, uint32_t flags) { 16 SkScalar ambientAlpha = isAmbient ? .5f : 0.f; 17 SkScalar spotAlpha = isAmbient ? 0.f : .5f; 18 SkShadowUtils::DrawShadow(canvas, path, height, lightPos, lightR, ambientAlpha, spotAlpha, 19 color, flags); 20 } 21 22 static constexpr int kW = 800; 23 static constexpr int kH = 800; 24 25 enum ShadowMode { 26 kDebugColorNoOccluders, 27 kDebugColorOccluders, 28 kGrayscale 29 }; 30 31 void draw_paths(SkCanvas* canvas, ShadowMode mode) { 32 SkTArray<SkPath> paths; 33 paths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10); 34 SkRRect oddRRect; 35 oddRRect.setNinePatch(SkRect::MakeWH(50, 50), 9, 13, 6, 16); 36 paths.push_back().addRRect(oddRRect); 37 paths.push_back().addRect(SkRect::MakeWH(50, 50)); 38 paths.push_back().addCircle(25, 25, 25); 39 paths.push_back().cubicTo(100, 50, 20, 100, 0, 0); 40 paths.push_back().addOval(SkRect::MakeWH(20, 60)); 41 42 static constexpr SkScalar kPad = 15.f; 43 static constexpr SkScalar kLightR = 100.f; 44 static constexpr SkScalar kHeight = 50.f; 45 46 // transform light position relative to canvas to handle tiling 47 SkPoint lightXY = canvas->getTotalMatrix().mapXY(250, 400); 48 SkPoint3 lightPos = { lightXY.fX, lightXY.fY, 500 }; 49 50 canvas->translate(3 * kPad, 3 * kPad); 51 canvas->save(); 52 SkScalar x = 0; 53 SkScalar dy = 0; 54 SkTDArray<SkMatrix> matrices; 55 matrices.push()->reset(); 56 SkMatrix* m = matrices.push(); 57 m->setRotate(33.f, 25.f, 25.f); 58 m->postScale(1.2f, 0.8f, 25.f, 25.f); 59 for (auto& m : matrices) { 60 for (int flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) { 61 for (const auto& path : paths) { 62 SkRect postMBounds = path.getBounds(); 63 m.mapRect(&postMBounds); 64 SkScalar w = postMBounds.width() + kHeight; 65 SkScalar dx = w + kPad; 66 if (x + dx > kW - 3 * kPad) { 67 canvas->restore(); 68 canvas->translate(0, dy); 69 canvas->save(); 70 x = 0; 71 dy = 0; 72 } 73 74 canvas->save(); 75 canvas->concat(m); 76 77 if (kDebugColorNoOccluders == mode || kDebugColorOccluders == mode) { 78 flags |= SkShadowFlags::kDisableTonalColor_ShadowFlag; 79 draw_shadow(canvas, path, kHeight, SK_ColorRED, lightPos, kLightR, 80 true, flags); 81 draw_shadow(canvas, path, kHeight, SK_ColorBLUE, lightPos, kLightR, 82 false, flags); 83 } else if (kGrayscale == mode) { 84 SkShadowUtils::DrawShadow(canvas, path, kHeight, lightPos, kLightR, 85 0.1f, 0.25f, SK_ColorBLACK, flags); 86 } 87 88 SkPaint paint; 89 paint.setAntiAlias(true); 90 if (kDebugColorNoOccluders == mode) { 91 // Draw the path outline in green on top of the ambient and spot shadows. 92 if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) { 93 paint.setColor(SK_ColorCYAN); 94 } else { 95 paint.setColor(SK_ColorGREEN); 96 } 97 paint.setStyle(SkPaint::kStroke_Style); 98 paint.setStrokeWidth(0); 99 } else { 100 paint.setColor(kDebugColorOccluders == mode ? SK_ColorLTGRAY : SK_ColorWHITE); 101 if (SkToBool(flags & kTransparentOccluder_ShadowFlag)) { 102 paint.setAlpha(128); 103 } 104 paint.setStyle(SkPaint::kFill_Style); 105 } 106 canvas->drawPath(path, paint); 107 canvas->restore(); 108 109 canvas->translate(dx, 0); 110 x += dx; 111 dy = SkTMax(dy, postMBounds.height() + kPad + kHeight); 112 } 113 } 114 } 115 // Show where the light is in x,y as a circle (specified in device space). 116 SkMatrix invCanvasM = canvas->getTotalMatrix(); 117 if (invCanvasM.invert(&invCanvasM)) { 118 canvas->save(); 119 canvas->concat(invCanvasM); 120 SkPaint paint; 121 paint.setColor(SK_ColorBLACK); 122 paint.setAntiAlias(true); 123 canvas->drawCircle(lightPos.fX, lightPos.fY, kLightR / 10.f, paint); 124 canvas->restore(); 125 } 126 } 127 128 DEF_SIMPLE_GM(shadow_utils, canvas, kW, kH) { 129 draw_paths(canvas, kDebugColorNoOccluders); 130 } 131 132 DEF_SIMPLE_GM(shadow_utils_occl, canvas, kW, kH) { 133 draw_paths(canvas, kDebugColorOccluders); 134 } 135 136 DEF_SIMPLE_GM(shadow_utils_gray, canvas, kW, kH) { 137 draw_paths(canvas, kGrayscale); 138 } 139