SampleAndroidShadows.cpp revision e7705780c9450bb190abddc47a78b8b89784ed79
1
2/*
3 * Copyright 2016 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 "SampleCode.h"
9#include "SkAnimTimer.h"
10#include "SkBlurMask.h"
11#include "SkBlurMaskFilter.h"
12#include "SkColorFilter.h"
13#include "SkCamera.h"
14#include "SkCanvas.h"
15#include "SkGaussianEdgeShader.h"
16#include "SkPath.h"
17#include "SkPathOps.h"
18#include "SkPoint3.h"
19#include "SkShadowUtils.h"
20#include "SkUtils.h"
21#include "SkView.h"
22#include "sk_tool_utils.h"
23
24////////////////////////////////////////////////////////////////////////////
25
26class ShadowsView : public SampleView {
27    SkPath    fRectPath;
28    SkPath    fRRPath;
29    SkPath    fCirclePath;
30    SkPath    fFunkyRRPath;
31    SkPath    fCubicPath;
32    SkPath    fSquareRRectPath;
33    SkPath    fWideRectPath;
34    SkPath    fWideOvalPath;
35    SkPoint3  fLightPos;
36    SkScalar  fZDelta;
37    SkScalar  fAnimTranslate;
38    SkScalar  fAnimAngle;
39
40    bool      fShowAmbient;
41    bool      fShowSpot;
42    bool      fUseAlt;
43    bool      fShowObject;
44    bool      fIgnoreShadowAlpha;
45
46public:
47    ShadowsView()
48        : fZDelta(0)
49        , fAnimTranslate(0)
50        , fAnimAngle(0)
51        , fShowAmbient(true)
52        , fShowSpot(true)
53        , fUseAlt(false)
54        , fShowObject(true)
55        , fIgnoreShadowAlpha(false) {}
56
57protected:
58    void onOnceBeforeDraw() override {
59        fCirclePath.addCircle(0, 0, 50);
60        fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100));
61        fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4));
62        fFunkyRRPath.addRoundRect(SkRect::MakeXYWH(-50, -50, SK_Scalar1 * 100, SK_Scalar1 * 100),
63                                  40 * SK_Scalar1, 20 * SK_Scalar1,
64                                  SkPath::kCW_Direction);
65        fCubicPath.cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1,
66                           20 * SK_Scalar1, 100 * SK_Scalar1,
67                           0 * SK_Scalar1, 0 * SK_Scalar1);
68        fSquareRRectPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-50, -50, 100, 100),
69                                                      10, 10));
70        fWideRectPath.addRect(SkRect::MakeXYWH(0, 0, 630, 70));
71        fWideOvalPath.addOval(SkRect::MakeXYWH(0, 0, 630, 70));
72
73        fLightPos = SkPoint3::Make(350, 0, 600);
74    }
75
76    // overrides from SkEventSink
77    bool onQuery(SkEvent* evt) override {
78        if (SampleCode::TitleQ(*evt)) {
79            SampleCode::TitleR(evt, "AndroidShadows");
80            return true;
81        }
82
83        SkUnichar uni;
84        if (SampleCode::CharQ(*evt, &uni)) {
85            bool handled = false;
86            switch (uni) {
87                case 'W':
88                    fShowAmbient = !fShowAmbient;
89                    handled = true;
90                    break;
91                case 'S':
92                    fShowSpot = !fShowSpot;
93                    handled = true;
94                    break;
95                case 'T':
96                    fUseAlt = !fUseAlt;
97                    handled = true;
98                    break;
99                case 'O':
100                    fShowObject = !fShowObject;
101                    handled = true;
102                    break;
103                case '>':
104                    fZDelta += 0.5f;
105                    handled = true;
106                    break;
107                case '<':
108                    fZDelta -= 0.5f;
109                    handled = true;
110                    break;
111                case '?':
112                    fIgnoreShadowAlpha = !fIgnoreShadowAlpha;
113                    handled = true;
114                    break;
115                default:
116                    break;
117            }
118            if (handled) {
119                this->inval(nullptr);
120                return true;
121            }
122        }
123        return this->INHERITED::onQuery(evt);
124    }
125
126    void drawBG(SkCanvas* canvas) {
127        canvas->drawColor(0xFFDDDDDD);
128    }
129
130    void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
131                          std::function<SkScalar(SkScalar, SkScalar)> zFunc,
132                          const SkPaint& paint, SkScalar ambientAlpha,
133                          const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
134        if (fIgnoreShadowAlpha) {
135            ambientAlpha = 255;
136            spotAlpha = 255;
137        }
138        if (!fShowAmbient) {
139            ambientAlpha = 0;
140        }
141        if (!fShowSpot) {
142            spotAlpha = 0;
143        }
144        uint32_t flags = 0;
145        if (fUseAlt) {
146            flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
147        }
148        //SkShadowUtils::DrawShadow(canvas, path,
149        //                          zValue,
150        //                          lightPos, lightWidth,
151        //                          ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
152        SkShadowUtils::DrawUncachedShadow(canvas, path, zFunc,
153                                          lightPos, lightWidth,
154                                          ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
155
156        if (fShowObject) {
157            canvas->drawPath(path, paint);
158        } else {
159            SkPaint strokePaint;
160
161            strokePaint.setColor(paint.getColor());
162            strokePaint.setStyle(SkPaint::kStroke_Style);
163
164            canvas->drawPath(path, strokePaint);
165        }
166    }
167
168    void onDrawContent(SkCanvas* canvas) override {
169        this->drawBG(canvas);
170        const SkScalar kLightWidth = 800;
171        const SkScalar kAmbientAlpha = 0.1f;
172        const SkScalar kSpotAlpha = 0.25f;
173
174        SkPaint paint;
175        paint.setAntiAlias(true);
176
177        SkPoint3 lightPos = fLightPos;
178
179        paint.setColor(SK_ColorWHITE);
180        canvas->translate(200, 90);
181        SkScalar zValue = SkTMax(1.0f, 2 + fZDelta);
182        std::function<SkScalar(SkScalar, SkScalar)> zFunc =
183            [zValue](SkScalar, SkScalar) { return zValue; };
184        this->drawShadowedPath(canvas, fRRPath, zFunc, paint, kAmbientAlpha,
185                               lightPos, kLightWidth, kSpotAlpha);
186
187        paint.setColor(SK_ColorRED);
188        canvas->translate(250, 0);
189        zValue = SkTMax(1.0f, 8 + fZDelta);
190        zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
191        this->drawShadowedPath(canvas, fRectPath, zFunc, paint, kAmbientAlpha,
192                               lightPos, kLightWidth, kSpotAlpha);
193
194        paint.setColor(SK_ColorBLUE);
195        canvas->translate(-250, 110);
196        zValue = SkTMax(1.0f, 12 + fZDelta);
197        zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
198        this->drawShadowedPath(canvas, fCirclePath, zFunc, paint, kAmbientAlpha,
199                               lightPos, kLightWidth, 0.5f);
200
201        paint.setColor(SK_ColorGREEN);
202        canvas->translate(250, 0);
203        zValue = SkTMax(1.0f, 64 + fZDelta);
204        zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
205        this->drawShadowedPath(canvas, fRRPath, zFunc, paint, kAmbientAlpha,
206                               lightPos, kLightWidth, kSpotAlpha);
207
208        paint.setColor(SK_ColorYELLOW);
209        canvas->translate(-250, 110);
210        zValue = SkTMax(1.0f, 8 + fZDelta);
211        zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
212        this->drawShadowedPath(canvas, fFunkyRRPath, zFunc, paint, kAmbientAlpha,
213                               lightPos, kLightWidth, kSpotAlpha);
214
215        paint.setColor(SK_ColorCYAN);
216        canvas->translate(250, 0);
217        zValue = SkTMax(1.0f, 16 + fZDelta);
218        zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
219        this->drawShadowedPath(canvas, fCubicPath, zFunc, paint,
220                               kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha);
221
222        // circular reveal
223        SkPath tmpPath;
224        SkPath tmpClipPath;
225        tmpClipPath.addCircle(fAnimTranslate, 0, 60);
226        Op(fSquareRRectPath, tmpClipPath, kIntersect_SkPathOp, &tmpPath);
227
228        paint.setColor(SK_ColorMAGENTA);
229        canvas->translate(-125, 60);
230        zValue = SkTMax(1.0f, 32 + fZDelta);
231        zFunc = [zValue](SkScalar, SkScalar) { return zValue; };
232        this->drawShadowedPath(canvas, tmpPath, zFunc, paint, .1f,
233                               lightPos, kLightWidth, .5f);
234
235        // perspective paths
236        SkPoint pivot = SkPoint::Make(fWideRectPath.getBounds().width()/2,
237                                      fWideRectPath.getBounds().height()/2);
238        SkPoint translate = SkPoint::Make(100, 450);
239        paint.setColor(SK_ColorWHITE);
240        Sk3DView view;
241        view.save();
242        view.rotateX(fAnimAngle);
243        SkMatrix persp;
244        view.getMatrix(&persp);
245        persp.preTranslate(-pivot.fX, -pivot.fY);
246        persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
247        canvas->setMatrix(persp);
248        zValue = SkTMax(1.0f, 16 + fZDelta);
249        SkScalar radians = SkDegreesToRadians(fAnimAngle);
250        zFunc = [zValue, pivot, radians](SkScalar x, SkScalar y) {
251            return SkScalarSin(-radians)*y +
252                   zValue - SkScalarSin(-radians)*pivot.fY;
253        };
254        this->drawShadowedPath(canvas, fWideRectPath, zFunc, paint, .1f,
255                               lightPos, kLightWidth, .5f);
256
257        pivot = SkPoint::Make(fWideOvalPath.getBounds().width() / 2,
258                              fWideOvalPath.getBounds().height() / 2);
259        translate = SkPoint::Make(100, 600);
260        view.restore();
261        view.rotateY(fAnimAngle);
262        view.getMatrix(&persp);
263        persp.preTranslate(-pivot.fX, -pivot.fY);
264        persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
265        canvas->setMatrix(persp);
266        zValue = SkTMax(1.0f, 32 + fZDelta);
267        zFunc = [zValue, pivot, radians](SkScalar x, SkScalar y) {
268            return -SkScalarSin(radians)*x +
269                zValue + SkScalarSin(radians)*pivot.fX;
270        };
271        this->drawShadowedPath(canvas, fWideOvalPath, zFunc, paint, .1f,
272                               lightPos, kLightWidth, .5f);
273    }
274
275    bool onAnimate(const SkAnimTimer& timer) override {
276        fAnimTranslate = timer.pingPong(30, 0, 200, -200);
277        fAnimAngle = timer.pingPong(15, 0, 0, 20);
278
279        return true;
280    }
281
282private:
283    typedef SampleView INHERITED;
284};
285
286//////////////////////////////////////////////////////////////////////////////
287
288static SkView* MyFactory() { return new ShadowsView; }
289static SkViewRegister reg(MyFactory);
290