blob: cad8f5012e9601bff361cff80af2e02b086602fe [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"
Jim Van Verth2aa535e2017-02-06 14:36:01 -050011#include "SkColorFilter.h"
jvanverthe1a3bc62016-08-12 10:40:38 -070012#include "SkCanvas.h"
jvanverth6c177a12016-08-17 07:59:41 -070013#include "SkGaussianEdgeShader.h"
jvanverthe1a3bc62016-08-12 10:40:38 -070014#include "SkPath.h"
15#include "SkPoint3.h"
Jim Van Verth43475ad2017-01-13 14:37:37 -050016#include "SkShadowUtils.h"
jvanverthe1a3bc62016-08-12 10:40:38 -070017#include "SkUtils.h"
18#include "SkView.h"
19#include "sk_tool_utils.h"
20
Jim Van Verth43475ad2017-01-13 14:37:37 -050021#define USE_SHADOW_UTILS
22
jvanverth6c177a12016-08-17 07:59:41 -070023////////////////////////////////////////////////////////////////////////////
24
jvanverthe1a3bc62016-08-12 10:40:38 -070025class ShadowsView : public SampleView {
26 SkPath fRectPath;
27 SkPath fRRPath;
28 SkPath fCirclePath;
Jim Van Verthbce74962017-01-25 09:39:46 -050029 SkPath fFunkyRRPath;
30 SkPath fCubicPath;
jvanverthe1a3bc62016-08-12 10:40:38 -070031 SkPoint3 fLightPos;
Jim Van Verth2aa535e2017-02-06 14:36:01 -050032 SkScalar fZDelta;
jvanverthe1a3bc62016-08-12 10:40:38 -070033
34 bool fShowAmbient;
35 bool fShowSpot;
jvanverthd7315f912016-08-17 10:06:18 -070036 bool fUseAlt;
jvanverthe1a3bc62016-08-12 10:40:38 -070037 bool fShowObject;
Robert Phillips95304e32016-10-07 14:44:07 -040038 bool fIgnoreShadowAlpha;
jvanverthe1a3bc62016-08-12 10:40:38 -070039
40public:
Jim Van Verth2aa535e2017-02-06 14:36:01 -050041 ShadowsView()
42 : fZDelta(0.0f)
43 , fShowAmbient(true)
jvanverthe1a3bc62016-08-12 10:40:38 -070044 , fShowSpot(true)
jvanverthd7315f912016-08-17 10:06:18 -070045 , fUseAlt(true)
Robert Phillips95304e32016-10-07 14:44:07 -040046 , fShowObject(true)
47 , fIgnoreShadowAlpha(false) {}
jvanverthe1a3bc62016-08-12 10:40:38 -070048
49protected:
50 void onOnceBeforeDraw() override {
51 fCirclePath.addCircle(0, 0, 50);
52 fRectPath.addRect(SkRect::MakeXYWH(-100, -50, 200, 100));
53 fRRPath.addRRect(SkRRect::MakeRectXY(SkRect::MakeXYWH(-100, -50, 200, 100), 4, 4));
Jim Van Verthbce74962017-01-25 09:39:46 -050054 fFunkyRRPath.addRoundRect(SkRect::MakeXYWH(-50, -50, SK_Scalar1 * 100, SK_Scalar1 * 100),
55 40 * SK_Scalar1, 20 * SK_Scalar1,
56 SkPath::kCW_Direction);
57 fCubicPath.cubicTo(100 * SK_Scalar1, 50 * SK_Scalar1,
58 20 * SK_Scalar1, 100 * SK_Scalar1,
59 0 * SK_Scalar1, 0 * SK_Scalar1);
60
jvanverthd99858a2016-09-12 07:51:04 -070061 fLightPos = SkPoint3::Make(-700, -700, 2800);
jvanverthe1a3bc62016-08-12 10:40:38 -070062 }
63
64 // overrides from SkEventSink
65 bool onQuery(SkEvent* evt) override {
66 if (SampleCode::TitleQ(*evt)) {
67 SampleCode::TitleR(evt, "AndroidShadows");
68 return true;
69 }
70
71 SkUnichar uni;
72 if (SampleCode::CharQ(*evt, &uni)) {
Jim Van Verth6f449692017-02-14 15:16:46 -050073 bool handled = false;
jvanverthe1a3bc62016-08-12 10:40:38 -070074 switch (uni) {
Jim Van Verth2aa535e2017-02-06 14:36:01 -050075 case 'W':
jvanverthe1a3bc62016-08-12 10:40:38 -070076 fShowAmbient = !fShowAmbient;
Jim Van Verth6f449692017-02-14 15:16:46 -050077 handled = true;
jvanverthe1a3bc62016-08-12 10:40:38 -070078 break;
79 case 'S':
80 fShowSpot = !fShowSpot;
Jim Van Verth6f449692017-02-14 15:16:46 -050081 handled = true;
jvanverthe1a3bc62016-08-12 10:40:38 -070082 break;
jvanverthd7315f912016-08-17 10:06:18 -070083 case 'T':
84 fUseAlt = !fUseAlt;
Jim Van Verth6f449692017-02-14 15:16:46 -050085 handled = true;
jvanverthd7315f912016-08-17 10:06:18 -070086 break;
jvanverthe1a3bc62016-08-12 10:40:38 -070087 case 'O':
88 fShowObject = !fShowObject;
Jim Van Verth6f449692017-02-14 15:16:46 -050089 handled = true;
jvanverthe1a3bc62016-08-12 10:40:38 -070090 break;
91 case '>':
Jim Van Verth2aa535e2017-02-06 14:36:01 -050092 fZDelta += 0.5f;
Jim Van Verth6f449692017-02-14 15:16:46 -050093 handled = true;
jvanverthe1a3bc62016-08-12 10:40:38 -070094 break;
95 case '<':
Jim Van Verth2aa535e2017-02-06 14:36:01 -050096 fZDelta -= 0.5f;
Jim Van Verth6f449692017-02-14 15:16:46 -050097 handled = true;
jvanverthe1a3bc62016-08-12 10:40:38 -070098 break;
Robert Phillips95304e32016-10-07 14:44:07 -040099 case '?':
100 fIgnoreShadowAlpha = !fIgnoreShadowAlpha;
Jim Van Verth6f449692017-02-14 15:16:46 -0500101 handled = true;
Robert Phillips95304e32016-10-07 14:44:07 -0400102 break;
jvanverthe1a3bc62016-08-12 10:40:38 -0700103 default:
104 break;
105 }
Jim Van Verth6f449692017-02-14 15:16:46 -0500106 if (handled) {
107 this->inval(nullptr);
108 return true;
109 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700110 }
111 return this->INHERITED::onQuery(evt);
112 }
113
114 void drawBG(SkCanvas* canvas) {
115 canvas->drawColor(0xFFDDDDDD);
116 }
117
118 static void GetOcclRect(const SkPath& path, SkRect* occlRect) {
119 SkRect pathRect;
120 SkRRect pathRRect;
121 if (path.isOval(&pathRect)) {
122 *occlRect = sk_tool_utils::compute_central_occluder(SkRRect::MakeOval(pathRect));
123 } else if (path.isRRect(&pathRRect)) {
124 *occlRect = sk_tool_utils::compute_central_occluder(pathRRect);
125 } else if (path.isRect(occlRect)) {
126 // the inverse transform for the spot shadow occluder doesn't always get us
127 // back to exactly the same position, so deducting a little slop
128 occlRect->inset(1, 1);
129 } else {
130 *occlRect = SkRect::MakeEmpty();
131 }
132 }
133
134 void drawAmbientShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
135 SkScalar ambientAlpha) {
136
137 if (ambientAlpha <= 0) {
138 return;
139 }
140
141 const SkScalar kHeightFactor = 1.f / 128.f;
142 const SkScalar kGeomFactor = 64;
143
144 SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
145 SkScalar radius = zValue*kHeightFactor*kGeomFactor;
146
147 // occlude blur
148 SkRect occlRect;
149 GetOcclRect(path, &occlRect);
150 sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
151 SkBlurMask::ConvertRadiusToSigma(radius),
152 occlRect,
153 SkBlurMaskFilter::kNone_BlurFlag);
154
155 SkPaint paint;
156 paint.setAntiAlias(true);
157 paint.setMaskFilter(std::move(mf));
Robert Phillips95304e32016-10-07 14:44:07 -0400158 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
159 ? 255
160 : (unsigned char)(ambientAlpha*umbraAlpha*255.999f), 0, 0, 0));
jvanverthe1a3bc62016-08-12 10:40:38 -0700161 canvas->drawPath(path, paint);
162
163 // draw occlusion rect
jvanverth6c177a12016-08-17 07:59:41 -0700164#if DRAW_OCCL_RECT
jvanverthe1a3bc62016-08-12 10:40:38 -0700165 SkPaint stroke;
166 stroke.setStyle(SkPaint::kStroke_Style);
167 stroke.setColor(SK_ColorBLUE);
168 canvas->drawRect(occlRect, stroke);
jvanverth6c177a12016-08-17 07:59:41 -0700169#endif
170 }
171
172 void drawAmbientShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
173 SkScalar ambientAlpha) {
174
175 if (ambientAlpha <= 0) {
176 return;
177 }
178
179 const SkScalar kHeightFactor = 1.f / 128.f;
180 const SkScalar kGeomFactor = 64;
181
182 SkScalar umbraAlpha = 1 / (1 + SkMaxScalar(zValue*kHeightFactor, 0));
183 SkScalar radius = zValue*kHeightFactor*kGeomFactor;
jvanverthd99858a2016-09-12 07:51:04 -0700184 // distance to outer of edge of geometry from original shape edge
185 SkScalar offset = radius*umbraAlpha;
jvanverth6c177a12016-08-17 07:59:41 -0700186
jvanvertha4f1af82016-08-29 07:17:47 -0700187 SkRect pathRect;
188 SkRRect pathRRect;
jvanverthd99858a2016-09-12 07:51:04 -0700189 SkScalar scaleFactors[2];
190 if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
191 return;
192 }
193 if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 64 ||
jvanvertha4f1af82016-08-29 07:17:47 -0700194 !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
195 (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
196 path.isRect(&pathRect))) {
197 this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
198 return;
199 }
200
jvanverthd99858a2016-09-12 07:51:04 -0700201 // For all of these, we inset the offset rect by half the radius to get our stroke shape.
202 SkScalar strokeOutset = offset - SK_ScalarHalf*radius;
203 // Make sure we'll have a radius of at least 0.5 after xform
204 if (strokeOutset*scaleFactors[0] < 0.5f) {
205 strokeOutset = 0.5f / scaleFactors[0];
206 }
jvanverthd7315f912016-08-17 10:06:18 -0700207 if (path.isOval(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700208 pathRect.outset(strokeOutset, strokeOutset);
jvanverthd7315f912016-08-17 10:06:18 -0700209 pathRRect = SkRRect::MakeOval(pathRect);
210 } else if (path.isRect(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700211 pathRect.outset(strokeOutset, strokeOutset);
212 pathRRect = SkRRect::MakeRectXY(pathRect, strokeOutset, strokeOutset);
jvanverth6c177a12016-08-17 07:59:41 -0700213 } else {
jvanverthd99858a2016-09-12 07:51:04 -0700214 pathRRect.outset(strokeOutset, strokeOutset);
jvanverth6c177a12016-08-17 07:59:41 -0700215 }
216
jvanverthd7315f912016-08-17 10:06:18 -0700217 SkPaint paint;
218 paint.setAntiAlias(true);
jvanvertha4f1af82016-08-29 07:17:47 -0700219 paint.setStyle(SkPaint::kStroke_Style);
220 // we outset the stroke a little to cover up AA on the interior edge
jvanverthd99858a2016-09-12 07:51:04 -0700221 SkScalar pad = 0.5f;
222 paint.setStrokeWidth(radius + 2*pad);
223 // handle scale of radius and pad due to CTM
224 radius *= scaleFactors[0];
225 pad *= scaleFactors[0];
226 SkASSERT(radius < 16384);
227 SkASSERT(pad < 64);
228 // Convert radius to 14.2 fixed point and place in the R & G components.
229 // Convert pad to 6.2 fixed point and place in the B component.
230 uint16_t iRadius = (uint16_t)(radius*4.0f);
231 unsigned char alpha = (unsigned char)(ambientAlpha*255.999f);
Robert Phillips95304e32016-10-07 14:44:07 -0400232 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
233 iRadius >> 8, iRadius & 0xff,
jvanverthd99858a2016-09-12 07:51:04 -0700234 (unsigned char)(4.0f*pad)));
jvanverthd7315f912016-08-17 10:06:18 -0700235
Jim Van Verth2aa535e2017-02-06 14:36:01 -0500236 paint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorBLACK, SkBlendMode::kModulate));
jvanverthc20c0c02016-09-14 07:04:49 -0700237 paint.setShader(SkGaussianEdgeShader::Make());
jvanverthd7315f912016-08-17 10:06:18 -0700238 canvas->drawRRect(pathRRect, paint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700239 }
240
241 void drawSpotShadow(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
242 SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
243 if (spotAlpha <= 0) {
244 return;
245 }
246
247 SkScalar zRatio = zValue / (lightPos.fZ - zValue);
248 if (zRatio < 0.0f) {
249 zRatio = 0.0f;
250 } else if (zRatio > 0.95f) {
251 zRatio = 0.95f;
252 }
jvanverthd99858a2016-09-12 07:51:04 -0700253 SkScalar blurRadius = lightWidth*zRatio;
jvanverthe1a3bc62016-08-12 10:40:38 -0700254
255 // compute the transformation params
256 SkPoint center = SkPoint::Make(path.getBounds().centerX(), path.getBounds().centerY());
jvanverthd99858a2016-09-12 07:51:04 -0700257 SkMatrix ctmInverse;
258 if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
259 return;
jvanverthe1a3bc62016-08-12 10:40:38 -0700260 }
jvanverthd99858a2016-09-12 07:51:04 -0700261 SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
262 ctmInverse.mapPoints(&lightPos2D, 1);
263 SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
264 zRatio*(center.fY - lightPos2D.fY));
265 SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
jvanverthe1a3bc62016-08-12 10:40:38 -0700266
267 SkAutoCanvasRestore acr(canvas, true);
268
jvanverthe1a3bc62016-08-12 10:40:38 -0700269 sk_sp<SkMaskFilter> mf = SkBlurMaskFilter::Make(kNormal_SkBlurStyle,
jvanverthd99858a2016-09-12 07:51:04 -0700270 SkBlurMask::ConvertRadiusToSigma(blurRadius),
jvanverthe1a3bc62016-08-12 10:40:38 -0700271 SkBlurMaskFilter::kNone_BlurFlag);
272
273 SkPaint paint;
274 paint.setAntiAlias(true);
275 paint.setMaskFilter(std::move(mf));
Robert Phillips95304e32016-10-07 14:44:07 -0400276 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha
277 ? 255
278 : (unsigned char)(spotAlpha*255.999f), 0, 0, 0));
jvanverthe1a3bc62016-08-12 10:40:38 -0700279
280 // apply transformation to shadow
jvanverthe1a3bc62016-08-12 10:40:38 -0700281 canvas->scale(scale, scale);
jvanverthd99858a2016-09-12 07:51:04 -0700282 canvas->translate(offset.fX, offset.fY);
jvanverthe1a3bc62016-08-12 10:40:38 -0700283 canvas->drawPath(path, paint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700284 }
285
jvanverthd7315f912016-08-17 10:06:18 -0700286 void drawSpotShadowAlt(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
287 SkPoint3 lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
288 if (spotAlpha <= 0) {
289 return;
290 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700291
jvanverthd7315f912016-08-17 10:06:18 -0700292 SkScalar zRatio = zValue / (lightPos.fZ - zValue);
293 if (zRatio < 0.0f) {
294 zRatio = 0.0f;
295 } else if (zRatio > 0.95f) {
296 zRatio = 0.95f;
297 }
jvanverthd99858a2016-09-12 07:51:04 -0700298 SkScalar radius = 2.0f*lightWidth*zRatio;
jvanverthd7315f912016-08-17 10:06:18 -0700299
jvanvertha4f1af82016-08-29 07:17:47 -0700300 SkRect pathRect;
301 SkRRect pathRRect;
jvanverthd99858a2016-09-12 07:51:04 -0700302 SkScalar scaleFactors[2];
303 if (!canvas->getTotalMatrix().getMinMaxScales(scaleFactors)) {
304 return;
305 }
306 if (scaleFactors[0] != scaleFactors[1] || radius*scaleFactors[0] >= 16384 ||
jvanvertha4f1af82016-08-29 07:17:47 -0700307 !((path.isOval(&pathRect) && pathRect.width() == pathRect.height()) ||
308 (path.isRRect(&pathRRect) && pathRRect.allCornersCircular()) ||
309 path.isRect(&pathRect))) {
310 this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
311 return;
312 }
313
jvanverthd99858a2016-09-12 07:51:04 -0700314 // 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 -0400315 const SkScalar minRadius = SK_ScalarHalf/scaleFactors[0];
jvanverthd7315f912016-08-17 10:06:18 -0700316 if (path.isOval(nullptr)) {
jvanverthd7315f912016-08-17 10:06:18 -0700317 pathRRect = SkRRect::MakeOval(pathRect);
318 } else if (path.isRect(nullptr)) {
jvanverthd99858a2016-09-12 07:51:04 -0700319 pathRRect = SkRRect::MakeRectXY(pathRect, minRadius, minRadius);
jvanverthd7315f912016-08-17 10:06:18 -0700320 } else {
jvanverthd99858a2016-09-12 07:51:04 -0700321 if (pathRRect.getSimpleRadii().fX < minRadius) {
322 pathRRect.setRectXY(pathRRect.rect(), minRadius, minRadius);
323 }
jvanverthd7315f912016-08-17 10:06:18 -0700324 }
325
jvanverthd99858a2016-09-12 07:51:04 -0700326 // compute the scale and translation for the shadow
327 SkScalar scale = lightPos.fZ / (lightPos.fZ - zValue);
328 SkRRect shadowRRect;
329 pathRRect.transform(SkMatrix::MakeScale(scale, scale), &shadowRRect);
330 SkPoint center = SkPoint::Make(shadowRRect.rect().centerX(), shadowRRect.rect().centerY());
331 SkMatrix ctmInverse;
332 if (!canvas->getTotalMatrix().invert(&ctmInverse)) {
333 return;
334 }
335 SkPoint lightPos2D = SkPoint::Make(lightPos.fX, lightPos.fY);
336 ctmInverse.mapPoints(&lightPos2D, 1);
337 SkPoint offset = SkPoint::Make(zRatio*(center.fX - lightPos2D.fX),
338 zRatio*(center.fY - lightPos2D.fY));
jvanverthd7315f912016-08-17 10:06:18 -0700339 SkAutoCanvasRestore acr(canvas, true);
340
341 SkPaint paint;
342 paint.setAntiAlias(true);
Robert Phillips95304e32016-10-07 14:44:07 -0400343 // We want to extend the stroked area in so that it meets up with the caster
344 // geometry. The stroked geometry will, by definition already be inset half the
345 // stroke width but we also have to account for the scaling.
346 // We also add 1/2 to cover up AA on the interior edge.
347 SkScalar scaleOffset = (scale - 1.0f) * SkTMax(SkTMax(SkTAbs(pathRect.fLeft),
348 SkTAbs(pathRect.fRight)),
349 SkTMax(SkTAbs(pathRect.fTop),
350 SkTAbs(pathRect.fBottom)));
351 SkScalar insetAmount = offset.length() - (0.5f * radius) + scaleOffset + 0.5f;
352
jvanvertha4f1af82016-08-29 07:17:47 -0700353 // compute area
Robert Phillips95304e32016-10-07 14:44:07 -0400354 SkScalar strokeWidth = radius + insetAmount;
jvanverthd99858a2016-09-12 07:51:04 -0700355 SkScalar strokedArea = 2.0f*strokeWidth*(shadowRRect.width() + shadowRRect.height());
356 SkScalar filledArea = (shadowRRect.height() + radius)*(shadowRRect.width() + radius);
jvanvertha4f1af82016-08-29 07:17:47 -0700357 // If the area of the stroked geometry is larger than the fill geometry, or
358 // if our pad is too big to convert to 6.2 fixed point, just fill it.
Robert Phillips95304e32016-10-07 14:44:07 -0400359 if (strokedArea > filledArea) {
jvanvertha4f1af82016-08-29 07:17:47 -0700360 paint.setStyle(SkPaint::kStrokeAndFill_Style);
361 paint.setStrokeWidth(radius);
362 } else {
Robert Phillips95304e32016-10-07 14:44:07 -0400363 // Since we can't have unequal strokes, inset the shadow rect so the inner
364 // and outer edges of the stroke will land where we want.
365 SkRect insetRect = shadowRRect.rect().makeInset(insetAmount/2.0f, insetAmount/2.0f);
366 SkScalar insetRad = SkTMax(shadowRRect.getSimpleRadii().fX - insetAmount/2.0f,
367 minRadius);
368
369 shadowRRect = SkRRect::MakeRectXY(insetRect, insetRad, insetRad);
jvanvertha4f1af82016-08-29 07:17:47 -0700370 paint.setStyle(SkPaint::kStroke_Style);
371 paint.setStrokeWidth(strokeWidth);
372 }
Jim Van Verth2aa535e2017-02-06 14:36:01 -0500373 paint.setColorFilter(SkColorFilter::MakeModeFilter(SK_ColorBLACK, SkBlendMode::kModulate));
jvanverthc20c0c02016-09-14 07:04:49 -0700374 paint.setShader(SkGaussianEdgeShader::Make());
jvanverthd7315f912016-08-17 10:06:18 -0700375 // handle scale of radius due to CTM
jvanverthd99858a2016-09-12 07:51:04 -0700376 radius *= scaleFactors[0];
377 // don't need to scale pad as it was computed from the transformed offset
378 SkASSERT(radius < 16384);
Robert Phillips95304e32016-10-07 14:44:07 -0400379 SkScalar pad = 0;
jvanvertha4f1af82016-08-29 07:17:47 -0700380 SkASSERT(pad < 64);
jvanverthd99858a2016-09-12 07:51:04 -0700381 // Convert radius to 14.2 fixed point and place in the R & G components.
382 // Convert pad to 6.2 fixed point and place in the B component.
383 uint16_t iRadius = (uint16_t)(radius*4.0f);
384 unsigned char alpha = (unsigned char)(spotAlpha*255.999f);
Robert Phillips95304e32016-10-07 14:44:07 -0400385 paint.setColor(SkColorSetARGB(fIgnoreShadowAlpha ? 255 : alpha,
386 iRadius >> 8, iRadius & 0xff,
jvanverthd99858a2016-09-12 07:51:04 -0700387 (unsigned char)(4.0f*pad)));
jvanverthd7315f912016-08-17 10:06:18 -0700388
389 // apply transformation to shadow
390 canvas->translate(offset.fX, offset.fY);
jvanverthd99858a2016-09-12 07:51:04 -0700391 canvas->drawRRect(shadowRRect, paint);
jvanverthd7315f912016-08-17 10:06:18 -0700392 }
393
394 void drawShadowedPath(SkCanvas* canvas, const SkPath& path, SkScalar zValue,
395 const SkPaint& paint, SkScalar ambientAlpha,
396 const SkPoint3& lightPos, SkScalar lightWidth, SkScalar spotAlpha) {
Jim Van Verth43475ad2017-01-13 14:37:37 -0500397#ifdef USE_SHADOW_UTILS
Jim Van Verth3c1b7db2016-10-31 16:06:51 -0400398 if (fUseAlt) {
399 if (fShowAmbient) {
400 this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
401 }
402 if (fShowSpot) {
403 this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
404 }
405 } else {
Jim Van Verth3c1b7db2016-10-31 16:06:51 -0400406 if (!fShowAmbient) {
407 ambientAlpha = 0;
408 }
409 if (!fShowSpot) {
410 spotAlpha = 0;
411 }
Jim Van Verth43475ad2017-01-13 14:37:37 -0500412 SkShadowUtils::DrawShadow(canvas, path, zValue, lightPos, lightWidth,
413 ambientAlpha, spotAlpha, SK_ColorBLACK);
Jim Van Verth3c1b7db2016-10-31 16:06:51 -0400414 }
415#else
jvanverthe1a3bc62016-08-12 10:40:38 -0700416 if (fShowAmbient) {
jvanverthd7315f912016-08-17 10:06:18 -0700417 if (fUseAlt) {
418 this->drawAmbientShadowAlt(canvas, path, zValue, ambientAlpha);
jvanverth6c177a12016-08-17 07:59:41 -0700419 } else {
jvanverthd7315f912016-08-17 10:06:18 -0700420 this->drawAmbientShadow(canvas, path, zValue, ambientAlpha);
jvanverth6c177a12016-08-17 07:59:41 -0700421 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700422 }
423 if (fShowSpot) {
jvanverthd7315f912016-08-17 10:06:18 -0700424 if (fUseAlt) {
425 this->drawSpotShadowAlt(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
426 } else {
427 this->drawSpotShadow(canvas, path, zValue, lightPos, lightWidth, spotAlpha);
428 }
jvanverthe1a3bc62016-08-12 10:40:38 -0700429 }
Jim Van Verth3c1b7db2016-10-31 16:06:51 -0400430#endif
431
jvanverthe1a3bc62016-08-12 10:40:38 -0700432 if (fShowObject) {
433 canvas->drawPath(path, paint);
Robert Phillips95304e32016-10-07 14:44:07 -0400434 } else {
435 SkPaint strokePaint;
436
437 strokePaint.setColor(paint.getColor());
438 strokePaint.setStyle(SkPaint::kStroke_Style);
439
440 canvas->drawPath(path, strokePaint);
jvanverthe1a3bc62016-08-12 10:40:38 -0700441 }
442 }
443
444 void onDrawContent(SkCanvas* canvas) override {
445 this->drawBG(canvas);
jvanverthd99858a2016-09-12 07:51:04 -0700446 const SkScalar kLightWidth = 2800;
jvanverthd7315f912016-08-17 10:06:18 -0700447 const SkScalar kAmbientAlpha = 0.25f;
448 const SkScalar kSpotAlpha = 0.25f;
jvanverthe1a3bc62016-08-12 10:40:38 -0700449
450 SkPaint paint;
451 paint.setAntiAlias(true);
452
jvanverthd7315f912016-08-17 10:06:18 -0700453 SkPoint3 lightPos = fLightPos;
454
jvanverthe1a3bc62016-08-12 10:40:38 -0700455 paint.setColor(SK_ColorWHITE);
456 canvas->translate(200, 90);
jvanverthd7315f912016-08-17 10:06:18 -0700457 lightPos.fX += 200;
458 lightPos.fY += 90;
Jim Van Verth2aa535e2017-02-06 14:36:01 -0500459 this->drawShadowedPath(canvas, fRRPath, SkTMax(1.0f, 2+fZDelta), paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700460 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700461
462 paint.setColor(SK_ColorRED);
463 canvas->translate(250, 0);
jvanverthd7315f912016-08-17 10:06:18 -0700464 lightPos.fX += 250;
Jim Van Verth2aa535e2017-02-06 14:36:01 -0500465 this->drawShadowedPath(canvas, fRectPath, SkTMax(1.0f, 4+fZDelta), paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700466 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700467
468 paint.setColor(SK_ColorBLUE);
469 canvas->translate(-250, 110);
jvanverthd7315f912016-08-17 10:06:18 -0700470 lightPos.fX -= 250;
471 lightPos.fY += 110;
Jim Van Verthcf40e302017-03-02 11:28:43 -0500472 this->drawShadowedPath(canvas, fCirclePath, SkTMax(1.0f, 8+fZDelta), paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700473 lightPos, kLightWidth, 0.5f);
jvanverth6c177a12016-08-17 07:59:41 -0700474
475 paint.setColor(SK_ColorGREEN);
476 canvas->translate(250, 0);
jvanverthd7315f912016-08-17 10:06:18 -0700477 lightPos.fX += 250;
Jim Van Verth2aa535e2017-02-06 14:36:01 -0500478 this->drawShadowedPath(canvas, fRRPath, SkTMax(1.0f, 64+fZDelta), paint, kAmbientAlpha,
jvanverthd7315f912016-08-17 10:06:18 -0700479 lightPos, kLightWidth, kSpotAlpha);
Jim Van Verthbce74962017-01-25 09:39:46 -0500480
481 paint.setColor(SK_ColorYELLOW);
482 canvas->translate(-250, 110);
483 lightPos.fX -= 250;
484 lightPos.fY += 110;
Jim Van Verth2aa535e2017-02-06 14:36:01 -0500485 this->drawShadowedPath(canvas, fFunkyRRPath, SkTMax(1.0f, 8+fZDelta), paint, kAmbientAlpha,
Jim Van Verthbce74962017-01-25 09:39:46 -0500486 lightPos, kLightWidth, kSpotAlpha);
487
488 paint.setColor(SK_ColorCYAN);
489 canvas->translate(250, 0);
490 lightPos.fX += 250;
491 this->drawShadowedPath(canvas, fCubicPath, 16, paint, kAmbientAlpha,
492 lightPos, kLightWidth, kSpotAlpha);
jvanverthe1a3bc62016-08-12 10:40:38 -0700493 }
494
495protected:
496 SkView::Click* onFindClickHandler(SkScalar x, SkScalar y, unsigned modi) override {
497 return new SkView::Click(this);
498 }
499
500 bool onClick(Click *click) override {
501 SkScalar x = click->fCurr.fX;
502 SkScalar y = click->fCurr.fY;
503
504 SkScalar dx = x - click->fPrev.fX;
505 SkScalar dy = y - click->fPrev.fY;
506
507 if (dx != 0 || dy != 0) {
508 fLightPos.fX += dx;
509 fLightPos.fY += dy;
510 this->inval(nullptr);
511 }
512
513 return true;
514 }
515
516private:
Jim Van Verth6f449692017-02-14 15:16:46 -0500517 typedef SampleView INHERITED;
jvanverthe1a3bc62016-08-12 10:40:38 -0700518};
519
520//////////////////////////////////////////////////////////////////////////////
521
522static SkView* MyFactory() { return new ShadowsView; }
523static SkViewRegister reg(MyFactory);