• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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