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