• 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/effects/SkBlurMaskFilter.h"
13 #include "include/pathops/SkPathOps.h"
14 #include "include/utils/SkCamera.h"
15 #include "include/utils/SkShadowUtils.h"
16 #include "samplecode/Sample.h"
17 #include "src/core/SkBlurMask.h"
18 #include "src/utils/SkUTF.h"
19 #include "tools/ToolUtils.h"
20 
21 ////////////////////////////////////////////////////////////////////////////
22 
23 class ShadowUtilsView : public Sample {
24     SkTArray<SkPath> fConvexPaths;
25     SkTArray<SkPath> fConcavePaths;
26     SkScalar         fZDelta;
27 
28     bool      fShowAmbient;
29     bool      fShowSpot;
30     bool      fUseAlt;
31     bool      fShowObject;
32     bool      fIgnoreShadowAlpha;
33 
34 public:
ShadowUtilsView()35     ShadowUtilsView()
36         : fZDelta(0)
37         , fShowAmbient(true)
38         , fShowSpot(true)
39         , fUseAlt(false)
40         , fShowObject(false)
41         , fIgnoreShadowAlpha(false) {}
42 
43 protected:
onOnceBeforeDraw()44     void onOnceBeforeDraw() 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 
name()75     SkString name() override { return SkString("ShadowUtils"); }
76 
onChar(SkUnichar uni)77     bool onChar(SkUnichar uni) override {
78             bool handled = false;
79             switch (uni) {
80                 case 'W':
81                     fShowAmbient = !fShowAmbient;
82                     handled = true;
83                     break;
84                 case 'S':
85                     fShowSpot = !fShowSpot;
86                     handled = true;
87                     break;
88                 case 'T':
89                     fUseAlt = !fUseAlt;
90                     handled = true;
91                     break;
92                 case 'O':
93                     fShowObject = !fShowObject;
94                     handled = true;
95                     break;
96                 case '>':
97                     fZDelta += 0.5f;
98                     handled = true;
99                     break;
100                 case '<':
101                     fZDelta -= 0.5f;
102                     handled = true;
103                     break;
104                 case '?':
105                     fIgnoreShadowAlpha = !fIgnoreShadowAlpha;
106                     handled = true;
107                     break;
108                 default:
109                     break;
110             }
111             if (handled) {
112                 return true;
113             }
114             return false;
115     }
116 
drawBG(SkCanvas * canvas)117     void drawBG(SkCanvas* canvas) {
118         canvas->drawColor(0xFFFFFFFF);
119     }
120 
drawShadowedPath(SkCanvas * canvas,const SkPath & path,const SkPoint3 & zPlaneParams,const SkPaint & paint,SkScalar ambientAlpha,const SkPoint3 & lightPos,SkScalar lightWidth,SkScalar spotAlpha,uint32_t flags)121     void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
122                           const SkPoint3& zPlaneParams,
123                           const SkPaint& paint, SkScalar ambientAlpha,
124                           const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha,
125                           uint32_t flags) {
126         if (fIgnoreShadowAlpha) {
127             ambientAlpha = 255;
128             spotAlpha = 255;
129         }
130         if (!fShowAmbient) {
131             ambientAlpha = 0;
132         }
133         if (!fShowSpot) {
134             spotAlpha = 0;
135         }
136         if (fUseAlt) {
137             flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
138         }
139 
140         SkColor ambientColor = SkColorSetARGB(ambientAlpha * 255, 255, 0, 0);
141         SkColor spotColor = SkColorSetARGB(spotAlpha * 255, 0, 0, 255);
142         SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
143                                   lightPos, lightWidth,
144                                   ambientColor, spotColor, flags);
145 
146         if (fShowObject) {
147             canvas->drawPath(path, paint);
148         } else {
149             SkPaint strokePaint;
150 
151             strokePaint.setColor(paint.getColor());
152             strokePaint.setStyle(SkPaint::kStroke_Style);
153 
154             canvas->drawPath(path, strokePaint);
155         }
156     }
157 
onDrawContent(SkCanvas * canvas)158     void onDrawContent(SkCanvas* canvas) override {
159         this->drawBG(canvas);
160 
161         static constexpr int kW = 800;
162         static constexpr SkScalar kPad = 15.f;
163         static constexpr SkScalar kLightR = 100.f;
164         static constexpr SkScalar kHeight = 50.f;
165         static constexpr SkScalar kAmbientAlpha = 0.5f;
166         static constexpr SkScalar kSpotAlpha = 0.5f;
167         static constexpr SkPoint3 lightPos = { 250, 400, 500 };
168 
169         canvas->translate(3 * kPad, 3 * kPad);
170         canvas->save();
171         SkScalar x = 0;
172         SkScalar dy = 0;
173         SkTDArray<SkMatrix> matrices;
174         matrices.push()->reset();
175         SkMatrix* m = matrices.push();
176         m->setRotate(33.f, 25.f, 25.f);
177         m->postScale(1.2f, 0.8f, 25.f, 25.f);
178         SkPaint paint;
179         paint.setColor(SK_ColorGREEN);
180         paint.setAntiAlias(true);
181         SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, SkTMax(1.0f, kHeight + fZDelta));
182 
183         // convex paths
184         for (auto& m : matrices) {
185             for (auto flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) {
186                 for (const auto& path : fConvexPaths) {
187                     SkRect postMBounds = path.getBounds();
188                     m.mapRect(&postMBounds);
189                     SkScalar w = postMBounds.width() + kHeight;
190                     SkScalar dx = w + kPad;
191                     if (x + dx > kW - 3 * kPad) {
192                         canvas->restore();
193                         canvas->translate(0, dy);
194                         canvas->save();
195                         x = 0;
196                         dy = 0;
197                     }
198 
199                     canvas->save();
200                     canvas->concat(m);
201                     this->drawShadowedPath(canvas, path, zPlaneParams, paint, kAmbientAlpha,
202                                            lightPos, kLightR, kSpotAlpha, flags);
203                     canvas->restore();
204 
205                     canvas->translate(dx, 0);
206                     x += dx;
207                     dy = SkTMax(dy, postMBounds.height() + kPad + kHeight);
208                 }
209             }
210         }
211 
212         // concave paths
213         canvas->restore();
214         canvas->translate(kPad, dy);
215         canvas->save();
216         x = kPad;
217         dy = 0;
218         for (auto& m : matrices) {
219             for (const auto& path : fConcavePaths) {
220                 SkRect postMBounds = path.getBounds();
221                 m.mapRect(&postMBounds);
222                 SkScalar w = postMBounds.width();
223                 SkScalar dx = w + kPad;
224 
225                 canvas->save();
226                 canvas->concat(m);
227                 this->drawShadowedPath(canvas, path, zPlaneParams, paint, kAmbientAlpha, lightPos,
228                                        kLightR, kSpotAlpha, kNone_ShadowFlag);
229                 canvas->restore();
230 
231                 canvas->translate(dx, 0);
232                 x += dx;
233                 dy = SkTMax(dy, postMBounds.height() + kPad + kHeight);
234             }
235         }
236 
237         // Show where the light is in x,y as a circle (specified in device space).
238         SkMatrix invCanvasM = canvas->getTotalMatrix();
239         if (invCanvasM.invert(&invCanvasM)) {
240             canvas->save();
241             canvas->concat(invCanvasM);
242             SkPaint paint;
243             paint.setColor(SK_ColorBLACK);
244             paint.setAntiAlias(true);
245             canvas->drawCircle(lightPos.fX, lightPos.fY, kLightR / 10.f, paint);
246             canvas->restore();
247         }
248     }
249 
250 private:
251     typedef Sample INHERITED;
252 };
253 
254 //////////////////////////////////////////////////////////////////////////////
255 
256 DEF_SAMPLE( return new ShadowUtilsView(); )
257