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