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 "SampleCode.h"
9#include "Resources.h"
10#include "SkCanvas.h"
11#include "SkImage.h"
12#include "SkPath.h"
13#include "SkPoint3.h"
14#include "SkShadowUtils.h"
15
16////////////////////////////////////////////////////////////////////////////
17// Sample to compare the Material Design shadow reference to our results
18
19class ShadowRefView : public SampleView {
20    SkPath         fRRectPath;
21    sk_sp<SkImage> fReferenceImage;
22
23    bool      fShowAmbient;
24    bool      fShowSpot;
25    bool      fUseAlt;
26    bool      fShowObject;
27
28public:
29    ShadowRefView()
30        : fShowAmbient(true)
31        , fShowSpot(true)
32        , fUseAlt(false)
33        , fShowObject(true) {}
34
35protected:
36    void onOnceBeforeDraw() override {
37        fRRectPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-130, -128.5, 130, 128.5), 4, 4));
38        fReferenceImage = GetResourceAsImage("images/shadowreference.png");
39    }
40
41    // overrides from SkEventSink
42    bool onQuery(SkEvent* evt) override {
43        if (SampleCode::TitleQ(*evt)) {
44            SampleCode::TitleR(evt, "ShadowReference");
45            return true;
46        }
47
48        SkUnichar uni;
49        if (SampleCode::CharQ(*evt, &uni)) {
50            bool handled = false;
51            switch (uni) {
52                case 'W':
53                    fShowAmbient = !fShowAmbient;
54                    handled = true;
55                    break;
56                case 'S':
57                    fShowSpot = !fShowSpot;
58                    handled = true;
59                    break;
60                case 'T':
61                    fUseAlt = !fUseAlt;
62                    handled = true;
63                    break;
64                case 'O':
65                    fShowObject = !fShowObject;
66                    handled = true;
67                    break;
68                default:
69                    break;
70            }
71            if (handled) {
72                return true;
73            }
74        }
75        return this->INHERITED::onQuery(evt);
76    }
77
78    void drawBG(SkCanvas* canvas) {
79        canvas->drawColor(0xFFFFFFFF);
80        canvas->drawImage(fReferenceImage, 10, 30);
81    }
82
83    void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
84                          const SkPoint3& zPlaneParams,
85                          const SkPaint& paint, SkScalar ambientAlpha,
86                          const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
87        if (!fShowAmbient) {
88            ambientAlpha = 0;
89        }
90        if (!fShowSpot) {
91            spotAlpha = 0;
92        }
93        uint32_t flags = 0;
94        if (fUseAlt) {
95            flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
96        }
97        SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
98                                  lightPos, lightWidth,
99                                  ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
100
101        if (fShowObject) {
102            canvas->drawPath(path, paint);
103        } else {
104            SkPaint strokePaint;
105
106            strokePaint.setColor(paint.getColor());
107            strokePaint.setStyle(SkPaint::kStroke_Style);
108
109            canvas->drawPath(path, strokePaint);
110        }
111    }
112
113    void onDrawContent(SkCanvas* canvas) override {
114        this->drawBG(canvas);
115        const SkScalar kDP = 4;  // the reference image is 4x bigger than it is displayed on
116                                 // on the web page, so we need to reflect that here and
117                                 // multiply the heights and light params accordingly
118        const SkScalar kLightWidth = kDP*400;
119        const SkScalar kAmbientAlpha = 0.03f;
120        const SkScalar kSpotAlpha = 0.35f;
121
122        SkPaint paint;
123        paint.setAntiAlias(true);
124        paint.setColor(SK_ColorWHITE);
125
126        SkPoint3 lightPos = { 175, -800, kDP * 600 };
127        SkScalar xPos = 230;
128        SkScalar yPos = 254.25f;
129        SkRect clipRect = SkRect::MakeXYWH(45, 75, 122, 250);
130        SkPoint clipDelta = SkPoint::Make(320, 0);
131        SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, kDP * 2);
132
133        canvas->save();
134        canvas->clipRect(clipRect);
135        canvas->translate(xPos, yPos);
136        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
137                               lightPos, kLightWidth, kSpotAlpha);
138        canvas->restore();
139
140        lightPos.fX += 320;
141        xPos += 320;
142        clipRect.offset(clipDelta);
143        zPlaneParams.fZ = kDP * 3;
144        canvas->save();
145        canvas->clipRect(clipRect);
146        canvas->translate(xPos, yPos);
147        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
148                               lightPos, kLightWidth, kSpotAlpha);
149        canvas->restore();
150
151        lightPos.fX += 320;
152        xPos += 320;
153        clipRect.offset(clipDelta);
154        zPlaneParams.fZ = kDP * 4;
155        canvas->save();
156        canvas->clipRect(clipRect);
157        canvas->translate(xPos, yPos);
158        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
159                               lightPos, kLightWidth, kSpotAlpha);
160        canvas->restore();
161
162        lightPos.fX += 320;
163        xPos += 320;
164        clipRect.offset(clipDelta);
165        zPlaneParams.fZ = kDP * 6;
166        canvas->save();
167        canvas->clipRect(clipRect);
168        canvas->translate(xPos, yPos);
169        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
170                               lightPos, kLightWidth, kSpotAlpha);
171        canvas->restore();
172
173        lightPos.fX += 320;
174        xPos += 320;
175        clipRect.offset(clipDelta);
176        zPlaneParams.fZ = kDP * 8;
177        canvas->save();
178        canvas->clipRect(clipRect);
179        canvas->translate(xPos, yPos);
180        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
181                               lightPos, kLightWidth, kSpotAlpha);
182        canvas->restore();
183
184        lightPos.fX += 320;
185        xPos += 320;
186        clipRect.offset(clipDelta);
187        zPlaneParams.fZ = kDP * 16;
188        canvas->save();
189        canvas->clipRect(clipRect);
190        canvas->translate(xPos, yPos);
191        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
192                               lightPos, kLightWidth, kSpotAlpha);
193        canvas->restore();
194
195    }
196
197private:
198    typedef SampleView INHERITED;
199};
200
201//////////////////////////////////////////////////////////////////////////////
202
203static SkView* MyFactory() { return new ShadowRefView; }
204static SkViewRegister reg(MyFactory);
205