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