blob: 8f2859282b1d1e339b1809a3946a3fdfff51d38e [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 Verth43475ad2017-01-13 14:37:37 -050015#include "SkShadowUtils.h"
jvanverthe1a3bc62016-08-12 10:40:38 -070016#include "SkUtils.h"
17#include "SkView.h"
18#include "sk_tool_utils.h"
19
Jim Van Verth43475ad2017-01-13 14:37:37 -050020#define USE_SHADOW_UTILS
21
jvanverth6c177a12016-08-17 07:59:41 -070022////////////////////////////////////////////////////////////////////////////
23
jvanverthe1a3bc62016-08-12 10:40:38 -070024class ShadowsView : public SampleView {
25 SkPath fRectPath;
26 SkPath fRRPath;
27 SkPath fCirclePath;
Jim Van Verthbce74962017-01-25 09:39:46 -050028 SkPath fFunkyRRPath;
29 SkPath fCubicPath;
jvanverthe1a3bc62016-08-12 10:40:38 -070030 SkPoint3 fLightPos;
31
32 bool fShowAmbient;
33 bool fShowSpot;
jvanverthd7315f912016-08-17 10:06:18 -070034 bool fUseAlt;
jvanverthe1a3bc62016-08-12 10:40:38 -070035 bool fShowObject;
Robert Phillips95304e32016-10-07 14:44:07 -040036 bool fIgnoreShadowAlpha;
jvanverthe1a3bc62016-08-12 10:40:38 -070037
38public:
39 ShadowsView()
40 : fShowAmbient(true)
41 , fShowSpot(true)
jvanverthd7315f912016-08-17 10:06:18 -070042 , fUseAlt(true)
Robert Phillips95304e32016-10-07 14:44:07 -040043 , fShowObject(true)
44 , fIgnoreShadowAlpha(false) {}
jvanverthe1a3bc62016-08-12 10:40:38 -070045
46protected:
47 void onOnceBeforeDraw() override {
48 fCirclePath.addCircle(0, 0, 50);
49 fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100));
50 fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4));
Jim Van Verthbce74962017-01-25 09:39:46 -050051 fFunkyRRPath.addRoundRect(SkRect::MakeXYWH(-50, -50, SK_Scalar1 * 100, SK_Scalar1 * 100),
52 40 * SK_Scalar1, 20 * SK_Scalar1,
53 SkPath::kCW_Direction);
54 fCubicPath.cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1,
55 20 * SK_Scalar1, 100 * SK_Scalar1,
56 0 * SK_Scalar1, 0 * SK_Scalar1);
57
jvanverthd99858a2016-09-12 07:51:04 -070058 fLightPos = SkPoint3::Make(-700, -700, 2800);
jvanverthe1a3bc62016-08-12 10:40:38 -070059 }
60
61 // overrides from SkEventSink
62 bool onQuery(SkEvent* evt) override {
63 if (SampleCode::TitleQ(*evt)) {
64 SampleCode::TitleR(evt, "AndroidShadows");
65 return true;
66 }
67
68 SkUnichar uni;
69 if (SampleCode::CharQ(*evt, &uni)) {
70 switch (uni) {
71 case 'B':
72 fShowAmbient = !fShowAmbient;
73 break;
74 case 'S':
75 fShowSpot = !fShowSpot;
76 break;
jvanverthd7315f912016-08-17 10:06:18 -070077 case 'T':
78 fUseAlt = !fUseAlt;
79 break;
jvanverthe1a3bc62016-08-12 10:40:38 -070080 case 'O':
81 fShowObject = !fShowObject;
82 break;
83 case '>':
84 fLightPos.fZ += 10;
85 break;
86 case '<':
87 fLightPos.fZ -= 10;
88 break;
Robert Phillips95304e32016-10-07 14:44:07 -040089 case '?':
90 fIgnoreShadowAlpha = !fIgnoreShadowAlpha;
91 break;
jvanverthe1a3bc62016-08-12 10:40:38 -070092 default:
93 break;
94 }
95 this->inval(nullptr);
96 }
97 return this->INHERITED::onQuery(evt);
98 }
99
100 void drawBG(SkCanvas* canvas) {
101 canvas->drawColor(0xFFDDDDDD);
102 }
103
104 static void GetOcclRect(const SkPath& path, SkRect* occlRect) {
105 SkRect pathRect;
106 SkRRect pathRRect;
107 if (path.isOval(&pathRect)) {
108 *occlRect = sk_tool_utils::compute_central_occluder(SkRRect::MakeOval(pathRect));
109 } else if (path.isRRect(&pathRRect)) {
110 *occlRect = sk_tool_utils::compute_central_occluder(pathRRect);
111 } else if (path.isRect(occlRect)) {
112 // the inverse transform for the spot shadow occluder doesn't always get us
113 // back to exactly the same position, so deducting a little slop
114 occlRect->inset(1, 1);
115 } else {
116 *occlRect = SkRect::MakeEmpty();
117 }
118 }
119
120 void drawAmbientShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
121 SkScalar ambientAlpha) {
122
123 if (ambientAlpha <= 0) {
124 return;
125 }
126
127 const SkScalar kHeightFactor = 1.f / 128.f;
128 const SkScalar kGeomFactor = 64;
129
130 SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
131 SkScalar radius = zValue*kHeightFactor*kGeomFactor;
132
133 // occlude blur
134 SkRect occlRect;
135 GetOcclRect(path, &occlRect);
136 sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
137 SkBlurMask::ConvertRadiusToSigma(radius),
138 occlRect,
139 SkBlurMaskFilter::kNone_BlurFlag);
140
141 SkPaint paint;
142 paint.setAntiAlias(true);
143 paint.setMaskFilter(std::move(mf));
Robert Phillips95304e32016-10-07 14:44:07 -0400144 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
145 ? 255
146 : (unsigned char)(ambientAlpha*umbraAlpha*255.999f), 0, 0, 0));
jvanverthe1a3bc62016-08-12 10:40:38 -0700147 canvas->drawPath(path, paint);
148
149 // draw occlusion rect
jvanverth6c177a12016-08-17 07:59:41 -0700150#if DRAW_OCCL_RECT
jvanverthe1a3bc62016-08-12 10:40:38 -0700151 SkPaint stroke;
152 stroke.setStyle(SkPaint::kStroke_Style);
153 stroke.setColor(SK_ColorBLUE);
154 canvas->drawRect(occlRect, stroke);
jvanverth6c177a12016-08-17 07:59:41 -0700155#endif
156 }
157
158 void drawAmbientShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
159 SkScalar ambientAlpha) {
160
161 if (ambientAlpha <= 0) {
162 return;
163 }
164
165 const SkScalar kHeightFactor = 1.f / 128.f;
166 const SkScalar kGeomFactor = 64;
167
168 SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
169 SkScalar radius = zValue*kHeightFactor*kGeomFactor;
jvanverthd99858a2016-09-12 07:51:04 -0700170 // distance to outer of edge of geometry from original shape edge
171 SkScalar offset = radius*umbraAlpha;
jvanverth6c177a12016-08-17 07:59:41 -0700172
jvanvertha4f1af82016-08-29 07:17:47 -0700173 SkRect pathRect;
174 SkRRect pathRRect;
jvanverthd99858a2016-09-12 07:51:04 -0700175 SkScalar scaleFactors[2];
176 if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
177 return;
178 }
179 if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 64 ||
jvanvertha4f1af82016-08-29 07:17:47 -0700180 !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
181 (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
182 path.isRect(&pathRect))) {
183 this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
184 return;
185 }
186
jvanverthd99858a2016-09-12 07:51:04 -0700187 // For all of these, we inset the offset rect by half the radius to get our stroke shape.
188 SkScalar strokeOutset = offset - SK_ScalarHalf*radius;
189 // Make sure we'll have a radius of at least 0.5 after xform
190 if (strokeOutset*scaleFactors[0] < 0.5f) {
191 strokeOutset = 0.5f / scaleFactors[0];
192 }
jvanverthd7315f912016-08-17 10:06:18 -0700193 if (path.isOval(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700194 pathRect.outset(strokeOutset, strokeOutset);
jvanverthd7315f912016-08-17 10:06:18 -0700195 pathRRect = SkRRect::MakeOval(pathRect);
196 } else if (path.isRect(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700197 pathRect.outset(strokeOutset, strokeOutset);
198 pathRRect = SkRRect::MakeRectXY(pathRect, strokeOutset, strokeOutset);
jvanverth6c177a12016-08-17 07:59:41 -0700199 } else {
jvanverthd99858a2016-09-12 07:51:04 -0700200 pathRRect.outset(strokeOutset, strokeOutset);
jvanverth6c177a12016-08-17 07:59:41 -0700201 }
202
jvanverthd7315f912016-08-17 10:06:18 -0700203 SkPaint paint;
204 paint.setAntiAlias(true);
jvanvertha4f1af82016-08-29 07:17:47 -0700205 paint.setStyle(SkPaint::kStroke_Style);
206 // we outset the stroke a little to cover up AA on the interior edge
jvanverthd99858a2016-09-12 07:51:04 -0700207 SkScalar pad = 0.5f;
208 paint.setStrokeWidth(radius + 2*pad);
209 // handle scale of radius and pad due to CTM
210 radius *= scaleFactors[0];
211 pad *= scaleFactors[0];
212 SkASSERT(radius < 16384);
213 SkASSERT(pad < 64);
214 // Convert radius to 14.2 fixed point and place in the R & G components.
215 // Convert pad to 6.2 fixed point and place in the B component.
216 uint16_t iRadius = (uint16_t)(radius*4.0f);
217 unsigned char alpha = (unsigned char)(ambientAlpha*255.999f);
Robert Phillips95304e32016-10-07 14:44:07 -0400218 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
219 iRadius >> 8, iRadius & 0xff,
jvanverthd99858a2016-09-12 07:51:04 -0700220 (unsigned char)(4.0f*pad)));
jvanverthd7315f912016-08-17 10:06:18 -0700221
jvanverthc20c0c02016-09-14 07:04:49 -0700222 paint.setShader(SkGaussianEdgeShader::Make());
jvanverthd7315f912016-08-17 10:06:18 -0700223 canvas->drawRRect(pathRRect, paint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700224 }
225
226 void drawSpotShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
227 SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
228 if (spotAlpha <= 0) {
229 return;
230 }
231
232 SkScalar zRatio = zValue / (lightPos.fZ - zValue);
233 if (zRatio < 0.0f) {
234 zRatio = 0.0f;
235 } else if (zRatio > 0.95f) {
236 zRatio = 0.95f;
237 }
jvanverthd99858a2016-09-12 07:51:04 -0700238 SkScalar blurRadius = lightWidth*zRatio;
jvanverthe1a3bc62016-08-12 10:40:38 -0700239
240 // compute the transformation params
241 SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
jvanverthd99858a2016-09-12 07:51:04 -0700242 SkMatrix ctmInverse;
243 if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
244 return;
jvanverthe1a3bc62016-08-12 10:40:38 -0700245 }
jvanverthd99858a2016-09-12 07:51:04 -0700246 SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
247 ctmInverse.mapPoints(&lightPos2D, 1);
248 SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
249 zRatio*(center.fY - lightPos2D.fY));
250 SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
jvanverthe1a3bc62016-08-12 10:40:38 -0700251
252 SkAutoCanvasRestore acr(canvas, true);
253
jvanverthe1a3bc62016-08-12 10:40:38 -0700254 sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
jvanverthd99858a2016-09-12 07:51:04 -0700255 SkBlurMask::ConvertRadiusToSigma(blurRadius),
jvanverthe1a3bc62016-08-12 10:40:38 -0700256 SkBlurMaskFilter::kNone_BlurFlag);
257
258 SkPaint paint;
259 paint.setAntiAlias(true);
260 paint.setMaskFilter(std::move(mf));
Robert Phillips95304e32016-10-07 14:44:07 -0400261 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
262 ? 255
263 : (unsigned char)(spotAlpha*255.999f), 0, 0, 0));
jvanverthe1a3bc62016-08-12 10:40:38 -0700264
265 // apply transformation to shadow
jvanverthe1a3bc62016-08-12 10:40:38 -0700266 canvas->scale(scale, scale);
jvanverthd99858a2016-09-12 07:51:04 -0700267 canvas->translate(offset.fX, offset.fY);
jvanverthe1a3bc62016-08-12 10:40:38 -0700268 canvas->drawPath(path, paint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700269 }
270
jvanverthd7315f912016-08-17 10:06:18 -0700271 void drawSpotShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
272 SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
273 if (spotAlpha <= 0) {
274 return;
275 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700276
jvanverthd7315f912016-08-17 10:06:18 -0700277 SkScalar zRatio = zValue / (lightPos.fZ - zValue);
278 if (zRatio < 0.0f) {
279 zRatio = 0.0f;
280 } else if (zRatio > 0.95f) {
281 zRatio = 0.95f;
282 }
jvanverthd99858a2016-09-12 07:51:04 -0700283 SkScalar radius = 2.0f*lightWidth*zRatio;
jvanverthd7315f912016-08-17 10:06:18 -0700284
jvanvertha4f1af82016-08-29 07:17:47 -0700285 SkRect pathRect;
286 SkRRect pathRRect;
jvanverthd99858a2016-09-12 07:51:04 -0700287 SkScalar scaleFactors[2];
288 if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
289 return;
290 }
291 if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 16384 ||
jvanvertha4f1af82016-08-29 07:17:47 -0700292 !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
293 (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
294 path.isRect(&pathRect))) {
295 this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
296 return;
297 }
298
jvanverthd99858a2016-09-12 07:51:04 -0700299 // 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 -0400300 const SkScalar minRadius = SK_ScalarHalf/scaleFactors[0];
jvanverthd7315f912016-08-17 10:06:18 -0700301 if (path.isOval(nullptr)) {
jvanverthd7315f912016-08-17 10:06:18 -0700302 pathRRect = SkRRect::MakeOval(pathRect);
303 } else if (path.isRect(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700304 pathRRect = SkRRect::MakeRectXY(pathRect, minRadius, minRadius);
jvanverthd7315f912016-08-17 10:06:18 -0700305 } else {
jvanverthd99858a2016-09-12 07:51:04 -0700306 if (pathRRect.getSimpleRadii().fX < minRadius) {
307 pathRRect.setRectXY(pathRRect.rect(), minRadius, minRadius);
308 }
jvanverthd7315f912016-08-17 10:06:18 -0700309 }
310
jvanverthd99858a2016-09-12 07:51:04 -0700311 // compute the scale and translation for the shadow
312 SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
313 SkRRect shadowRRect;
314 pathRRect.transform(SkMatrix::MakeScale(scale, scale), &shadowRRect);
315 SkPoint center = SkPoint::Make(shadowRRect.rect().centerX(), shadowRRect.rect().centerY());
316 SkMatrix ctmInverse;
317 if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
318 return;
319 }
320 SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
321 ctmInverse.mapPoints(&lightPos2D, 1);
322 SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
323 zRatio*(center.fY - lightPos2D.fY));
jvanverthd7315f912016-08-17 10:06:18 -0700324 SkAutoCanvasRestore acr(canvas, true);
325
326 SkPaint paint;
327 paint.setAntiAlias(true);
Robert Phillips95304e32016-10-07 14:44:07 -0400328 // We want to extend the stroked area in so that it meets up with the caster
329 // geometry. The stroked geometry will, by definition already be inset half the
330 // stroke width but we also have to account for the scaling.
331 // We also add 1/2 to cover up AA on the interior edge.
332 SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(pathRect.fLeft),
333 SkTAbs(pathRect.fRight)),
334 SkTMax(SkTAbs(pathRect.fTop),
335 SkTAbs(pathRect.fBottom)));
336 SkScalar insetAmount = offset.length() - (0.5f * radius) + scaleOffset + 0.5f;
337
jvanvertha4f1af82016-08-29 07:17:47 -0700338 // compute area
Robert Phillips95304e32016-10-07 14:44:07 -0400339 SkScalar strokeWidth = radius + insetAmount;
jvanverthd99858a2016-09-12 07:51:04 -0700340 SkScalar strokedArea = 2.0f*strokeWidth*(shadowRRect.width() + shadowRRect.height());
341 SkScalar filledArea = (shadowRRect.height() + radius)*(shadowRRect.width() + radius);
jvanvertha4f1af82016-08-29 07:17:47 -0700342 // If the area of the stroked geometry is larger than the fill geometry, or
343 // if our pad is too big to convert to 6.2 fixed point, just fill it.
Robert Phillips95304e32016-10-07 14:44:07 -0400344 if (strokedArea > filledArea) {
jvanvertha4f1af82016-08-29 07:17:47 -0700345 paint.setStyle(SkPaint::kStrokeAndFill_Style);
346 paint.setStrokeWidth(radius);
347 } else {
Robert Phillips95304e32016-10-07 14:44:07 -0400348 // Since we can't have unequal strokes, inset the shadow rect so the inner
349 // and outer edges of the stroke will land where we want.
350 SkRect insetRect = shadowRRect.rect().makeInset(insetAmount/2.0f, insetAmount/2.0f);
351 SkScalar insetRad = SkTMax(shadowRRect.getSimpleRadii().fX - insetAmount/2.0f,
352 minRadius);
353
354 shadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad);
jvanvertha4f1af82016-08-29 07:17:47 -0700355 paint.setStyle(SkPaint::kStroke_Style);
356 paint.setStrokeWidth(strokeWidth);
357 }
jvanverthc20c0c02016-09-14 07:04:49 -0700358 paint.setShader(SkGaussianEdgeShader::Make());
jvanverthd7315f912016-08-17 10:06:18 -0700359 // handle scale of radius due to CTM
jvanverthd99858a2016-09-12 07:51:04 -0700360 radius *= scaleFactors[0];
361 // don't need to scale pad as it was computed from the transformed offset
362 SkASSERT(radius < 16384);
Robert Phillips95304e32016-10-07 14:44:07 -0400363 SkScalar pad = 0;
jvanvertha4f1af82016-08-29 07:17:47 -0700364 SkASSERT(pad < 64);
jvanverthd99858a2016-09-12 07:51:04 -0700365 // Convert radius to 14.2 fixed point and place in the R & G components.
366 // Convert pad to 6.2 fixed point and place in the B component.
367 uint16_t iRadius = (uint16_t)(radius*4.0f);
368 unsigned char alpha = (unsigned char)(spotAlpha*255.999f);
Robert Phillips95304e32016-10-07 14:44:07 -0400369 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
370 iRadius >> 8, iRadius & 0xff,
jvanverthd99858a2016-09-12 07:51:04 -0700371 (unsigned char)(4.0f*pad)));
jvanverthd7315f912016-08-17 10:06:18 -0700372
373 // apply transformation to shadow
374 canvas->translate(offset.fX, offset.fY);
jvanverthd99858a2016-09-12 07:51:04 -0700375 canvas->drawRRect(shadowRRect, paint);
jvanverthd7315f912016-08-17 10:06:18 -0700376 }
377
378 void drawShadowedPath(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
379 const SkPaint& paint, SkScalar ambientAlpha,
380 const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
Jim Van Verth43475ad2017-01-13 14:37:37 -0500381#ifdef USE_SHADOW_UTILS
Jim Van Verth3c1b7db2016-10-31 16:06:51 -0400382 if (fUseAlt) {
383 if (fShowAmbient) {
384 this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
385 }
386 if (fShowSpot) {
387 this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
388 }
389 } else {
Jim Van Verth3c1b7db2016-10-31 16:06:51 -0400390 if (!fShowAmbient) {
391 ambientAlpha = 0;
392 }
393 if (!fShowSpot) {
394 spotAlpha = 0;
395 }
Jim Van Verth43475ad2017-01-13 14:37:37 -0500396 SkShadowUtils::DrawShadow(canvas, path, zValue, lightPos, lightWidth,
397 ambientAlpha, spotAlpha, SK_ColorBLACK);
Jim Van Verth3c1b7db2016-10-31 16:06:51 -0400398 }
399#else
jvanverthe1a3bc62016-08-12 10:40:38 -0700400 if (fShowAmbient) {
jvanverthd7315f912016-08-17 10:06:18 -0700401 if (fUseAlt) {
402 this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
jvanverth6c177a12016-08-17 07:59:41 -0700403 } else {
jvanverthd7315f912016-08-17 10:06:18 -0700404 this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
jvanverth6c177a12016-08-17 07:59:41 -0700405 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700406 }
407 if (fShowSpot) {
jvanverthd7315f912016-08-17 10:06:18 -0700408 if (fUseAlt) {
409 this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
410 } else {
411 this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
412 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700413 }
Jim Van Verth3c1b7db2016-10-31 16:06:51 -0400414#endif
415
jvanverthe1a3bc62016-08-12 10:40:38 -0700416 if (fShowObject) {
417 canvas->drawPath(path, paint);
Robert Phillips95304e32016-10-07 14:44:07 -0400418 } else {
419 SkPaint strokePaint;
420
421 strokePaint.setColor(paint.getColor());
422 strokePaint.setStyle(SkPaint::kStroke_Style);
423
424 canvas->drawPath(path, strokePaint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700425 }
426 }
427
428 void onDrawContent(SkCanvas* canvas) override {
429 this->drawBG(canvas);
jvanverthd99858a2016-09-12 07:51:04 -0700430 const SkScalar kLightWidth = 2800;
jvanverthd7315f912016-08-17 10:06:18 -0700431 const SkScalar kAmbientAlpha = 0.25f;
432 const SkScalar kSpotAlpha = 0.25f;
jvanverthe1a3bc62016-08-12 10:40:38 -0700433
434 SkPaint paint;
435 paint.setAntiAlias(true);
436
jvanverthd7315f912016-08-17 10:06:18 -0700437 SkPoint3 lightPos = fLightPos;
438
jvanverthe1a3bc62016-08-12 10:40:38 -0700439 paint.setColor(SK_ColorWHITE);
440 canvas->translate(200, 90);
jvanverthd7315f912016-08-17 10:06:18 -0700441 lightPos.fX += 200;
442 lightPos.fY += 90;
Jim Van Verthbce74962017-01-25 09:39:46 -0500443 this->drawShadowedPath(canvas, fRRPath, 2, paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700444 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700445
446 paint.setColor(SK_ColorRED);
447 canvas->translate(250, 0);
jvanverthd7315f912016-08-17 10:06:18 -0700448 lightPos.fX += 250;
Jim Van Verthbce74962017-01-25 09:39:46 -0500449 this->drawShadowedPath(canvas, fRectPath, 4, paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700450 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700451
452 paint.setColor(SK_ColorBLUE);
453 canvas->translate(-250, 110);
jvanverthd7315f912016-08-17 10:06:18 -0700454 lightPos.fX -= 250;
455 lightPos.fY += 110;
Jim Van Verthbce74962017-01-25 09:39:46 -0500456 this->drawShadowedPath(canvas, fCirclePath, 8, paint, 0,
jvanverthd7315f912016-08-17 10:06:18 -0700457 lightPos, kLightWidth, 0.5f);
jvanverth6c177a12016-08-17 07:59:41 -0700458
459 paint.setColor(SK_ColorGREEN);
460 canvas->translate(250, 0);
jvanverthd7315f912016-08-17 10:06:18 -0700461 lightPos.fX += 250;
jvanverthd99858a2016-09-12 07:51:04 -0700462 this->drawShadowedPath(canvas, fRRPath, 64, paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700463 lightPos, kLightWidth, kSpotAlpha);
Jim Van Verthbce74962017-01-25 09:39:46 -0500464
465 paint.setColor(SK_ColorYELLOW);
466 canvas->translate(-250, 110);
467 lightPos.fX -= 250;
468 lightPos.fY += 110;
469 this->drawShadowedPath(canvas, fFunkyRRPath, 8, paint, kAmbientAlpha,
470 lightPos, kLightWidth, kSpotAlpha);
471
472 paint.setColor(SK_ColorCYAN);
473 canvas->translate(250, 0);
474 lightPos.fX += 250;
475 this->drawShadowedPath(canvas, fCubicPath, 16, paint, kAmbientAlpha,
476 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700477 }
478
479protected:
480 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
481 return new SkView::Click(this);
482 }
483
484 bool onClick(Click *click) override {
485 SkScalar x = click->fCurr.fX;
486 SkScalar y = click->fCurr.fY;
487
488 SkScalar dx = x - click->fPrev.fX;
489 SkScalar dy = y - click->fPrev.fY;
490
491 if (dx != 0 || dy != 0) {
492 fLightPos.fX += dx;
493 fLightPos.fY += dy;
494 this->inval(nullptr);
495 }
496
497 return true;
498 }
499
500private:
501 typedef SkView INHERITED;
502};
503
504//////////////////////////////////////////////////////////////////////////////
505
506static SkView* MyFactory() { return new ShadowsView; }
507static SkViewRegister reg(MyFactory);