blob: 87fa0510fe59b39812c7a34b0511f8d7035668a4 [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"
Jim Van Verth3c1b7db2016-10-31 16:06:51 -040015#include "SkShadowMaskFilter.h"
jvanverthe1a3bc62016-08-12 10:40:38 -070016#include "SkUtils.h"
17#include "SkView.h"
18#include "sk_tool_utils.h"
19
jvanverth6c177a12016-08-17 07:59:41 -070020////////////////////////////////////////////////////////////////////////////
21
jvanverthe1a3bc62016-08-12 10:40:38 -070022class ShadowsView : public SampleView {
23 SkPath fRectPath;
24 SkPath fRRPath;
25 SkPath fCirclePath;
26 SkPoint3 fLightPos;
27
28 bool fShowAmbient;
29 bool fShowSpot;
jvanverthd7315f912016-08-17 10:06:18 -070030 bool fUseAlt;
jvanverthe1a3bc62016-08-12 10:40:38 -070031 bool fShowObject;
Robert Phillips95304e32016-10-07 14:44:07 -040032 bool fIgnoreShadowAlpha;
jvanverthe1a3bc62016-08-12 10:40:38 -070033
34public:
35 ShadowsView()
36 : fShowAmbient(true)
37 , fShowSpot(true)
jvanverthd7315f912016-08-17 10:06:18 -070038 , fUseAlt(true)
Robert Phillips95304e32016-10-07 14:44:07 -040039 , fShowObject(true)
40 , fIgnoreShadowAlpha(false) {}
jvanverthe1a3bc62016-08-12 10:40:38 -070041
42protected:
43 void onOnceBeforeDraw() override {
44 fCirclePath.addCircle(0, 0, 50);
45 fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100));
46 fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4));
jvanverthd99858a2016-09-12 07:51:04 -070047 fLightPos = SkPoint3::Make(-700, -700, 2800);
jvanverthe1a3bc62016-08-12 10:40:38 -070048 }
49
50 // overrides from SkEventSink
51 bool onQuery(SkEvent* evt) override {
52 if (SampleCode::TitleQ(*evt)) {
53 SampleCode::TitleR(evt, "AndroidShadows");
54 return true;
55 }
56
57 SkUnichar uni;
58 if (SampleCode::CharQ(*evt, &uni)) {
59 switch (uni) {
60 case 'B':
61 fShowAmbient = !fShowAmbient;
62 break;
63 case 'S':
64 fShowSpot = !fShowSpot;
65 break;
jvanverthd7315f912016-08-17 10:06:18 -070066 case 'T':
67 fUseAlt = !fUseAlt;
68 break;
jvanverthe1a3bc62016-08-12 10:40:38 -070069 case 'O':
70 fShowObject = !fShowObject;
71 break;
72 case '>':
73 fLightPos.fZ += 10;
74 break;
75 case '<':
76 fLightPos.fZ -= 10;
77 break;
Robert Phillips95304e32016-10-07 14:44:07 -040078 case '?':
79 fIgnoreShadowAlpha = !fIgnoreShadowAlpha;
80 break;
jvanverthe1a3bc62016-08-12 10:40:38 -070081 default:
82 break;
83 }
84 this->inval(nullptr);
85 }
86 return this->INHERITED::onQuery(evt);
87 }
88
89 void drawBG(SkCanvas* canvas) {
90 canvas->drawColor(0xFFDDDDDD);
91 }
92
93 static void GetOcclRect(const SkPath& path, SkRect* occlRect) {
94 SkRect pathRect;
95 SkRRect pathRRect;
96 if (path.isOval(&pathRect)) {
97 *occlRect = sk_tool_utils::compute_central_occluder(SkRRect::MakeOval(pathRect));
98 } else if (path.isRRect(&pathRRect)) {
99 *occlRect = sk_tool_utils::compute_central_occluder(pathRRect);
100 } else if (path.isRect(occlRect)) {
101 // the inverse transform for the spot shadow occluder doesn't always get us
102 // back to exactly the same position, so deducting a little slop
103 occlRect->inset(1, 1);
104 } else {
105 *occlRect = SkRect::MakeEmpty();
106 }
107 }
108
109 void drawAmbientShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
110 SkScalar ambientAlpha) {
111
112 if (ambientAlpha <= 0) {
113 return;
114 }
115
116 const SkScalar kHeightFactor = 1.f / 128.f;
117 const SkScalar kGeomFactor = 64;
118
119 SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
120 SkScalar radius = zValue*kHeightFactor*kGeomFactor;
121
122 // occlude blur
123 SkRect occlRect;
124 GetOcclRect(path, &occlRect);
125 sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
126 SkBlurMask::ConvertRadiusToSigma(radius),
127 occlRect,
128 SkBlurMaskFilter::kNone_BlurFlag);
129
130 SkPaint paint;
131 paint.setAntiAlias(true);
132 paint.setMaskFilter(std::move(mf));
Robert Phillips95304e32016-10-07 14:44:07 -0400133 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
134 ? 255
135 : (unsigned char)(ambientAlpha*umbraAlpha*255.999f), 0, 0, 0));
jvanverthe1a3bc62016-08-12 10:40:38 -0700136 canvas->drawPath(path, paint);
137
138 // draw occlusion rect
jvanverth6c177a12016-08-17 07:59:41 -0700139#if DRAW_OCCL_RECT
jvanverthe1a3bc62016-08-12 10:40:38 -0700140 SkPaint stroke;
141 stroke.setStyle(SkPaint::kStroke_Style);
142 stroke.setColor(SK_ColorBLUE);
143 canvas->drawRect(occlRect, stroke);
jvanverth6c177a12016-08-17 07:59:41 -0700144#endif
145 }
146
147 void drawAmbientShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
148 SkScalar ambientAlpha) {
149
150 if (ambientAlpha <= 0) {
151 return;
152 }
153
154 const SkScalar kHeightFactor = 1.f / 128.f;
155 const SkScalar kGeomFactor = 64;
156
157 SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
158 SkScalar radius = zValue*kHeightFactor*kGeomFactor;
jvanverthd99858a2016-09-12 07:51:04 -0700159 // distance to outer of edge of geometry from original shape edge
160 SkScalar offset = radius*umbraAlpha;
jvanverth6c177a12016-08-17 07:59:41 -0700161
jvanvertha4f1af82016-08-29 07:17:47 -0700162 SkRect pathRect;
163 SkRRect pathRRect;
jvanverthd99858a2016-09-12 07:51:04 -0700164 SkScalar scaleFactors[2];
165 if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
166 return;
167 }
168 if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 64 ||
jvanvertha4f1af82016-08-29 07:17:47 -0700169 !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
170 (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
171 path.isRect(&pathRect))) {
172 this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
173 return;
174 }
175
jvanverthd99858a2016-09-12 07:51:04 -0700176 // For all of these, we inset the offset rect by half the radius to get our stroke shape.
177 SkScalar strokeOutset = offset - SK_ScalarHalf*radius;
178 // Make sure we'll have a radius of at least 0.5 after xform
179 if (strokeOutset*scaleFactors[0] < 0.5f) {
180 strokeOutset = 0.5f / scaleFactors[0];
181 }
jvanverthd7315f912016-08-17 10:06:18 -0700182 if (path.isOval(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700183 pathRect.outset(strokeOutset, strokeOutset);
jvanverthd7315f912016-08-17 10:06:18 -0700184 pathRRect = SkRRect::MakeOval(pathRect);
185 } else if (path.isRect(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700186 pathRect.outset(strokeOutset, strokeOutset);
187 pathRRect = SkRRect::MakeRectXY(pathRect, strokeOutset, strokeOutset);
jvanverth6c177a12016-08-17 07:59:41 -0700188 } else {
jvanverthd99858a2016-09-12 07:51:04 -0700189 pathRRect.outset(strokeOutset, strokeOutset);
jvanverth6c177a12016-08-17 07:59:41 -0700190 }
191
jvanverthd7315f912016-08-17 10:06:18 -0700192 SkPaint paint;
193 paint.setAntiAlias(true);
jvanvertha4f1af82016-08-29 07:17:47 -0700194 paint.setStyle(SkPaint::kStroke_Style);
195 // we outset the stroke a little to cover up AA on the interior edge
jvanverthd99858a2016-09-12 07:51:04 -0700196 SkScalar pad = 0.5f;
197 paint.setStrokeWidth(radius + 2*pad);
198 // handle scale of radius and pad due to CTM
199 radius *= scaleFactors[0];
200 pad *= scaleFactors[0];
201 SkASSERT(radius < 16384);
202 SkASSERT(pad < 64);
203 // Convert radius to 14.2 fixed point and place in the R & G components.
204 // Convert pad to 6.2 fixed point and place in the B component.
205 uint16_t iRadius = (uint16_t)(radius*4.0f);
206 unsigned char alpha = (unsigned char)(ambientAlpha*255.999f);
Robert Phillips95304e32016-10-07 14:44:07 -0400207 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
208 iRadius >> 8, iRadius & 0xff,
jvanverthd99858a2016-09-12 07:51:04 -0700209 (unsigned char)(4.0f*pad)));
jvanverthd7315f912016-08-17 10:06:18 -0700210
jvanverthc20c0c02016-09-14 07:04:49 -0700211 paint.setShader(SkGaussianEdgeShader::Make());
jvanverthd7315f912016-08-17 10:06:18 -0700212 canvas->drawRRect(pathRRect, paint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700213 }
214
215 void drawSpotShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
216 SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
217 if (spotAlpha <= 0) {
218 return;
219 }
220
221 SkScalar zRatio = zValue / (lightPos.fZ - zValue);
222 if (zRatio < 0.0f) {
223 zRatio = 0.0f;
224 } else if (zRatio > 0.95f) {
225 zRatio = 0.95f;
226 }
jvanverthd99858a2016-09-12 07:51:04 -0700227 SkScalar blurRadius = lightWidth*zRatio;
jvanverthe1a3bc62016-08-12 10:40:38 -0700228
229 // compute the transformation params
230 SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
jvanverthd99858a2016-09-12 07:51:04 -0700231 SkMatrix ctmInverse;
232 if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
233 return;
jvanverthe1a3bc62016-08-12 10:40:38 -0700234 }
jvanverthd99858a2016-09-12 07:51:04 -0700235 SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
236 ctmInverse.mapPoints(&lightPos2D, 1);
237 SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
238 zRatio*(center.fY - lightPos2D.fY));
239 SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
jvanverthe1a3bc62016-08-12 10:40:38 -0700240
241 SkAutoCanvasRestore acr(canvas, true);
242
jvanverthe1a3bc62016-08-12 10:40:38 -0700243 sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
jvanverthd99858a2016-09-12 07:51:04 -0700244 SkBlurMask::ConvertRadiusToSigma(blurRadius),
jvanverthe1a3bc62016-08-12 10:40:38 -0700245 SkBlurMaskFilter::kNone_BlurFlag);
246
247 SkPaint paint;
248 paint.setAntiAlias(true);
249 paint.setMaskFilter(std::move(mf));
Robert Phillips95304e32016-10-07 14:44:07 -0400250 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
251 ? 255
252 : (unsigned char)(spotAlpha*255.999f), 0, 0, 0));
jvanverthe1a3bc62016-08-12 10:40:38 -0700253
254 // apply transformation to shadow
jvanverthe1a3bc62016-08-12 10:40:38 -0700255 canvas->scale(scale, scale);
jvanverthd99858a2016-09-12 07:51:04 -0700256 canvas->translate(offset.fX, offset.fY);
jvanverthe1a3bc62016-08-12 10:40:38 -0700257 canvas->drawPath(path, paint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700258 }
259
jvanverthd7315f912016-08-17 10:06:18 -0700260 void drawSpotShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
261 SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
262 if (spotAlpha <= 0) {
263 return;
264 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700265
jvanverthd7315f912016-08-17 10:06:18 -0700266 SkScalar zRatio = zValue / (lightPos.fZ - zValue);
267 if (zRatio < 0.0f) {
268 zRatio = 0.0f;
269 } else if (zRatio > 0.95f) {
270 zRatio = 0.95f;
271 }
jvanverthd99858a2016-09-12 07:51:04 -0700272 SkScalar radius = 2.0f*lightWidth*zRatio;
jvanverthd7315f912016-08-17 10:06:18 -0700273
jvanvertha4f1af82016-08-29 07:17:47 -0700274 SkRect pathRect;
275 SkRRect pathRRect;
jvanverthd99858a2016-09-12 07:51:04 -0700276 SkScalar scaleFactors[2];
277 if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
278 return;
279 }
280 if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 16384 ||
jvanvertha4f1af82016-08-29 07:17:47 -0700281 !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
282 (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
283 path.isRect(&pathRect))) {
284 this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
285 return;
286 }
287
jvanverthd99858a2016-09-12 07:51:04 -0700288 // 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 -0400289 const SkScalar minRadius = SK_ScalarHalf/scaleFactors[0];
jvanverthd7315f912016-08-17 10:06:18 -0700290 if (path.isOval(nullptr)) {
jvanverthd7315f912016-08-17 10:06:18 -0700291 pathRRect = SkRRect::MakeOval(pathRect);
292 } else if (path.isRect(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700293 pathRRect = SkRRect::MakeRectXY(pathRect, minRadius, minRadius);
jvanverthd7315f912016-08-17 10:06:18 -0700294 } else {
jvanverthd99858a2016-09-12 07:51:04 -0700295 if (pathRRect.getSimpleRadii().fX < minRadius) {
296 pathRRect.setRectXY(pathRRect.rect(), minRadius, minRadius);
297 }
jvanverthd7315f912016-08-17 10:06:18 -0700298 }
299
jvanverthd99858a2016-09-12 07:51:04 -0700300 // compute the scale and translation for the shadow
301 SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
302 SkRRect shadowRRect;
303 pathRRect.transform(SkMatrix::MakeScale(scale, scale), &shadowRRect);
304 SkPoint center = SkPoint::Make(shadowRRect.rect().centerX(), shadowRRect.rect().centerY());
305 SkMatrix ctmInverse;
306 if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
307 return;
308 }
309 SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
310 ctmInverse.mapPoints(&lightPos2D, 1);
311 SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
312 zRatio*(center.fY - lightPos2D.fY));
jvanverthd7315f912016-08-17 10:06:18 -0700313 SkAutoCanvasRestore acr(canvas, true);
314
315 SkPaint paint;
316 paint.setAntiAlias(true);
Robert Phillips95304e32016-10-07 14:44:07 -0400317 // We want to extend the stroked area in so that it meets up with the caster
318 // geometry. The stroked geometry will, by definition already be inset half the
319 // stroke width but we also have to account for the scaling.
320 // We also add 1/2 to cover up AA on the interior edge.
321 SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(pathRect.fLeft),
322 SkTAbs(pathRect.fRight)),
323 SkTMax(SkTAbs(pathRect.fTop),
324 SkTAbs(pathRect.fBottom)));
325 SkScalar insetAmount = offset.length() - (0.5f * radius) + scaleOffset + 0.5f;
326
jvanvertha4f1af82016-08-29 07:17:47 -0700327 // compute area
Robert Phillips95304e32016-10-07 14:44:07 -0400328 SkScalar strokeWidth = radius + insetAmount;
jvanverthd99858a2016-09-12 07:51:04 -0700329 SkScalar strokedArea = 2.0f*strokeWidth*(shadowRRect.width() + shadowRRect.height());
330 SkScalar filledArea = (shadowRRect.height() + radius)*(shadowRRect.width() + radius);
jvanvertha4f1af82016-08-29 07:17:47 -0700331 // If the area of the stroked geometry is larger than the fill geometry, or
332 // if our pad is too big to convert to 6.2 fixed point, just fill it.
Robert Phillips95304e32016-10-07 14:44:07 -0400333 if (strokedArea > filledArea) {
jvanvertha4f1af82016-08-29 07:17:47 -0700334 paint.setStyle(SkPaint::kStrokeAndFill_Style);
335 paint.setStrokeWidth(radius);
336 } else {
Robert Phillips95304e32016-10-07 14:44:07 -0400337 // Since we can't have unequal strokes, inset the shadow rect so the inner
338 // and outer edges of the stroke will land where we want.
339 SkRect insetRect = shadowRRect.rect().makeInset(insetAmount/2.0f, insetAmount/2.0f);
340 SkScalar insetRad = SkTMax(shadowRRect.getSimpleRadii().fX - insetAmount/2.0f,
341 minRadius);
342
343 shadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad);
jvanvertha4f1af82016-08-29 07:17:47 -0700344 paint.setStyle(SkPaint::kStroke_Style);
345 paint.setStrokeWidth(strokeWidth);
346 }
jvanverthc20c0c02016-09-14 07:04:49 -0700347 paint.setShader(SkGaussianEdgeShader::Make());
jvanverthd7315f912016-08-17 10:06:18 -0700348 // handle scale of radius due to CTM
jvanverthd99858a2016-09-12 07:51:04 -0700349 radius *= scaleFactors[0];
350 // don't need to scale pad as it was computed from the transformed offset
351 SkASSERT(radius < 16384);
Robert Phillips95304e32016-10-07 14:44:07 -0400352 SkScalar pad = 0;
jvanvertha4f1af82016-08-29 07:17:47 -0700353 SkASSERT(pad < 64);
jvanverthd99858a2016-09-12 07:51:04 -0700354 // Convert radius to 14.2 fixed point and place in the R & G components.
355 // Convert pad to 6.2 fixed point and place in the B component.
356 uint16_t iRadius = (uint16_t)(radius*4.0f);
357 unsigned char alpha = (unsigned char)(spotAlpha*255.999f);
Robert Phillips95304e32016-10-07 14:44:07 -0400358 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
359 iRadius >> 8, iRadius & 0xff,
jvanverthd99858a2016-09-12 07:51:04 -0700360 (unsigned char)(4.0f*pad)));
jvanverthd7315f912016-08-17 10:06:18 -0700361
362 // apply transformation to shadow
363 canvas->translate(offset.fX, offset.fY);
jvanverthd99858a2016-09-12 07:51:04 -0700364 canvas->drawRRect(shadowRRect, paint);
jvanverthd7315f912016-08-17 10:06:18 -0700365 }
366
367 void drawShadowedPath(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
368 const SkPaint& paint, SkScalar ambientAlpha,
369 const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
Jim Van Verth3c1b7db2016-10-31 16:06:51 -0400370#ifdef USE_MASK_FILTER
371 if (fUseAlt) {
372 if (fShowAmbient) {
373 this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
374 }
375 if (fShowSpot) {
376 this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
377 }
378 } else {
379 SkPaint newPaint;
380 newPaint.setColor(SK_ColorBLACK);
381 if (!fShowAmbient) {
382 ambientAlpha = 0;
383 }
384 if (!fShowSpot) {
385 spotAlpha = 0;
386 }
387
388 newPaint.setMaskFilter(SkShadowMaskFilter::Make(zValue, lightPos, lightWidth,
389 ambientAlpha, spotAlpha));
390
391 canvas->drawPath(path, newPaint);
392 }
393#else
jvanverthe1a3bc62016-08-12 10:40:38 -0700394 if (fShowAmbient) {
jvanverthd7315f912016-08-17 10:06:18 -0700395 if (fUseAlt) {
396 this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
jvanverth6c177a12016-08-17 07:59:41 -0700397 } else {
jvanverthd7315f912016-08-17 10:06:18 -0700398 this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
jvanverth6c177a12016-08-17 07:59:41 -0700399 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700400 }
401 if (fShowSpot) {
jvanverthd7315f912016-08-17 10:06:18 -0700402 if (fUseAlt) {
403 this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
404 } else {
405 this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
406 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700407 }
Jim Van Verth3c1b7db2016-10-31 16:06:51 -0400408#endif
409
jvanverthe1a3bc62016-08-12 10:40:38 -0700410 if (fShowObject) {
411 canvas->drawPath(path, paint);
Robert Phillips95304e32016-10-07 14:44:07 -0400412 } else {
413 SkPaint strokePaint;
414
415 strokePaint.setColor(paint.getColor());
416 strokePaint.setStyle(SkPaint::kStroke_Style);
417
418 canvas->drawPath(path, strokePaint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700419 }
420 }
421
422 void onDrawContent(SkCanvas* canvas) override {
423 this->drawBG(canvas);
jvanverthd99858a2016-09-12 07:51:04 -0700424 const SkScalar kLightWidth = 2800;
jvanverthd7315f912016-08-17 10:06:18 -0700425 const SkScalar kAmbientAlpha = 0.25f;
426 const SkScalar kSpotAlpha = 0.25f;
jvanverthe1a3bc62016-08-12 10:40:38 -0700427
428 SkPaint paint;
429 paint.setAntiAlias(true);
430
jvanverthd7315f912016-08-17 10:06:18 -0700431 SkPoint3 lightPos = fLightPos;
432
jvanverthe1a3bc62016-08-12 10:40:38 -0700433 paint.setColor(SK_ColorWHITE);
434 canvas->translate(200, 90);
jvanverthd7315f912016-08-17 10:06:18 -0700435 lightPos.fX += 200;
436 lightPos.fY += 90;
Jim Van Verthc5903412016-11-17 15:27:09 -0500437 this->drawShadowedPath(canvas, fRectPath, 2, paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700438 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700439
440 paint.setColor(SK_ColorRED);
441 canvas->translate(250, 0);
jvanverthd7315f912016-08-17 10:06:18 -0700442 lightPos.fX += 250;
jvanverthd99858a2016-09-12 07:51:04 -0700443 this->drawShadowedPath(canvas, fRRPath, 4, paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700444 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700445
446 paint.setColor(SK_ColorBLUE);
447 canvas->translate(-250, 110);
jvanverthd7315f912016-08-17 10:06:18 -0700448 lightPos.fX -= 250;
449 lightPos.fY += 110;
jvanverthd99858a2016-09-12 07:51:04 -0700450 this->drawShadowedPath(canvas, fCirclePath, 8, paint, 0.0f,
jvanverthd7315f912016-08-17 10:06:18 -0700451 lightPos, kLightWidth, 0.5f);
jvanverth6c177a12016-08-17 07:59:41 -0700452
453 paint.setColor(SK_ColorGREEN);
454 canvas->translate(250, 0);
jvanverthd7315f912016-08-17 10:06:18 -0700455 lightPos.fX += 250;
jvanverthd99858a2016-09-12 07:51:04 -0700456 this->drawShadowedPath(canvas, fRRPath, 64, paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700457 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700458 }
459
460protected:
461 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
462 return new SkView::Click(this);
463 }
464
465 bool onClick(Click *click) override {
466 SkScalar x = click->fCurr.fX;
467 SkScalar y = click->fCurr.fY;
468
469 SkScalar dx = x - click->fPrev.fX;
470 SkScalar dy = y - click->fPrev.fY;
471
472 if (dx != 0 || dy != 0) {
473 fLightPos.fX += dx;
474 fLightPos.fY += dy;
475 this->inval(nullptr);
476 }
477
478 return true;
479 }
480
481private:
482 typedef SkView INHERITED;
483};
484
485//////////////////////////////////////////////////////////////////////////////
486
487static SkView* MyFactory() { return new ShadowsView; }
488static SkViewRegister reg(MyFactory);