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