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 "Sample.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 "SkUTF.h"
20 #include "sk_tool_utils.h"
21 
22 ////////////////////////////////////////////////////////////////////////////
23 
24 class ShadowsView : public Sample {
25     SkPath    fRectPath;
26     SkPath    fRRPath;
27     SkPath    fCirclePath;
28     SkPath    fFunkyRRPath;
29     SkPath    fCubicPath;
30     SkPath    fStarPath;
31     SkPath    fSquareRRectPath;
32     SkPath    fWideRectPath;
33     SkPath    fWideOvalPath;
34     SkPath    fNotchPath;
35     SkPath    fTabPath;
36 
37     SkPoint3  fLightPos;
38     SkScalar  fZDelta;
39     SkScalar  fAnimTranslate;
40     SkScalar  fAnimAngle;
41     SkScalar  fAnimAlpha;
42 
43     bool      fShowAmbient;
44     bool      fShowSpot;
45     bool      fUseAlt;
46     bool      fShowObject;
47     bool      fIgnoreShadowAlpha;
48     bool      fDoAlphaAnimation;
49 
50 public:
ShadowsView()51     ShadowsView()
52         : fZDelta(0)
53         , fAnimTranslate(0)
54         , fAnimAngle(0)
55         , fAnimAlpha(1)
56         , fShowAmbient(true)
57         , fShowSpot(true)
58         , fUseAlt(false)
59         , fShowObject(true)
60         , fIgnoreShadowAlpha(false)
61         , fDoAlphaAnimation(false) {}
62 
63 protected:
onOnceBeforeDraw()64     void onOnceBeforeDraw() override {
65         fCirclePath.addCircle(0, 0, 50);
66         fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100));
67         fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4));
68         fFunkyRRPath.addRoundRect(SkRect::MakeXYWH(-50, -50, SK_Scalar1 * 100, SK_Scalar1 * 100),
69                                   40 * SK_Scalar1, 20 * SK_Scalar1,
70                                   SkPath::kCW_Direction);
71         fCubicPath.cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1,
72                            20 * SK_Scalar1, 100 * SK_Scalar1,
73                            0 * SK_Scalar1, 0 * SK_Scalar1);
74         fStarPath.moveTo(0.0f, -50.0f);
75         fStarPath.lineTo(14.43f, -25.0f);
76         fStarPath.lineTo(43.30f, -25.0f);
77         fStarPath.lineTo(28.86f, 0.0f);
78         fStarPath.lineTo(43.30f, 25.0f);
79         fStarPath.lineTo(14.43f, 25.0f);
80         fStarPath.lineTo(0.0f, 50.0f);
81         fStarPath.lineTo(-14.43f, 25.0f);
82         fStarPath.lineTo(-43.30f, 25.0f);
83         fStarPath.lineTo(-28.86f, 0.0f);
84         fStarPath.lineTo(-43.30f, -25.0f);
85         fStarPath.lineTo(-14.43f, -25.0f);
86         fSquareRRectPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-50, -50, 100, 100),
87                                                       10, 10));
88         fWideRectPath.addRect(SkRect::MakeXYWH(0, 0, 630, 70));
89         fWideOvalPath.addOval(SkRect::MakeXYWH(0, 0, 630, 70));
90 
91         fNotchPath.moveTo(0, 80);
92         fNotchPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), -90, -90, false);
93         fNotchPath.lineTo(-75, 100);
94         fNotchPath.lineTo(-75, -100);
95         fNotchPath.lineTo(75, -100);
96         fNotchPath.lineTo(75, 100);
97         fNotchPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 0, -90, false);
98 
99         fTabPath.moveTo(-75, -100);
100         fTabPath.lineTo(75, -100);
101         fTabPath.lineTo(75, 100);
102         fTabPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 0, 90, false);
103         fTabPath.arcTo(SkRect::MakeLTRB(-20, 80, 20, 120), 90, 90, false);
104         fTabPath.lineTo(-75, 100);
105 
106         fLightPos = SkPoint3::Make(350, 0, 600);
107     }
108 
onQuery(Sample::Event * evt)109     bool onQuery(Sample::Event* evt) override {
110         if (Sample::TitleQ(*evt)) {
111             Sample::TitleR(evt, "AndroidShadows");
112             return true;
113         }
114 
115         SkUnichar uni;
116         if (Sample::CharQ(*evt, &uni)) {
117             bool handled = false;
118             switch (uni) {
119                 case 'W':
120                     fShowAmbient = !fShowAmbient;
121                     handled = true;
122                     break;
123                 case 'S':
124                     fShowSpot = !fShowSpot;
125                     handled = true;
126                     break;
127                 case 'T':
128                     fUseAlt = !fUseAlt;
129                     handled = true;
130                     break;
131                 case 'O':
132                     fShowObject = !fShowObject;
133                     handled = true;
134                     break;
135                 case 'N':
136                     fDoAlphaAnimation = !fDoAlphaAnimation;
137                     if (!fDoAlphaAnimation) {
138                         fAnimAlpha = 1;
139                     }
140                     handled = true;
141                     break;
142                 case '>':
143                     fZDelta += 0.5f;
144                     handled = true;
145                     break;
146                 case '<':
147                     fZDelta -= 0.5f;
148                     handled = true;
149                     break;
150                 case '?':
151                     fIgnoreShadowAlpha = !fIgnoreShadowAlpha;
152                     handled = true;
153                     break;
154                 default:
155                     break;
156             }
157             if (handled) {
158                 return true;
159             }
160         }
161         return this->INHERITED::onQuery(evt);
162     }
163 
drawBG(SkCanvas * canvas)164     void drawBG(SkCanvas* canvas) {
165         canvas->drawColor(0xFFDDDDDD);
166     }
167 
drawShadowedPath(SkCanvas * canvas,const SkPath & path,const SkPoint3 & zPlaneParams,const SkPaint & paint,SkScalar ambientAlpha,const SkPoint3 & lightPos,SkScalar lightWidth,SkScalar spotAlpha)168     void drawShadowedPath(SkCanvas* canvas, const SkPath& path,
169                           const SkPoint3& zPlaneParams,
170                           const SkPaint& paint, SkScalar ambientAlpha,
171                           const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
172         if (fIgnoreShadowAlpha) {
173             ambientAlpha = 1;
174             spotAlpha = 1;
175         }
176         if (!fShowAmbient) {
177             ambientAlpha = 0;
178         }
179         if (!fShowSpot) {
180             spotAlpha = 0;
181         }
182         uint32_t flags = 0;
183         if (fUseAlt) {
184             flags |= SkShadowFlags::kGeometricOnly_ShadowFlag;
185         }
186 
187         SkColor ambientColor = SkColorSetARGB(ambientAlpha * 255, 0, 0, 0);
188         SkColor spotColor = SkColorSetARGB(spotAlpha * 255, 0, 0, 0);
189         SkShadowUtils::DrawShadow(canvas, path, zPlaneParams, lightPos, lightWidth,
190                                   ambientColor, spotColor, flags);
191 
192         if (fShowObject) {
193             canvas->drawPath(path, paint);
194         } else {
195             SkPaint strokePaint;
196 
197             strokePaint.setColor(paint.getColor());
198             strokePaint.setStyle(SkPaint::kStroke_Style);
199 
200             canvas->drawPath(path, strokePaint);
201         }
202     }
203 
onDrawContent(SkCanvas * canvas)204     void onDrawContent(SkCanvas* canvas) override {
205         this->drawBG(canvas);
206         const SkScalar kLightWidth = 800;
207         const SkScalar kAmbientAlpha = 0.039f;
208         const SkScalar kSpotAlpha = 0.19f;
209 
210         SkPaint paint;
211         paint.setAntiAlias(true);
212 
213         SkPoint3 lightPos = fLightPos;
214         SkPoint3 zPlaneParams = SkPoint3::Make(0, 0, 0);
215 
216         paint.setColor(SK_ColorWHITE);
217         canvas->translate(200, 90);
218         zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta);
219         this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
220                                lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
221 
222         paint.setColor(SK_ColorRED);
223         canvas->translate(250, 0);
224         zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta);
225         this->drawShadowedPath(canvas, fRectPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
226                                lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
227 
228         paint.setColor(SK_ColorBLUE);
229         canvas->translate(-250, 110);
230         zPlaneParams.fZ = SkTMax(1.0f, 12 + fZDelta);
231         this->drawShadowedPath(canvas, fCirclePath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
232                                lightPos, kLightWidth, fAnimAlpha*0.5f);
233 
234         paint.setColor(SK_ColorGREEN);
235         canvas->translate(250, 0);
236         zPlaneParams.fZ = SkTMax(1.0f, 64 + fZDelta);
237         this->drawShadowedPath(canvas, fRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
238                                lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
239 
240         paint.setColor(SK_ColorYELLOW);
241         canvas->translate(-250, 110);
242         zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta);
243         this->drawShadowedPath(canvas, fFunkyRRPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
244                                lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
245 
246         paint.setColor(SK_ColorCYAN);
247         canvas->translate(250, 0);
248         zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta);
249         this->drawShadowedPath(canvas, fCubicPath, zPlaneParams, paint, fAnimAlpha*kAmbientAlpha,
250                                lightPos, kLightWidth, fAnimAlpha*kSpotAlpha);
251 
252         paint.setColor(SK_ColorWHITE);
253         canvas->translate(250, -180);
254         zPlaneParams.fZ = SkTMax(1.0f, 8 + fZDelta);
255         this->drawShadowedPath(canvas, fStarPath, zPlaneParams, paint,
256                                kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha);
257 
258         paint.setColor(SK_ColorWHITE);
259         canvas->translate(150, 0);
260         zPlaneParams.fZ = SkTMax(1.0f, 2 + fZDelta);
261         this->drawShadowedPath(canvas, fNotchPath, zPlaneParams, paint,
262                                kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha);
263 
264         paint.setColor(SK_ColorWHITE);
265         canvas->translate(200, 0);
266         zPlaneParams.fZ = SkTMax(1.0f, 16 + fZDelta);
267         this->drawShadowedPath(canvas, fTabPath, zPlaneParams, paint,
268                                kAmbientAlpha, lightPos, kLightWidth, kSpotAlpha);
269 
270         // circular reveal
271         SkPath tmpPath;
272         SkPath tmpClipPath;
273         tmpClipPath.addCircle(fAnimTranslate, 0, 60);
274         Op(fSquareRRectPath, tmpClipPath, kIntersect_SkPathOp, &tmpPath);
275 
276         paint.setColor(SK_ColorMAGENTA);
277         canvas->translate(-725, 240);
278         zPlaneParams.fZ = SkTMax(1.0f, 32 + fZDelta);
279         this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f,
280                                lightPos, kLightWidth, .5f);
281 
282         // path ops bug
283         SkPath tmpClipPathBug;
284         tmpClipPathBug.addCircle(88.0344925f, 0, 60);
285         Op(fSquareRRectPath, tmpClipPathBug, kIntersect_SkPathOp, &tmpPath);
286 
287         canvas->translate(250, 0);
288         zPlaneParams.fZ = SkTMax(1.0f, 32 + fZDelta);
289         this->drawShadowedPath(canvas, tmpPath, zPlaneParams, paint, .1f,
290                                lightPos, kLightWidth, .5f);
291 
292         // perspective paths
293         SkPoint pivot = SkPoint::Make(fWideRectPath.getBounds().width()/2,
294                                       fWideRectPath.getBounds().height()/2);
295         SkPoint translate = SkPoint::Make(100, 450);
296         paint.setColor(SK_ColorWHITE);
297         Sk3DView view;
298         view.save();
299         view.rotateX(fAnimAngle);
300         SkMatrix persp;
301         view.getMatrix(&persp);
302         persp.preTranslate(-pivot.fX, -pivot.fY);
303         persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
304         canvas->setMatrix(persp);
305         SkScalar radians = SkDegreesToRadians(fAnimAngle);
306         zPlaneParams = SkPoint3::Make(0,
307                                       SkScalarSin(radians),
308                                       SkTMax(1.0f, 16 + fZDelta) - SkScalarSin(radians)*pivot.fY);
309         this->drawShadowedPath(canvas, fWideRectPath, zPlaneParams, paint, .1f,
310                                lightPos, kLightWidth, .5f);
311 
312         pivot = SkPoint::Make(fWideOvalPath.getBounds().width() / 2,
313                               fWideOvalPath.getBounds().height() / 2);
314         translate = SkPoint::Make(100, 600);
315         view.restore();
316         view.save();
317         view.rotateY(fAnimAngle);
318         view.getMatrix(&persp);
319         persp.preTranslate(-pivot.fX, -pivot.fY);
320         persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
321         canvas->setMatrix(persp);
322         zPlaneParams = SkPoint3::Make(-SkScalarSin(radians),
323                                       0,
324                                       SkTMax(1.0f, 32 + fZDelta) + SkScalarSin(radians)*pivot.fX);
325         this->drawShadowedPath(canvas, fWideOvalPath, zPlaneParams, paint, .1f,
326                                lightPos, kLightWidth, .5f);
327 
328         pivot = SkPoint::Make(fStarPath.getBounds().width() / 2,
329                               fStarPath.getBounds().height() / 2);
330         translate = SkPoint::Make(700, 250);
331         view.restore();
332         view.rotateY(fAnimAngle);
333         view.getMatrix(&persp);
334         persp.preTranslate(-pivot.fX, -pivot.fY);
335         persp.postTranslate(pivot.fX + translate.fX, pivot.fY + translate.fY);
336         canvas->setMatrix(persp);
337         zPlaneParams = SkPoint3::Make(-SkScalarSin(radians),
338                                       0,
339                                       SkTMax(1.0f, 8 + fZDelta) + SkScalarSin(radians)*pivot.fX);
340         this->drawShadowedPath(canvas, fStarPath, zPlaneParams, paint, .1f,
341                                lightPos, kLightWidth, .5f);
342     }
343 
onAnimate(const SkAnimTimer & timer)344     bool onAnimate(const SkAnimTimer& timer) override {
345         fAnimTranslate = timer.pingPong(30, 0, 125, -125);
346         fAnimAngle = timer.pingPong(15, 0, 0, 20);
347         if (fDoAlphaAnimation) {
348             fAnimAlpha = timer.pingPong(5, 0, 1, 0);
349         }
350         return true;
351     }
352 
353 private:
354     typedef Sample INHERITED;
355 };
356 
357 //////////////////////////////////////////////////////////////////////////////
358 
359 DEF_SAMPLE( return new ShadowsView(); )
360