xref: /aosp_15_r20/external/skia/tools/viewer/ShadowUtilsSlide.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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/core/SkRRect.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 using namespace skia_private;
21 
22 ////////////////////////////////////////////////////////////////////////////
23 
24 class ShadowUtilsSlide : public Slide {
25     TArray<SkPath> fConvexPaths;
26     TArray<SkPath> fConcavePaths;
27     SkScalar         fZDelta;
28 
29     bool      fShowAmbient;
30     bool      fShowSpot;
31     bool      fUseAlt;
32     bool      fShowObject;
33     bool      fIgnoreShadowAlpha;
34 
35 public:
ShadowUtilsSlide()36     ShadowUtilsSlide()
37         : fZDelta(0)
38         , fShowAmbient(true)
39         , fShowSpot(true)
40         , fUseAlt(false)
41         , fShowObject(false)
42         , fIgnoreShadowAlpha(false) {
43         fName = "ShadowUtils";
44     }
45 
load(SkScalar w,SkScalar h)46     void load(SkScalar w, SkScalar h) override {
47         fConvexPaths.push_back().addRoundRect(SkRect::MakeWH(50, 50), 10, 10);
48         SkRRect oddRRect;
49         oddRRect.setNinePatch(SkRect::MakeWH(50, 50), 9, 13, 6, 16);
50         fConvexPaths.push_back().addRRect(oddRRect);
51         fConvexPaths.push_back().addRect(SkRect::MakeWH(50, 50));
52         fConvexPaths.push_back().addCircle(25, 25, 25);
53         fConvexPaths.push_back().cubicTo(100, 50, 20, 100, 0, 0);
54         fConvexPaths.push_back().addOval(SkRect::MakeWH(20, 60));
55 
56         // star
57         fConcavePaths.push_back().moveTo(0.0f, -33.3333f);
58         fConcavePaths.back().lineTo(9.62f, -16.6667f);
59         fConcavePaths.back().lineTo(28.867f, -16.6667f);
60         fConcavePaths.back().lineTo(19.24f, 0.0f);
61         fConcavePaths.back().lineTo(28.867f, 16.6667f);
62         fConcavePaths.back().lineTo(9.62f, 16.6667f);
63         fConcavePaths.back().lineTo(0.0f, 33.3333f);
64         fConcavePaths.back().lineTo(-9.62f, 16.6667f);
65         fConcavePaths.back().lineTo(-28.867f, 16.6667f);
66         fConcavePaths.back().lineTo(-19.24f, 0.0f);
67         fConcavePaths.back().lineTo(-28.867f, -16.6667f);
68         fConcavePaths.back().lineTo(-9.62f, -16.6667f);
69         fConcavePaths.back().close();
70 
71         // dumbbell
72         fConcavePaths.push_back().moveTo(50, 0);
73         fConcavePaths.back().cubicTo(100, 25, 60, 50, 50, 0);
74         fConcavePaths.back().cubicTo(0, -25, 40, -50, 50, 0);
75     }
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 
draw(SkCanvas * canvas)117     void draw(SkCanvas* canvas) override {
118         this->drawBG(canvas);
119 
120         static constexpr int kW = 800;
121         static constexpr SkScalar kPad = 15.f;
122         static constexpr SkScalar kLightR = 100.f;
123         static constexpr SkScalar kHeight = 50.f;
124         static constexpr SkScalar kAmbientAlpha = 0.5f;
125         static constexpr SkScalar kSpotAlpha = 0.5f;
126         static constexpr SkPoint3 lightPos = { 250, 400, 500 };
127 
128         canvas->translate(3 * kPad, 3 * kPad);
129         canvas->save();
130         SkScalar x = 0;
131         SkScalar dy = 0;
132         SkTDArray<SkMatrix> matrices;
133         matrices.append()->reset();
134         matrices.append()->setRotate(33.f, 25.f, 25.f).postScale(1.2f, 0.8f, 25.f, 25.f);
135         SkPaint greenPaint;
136         greenPaint.setColor(SK_ColorGREEN);
137         greenPaint.setAntiAlias(true);
138         SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, std::max(1.0f, kHeight + fZDelta));
139 
140         // convex paths
141         for (auto& m : matrices) {
142             for (auto flags : { kNone_ShadowFlag, kTransparentOccluder_ShadowFlag }) {
143                 for (const auto& path : fConvexPaths) {
144                     SkRect postMBounds = path.getBounds();
145                     m.mapRect(&postMBounds);
146                     SkScalar w = postMBounds.width() + kHeight;
147                     SkScalar dx = w + kPad;
148                     if (x + dx > kW - 3 * kPad) {
149                         canvas->restore();
150                         canvas->translate(0, dy);
151                         canvas->save();
152                         x = 0;
153                         dy = 0;
154                     }
155 
156                     canvas->save();
157                     canvas->concat(m);
158                     this->drawShadowedPath(canvas, path, zPlaneParams, greenPaint, kAmbientAlpha,
159                                            lightPos, kLightR, kSpotAlpha, flags);
160                     canvas->restore();
161 
162                     canvas->translate(dx, 0);
163                     x += dx;
164                     dy = std::max(dy, postMBounds.height() + kPad + kHeight);
165                 }
166             }
167         }
168 
169         // concave paths
170         canvas->restore();
171         canvas->translate(kPad, dy);
172         canvas->save();
173         x = kPad;
174         dy = 0;
175         for (auto& m : matrices) {
176             for (const auto& path : fConcavePaths) {
177                 SkRect postMBounds = path.getBounds();
178                 m.mapRect(&postMBounds);
179                 SkScalar w = postMBounds.width();
180                 SkScalar dx = w + kPad;
181 
182                 canvas->save();
183                 canvas->concat(m);
184                 this->drawShadowedPath(canvas, path, zPlaneParams, greenPaint, kAmbientAlpha,
185                                        lightPos, kLightR, kSpotAlpha, kNone_ShadowFlag);
186                 canvas->restore();
187 
188                 canvas->translate(dx, 0);
189                 x += dx;
190                 dy = std::max(dy, postMBounds.height() + kPad + kHeight);
191             }
192         }
193 
194         // Show where the light is in x,y as a circle (specified in device space).
195         SkMatrix invCanvasM = canvas->getTotalMatrix();
196         if (invCanvasM.invert(&invCanvasM)) {
197             canvas->save();
198             canvas->concat(invCanvasM);
199             SkPaint blackPaint;
200             blackPaint.setColor(SK_ColorBLACK);
201             blackPaint.setAntiAlias(true);
202             canvas->drawCircle(lightPos.fX, lightPos.fY, kLightR / 10.f, blackPaint);
203             canvas->restore();
204         }
205     }
206 
207 private:
drawBG(SkCanvas * canvas)208     void drawBG(SkCanvas* canvas) {
209         canvas->drawColor(0xFFFFFFFF);
210     }
211 
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     void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
213                           const SkPoint3& zPlaneParams,
214                           const SkPaint& paint, SkScalar ambientAlpha,
215                           const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha,
216                           uint32_t flags) {
217         if (fIgnoreShadowAlpha) {
218             ambientAlpha = 255;
219             spotAlpha = 255;
220         }
221         if (!fShowAmbient) {
222             ambientAlpha = 0;
223         }
224         if (!fShowSpot) {
225             spotAlpha = 0;
226         }
227         if (fUseAlt) {
228             flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
229         }
230 
231         SkColor ambientColor = SkColorSetARGB(ambientAlpha * 255, 255, 0, 0);
232         SkColor spotColor = SkColorSetARGB(spotAlpha * 255, 0, 0, 255);
233         SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
234                                   lightPos, lightWidth,
235                                   ambientColor, spotColor, flags);
236 
237         if (fShowObject) {
238             canvas->drawPath(path, paint);
239         } else {
240             SkPaint strokePaint;
241 
242             strokePaint.setColor(paint.getColor());
243             strokePaint.setStyle(SkPaint::kStroke_Style);
244 
245             canvas->drawPath(path, strokePaint);
246         }
247     }
248 };
249 
250 //////////////////////////////////////////////////////////////////////////////
251 
252 DEF_SLIDE( return new ShadowUtilsSlide(); )
253