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