blob: a23cac423da3eb962514bf875db3ea178d77bf42 [file] [log] [blame]
jvanverthe1a3bc62016-08-12 10:40:38 -07001
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 "SkBlurMask.h"
10#include "SkBlurMaskFilter.h"
11#include "SkCanvas.h"
jvanverth6c177a12016-08-17 07:59:41 -070012#include "SkGaussianEdgeShader.h"
jvanverthe1a3bc62016-08-12 10:40:38 -070013#include "SkPath.h"
14#include "SkPoint3.h"
15#include "SkUtils.h"
16#include "SkView.h"
17#include "sk_tool_utils.h"
18
jvanverth6c177a12016-08-17 07:59:41 -070019////////////////////////////////////////////////////////////////////////////
20
jvanverthe1a3bc62016-08-12 10:40:38 -070021class ShadowsView : public SampleView {
22 SkPath fRectPath;
23 SkPath fRRPath;
24 SkPath fCirclePath;
25 SkPoint3 fLightPos;
26
27 bool fShowAmbient;
28 bool fShowSpot;
jvanverthd7315f912016-08-17 10:06:18 -070029 bool fUseAlt;
jvanverthe1a3bc62016-08-12 10:40:38 -070030 bool fShowObject;
Robert Phillips95304e32016-10-07 14:44:07 -040031 bool fIgnoreShadowAlpha;
jvanverthe1a3bc62016-08-12 10:40:38 -070032
33public:
34 ShadowsView()
35 : fShowAmbient(true)
36 , fShowSpot(true)
jvanverthd7315f912016-08-17 10:06:18 -070037 , fUseAlt(true)
Robert Phillips95304e32016-10-07 14:44:07 -040038 , fShowObject(true)
39 , fIgnoreShadowAlpha(false) {}
jvanverthe1a3bc62016-08-12 10:40:38 -070040
41protected:
42 void onOnceBeforeDraw() override {
43 fCirclePath.addCircle(0, 0, 50);
44 fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100));
45 fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4));
jvanverthd99858a2016-09-12 07:51:04 -070046 fLightPos = SkPoint3::Make(-700, -700, 2800);
jvanverthe1a3bc62016-08-12 10:40:38 -070047 }
48
49 // overrides from SkEventSink
50 bool onQuery(SkEvent* evt) override {
51 if (SampleCode::TitleQ(*evt)) {
52 SampleCode::TitleR(evt, "AndroidShadows");
53 return true;
54 }
55
56 SkUnichar uni;
57 if (SampleCode::CharQ(*evt, &uni)) {
58 switch (uni) {
59 case 'B':
60 fShowAmbient = !fShowAmbient;
61 break;
62 case 'S':
63 fShowSpot = !fShowSpot;
64 break;
jvanverthd7315f912016-08-17 10:06:18 -070065 case 'T':
66 fUseAlt = !fUseAlt;
67 break;
jvanverthe1a3bc62016-08-12 10:40:38 -070068 case 'O':
69 fShowObject = !fShowObject;
70 break;
71 case '>':
72 fLightPos.fZ += 10;
73 break;
74 case '<':
75 fLightPos.fZ -= 10;
76 break;
Robert Phillips95304e32016-10-07 14:44:07 -040077 case '?':
78 fIgnoreShadowAlpha = !fIgnoreShadowAlpha;
79 break;
jvanverthe1a3bc62016-08-12 10:40:38 -070080 default:
81 break;
82 }
83 this->inval(nullptr);
84 }
85 return this->INHERITED::onQuery(evt);
86 }
87
88 void drawBG(SkCanvas* canvas) {
89 canvas->drawColor(0xFFDDDDDD);
90 }
91
92 static void GetOcclRect(const SkPath& path, SkRect* occlRect) {
93 SkRect pathRect;
94 SkRRect pathRRect;
95 if (path.isOval(&pathRect)) {
96 *occlRect = sk_tool_utils::compute_central_occluder(SkRRect::MakeOval(pathRect));
97 } else if (path.isRRect(&pathRRect)) {
98 *occlRect = sk_tool_utils::compute_central_occluder(pathRRect);
99 } else if (path.isRect(occlRect)) {
100 // the inverse transform for the spot shadow occluder doesn't always get us
101 // back to exactly the same position, so deducting a little slop
102 occlRect->inset(1, 1);
103 } else {
104 *occlRect = SkRect::MakeEmpty();
105 }
106 }
107
108 void drawAmbientShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
109 SkScalar ambientAlpha) {
110
111 if (ambientAlpha <= 0) {
112 return;
113 }
114
115 const SkScalar kHeightFactor = 1.f / 128.f;
116 const SkScalar kGeomFactor = 64;
117
118 SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
119 SkScalar radius = zValue*kHeightFactor*kGeomFactor;
120
121 // occlude blur
122 SkRect occlRect;
123 GetOcclRect(path, &occlRect);
124 sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
125 SkBlurMask::ConvertRadiusToSigma(radius),
126 occlRect,
127 SkBlurMaskFilter::kNone_BlurFlag);
128
129 SkPaint paint;
130 paint.setAntiAlias(true);
131 paint.setMaskFilter(std::move(mf));
Robert Phillips95304e32016-10-07 14:44:07 -0400132 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
133 ? 255
134 : (unsigned char)(ambientAlpha*umbraAlpha*255.999f), 0, 0, 0));
jvanverthe1a3bc62016-08-12 10:40:38 -0700135 canvas->drawPath(path, paint);
136
137 // draw occlusion rect
jvanverth6c177a12016-08-17 07:59:41 -0700138#if DRAW_OCCL_RECT
jvanverthe1a3bc62016-08-12 10:40:38 -0700139 SkPaint stroke;
140 stroke.setStyle(SkPaint::kStroke_Style);
141 stroke.setColor(SK_ColorBLUE);
142 canvas->drawRect(occlRect, stroke);
jvanverth6c177a12016-08-17 07:59:41 -0700143#endif
144 }
145
146 void drawAmbientShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
147 SkScalar ambientAlpha) {
148
149 if (ambientAlpha <= 0) {
150 return;
151 }
152
153 const SkScalar kHeightFactor = 1.f / 128.f;
154 const SkScalar kGeomFactor = 64;
155
156 SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
157 SkScalar radius = zValue*kHeightFactor*kGeomFactor;
jvanverthd99858a2016-09-12 07:51:04 -0700158 // distance to outer of edge of geometry from original shape edge
159 SkScalar offset = radius*umbraAlpha;
jvanverth6c177a12016-08-17 07:59:41 -0700160
jvanvertha4f1af82016-08-29 07:17:47 -0700161 SkRect pathRect;
162 SkRRect pathRRect;
jvanverthd99858a2016-09-12 07:51:04 -0700163 SkScalar scaleFactors[2];
164 if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
165 return;
166 }
167 if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 64 ||
jvanvertha4f1af82016-08-29 07:17:47 -0700168 !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
169 (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
170 path.isRect(&pathRect))) {
171 this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
172 return;
173 }
174
jvanverthd99858a2016-09-12 07:51:04 -0700175 // For all of these, we inset the offset rect by half the radius to get our stroke shape.
176 SkScalar strokeOutset = offset - SK_ScalarHalf*radius;
177 // Make sure we'll have a radius of at least 0.5 after xform
178 if (strokeOutset*scaleFactors[0] < 0.5f) {
179 strokeOutset = 0.5f / scaleFactors[0];
180 }
jvanverthd7315f912016-08-17 10:06:18 -0700181 if (path.isOval(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700182 pathRect.outset(strokeOutset, strokeOutset);
jvanverthd7315f912016-08-17 10:06:18 -0700183 pathRRect = SkRRect::MakeOval(pathRect);
184 } else if (path.isRect(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700185 pathRect.outset(strokeOutset, strokeOutset);
186 pathRRect = SkRRect::MakeRectXY(pathRect, strokeOutset, strokeOutset);
jvanverth6c177a12016-08-17 07:59:41 -0700187 } else {
jvanverthd99858a2016-09-12 07:51:04 -0700188 pathRRect.outset(strokeOutset, strokeOutset);
jvanverth6c177a12016-08-17 07:59:41 -0700189 }
190
jvanverthd7315f912016-08-17 10:06:18 -0700191 SkPaint paint;
192 paint.setAntiAlias(true);
jvanvertha4f1af82016-08-29 07:17:47 -0700193 paint.setStyle(SkPaint::kStroke_Style);
194 // we outset the stroke a little to cover up AA on the interior edge
jvanverthd99858a2016-09-12 07:51:04 -0700195 SkScalar pad = 0.5f;
196 paint.setStrokeWidth(radius + 2*pad);
197 // handle scale of radius and pad due to CTM
198 radius *= scaleFactors[0];
199 pad *= scaleFactors[0];
200 SkASSERT(radius < 16384);
201 SkASSERT(pad < 64);
202 // Convert radius to 14.2 fixed point and place in the R & G components.
203 // Convert pad to 6.2 fixed point and place in the B component.
204 uint16_t iRadius = (uint16_t)(radius*4.0f);
205 unsigned char alpha = (unsigned char)(ambientAlpha*255.999f);
Robert Phillips95304e32016-10-07 14:44:07 -0400206 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
207 iRadius >> 8, iRadius & 0xff,
jvanverthd99858a2016-09-12 07:51:04 -0700208 (unsigned char)(4.0f*pad)));
jvanverthd7315f912016-08-17 10:06:18 -0700209
jvanverthc20c0c02016-09-14 07:04:49 -0700210 paint.setShader(SkGaussianEdgeShader::Make());
jvanverthd7315f912016-08-17 10:06:18 -0700211 canvas->drawRRect(pathRRect, paint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700212 }
213
214 void drawSpotShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
215 SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
216 if (spotAlpha <= 0) {
217 return;
218 }
219
220 SkScalar zRatio = zValue / (lightPos.fZ - zValue);
221 if (zRatio < 0.0f) {
222 zRatio = 0.0f;
223 } else if (zRatio > 0.95f) {
224 zRatio = 0.95f;
225 }
jvanverthd99858a2016-09-12 07:51:04 -0700226 SkScalar blurRadius = lightWidth*zRatio;
jvanverthe1a3bc62016-08-12 10:40:38 -0700227
228 // compute the transformation params
229 SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
jvanverthd99858a2016-09-12 07:51:04 -0700230 SkMatrix ctmInverse;
231 if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
232 return;
jvanverthe1a3bc62016-08-12 10:40:38 -0700233 }
jvanverthd99858a2016-09-12 07:51:04 -0700234 SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
235 ctmInverse.mapPoints(&lightPos2D, 1);
236 SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
237 zRatio*(center.fY - lightPos2D.fY));
238 SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
jvanverthe1a3bc62016-08-12 10:40:38 -0700239
240 SkAutoCanvasRestore acr(canvas, true);
241
jvanverthe1a3bc62016-08-12 10:40:38 -0700242 sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
jvanverthd99858a2016-09-12 07:51:04 -0700243 SkBlurMask::ConvertRadiusToSigma(blurRadius),
jvanverthe1a3bc62016-08-12 10:40:38 -0700244 SkBlurMaskFilter::kNone_BlurFlag);
245
246 SkPaint paint;
247 paint.setAntiAlias(true);
248 paint.setMaskFilter(std::move(mf));
Robert Phillips95304e32016-10-07 14:44:07 -0400249 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
250 ? 255
251 : (unsigned char)(spotAlpha*255.999f), 0, 0, 0));
jvanverthe1a3bc62016-08-12 10:40:38 -0700252
253 // apply transformation to shadow
jvanverthe1a3bc62016-08-12 10:40:38 -0700254 canvas->scale(scale, scale);
jvanverthd99858a2016-09-12 07:51:04 -0700255 canvas->translate(offset.fX, offset.fY);
jvanverthe1a3bc62016-08-12 10:40:38 -0700256 canvas->drawPath(path, paint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700257 }
258
jvanverthd7315f912016-08-17 10:06:18 -0700259 void drawSpotShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
260 SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
261 if (spotAlpha <= 0) {
262 return;
263 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700264
jvanverthd7315f912016-08-17 10:06:18 -0700265 SkScalar zRatio = zValue / (lightPos.fZ - zValue);
266 if (zRatio < 0.0f) {
267 zRatio = 0.0f;
268 } else if (zRatio > 0.95f) {
269 zRatio = 0.95f;
270 }
jvanverthd99858a2016-09-12 07:51:04 -0700271 SkScalar radius = 2.0f*lightWidth*zRatio;
jvanverthd7315f912016-08-17 10:06:18 -0700272
jvanvertha4f1af82016-08-29 07:17:47 -0700273 SkRect pathRect;
274 SkRRect pathRRect;
jvanverthd99858a2016-09-12 07:51:04 -0700275 SkScalar scaleFactors[2];
276 if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
277 return;
278 }
279 if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 16384 ||
jvanvertha4f1af82016-08-29 07:17:47 -0700280 !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
281 (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
282 path.isRect(&pathRect))) {
283 this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
284 return;
285 }
286
jvanverthd99858a2016-09-12 07:51:04 -0700287 // For all of these, we need to ensure we have a rrect with radius >= 0.5f in device space
Robert Phillips95304e32016-10-07 14:44:07 -0400288 const SkScalar minRadius = SK_ScalarHalf/scaleFactors[0];
jvanverthd7315f912016-08-17 10:06:18 -0700289 if (path.isOval(nullptr)) {
jvanverthd7315f912016-08-17 10:06:18 -0700290 pathRRect = SkRRect::MakeOval(pathRect);
291 } else if (path.isRect(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700292 pathRRect = SkRRect::MakeRectXY(pathRect, minRadius, minRadius);
jvanverthd7315f912016-08-17 10:06:18 -0700293 } else {
jvanverthd99858a2016-09-12 07:51:04 -0700294 if (pathRRect.getSimpleRadii().fX < minRadius) {
295 pathRRect.setRectXY(pathRRect.rect(), minRadius, minRadius);
296 }
jvanverthd7315f912016-08-17 10:06:18 -0700297 }
298
jvanverthd99858a2016-09-12 07:51:04 -0700299 // compute the scale and translation for the shadow
300 SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
301 SkRRect shadowRRect;
302 pathRRect.transform(SkMatrix::MakeScale(scale, scale), &shadowRRect);
303 SkPoint center = SkPoint::Make(shadowRRect.rect().centerX(), shadowRRect.rect().centerY());
304 SkMatrix ctmInverse;
305 if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
306 return;
307 }
308 SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
309 ctmInverse.mapPoints(&lightPos2D, 1);
310 SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
311 zRatio*(center.fY - lightPos2D.fY));
jvanverthd7315f912016-08-17 10:06:18 -0700312 SkAutoCanvasRestore acr(canvas, true);
313
314 SkPaint paint;
315 paint.setAntiAlias(true);
Robert Phillips95304e32016-10-07 14:44:07 -0400316 // We want to extend the stroked area in so that it meets up with the caster
317 // geometry. The stroked geometry will, by definition already be inset half the
318 // stroke width but we also have to account for the scaling.
319 // We also add 1/2 to cover up AA on the interior edge.
320 SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(pathRect.fLeft),
321 SkTAbs(pathRect.fRight)),
322 SkTMax(SkTAbs(pathRect.fTop),
323 SkTAbs(pathRect.fBottom)));
324 SkScalar insetAmount = offset.length() - (0.5f * radius) + scaleOffset + 0.5f;
325
jvanvertha4f1af82016-08-29 07:17:47 -0700326 // compute area
Robert Phillips95304e32016-10-07 14:44:07 -0400327 SkScalar strokeWidth = radius + insetAmount;
jvanverthd99858a2016-09-12 07:51:04 -0700328 SkScalar strokedArea = 2.0f*strokeWidth*(shadowRRect.width() + shadowRRect.height());
329 SkScalar filledArea = (shadowRRect.height() + radius)*(shadowRRect.width() + radius);
jvanvertha4f1af82016-08-29 07:17:47 -0700330 // If the area of the stroked geometry is larger than the fill geometry, or
331 // if our pad is too big to convert to 6.2 fixed point, just fill it.
Robert Phillips95304e32016-10-07 14:44:07 -0400332 if (strokedArea > filledArea) {
jvanvertha4f1af82016-08-29 07:17:47 -0700333 paint.setStyle(SkPaint::kStrokeAndFill_Style);
334 paint.setStrokeWidth(radius);
335 } else {
Robert Phillips95304e32016-10-07 14:44:07 -0400336 // Since we can't have unequal strokes, inset the shadow rect so the inner
337 // and outer edges of the stroke will land where we want.
338 SkRect insetRect = shadowRRect.rect().makeInset(insetAmount/2.0f, insetAmount/2.0f);
339 SkScalar insetRad = SkTMax(shadowRRect.getSimpleRadii().fX - insetAmount/2.0f,
340 minRadius);
341
342 shadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad);
jvanvertha4f1af82016-08-29 07:17:47 -0700343 paint.setStyle(SkPaint::kStroke_Style);
344 paint.setStrokeWidth(strokeWidth);
345 }
jvanverthc20c0c02016-09-14 07:04:49 -0700346 paint.setShader(SkGaussianEdgeShader::Make());
jvanverthd7315f912016-08-17 10:06:18 -0700347 // handle scale of radius due to CTM
jvanverthd99858a2016-09-12 07:51:04 -0700348 radius *= scaleFactors[0];
349 // don't need to scale pad as it was computed from the transformed offset
350 SkASSERT(radius < 16384);
Robert Phillips95304e32016-10-07 14:44:07 -0400351 SkScalar pad = 0;
jvanvertha4f1af82016-08-29 07:17:47 -0700352 SkASSERT(pad < 64);
jvanverthd99858a2016-09-12 07:51:04 -0700353 // Convert radius to 14.2 fixed point and place in the R & G components.
354 // Convert pad to 6.2 fixed point and place in the B component.
355 uint16_t iRadius = (uint16_t)(radius*4.0f);
356 unsigned char alpha = (unsigned char)(spotAlpha*255.999f);
Robert Phillips95304e32016-10-07 14:44:07 -0400357 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
358 iRadius >> 8, iRadius & 0xff,
jvanverthd99858a2016-09-12 07:51:04 -0700359 (unsigned char)(4.0f*pad)));
jvanverthd7315f912016-08-17 10:06:18 -0700360
361 // apply transformation to shadow
362 canvas->translate(offset.fX, offset.fY);
jvanverthd99858a2016-09-12 07:51:04 -0700363 canvas->drawRRect(shadowRRect, paint);
jvanverthd7315f912016-08-17 10:06:18 -0700364 }
365
366 void drawShadowedPath(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
367 const SkPaint& paint, SkScalar ambientAlpha,
368 const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
jvanverthe1a3bc62016-08-12 10:40:38 -0700369 if (fShowAmbient) {
jvanverthd7315f912016-08-17 10:06:18 -0700370 if (fUseAlt) {
371 this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
jvanverth6c177a12016-08-17 07:59:41 -0700372 } else {
jvanverthd7315f912016-08-17 10:06:18 -0700373 this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
jvanverth6c177a12016-08-17 07:59:41 -0700374 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700375 }
376 if (fShowSpot) {
jvanverthd7315f912016-08-17 10:06:18 -0700377 if (fUseAlt) {
378 this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
379 } else {
380 this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
381 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700382 }
383 if (fShowObject) {
384 canvas->drawPath(path, paint);
Robert Phillips95304e32016-10-07 14:44:07 -0400385 } else {
386 SkPaint strokePaint;
387
388 strokePaint.setColor(paint.getColor());
389 strokePaint.setStyle(SkPaint::kStroke_Style);
390
391 canvas->drawPath(path, strokePaint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700392 }
393 }
394
395 void onDrawContent(SkCanvas* canvas) override {
396 this->drawBG(canvas);
jvanverthd99858a2016-09-12 07:51:04 -0700397 const SkScalar kLightWidth = 2800;
jvanverthd7315f912016-08-17 10:06:18 -0700398 const SkScalar kAmbientAlpha = 0.25f;
399 const SkScalar kSpotAlpha = 0.25f;
jvanverthe1a3bc62016-08-12 10:40:38 -0700400
401 SkPaint paint;
402 paint.setAntiAlias(true);
403
jvanverthd7315f912016-08-17 10:06:18 -0700404 SkPoint3 lightPos = fLightPos;
405
jvanverthe1a3bc62016-08-12 10:40:38 -0700406 paint.setColor(SK_ColorWHITE);
407 canvas->translate(200, 90);
jvanverthd7315f912016-08-17 10:06:18 -0700408 lightPos.fX += 200;
409 lightPos.fY += 90;
jvanverthd99858a2016-09-12 07:51:04 -0700410 this->drawShadowedPath(canvas, fRectPath, 2, paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700411 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700412
413 paint.setColor(SK_ColorRED);
414 canvas->translate(250, 0);
jvanverthd7315f912016-08-17 10:06:18 -0700415 lightPos.fX += 250;
jvanverthd99858a2016-09-12 07:51:04 -0700416 this->drawShadowedPath(canvas, fRRPath, 4, paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700417 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700418
419 paint.setColor(SK_ColorBLUE);
420 canvas->translate(-250, 110);
jvanverthd7315f912016-08-17 10:06:18 -0700421 lightPos.fX -= 250;
422 lightPos.fY += 110;
jvanverthd99858a2016-09-12 07:51:04 -0700423 this->drawShadowedPath(canvas, fCirclePath, 8, paint, 0.0f,
jvanverthd7315f912016-08-17 10:06:18 -0700424 lightPos, kLightWidth, 0.5f);
jvanverth6c177a12016-08-17 07:59:41 -0700425
426 paint.setColor(SK_ColorGREEN);
427 canvas->translate(250, 0);
jvanverthd7315f912016-08-17 10:06:18 -0700428 lightPos.fX += 250;
jvanverthd99858a2016-09-12 07:51:04 -0700429 this->drawShadowedPath(canvas, fRRPath, 64, paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700430 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700431 }
432
433protected:
434 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
435 return new SkView::Click(this);
436 }
437
438 bool onClick(Click *click) override {
439 SkScalar x = click->fCurr.fX;
440 SkScalar y = click->fCurr.fY;
441
442 SkScalar dx = x - click->fPrev.fX;
443 SkScalar dy = y - click->fPrev.fY;
444
445 if (dx != 0 || dy != 0) {
446 fLightPos.fX += dx;
447 fLightPos.fY += dy;
448 this->inval(nullptr);
449 }
450
451 return true;
452 }
453
454private:
455 typedef SkView INHERITED;
456};
457
458//////////////////////////////////////////////////////////////////////////////
459
460static SkView* MyFactory() { return new ShadowsView; }
461static SkViewRegister reg(MyFactory);