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/Sample.h"
9#include "tools/Resources.h"
10
11#include "include/core/SkCanvas.h"
12#include "include/core/SkFont.h"
13#include "include/core/SkImage.h"
14#include "include/core/SkPath.h"
15#include "include/core/SkPoint3.h"
16#include "include/utils/SkShadowUtils.h"
17
18////////////////////////////////////////////////////////////////////////////
19// Sample to demonstrate tonal color shadows
20
21class ShadowColorView : public Sample {
22    SkPath    fRectPath;
23    int       fZIndex;
24
25    bool      fShowAmbient;
26    bool      fShowSpot;
27    bool      fUseAlt;
28    bool      fShowObject;
29    bool      fTwoPassColor;
30    bool      fDarkBackground;
31
32public:
33    ShadowColorView()
34        : fZIndex(8)
35        , fShowAmbient(true)
36        , fShowSpot(true)
37        , fUseAlt(false)
38        , fShowObject(true)
39        , fTwoPassColor(false)
40        , fDarkBackground(false) {}
41
42protected:
43    void onOnceBeforeDraw() override {
44        fRectPath.addRect(SkRect::MakeXYWH(-50, -50, 100, 100));
45    }
46
47    SkString name() override { return SkString("ShadowColor"); }
48
49    bool onChar(SkUnichar uni) override {
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                case 'X':
69                    fTwoPassColor = !fTwoPassColor;
70                    handled = true;
71                    break;
72                case 'Z':
73                    fDarkBackground = !fDarkBackground;
74                    handled = true;
75                    break;
76                case '>':
77                    fZIndex = std::min(9, fZIndex+1);
78                    handled = true;
79                    break;
80                case '<':
81                    fZIndex = std::max(0, fZIndex-1);
82                    handled = true;
83                    break;
84                default:
85                    break;
86            }
87            if (handled) {
88                return true;
89            }
90            return false;
91    }
92
93
94    void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
95                          const SkPoint3& zPlaneParams,
96                          const SkPaint& paint, SkScalar ambientAlpha,
97                          const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
98        if (!fShowAmbient) {
99            ambientAlpha = 0;
100        }
101        if (!fShowSpot) {
102            spotAlpha = 0;
103        }
104        uint32_t flags = 0;
105        if (fUseAlt) {
106            flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
107        }
108
109        if (fTwoPassColor) {
110            SkColor ambientColor = SkColorSetARGB(ambientAlpha*255, 0, 0, 0);
111            SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
112                                      lightPos, lightWidth,
113                                      ambientColor, SK_ColorTRANSPARENT, flags);
114
115            if (paint.getColor() != SK_ColorBLACK) {
116                SkColor color = paint.getColor();
117
118                uint8_t max = std::max(std::max(SkColorGetR(color), SkColorGetG(color)),
119                                     SkColorGetB(color));
120                uint8_t min = std::min(std::min(SkColorGetR(color), SkColorGetG(color)),
121                                     SkColorGetB(color));
122                SkScalar luminance = 0.5f*(max + min) / 255.f;
123                SkScalar alpha = (.6 - .4*luminance)*luminance*luminance + 0.3f;
124                spotAlpha -= (alpha - 0.3f)*.5f;
125                SkColor spotColor = SkColorSetARGB(alpha*SkColorGetA(color), SkColorGetR(color),
126                                                   SkColorGetG(color), SkColorGetB(color));
127
128                SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
129                                          lightPos, lightWidth,
130                                          SK_ColorTRANSPARENT, spotColor, flags);
131            }
132
133            SkColor spotGreyscale = SkColorSetARGB(spotAlpha * 255, 0, 0, 0);
134            SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
135                                      lightPos, lightWidth,
136                                      SK_ColorTRANSPARENT, spotGreyscale, flags);
137        } else {
138            SkColor color = paint.getColor();
139            SkColor baseAmbient = SkColorSetARGB(ambientAlpha*SkColorGetA(color),
140                                                 SkColorGetR(color), SkColorGetG(color),
141                                                 SkColorGetB(color));
142            SkColor baseSpot = SkColorSetARGB(spotAlpha*SkColorGetA(color),
143                                              SkColorGetR(color), SkColorGetG(color),
144                                              SkColorGetB(color));
145            SkColor tonalAmbient, tonalSpot;
146            SkShadowUtils::ComputeTonalColors(baseAmbient, baseSpot, &tonalAmbient, &tonalSpot);
147            SkShadowUtils::DrawShadow(canvas, path, zPlaneParams,
148                                      lightPos, lightWidth,
149                                      tonalAmbient, tonalSpot, flags);
150        }
151        if (fShowObject) {
152            canvas->drawPath(path, paint);
153        } else {
154            SkPaint strokePaint;
155
156            strokePaint.setColor(paint.getColor());
157            strokePaint.setStyle(SkPaint::kStroke_Style);
158
159            canvas->drawPath(path, strokePaint);
160        }
161    }
162
163    void onDrawContent(SkCanvas* canvas) override {
164        const SkScalar kLightWidth = 600;
165        const SkScalar kAmbientAlpha = 0.03f;
166        const SkScalar kSpotAlpha = 0.25f;
167
168        const SkScalar kZValues[10] = { 1, 2, 3, 4, 6, 8, 9, 12, 16, 24 };
169
170        const SkColor kColors[30] = {
171            // purples
172            0xFF3A0072, 0xFF5D0099, 0xFF7F12B2, 0xFFA02AD1, 0xFFC245E5,
173            0xFFE95AF9, 0xFFFC79F0, 0xFFFDA6F0, 0xFFFFCCF8, 0xFFFFE1F9,
174            // oranges
175            0xFFEA3200, 0xFFFF4E00, 0xFFFF7300, 0xFFFF9100, 0xFFFFB000,
176            0xFFFFCE00, 0xFFFFE000, 0xFFFFF64D, 0xFFFFF98F, 0xFFFFFBCC,
177            // teals
178            0xFF004D51, 0xFF066266, 0xFF057F7F, 0xFF009999, 0xFF00B2B2,
179            0xFF15CCBE, 0xFF25E5CE, 0xFF2CFFE0, 0xFF80FFEA, 0xFFB3FFF0
180        };
181
182        SkFont font;
183        SkPaint paint;
184        paint.setAntiAlias(true);
185        if (fDarkBackground) {
186            canvas->drawColor(0xFF111111);
187            paint.setColor(SK_ColorWHITE);
188        } else {
189            canvas->drawColor(0xFFEAEAEA);
190            paint.setColor(SK_ColorBLACK);
191        }
192        if (fTwoPassColor) {
193            canvas->drawString("Two pass", 10, 15, font, paint);
194        } else {
195            canvas->drawString("One pass", 10, 15, font, paint);
196        }
197
198        SkPoint3 lightPos = { 75, -400, 600 };
199        SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, kZValues[fZIndex]);
200        SkScalar yPos = 75;
201
202        for (int row = 0; row < 3; ++row) {
203            lightPos.fX = 75;
204            SkScalar xPos = 75;
205            for (int col = 0; col < 10; ++col) {
206                paint.setColor(kColors[10*row + col]);
207
208                canvas->save();
209                canvas->translate(xPos, yPos);
210                this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, kAmbientAlpha,
211                                       lightPos, kLightWidth, kSpotAlpha);
212                canvas->restore();
213
214                lightPos.fX += 120;
215                xPos += 120;
216            }
217
218            lightPos.fY += 200;
219            yPos += 200;
220        }
221    }
222
223private:
224    using INHERITED = Sample;
225};
226
227//////////////////////////////////////////////////////////////////////////////
228
229DEF_SAMPLE( return new ShadowColorView(); )
230