• 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 "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