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("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                this->inval(nullptr);
73                return true;
74            }
75        }
76        return this->INHERITED::onQuery(evt);
77    }
78
79    void drawBG(SkCanvas* canvas) {
80        canvas->drawColor(0xFFFFFFFF);
81        canvas->drawImage(fReferenceImage, 10, 30);
82    }
83
84    void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
85                          const SkPoint3& zPlaneParams,
86                          const SkPaint& paint, SkScalar ambientAlpha,
87                          const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
88        if (!fShowAmbient) {
89            ambientAlpha = 0;
90        }
91        if (!fShowSpot) {
92            spotAlpha = 0;
93        }
94        uint32_t flags = 0;
95        if (fUseAlt) {
96            flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
97        }
98        SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
99                                  lightPos, lightWidth,
100                                  ambientAlpha, spotAlpha, SK_ColorBLACK, flags);
101
102        if (fShowObject) {
103            canvas->drawPath(path, paint);
104        } else {
105            SkPaint strokePaint;
106
107            strokePaint.setColor(paint.getColor());
108            strokePaint.setStyle(SkPaint::kStroke_Style);
109
110            canvas->drawPath(path, strokePaint);
111        }
112    }
113
114    void onDrawContent(SkCanvas* canvas) override {
115        this->drawBG(canvas);
116        const SkScalar kDP = 4;  // the reference image is 4x bigger than it is displayed on
117                                 // on the web page, so we need to reflect that here and
118                                 // multiply the heights and light params accordingly
119        const SkScalar kLightWidth = kDP*400;
120        const SkScalar kAmbientAlpha = 0.03f;
121        const SkScalar kSpotAlpha = 0.35f;
122
123        SkPaint paint;
124        paint.setAntiAlias(true);
125        paint.setColor(SK_ColorWHITE);
126
127        SkPoint3 lightPos = { 175, -800, kDP * 600 };
128        SkScalar xPos = 230;
129        SkScalar yPos = 254.25f;
130        SkRect clipRect = SkRect::MakeXYWH(45, 75, 122, 250);
131        SkPoint clipDelta = SkPoint::Make(320, 0);
132        SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, kDP * 2);
133
134        canvas->save();
135        canvas->clipRect(clipRect);
136        canvas->translate(xPos, yPos);
137        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
138                               lightPos, kLightWidth, kSpotAlpha);
139        canvas->restore();
140
141        lightPos.fX += 320;
142        xPos += 320;
143        clipRect.offset(clipDelta);
144        zPlaneParams.fZ = kDP * 3;
145        canvas->save();
146        canvas->clipRect(clipRect);
147        canvas->translate(xPos, yPos);
148        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
149                               lightPos, kLightWidth, kSpotAlpha);
150        canvas->restore();
151
152        lightPos.fX += 320;
153        xPos += 320;
154        clipRect.offset(clipDelta);
155        zPlaneParams.fZ = kDP * 4;
156        canvas->save();
157        canvas->clipRect(clipRect);
158        canvas->translate(xPos, yPos);
159        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
160                               lightPos, kLightWidth, kSpotAlpha);
161        canvas->restore();
162
163        lightPos.fX += 320;
164        xPos += 320;
165        clipRect.offset(clipDelta);
166        zPlaneParams.fZ = kDP * 6;
167        canvas->save();
168        canvas->clipRect(clipRect);
169        canvas->translate(xPos, yPos);
170        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
171                               lightPos, kLightWidth, kSpotAlpha);
172        canvas->restore();
173
174        lightPos.fX += 320;
175        xPos += 320;
176        clipRect.offset(clipDelta);
177        zPlaneParams.fZ = kDP * 8;
178        canvas->save();
179        canvas->clipRect(clipRect);
180        canvas->translate(xPos, yPos);
181        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
182                               lightPos, kLightWidth, kSpotAlpha);
183        canvas->restore();
184
185        lightPos.fX += 320;
186        xPos += 320;
187        clipRect.offset(clipDelta);
188        zPlaneParams.fZ = kDP * 16;
189        canvas->save();
190        canvas->clipRect(clipRect);
191        canvas->translate(xPos, yPos);
192        this->drawShadowedPath(canvas, fRRectPath, zPlaneParams, paint, kAmbientAlpha,
193                               lightPos, kLightWidth, kSpotAlpha);
194        canvas->restore();
195
196    }
197
198private:
199    typedef SampleView INHERITED;
200};
201
202//////////////////////////////////////////////////////////////////////////////
203
204static SkView* MyFactory() { return new ShadowRefView; }
205static SkViewRegister reg(MyFactory);
206