1
2 /*
3 * Copyright 2016 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 "SkAnimTimer.h"
10 #include "SkBlurMask.h"
11 #include "SkBlurMaskFilter.h"
12 #include "SkColorFilter.h"
13 #include "SkCamera.h"
14 #include "SkCanvas.h"
15 #include "SkPath.h"
16 #include "SkPathOps.h"
17 #include "SkPoint3.h"
18 #include "SkShadowUtils.h"
19 #include "SkUtils.h"
20 #include "SkView.h"
21 #include "sk_tool_utils.h"
22
23 ////////////////////////////////////////////////////////////////////////////
24
25 class ShadowsView : public SampleView {
26 SkPath fRectPath;
27 SkPath fRRPath;
28 SkPath fCirclePath;
29 SkPath fFunkyRRPath;
30 SkPath fCubicPath;
31 SkPath fSquareRRectPath;
32 SkPath fWideRectPath;
33 SkPath fWideOvalPath;
34 SkPoint3 fLightPos;
35 SkScalar fZDelta;
36 SkScalar fAnimTranslate;
37 SkScalar fAnimAngle;
38 SkScalar fAnimAlpha;
39
40 bool fShowAmbient;
41 bool fShowSpot;
42 bool fUseAlt;
43 bool fShowObject;
44 bool fIgnoreShadowAlpha;
45 bool fDoAlphaAnimation;
46
47 public:
ShadowsView()48 ShadowsView()
49 : fZDelta(0)
50 , fAnimTranslate(0)
51 , fAnimAngle(0)
52 , fAnimAlpha(1)
53 , fShowAmbient(true)
54 , fShowSpot(true)
55 , fUseAlt(false)
56 , fShowObject(true)
57 , fIgnoreShadowAlpha(false)
58 , fDoAlphaAnimation(false) {}
59
60 protected:
onOnceBeforeDraw()61 void onOnceBeforeDraw() override {
62 fCirclePath.addCircle(0, 0, 50);
63 fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100));
64 fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4));
65 fFunkyRRPath.addRoundRect(SkRect::MakeXYWH(-50, -50, SK_Scalar1 * 100, SK_Scalar1 * 100),
66 40 * SK_Scalar1, 20 * SK_Scalar1,
67 SkPath::kCW_Direction);
68 fCubicPath.cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1,
69 20 * SK_Scalar1, 100 * SK_Scalar1,
70 0 * SK_Scalar1, 0 * SK_Scalar1);
71 fSquareRRectPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-50, -50, 100, 100),
72 10, 10));
73 fWideRectPath.addRect(SkRect::MakeXYWH(0, 0, 630, 70));
74 fWideOvalPath.addOval(SkRect::MakeXYWH(0, 0, 630, 70));
75
76 fLightPos = SkPoint3::Make(350, 0, 600);
77 }
78
79 // overrides from SkEventSink
onQuery(SkEvent * evt)80 bool onQuery(SkEvent* evt) override {
81 if (SampleCode::TitleQ(*evt)) {
82 SampleCode::TitleR(evt, "AndroidShadows");
83 return true;
84 }
85
86 SkUnichar uni;
87 if (SampleCode::CharQ(*evt, &uni)) {
88 bool handled = false;
89 switch (uni) {
90 case 'W':
91 fShowAmbient = !fShowAmbient;
92 handled = true;
93 break;
94 case 'S':
95 fShowSpot = !fShowSpot;
96 handled = true;
97 break;
98 case 'T':
99 fUseAlt = !fUseAlt;
100 handled = true;
101 break;
102 case 'O':
103 fShowObject = !fShowObject;
104 handled = true;
105 break;
106 case 'N':
107 fDoAlphaAnimation = !fDoAlphaAnimation;
108 if (!fDoAlphaAnimation) {
109 fAnimAlpha = 1;
110 }
111 handled = true;
112 break;
113 case '>':
114 fZDelta += 0.5f;
115 handled = true;
116 break;
117 case '<':
118 fZDelta -= 0.5f;
119 handled = true;
120 break;
121 case '?':
122 fIgnoreShadowAlpha = !fIgnoreShadowAlpha;
123 handled = true;
124 break;
125 default:
126 break;
127 }
128 if (handled) {
129 return true;
130 }
131 }
132 return this->INHERITED::onQuery(evt);
133 }
134
drawBG(SkCanvas * canvas)135 void drawBG(SkCanvas* canvas) {
136 canvas->drawColor(0xFFDDDDDD);
137 }
138
drawShadowedPath(SkCanvas * canvas,const SkPath & path,const SkPoint3 & zPlaneParams,const SkPaint & paint,SkScalar ambientAlpha,const SkPoint3 & lightPos,SkScalar lightWidth,SkScalar spotAlpha)139 void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
140 const SkPoint3& zPlaneParams,
141 const SkPaint& paint, SkScalar ambientAlpha,
142 const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
143 if (fIgnoreShadowAlpha) {
144 ambientAlpha = 255;
145 spotAlpha = 255;
146 }
147 if (!fShowAmbient) {
148 ambientAlpha = 0;
149 }
150 if (!fShowSpot) {
151 spotAlpha = 0;
152 }
153 uint32_t flags = 0;
154 if (fUseAlt) {
155 flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
156 }
157
158 SkColor ambientColor = SkColorSetARGB(ambientAlpha * 255, 0, 0, 0);
159 SkColor spotColor = SkColorSetARGB(spotAlpha * 255, 0, 0, 0);
160 SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, lightPos, lightWidth,
161 ambientColor, spotColor, flags);
162
163 if (fShowObject) {
164 canvas->drawPath(path, paint);
165 } else {
166 SkPaint strokePaint;
167
168 strokePaint.setColor(paint.getColor());
169 strokePaint.setStyle(SkPaint::kStroke_Style);
170
171 canvas->drawPath(path, strokePaint);
172 }
173 }
174
onDrawContent(SkCanvas * canvas)175 void onDrawContent(SkCanvas* canvas) override {
176 this->drawBG(canvas);
177 const SkScalar kLightWidth = 800;
178 const SkScalar kAmbientAlpha = 0.1f;
179 const SkScalar kSpotAlpha = 0.25f;
180
181 SkPaint paint;
182 paint.setAntiAlias(true);
183
184 SkPoint3 lightPos = fLightPos;
185 SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, 0);
186
187 paint.setColor(SK_ColorWHITE);
188 canvas->translate(200, 90);
189 zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta);
190 this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
191 lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
192
193 paint.setColor(SK_ColorRED);
194 canvas->translate(250, 0);
195 zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta);
196 this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
197 lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
198
199 paint.setColor(SK_ColorBLUE);
200 canvas->translate(-250, 110);
201 zPlaneParams.fZ = SkTMax(1.0f, 12 + fZDelta);
202 this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
203 lightPos, kLightWidth, fAnimAlpha*0.5f);
204
205 paint.setColor(SK_ColorGREEN);
206 canvas->translate(250, 0);
207 zPlaneParams.fZ = SkTMax(1.0f, 64 + fZDelta);
208 this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
209 lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
210
211 paint.setColor(SK_ColorYELLOW);
212 canvas->translate(-250, 110);
213 zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta);
214 this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
215 lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
216
217 paint.setColor(SK_ColorCYAN);
218 canvas->translate(250, 0);
219 zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta);
220 this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
221 lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
222
223 // circular reveal
224 SkPath tmpPath;
225 SkPath tmpClipPath;
226 tmpClipPath.addCircle(fAnimTranslate, 0, 60);
227 Op(fSquareRRectPath, tmpClipPath, kIntersect_SkPathOp, &tmpPath);
228
229 paint.setColor(SK_ColorMAGENTA);
230 canvas->translate(-125, 60);
231 zPlaneParams.fZ = SkTMax(1.0f, 32 + fZDelta);
232 this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f,
233 lightPos, kLightWidth, .5f);
234
235 // perspective paths
236 SkPoint pivot = SkPoint::Make(fWideRectPath.getBounds().width()/2,
237 fWideRectPath.getBounds().height()/2);
238 SkPoint translate = SkPoint::Make(100, 450);
239 paint.setColor(SK_ColorWHITE);
240 Sk3DView view;
241 view.save();
242 view.rotateX(fAnimAngle);
243 SkMatrix persp;
244 view.getMatrix(&persp);
245 persp.preTranslate(-pivot.fX, -pivot.fY);
246 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
247 canvas->setMatrix(persp);
248 SkScalar radians = SkDegreesToRadians(fAnimAngle);
249 zPlaneParams = SkPoint3::Make(0,
250 SkScalarSin(-radians),
251 SkTMax(1.0f, 16 + fZDelta) - SkScalarSin(-radians)*pivot.fY);
252 this->drawShadowedPath(canvas, fWideRectPath, zPlaneParams, paint, .1f,
253 lightPos, kLightWidth, .5f);
254
255 pivot = SkPoint::Make(fWideOvalPath.getBounds().width() / 2,
256 fWideOvalPath.getBounds().height() / 2);
257 translate = SkPoint::Make(100, 600);
258 view.restore();
259 view.rotateY(fAnimAngle);
260 view.getMatrix(&persp);
261 persp.preTranslate(-pivot.fX, -pivot.fY);
262 persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
263 canvas->setMatrix(persp);
264 zPlaneParams = SkPoint3::Make(-SkScalarSin(radians),
265 0,
266 SkTMax(1.0f, 32 + fZDelta) + SkScalarSin(radians)*pivot.fX);
267 this->drawShadowedPath(canvas, fWideOvalPath, zPlaneParams, paint, .1f,
268 lightPos, kLightWidth, .5f);
269 }
270
onAnimate(const SkAnimTimer & timer)271 bool onAnimate(const SkAnimTimer& timer) override {
272 fAnimTranslate = timer.pingPong(30, 0, 200, -200);
273 fAnimAngle = timer.pingPong(15, 0, 0, 20);
274 if (fDoAlphaAnimation) {
275 fAnimAlpha = timer.pingPong(5, 0, 1, 0);
276 }
277 return true;
278 }
279
280 private:
281 typedef SampleView INHERITED;
282 };
283
284 //////////////////////////////////////////////////////////////////////////////
285
MyFactory()286 static SkView* MyFactory() { return new ShadowsView; }
287 static SkViewRegister reg(MyFactory);
288