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