blob: 9baa29c7f70a152999f3350ca6c8843c62dd0676 [file] [log] [blame]
Jim Van Verthbce74962017-01-25 09:39:46 -05001/*
2 * Copyright 2017 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkPath.h"
9#include "include/core/SkPoint3.h"
10#include "include/core/SkVertices.h"
11#include "include/private/SkColorData.h"
Mike Klein8aa0edf2020-10-16 11:04:18 -050012#include "include/private/SkTPin.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/core/SkDrawShadowInfo.h"
14#include "src/core/SkGeometry.h"
15#include "src/core/SkPointPriv.h"
16#include "src/utils/SkPolyUtils.h"
17#include "src/utils/SkShadowTessellator.h"
Jim Van Verth85dc96b2017-01-30 14:49:21 -050018
19#if SK_SUPPORT_GPU
Michael Ludwig663afe52019-06-03 16:46:19 -040020#include "src/gpu/geometry/GrPathUtils.h"
Jim Van Verth85dc96b2017-01-30 14:49:21 -050021#endif
Jim Van Verth58abc9e2017-01-25 11:05:01 -050022
Brian Salomon958fbc42017-01-30 17:01:28 -050023
Jim Van Vertha84898d2017-02-06 13:38:23 -050024/**
25 * Base class
26 */
Brian Salomonaff27a22017-02-06 15:47:44 -050027class SkBaseShadowTessellator {
Brian Salomon958fbc42017-01-30 17:01:28 -050028public:
Jim Van Vertha5ef3972019-05-01 13:28:07 -040029 SkBaseShadowTessellator(const SkPoint3& zPlaneParams, const SkRect& bounds, bool transparent);
Brian Salomonaff27a22017-02-06 15:47:44 -050030 virtual ~SkBaseShadowTessellator() {}
Brian Salomon958fbc42017-01-30 17:01:28 -050031
Brian Salomonaff27a22017-02-06 15:47:44 -050032 sk_sp<SkVertices> releaseVertices() {
33 if (!fSucceeded) {
34 return nullptr;
35 }
Mike Reed887cdf12017-04-03 11:11:09 -040036 return SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, this->vertexCount(),
Mike Reed97eb4fe2017-03-14 12:04:16 -040037 fPositions.begin(), nullptr, fColors.begin(),
38 this->indexCount(), fIndices.begin());
Brian Salomon1a8b79a2017-01-31 11:26:26 -050039 }
Brian Salomon958fbc42017-01-30 17:01:28 -050040
Jim Van Vertha84898d2017-02-06 13:38:23 -050041protected:
Jim Van Verthda965502017-04-11 15:29:14 -040042 static constexpr auto kMinHeight = 0.1f;
Jim Van Verthfb186392018-09-11 11:37:46 -040043 static constexpr auto kPenumbraColor = SK_ColorTRANSPARENT;
44 static constexpr auto kUmbraColor = SK_ColorBLACK;
Jim Van Verthda965502017-04-11 15:29:14 -040045
Brian Salomonaff27a22017-02-06 15:47:44 -050046 int vertexCount() const { return fPositions.count(); }
47 int indexCount() const { return fIndices.count(); }
48
Jim Van Verthd737ab92018-09-10 15:19:01 -040049 // initialization methods
Jim Van Verthcdaf6612018-06-05 15:21:13 -040050 bool accumulateCentroid(const SkPoint& c, const SkPoint& n);
51 bool checkConvexity(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2);
52 void finishPathPolygon();
Jim Van Verthd737ab92018-09-10 15:19:01 -040053
54 // convex shadow methods
55 bool computeConvexShadow(SkScalar inset, SkScalar outset, bool doClip);
56 void computeClipVectorsAndTestCentroid();
57 bool clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid, SkPoint* clipPoint);
Jim Van Verthfb186392018-09-11 11:37:46 -040058 void addEdge(const SkVector& nextPoint, const SkVector& nextNormal, SkColor umbraColor,
Jim Van Verth6bdfebe2018-09-17 11:46:50 -040059 const SkTDArray<SkPoint>& umbraPolygon, bool lastEdge, bool doClip);
60 bool addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor,
61 const SkTDArray<SkPoint>& umbraPolygon, int* currUmbraIndex);
62 int getClosestUmbraIndex(const SkPoint& point, const SkTDArray<SkPoint>& umbraPolygon);
Jim Van Verthd737ab92018-09-10 15:19:01 -040063
64 // concave shadow methods
65 bool computeConcaveShadow(SkScalar inset, SkScalar outset);
Jim Van Verth8760e2f2018-06-12 14:21:38 -040066 void stitchConcaveRings(const SkTDArray<SkPoint>& umbraPolygon,
67 SkTDArray<int>* umbraIndices,
68 const SkTDArray<SkPoint>& penumbraPolygon,
69 SkTDArray<int>* penumbraIndices);
Jim Van Verthcdaf6612018-06-05 15:21:13 -040070
71 void handleLine(const SkPoint& p);
Jim Van Vertha84898d2017-02-06 13:38:23 -050072 void handleLine(const SkMatrix& m, SkPoint* p);
Brian Salomon958fbc42017-01-30 17:01:28 -050073
74 void handleQuad(const SkPoint pts[3]);
Jim Van Vertha84898d2017-02-06 13:38:23 -050075 void handleQuad(const SkMatrix& m, SkPoint pts[3]);
Brian Salomon958fbc42017-01-30 17:01:28 -050076
Jim Van Vertha84898d2017-02-06 13:38:23 -050077 void handleCubic(const SkMatrix& m, SkPoint pts[4]);
Brian Salomon958fbc42017-01-30 17:01:28 -050078
Jim Van Vertha84898d2017-02-06 13:38:23 -050079 void handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w);
Brian Salomon958fbc42017-01-30 17:01:28 -050080
Jim Van Verthd737ab92018-09-10 15:19:01 -040081 bool addArc(const SkVector& nextNormal, SkScalar offset, bool finishArc);
Jim Van Verthb4366552017-03-27 14:25:29 -040082
Jim Van Verth872da6b2018-04-10 11:24:11 -040083 void appendTriangle(uint16_t index0, uint16_t index1, uint16_t index2);
84 void appendQuad(uint16_t index0, uint16_t index1, uint16_t index2, uint16_t index3);
85
Jim Van Verthe308a122017-05-08 14:19:30 -040086 SkScalar heightFunc(SkScalar x, SkScalar y) {
87 return fZPlaneParams.fX*x + fZPlaneParams.fY*y + fZPlaneParams.fZ;
88 }
89
Jim Van Verth0b7645f2018-08-31 12:36:52 -040090 SkPoint3 fZPlaneParams;
Jim Van Verthda965502017-04-11 15:29:14 -040091
Brian Salomon958fbc42017-01-30 17:01:28 -050092 // temporary buffer
93 SkTDArray<SkPoint> fPointBuffer;
Brian Salomon0dda9cb2017-02-03 10:33:25 -050094
Jim Van Vertha84898d2017-02-06 13:38:23 -050095 SkTDArray<SkPoint> fPositions;
96 SkTDArray<SkColor> fColors;
97 SkTDArray<uint16_t> fIndices;
98
Jim Van Verth6bdfebe2018-09-17 11:46:50 -040099 SkTDArray<SkPoint> fPathPolygon;
100 SkTDArray<SkPoint> fClipPolygon;
101 SkTDArray<SkVector> fClipVectors;
Jim Van Verthd737ab92018-09-10 15:19:01 -0400102
Jim Van Vertha5ef3972019-05-01 13:28:07 -0400103 SkRect fPathBounds;
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400104 SkPoint fCentroid;
105 SkScalar fArea;
106 SkScalar fLastArea;
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400107 SkScalar fLastCross;
108
Jim Van Verth76387852017-05-16 16:55:16 -0400109 int fFirstVertexIndex;
110 SkVector fFirstOutset;
Jim Van Vertha84898d2017-02-06 13:38:23 -0500111 SkPoint fFirstPoint;
112
Brian Salomon0dda9cb2017-02-03 10:33:25 -0500113 bool fSucceeded;
Jim Van Vertha84898d2017-02-06 13:38:23 -0500114 bool fTransparent;
Jim Van Verthf507c282018-05-11 10:48:20 -0400115 bool fIsConvex;
Jim Van Verthd737ab92018-09-10 15:19:01 -0400116 bool fValidUmbra;
Jim Van Vertha84898d2017-02-06 13:38:23 -0500117
Jim Van Vertha84898d2017-02-06 13:38:23 -0500118 SkScalar fDirection;
119 int fPrevUmbraIndex;
Jim Van Verthd737ab92018-09-10 15:19:01 -0400120 int fCurrUmbraIndex;
121 int fCurrClipIndex;
122 bool fPrevUmbraOutside;
123 bool fFirstUmbraOutside;
Jim Van Verth76387852017-05-16 16:55:16 -0400124 SkVector fPrevOutset;
Jim Van Vertha84898d2017-02-06 13:38:23 -0500125 SkPoint fPrevPoint;
Brian Salomon958fbc42017-01-30 17:01:28 -0500126};
127
Jim Van Verthfb186392018-09-11 11:37:46 -0400128// make external linkage happy
129constexpr SkColor SkBaseShadowTessellator::kUmbraColor;
130constexpr SkColor SkBaseShadowTessellator::kPenumbraColor;
131
Jim Van Verthda965502017-04-11 15:29:14 -0400132static bool compute_normal(const SkPoint& p0, const SkPoint& p1, SkScalar dir,
Jim Van Verthbce74962017-01-25 09:39:46 -0500133 SkVector* newNormal) {
134 SkVector normal;
135 // compute perpendicular
136 normal.fX = p0.fY - p1.fY;
137 normal.fY = p1.fX - p0.fX;
Jim Van Verthda965502017-04-11 15:29:14 -0400138 normal *= dir;
Jim Van Verthbce74962017-01-25 09:39:46 -0500139 if (!normal.normalize()) {
140 return false;
141 }
Jim Van Verthbce74962017-01-25 09:39:46 -0500142 *newNormal = normal;
143 return true;
144}
145
Jim Van Verthf507c282018-05-11 10:48:20 -0400146static bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) {
147 static constexpr SkScalar kClose = (SK_Scalar1 / 16);
148 static constexpr SkScalar kCloseSqd = kClose * kClose;
149
150 SkScalar distSq = SkPointPriv::DistanceToSqd(p0, p1);
151 return distSq < kCloseSqd;
152}
153
154static SkScalar perp_dot(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
155 SkVector v0 = p1 - p0;
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400156 SkVector v1 = p2 - p1;
Jim Van Verthf507c282018-05-11 10:48:20 -0400157 return v0.cross(v1);
158}
159
Jim Van Vertha5ef3972019-05-01 13:28:07 -0400160SkBaseShadowTessellator::SkBaseShadowTessellator(const SkPoint3& zPlaneParams, const SkRect& bounds,
161 bool transparent)
Jim Van Verthe308a122017-05-08 14:19:30 -0400162 : fZPlaneParams(zPlaneParams)
Jim Van Vertha5ef3972019-05-01 13:28:07 -0400163 , fPathBounds(bounds)
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400164 , fCentroid({0, 0})
165 , fArea(0)
166 , fLastArea(0)
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400167 , fLastCross(0)
Jim Van Verth76387852017-05-16 16:55:16 -0400168 , fFirstVertexIndex(-1)
Brian Salomonaff27a22017-02-06 15:47:44 -0500169 , fSucceeded(false)
170 , fTransparent(transparent)
Jim Van Verthf507c282018-05-11 10:48:20 -0400171 , fIsConvex(true)
Jim Van Verthd737ab92018-09-10 15:19:01 -0400172 , fValidUmbra(true)
Brian Salomonaff27a22017-02-06 15:47:44 -0500173 , fDirection(1)
Jim Van Verthd737ab92018-09-10 15:19:01 -0400174 , fPrevUmbraIndex(-1)
175 , fCurrUmbraIndex(0)
176 , fCurrClipIndex(0)
177 , fPrevUmbraOutside(false)
178 , fFirstUmbraOutside(false) {
Jim Van Vertha84898d2017-02-06 13:38:23 -0500179 // child classes will set reserve for positions, colors and indices
180}
181
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400182bool SkBaseShadowTessellator::accumulateCentroid(const SkPoint& curr, const SkPoint& next) {
183 if (duplicate_pt(curr, next)) {
184 return false;
185 }
186
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400187 SkASSERT(fPathPolygon.count() > 0);
188 SkVector v0 = curr - fPathPolygon[0];
189 SkVector v1 = next - fPathPolygon[0];
190 SkScalar quadArea = v0.cross(v1);
191 fCentroid.fX += (v0.fX + v1.fX) * quadArea;
192 fCentroid.fY += (v0.fY + v1.fY) * quadArea;
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400193 fArea += quadArea;
194 // convexity check
Jim Van Verth3645bb02018-06-26 14:58:58 -0400195 if (quadArea*fLastArea < 0) {
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400196 fIsConvex = false;
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400197 }
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400198 if (0 != quadArea) {
199 fLastArea = quadArea;
200 }
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400201
202 return true;
203}
204
205bool SkBaseShadowTessellator::checkConvexity(const SkPoint& p0,
206 const SkPoint& p1,
207 const SkPoint& p2) {
208 SkScalar cross = perp_dot(p0, p1, p2);
209 // skip collinear point
210 if (SkScalarNearlyZero(cross)) {
211 return false;
212 }
213
214 // check for convexity
215 if (fLastCross*cross < 0) {
216 fIsConvex = false;
217 }
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400218 if (0 != cross) {
219 fLastCross = cross;
220 }
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400221
222 return true;
223}
224
225void SkBaseShadowTessellator::finishPathPolygon() {
226 if (fPathPolygon.count() > 1) {
227 if (!this->accumulateCentroid(fPathPolygon[fPathPolygon.count() - 1], fPathPolygon[0])) {
228 // remove coincident point
229 fPathPolygon.pop();
230 }
231 }
232
233 if (fPathPolygon.count() > 2) {
Jim Van Verth6784ffa2018-07-03 16:12:39 -0400234 // do this before the final convexity check, so we use the correct fPathPolygon[0]
235 fCentroid *= sk_ieee_float_divide(1, 3 * fArea);
236 fCentroid += fPathPolygon[0];
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400237 if (!checkConvexity(fPathPolygon[fPathPolygon.count() - 2],
238 fPathPolygon[fPathPolygon.count() - 1],
239 fPathPolygon[0])) {
240 // remove collinear point
241 fPathPolygon[0] = fPathPolygon[fPathPolygon.count() - 1];
242 fPathPolygon.pop();
243 }
244 }
245
Jim Van Verth7deacf42018-06-08 15:13:25 -0400246 // if area is positive, winding is ccw
247 fDirection = fArea > 0 ? -1 : 1;
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400248}
249
Jim Van Verthd737ab92018-09-10 15:19:01 -0400250bool SkBaseShadowTessellator::computeConvexShadow(SkScalar inset, SkScalar outset, bool doClip) {
251 if (doClip) {
252 this->computeClipVectorsAndTestCentroid();
253 }
254
Jim Van Verthfb186392018-09-11 11:37:46 -0400255 // adjust inset distance and umbra color if necessary
256 auto umbraColor = kUmbraColor;
257 SkScalar minDistSq = SkPointPriv::DistanceToLineSegmentBetweenSqd(fCentroid,
258 fPathPolygon[0],
259 fPathPolygon[1]);
260 SkRect bounds;
261 bounds.setBounds(&fPathPolygon[0], fPathPolygon.count());
262 for (int i = 1; i < fPathPolygon.count(); ++i) {
263 int j = i + 1;
264 if (i == fPathPolygon.count() - 1) {
265 j = 0;
266 }
267 SkPoint currPoint = fPathPolygon[i];
268 SkPoint nextPoint = fPathPolygon[j];
269 SkScalar distSq = SkPointPriv::DistanceToLineSegmentBetweenSqd(fCentroid, currPoint,
270 nextPoint);
271 if (distSq < minDistSq) {
272 minDistSq = distSq;
273 }
274 }
Jim Van Verthfb186392018-09-11 11:37:46 -0400275
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400276 SkTDArray<SkPoint> insetPolygon;
277 if (inset > SK_ScalarNearlyZero) {
278 static constexpr auto kTolerance = 1.0e-2f;
279 if (minDistSq < (inset + kTolerance)*(inset + kTolerance)) {
280 // if the umbra would collapse, we back off a bit on inner blur and adjust the alpha
281 auto newInset = SkScalarSqrt(minDistSq) - kTolerance;
282 auto ratio = 128 * (newInset / inset + 1);
283 SkASSERT(SkScalarIsFinite(ratio));
284 // they aren't PMColors, but the interpolation algorithm is the same
285 umbraColor = SkPMLerp(kUmbraColor, kPenumbraColor, (unsigned)ratio);
286 inset = newInset;
287 }
288
289 // generate inner ring
290 if (!SkInsetConvexPolygon(&fPathPolygon[0], fPathPolygon.count(), inset,
291 &insetPolygon)) {
292 // not ideal, but in this case we'll inset using the centroid
293 fValidUmbra = false;
294 }
Jim Van Verthd737ab92018-09-10 15:19:01 -0400295 }
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400296 const SkTDArray<SkPoint>& umbraPolygon = (inset > SK_ScalarNearlyZero) ? insetPolygon
297 : fPathPolygon;
Jim Van Verthd737ab92018-09-10 15:19:01 -0400298
299 // walk around the path polygon, generate outer ring and connect to inner ring
300 if (fTransparent) {
301 fPositions.push_back(fCentroid);
Jim Van Verthfb186392018-09-11 11:37:46 -0400302 fColors.push_back(umbraColor);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400303 }
304 fCurrUmbraIndex = 0;
305
306 // initial setup
307 // add first quad
308 int polyCount = fPathPolygon.count();
309 if (!compute_normal(fPathPolygon[polyCount - 1], fPathPolygon[0], fDirection, &fFirstOutset)) {
310 // polygon should be sanitized by this point, so this is unrecoverable
311 return false;
312 }
313
314 fFirstOutset *= outset;
315 fFirstPoint = fPathPolygon[polyCount - 1];
316 fFirstVertexIndex = fPositions.count();
317 fPrevOutset = fFirstOutset;
318 fPrevPoint = fFirstPoint;
319 fPrevUmbraIndex = -1;
320
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400321 this->addInnerPoint(fFirstPoint, umbraColor, umbraPolygon, &fPrevUmbraIndex);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400322
323 if (!fTransparent && doClip) {
324 SkPoint clipPoint;
325 bool isOutside = this->clipUmbraPoint(fPositions[fFirstVertexIndex],
326 fCentroid, &clipPoint);
327 if (isOutside) {
328 fPositions.push_back(clipPoint);
Jim Van Verthfb186392018-09-11 11:37:46 -0400329 fColors.push_back(umbraColor);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400330 }
331 fPrevUmbraOutside = isOutside;
332 fFirstUmbraOutside = isOutside;
333 }
334
335 SkPoint newPoint = fFirstPoint + fFirstOutset;
336 fPositions.push_back(newPoint);
Jim Van Verthfb186392018-09-11 11:37:46 -0400337 fColors.push_back(kPenumbraColor);
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400338 this->addEdge(fPathPolygon[0], fFirstOutset, umbraColor, umbraPolygon, false, doClip);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400339
340 for (int i = 1; i < polyCount; ++i) {
341 SkVector normal;
342 if (!compute_normal(fPrevPoint, fPathPolygon[i], fDirection, &normal)) {
343 return false;
344 }
345 normal *= outset;
346 this->addArc(normal, outset, true);
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400347 this->addEdge(fPathPolygon[i], normal, umbraColor, umbraPolygon,
348 i == polyCount - 1, doClip);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400349 }
350 SkASSERT(this->indexCount());
351
352 // final fan
353 SkASSERT(fPositions.count() >= 3);
354 if (this->addArc(fFirstOutset, outset, false)) {
355 if (fFirstUmbraOutside) {
356 this->appendTriangle(fFirstVertexIndex, fPositions.count() - 1,
357 fFirstVertexIndex + 2);
358 } else {
359 this->appendTriangle(fFirstVertexIndex, fPositions.count() - 1,
360 fFirstVertexIndex + 1);
361 }
362 } else {
363 // no arc added, fix up by setting first penumbra point position to last one
364 if (fFirstUmbraOutside) {
365 fPositions[fFirstVertexIndex + 2] = fPositions[fPositions.count() - 1];
366 } else {
367 fPositions[fFirstVertexIndex + 1] = fPositions[fPositions.count() - 1];
368 }
369 }
370
371 return true;
372}
373
374void SkBaseShadowTessellator::computeClipVectorsAndTestCentroid() {
375 SkASSERT(fClipPolygon.count() >= 3);
376 fCurrClipIndex = fClipPolygon.count() - 1;
377
378 // init clip vectors
379 SkVector v0 = fClipPolygon[1] - fClipPolygon[0];
380 SkVector v1 = fClipPolygon[2] - fClipPolygon[0];
381 fClipVectors.push_back(v0);
382
383 // init centroid check
384 bool hiddenCentroid = true;
385 v1 = fCentroid - fClipPolygon[0];
386 SkScalar initCross = v0.cross(v1);
387
388 for (int p = 1; p < fClipPolygon.count(); ++p) {
389 // add to clip vectors
390 v0 = fClipPolygon[(p + 1) % fClipPolygon.count()] - fClipPolygon[p];
391 fClipVectors.push_back(v0);
392 // Determine if transformed centroid is inside clipPolygon.
393 v1 = fCentroid - fClipPolygon[p];
394 if (initCross*v0.cross(v1) <= 0) {
395 hiddenCentroid = false;
396 }
397 }
398 SkASSERT(fClipVectors.count() == fClipPolygon.count());
399
400 fTransparent = fTransparent || !hiddenCentroid;
401}
402
403void SkBaseShadowTessellator::addEdge(const SkPoint& nextPoint, const SkVector& nextNormal,
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400404 SkColor umbraColor, const SkTDArray<SkPoint>& umbraPolygon,
405 bool lastEdge, bool doClip) {
Jim Van Verthd737ab92018-09-10 15:19:01 -0400406 // add next umbra point
407 int currUmbraIndex;
408 bool duplicate;
409 if (lastEdge) {
410 duplicate = false;
411 currUmbraIndex = fFirstVertexIndex;
412 fPrevPoint = nextPoint;
413 } else {
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400414 duplicate = this->addInnerPoint(nextPoint, umbraColor, umbraPolygon, &currUmbraIndex);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400415 }
416 int prevPenumbraIndex = duplicate || (currUmbraIndex == fFirstVertexIndex)
417 ? fPositions.count() - 1
418 : fPositions.count() - 2;
419 if (!duplicate) {
420 // add to center fan if transparent or centroid showing
421 if (fTransparent) {
422 this->appendTriangle(0, fPrevUmbraIndex, currUmbraIndex);
423 // otherwise add to clip ring
424 } else if (doClip) {
425 SkPoint clipPoint;
426 bool isOutside = lastEdge ? fFirstUmbraOutside
427 : this->clipUmbraPoint(fPositions[currUmbraIndex], fCentroid,
428 &clipPoint);
429 if (isOutside) {
430 if (!lastEdge) {
431 fPositions.push_back(clipPoint);
Jim Van Verthfb186392018-09-11 11:37:46 -0400432 fColors.push_back(umbraColor);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400433 }
434 this->appendTriangle(fPrevUmbraIndex, currUmbraIndex, currUmbraIndex + 1);
435 if (fPrevUmbraOutside) {
436 // fill out quad
437 this->appendTriangle(fPrevUmbraIndex, currUmbraIndex + 1,
438 fPrevUmbraIndex + 1);
439 }
440 } else if (fPrevUmbraOutside) {
441 // add tri
442 this->appendTriangle(fPrevUmbraIndex, currUmbraIndex, fPrevUmbraIndex + 1);
443 }
444
445 fPrevUmbraOutside = isOutside;
446 }
447 }
448
449 // add next penumbra point and quad
450 SkPoint newPoint = nextPoint + nextNormal;
451 fPositions.push_back(newPoint);
Jim Van Verthfb186392018-09-11 11:37:46 -0400452 fColors.push_back(kPenumbraColor);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400453
454 if (!duplicate) {
455 this->appendTriangle(fPrevUmbraIndex, prevPenumbraIndex, currUmbraIndex);
456 }
457 this->appendTriangle(prevPenumbraIndex, fPositions.count() - 1, currUmbraIndex);
458
459 fPrevUmbraIndex = currUmbraIndex;
460 fPrevOutset = nextNormal;
461}
462
463bool SkBaseShadowTessellator::clipUmbraPoint(const SkPoint& umbraPoint, const SkPoint& centroid,
464 SkPoint* clipPoint) {
465 SkVector segmentVector = centroid - umbraPoint;
466
467 int startClipPoint = fCurrClipIndex;
468 do {
469 SkVector dp = umbraPoint - fClipPolygon[fCurrClipIndex];
470 SkScalar denom = fClipVectors[fCurrClipIndex].cross(segmentVector);
471 SkScalar t_num = dp.cross(segmentVector);
472 // if line segments are nearly parallel
473 if (SkScalarNearlyZero(denom)) {
474 // and collinear
475 if (SkScalarNearlyZero(t_num)) {
476 return false;
477 }
478 // otherwise are separate, will try the next poly segment
479 // else if crossing lies within poly segment
480 } else if (t_num >= 0 && t_num <= denom) {
481 SkScalar s_num = dp.cross(fClipVectors[fCurrClipIndex]);
482 // if umbra point is inside the clip polygon
483 if (s_num >= 0 && s_num <= denom) {
484 segmentVector *= s_num / denom;
485 *clipPoint = umbraPoint + segmentVector;
486 return true;
487 }
488 }
489 fCurrClipIndex = (fCurrClipIndex + 1) % fClipPolygon.count();
490 } while (fCurrClipIndex != startClipPoint);
491
492 return false;
493}
494
Jim Van Verthfb186392018-09-11 11:37:46 -0400495bool SkBaseShadowTessellator::addInnerPoint(const SkPoint& pathPoint, SkColor umbraColor,
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400496 const SkTDArray<SkPoint>& umbraPolygon,
Jim Van Verthfb186392018-09-11 11:37:46 -0400497 int* currUmbraIndex) {
Jim Van Verthd737ab92018-09-10 15:19:01 -0400498 SkPoint umbraPoint;
499 if (!fValidUmbra) {
500 SkVector v = fCentroid - pathPoint;
501 v *= 0.95f;
502 umbraPoint = pathPoint + v;
503 } else {
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400504 umbraPoint = umbraPolygon[this->getClosestUmbraIndex(pathPoint, umbraPolygon)];
Jim Van Verthd737ab92018-09-10 15:19:01 -0400505 }
506
507 fPrevPoint = pathPoint;
508
509 // merge "close" points
510 if (fPrevUmbraIndex == -1 ||
511 !duplicate_pt(umbraPoint, fPositions[fPrevUmbraIndex])) {
512 // if we've wrapped around, don't add a new point
513 if (fPrevUmbraIndex >= 0 && duplicate_pt(umbraPoint, fPositions[fFirstVertexIndex])) {
514 *currUmbraIndex = fFirstVertexIndex;
515 } else {
516 *currUmbraIndex = fPositions.count();
517 fPositions.push_back(umbraPoint);
Jim Van Verthfb186392018-09-11 11:37:46 -0400518 fColors.push_back(umbraColor);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400519 }
520 return false;
521 } else {
522 *currUmbraIndex = fPrevUmbraIndex;
523 return true;
524 }
525}
526
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400527int SkBaseShadowTessellator::getClosestUmbraIndex(const SkPoint& p,
528 const SkTDArray<SkPoint>& umbraPolygon) {
529 SkScalar minDistance = SkPointPriv::DistanceToSqd(p, umbraPolygon[fCurrUmbraIndex]);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400530 int index = fCurrUmbraIndex;
531 int dir = 1;
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400532 int next = (index + dir) % umbraPolygon.count();
Jim Van Verthd737ab92018-09-10 15:19:01 -0400533
534 // init travel direction
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400535 SkScalar distance = SkPointPriv::DistanceToSqd(p, umbraPolygon[next]);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400536 if (distance < minDistance) {
537 index = next;
538 minDistance = distance;
539 } else {
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400540 dir = umbraPolygon.count() - 1;
Jim Van Verthd737ab92018-09-10 15:19:01 -0400541 }
542
543 // iterate until we find a point that increases the distance
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400544 next = (index + dir) % umbraPolygon.count();
545 distance = SkPointPriv::DistanceToSqd(p, umbraPolygon[next]);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400546 while (distance < minDistance) {
547 index = next;
548 minDistance = distance;
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400549 next = (index + dir) % umbraPolygon.count();
550 distance = SkPointPriv::DistanceToSqd(p, umbraPolygon[next]);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400551 }
552
553 fCurrUmbraIndex = index;
554 return index;
555}
556
557bool SkBaseShadowTessellator::computeConcaveShadow(SkScalar inset, SkScalar outset) {
558 if (!SkIsSimplePolygon(&fPathPolygon[0], fPathPolygon.count())) {
559 return false;
560 }
561
562 // generate inner ring
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400563 SkTDArray<SkPoint> umbraPolygon;
Jim Van Verthd737ab92018-09-10 15:19:01 -0400564 SkTDArray<int> umbraIndices;
565 umbraIndices.setReserve(fPathPolygon.count());
Jim Van Vertha5ef3972019-05-01 13:28:07 -0400566 if (!SkOffsetSimplePolygon(&fPathPolygon[0], fPathPolygon.count(), fPathBounds, inset,
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400567 &umbraPolygon, &umbraIndices)) {
Jim Van Verthd737ab92018-09-10 15:19:01 -0400568 // TODO: figure out how to handle this case
569 return false;
570 }
571
572 // generate outer ring
573 SkTDArray<SkPoint> penumbraPolygon;
574 SkTDArray<int> penumbraIndices;
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400575 penumbraPolygon.setReserve(umbraPolygon.count());
576 penumbraIndices.setReserve(umbraPolygon.count());
Jim Van Vertha5ef3972019-05-01 13:28:07 -0400577 if (!SkOffsetSimplePolygon(&fPathPolygon[0], fPathPolygon.count(), fPathBounds, -outset,
Jim Van Verthd737ab92018-09-10 15:19:01 -0400578 &penumbraPolygon, &penumbraIndices)) {
579 // TODO: figure out how to handle this case
580 return false;
581 }
582
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400583 if (!umbraPolygon.count() || !penumbraPolygon.count()) {
Jim Van Verthd737ab92018-09-10 15:19:01 -0400584 return false;
585 }
586
587 // attach the rings together
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400588 this->stitchConcaveRings(umbraPolygon, &umbraIndices, penumbraPolygon, &penumbraIndices);
Jim Van Verthd737ab92018-09-10 15:19:01 -0400589
590 return true;
591}
592
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400593void SkBaseShadowTessellator::stitchConcaveRings(const SkTDArray<SkPoint>& umbraPolygon,
594 SkTDArray<int>* umbraIndices,
595 const SkTDArray<SkPoint>& penumbraPolygon,
596 SkTDArray<int>* penumbraIndices) {
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400597 // TODO: only create and fill indexMap when fTransparent is true?
598 SkAutoSTMalloc<64, uint16_t> indexMap(umbraPolygon.count());
599
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400600 // find minimum indices
601 int minIndex = 0;
602 int min = (*penumbraIndices)[0];
603 for (int i = 1; i < (*penumbraIndices).count(); ++i) {
604 if ((*penumbraIndices)[i] < min) {
605 min = (*penumbraIndices)[i];
606 minIndex = i;
607 }
608 }
609 int currPenumbra = minIndex;
610
611 minIndex = 0;
612 min = (*umbraIndices)[0];
613 for (int i = 1; i < (*umbraIndices).count(); ++i) {
614 if ((*umbraIndices)[i] < min) {
615 min = (*umbraIndices)[i];
616 minIndex = i;
617 }
618 }
619 int currUmbra = minIndex;
620
621 // now find a case where the indices are equal (there should be at least one)
622 int maxPenumbraIndex = fPathPolygon.count() - 1;
623 int maxUmbraIndex = fPathPolygon.count() - 1;
624 while ((*penumbraIndices)[currPenumbra] != (*umbraIndices)[currUmbra]) {
625 if ((*penumbraIndices)[currPenumbra] < (*umbraIndices)[currUmbra]) {
626 (*penumbraIndices)[currPenumbra] += fPathPolygon.count();
627 maxPenumbraIndex = (*penumbraIndices)[currPenumbra];
628 currPenumbra = (currPenumbra + 1) % penumbraPolygon.count();
629 } else {
630 (*umbraIndices)[currUmbra] += fPathPolygon.count();
631 maxUmbraIndex = (*umbraIndices)[currUmbra];
632 currUmbra = (currUmbra + 1) % umbraPolygon.count();
633 }
634 }
635
Jim Van Verthd737ab92018-09-10 15:19:01 -0400636 fPositions.push_back(penumbraPolygon[currPenumbra]);
Jim Van Verthfb186392018-09-11 11:37:46 -0400637 fColors.push_back(kPenumbraColor);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400638 int prevPenumbraIndex = 0;
Jim Van Verthd737ab92018-09-10 15:19:01 -0400639 fPositions.push_back(umbraPolygon[currUmbra]);
Jim Van Verthfb186392018-09-11 11:37:46 -0400640 fColors.push_back(kUmbraColor);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400641 fPrevUmbraIndex = 1;
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400642 indexMap[currUmbra] = 1;
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400643
644 int nextPenumbra = (currPenumbra + 1) % penumbraPolygon.count();
645 int nextUmbra = (currUmbra + 1) % umbraPolygon.count();
646 while ((*penumbraIndices)[nextPenumbra] <= maxPenumbraIndex ||
647 (*umbraIndices)[nextUmbra] <= maxUmbraIndex) {
648
649 if ((*umbraIndices)[nextUmbra] == (*penumbraIndices)[nextPenumbra]) {
650 // advance both one step
Jim Van Verthd737ab92018-09-10 15:19:01 -0400651 fPositions.push_back(penumbraPolygon[nextPenumbra]);
Jim Van Verthfb186392018-09-11 11:37:46 -0400652 fColors.push_back(kPenumbraColor);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400653 int currPenumbraIndex = fPositions.count() - 1;
654
Jim Van Verthd737ab92018-09-10 15:19:01 -0400655 fPositions.push_back(umbraPolygon[nextUmbra]);
Jim Van Verthfb186392018-09-11 11:37:46 -0400656 fColors.push_back(kUmbraColor);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400657 int currUmbraIndex = fPositions.count() - 1;
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400658 indexMap[nextUmbra] = currUmbraIndex;
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400659
660 this->appendQuad(prevPenumbraIndex, currPenumbraIndex,
661 fPrevUmbraIndex, currUmbraIndex);
662
663 prevPenumbraIndex = currPenumbraIndex;
664 (*penumbraIndices)[currPenumbra] += fPathPolygon.count();
665 currPenumbra = nextPenumbra;
666 nextPenumbra = (currPenumbra + 1) % penumbraPolygon.count();
667
668 fPrevUmbraIndex = currUmbraIndex;
669 (*umbraIndices)[currUmbra] += fPathPolygon.count();
670 currUmbra = nextUmbra;
671 nextUmbra = (currUmbra + 1) % umbraPolygon.count();
672 }
673
674 while ((*penumbraIndices)[nextPenumbra] < (*umbraIndices)[nextUmbra] &&
675 (*penumbraIndices)[nextPenumbra] <= maxPenumbraIndex) {
676 // fill out penumbra arc
Jim Van Verthd737ab92018-09-10 15:19:01 -0400677 fPositions.push_back(penumbraPolygon[nextPenumbra]);
Jim Van Verthfb186392018-09-11 11:37:46 -0400678 fColors.push_back(kPenumbraColor);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400679 int currPenumbraIndex = fPositions.count() - 1;
680
681 this->appendTriangle(prevPenumbraIndex, currPenumbraIndex, fPrevUmbraIndex);
682
683 prevPenumbraIndex = currPenumbraIndex;
684 // this ensures the ordering when we wrap around
685 (*penumbraIndices)[currPenumbra] += fPathPolygon.count();
686 currPenumbra = nextPenumbra;
687 nextPenumbra = (currPenumbra + 1) % penumbraPolygon.count();
688 }
689
690 while ((*umbraIndices)[nextUmbra] < (*penumbraIndices)[nextPenumbra] &&
691 (*umbraIndices)[nextUmbra] <= maxUmbraIndex) {
692 // fill out umbra arc
Jim Van Verthd737ab92018-09-10 15:19:01 -0400693 fPositions.push_back(umbraPolygon[nextUmbra]);
Jim Van Verthfb186392018-09-11 11:37:46 -0400694 fColors.push_back(kUmbraColor);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400695 int currUmbraIndex = fPositions.count() - 1;
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400696 indexMap[nextUmbra] = currUmbraIndex;
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400697
698 this->appendTriangle(fPrevUmbraIndex, prevPenumbraIndex, currUmbraIndex);
699
700 fPrevUmbraIndex = currUmbraIndex;
701 // this ensures the ordering when we wrap around
702 (*umbraIndices)[currUmbra] += fPathPolygon.count();
703 currUmbra = nextUmbra;
704 nextUmbra = (currUmbra + 1) % umbraPolygon.count();
705 }
706 }
707 // finish up by advancing both one step
Jim Van Verthd737ab92018-09-10 15:19:01 -0400708 fPositions.push_back(penumbraPolygon[nextPenumbra]);
Jim Van Verthfb186392018-09-11 11:37:46 -0400709 fColors.push_back(kPenumbraColor);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400710 int currPenumbraIndex = fPositions.count() - 1;
711
Jim Van Verthd737ab92018-09-10 15:19:01 -0400712 fPositions.push_back(umbraPolygon[nextUmbra]);
Jim Van Verthfb186392018-09-11 11:37:46 -0400713 fColors.push_back(kUmbraColor);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400714 int currUmbraIndex = fPositions.count() - 1;
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400715 indexMap[nextUmbra] = currUmbraIndex;
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400716
717 this->appendQuad(prevPenumbraIndex, currPenumbraIndex,
718 fPrevUmbraIndex, currUmbraIndex);
719
720 if (fTransparent) {
Jim Van Verth8664a1d2018-06-28 16:26:50 -0400721 SkTriangulateSimplePolygon(umbraPolygon.begin(), indexMap, umbraPolygon.count(),
722 &fIndices);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400723 }
724}
725
726
Jim Van Vertha84898d2017-02-06 13:38:23 -0500727// tesselation tolerance values, in device space pixels
Mike Kleinb8b51e62017-02-09 15:22:53 -0500728#if SK_SUPPORT_GPU
Jim Van Vertha84898d2017-02-06 13:38:23 -0500729static const SkScalar kQuadTolerance = 0.2f;
730static const SkScalar kCubicTolerance = 0.2f;
Mike Kleinb8b51e62017-02-09 15:22:53 -0500731#endif
Brian Osmane3deee12018-11-20 11:10:15 -0500732static const SkScalar kConicTolerance = 0.25f;
Jim Van Vertha84898d2017-02-06 13:38:23 -0500733
Jim Van Verth3645bb02018-06-26 14:58:58 -0400734// clamps the point to the nearest 16th of a pixel
735static void sanitize_point(const SkPoint& in, SkPoint* out) {
736 out->fX = SkScalarRoundToScalar(16.f*in.fX)*0.0625f;
737 out->fY = SkScalarRoundToScalar(16.f*in.fY)*0.0625f;
738}
739
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400740void SkBaseShadowTessellator::handleLine(const SkPoint& p) {
Jim Van Verth3645bb02018-06-26 14:58:58 -0400741 SkPoint pSanitized;
742 sanitize_point(p, &pSanitized);
743
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400744 if (fPathPolygon.count() > 0) {
Jim Van Verth3645bb02018-06-26 14:58:58 -0400745 if (!this->accumulateCentroid(fPathPolygon[fPathPolygon.count() - 1], pSanitized)) {
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400746 // skip coincident point
747 return;
748 }
749 }
750
751 if (fPathPolygon.count() > 1) {
752 if (!checkConvexity(fPathPolygon[fPathPolygon.count() - 2],
753 fPathPolygon[fPathPolygon.count() - 1],
Jim Van Verth3645bb02018-06-26 14:58:58 -0400754 pSanitized)) {
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400755 // remove collinear point
756 fPathPolygon.pop();
Jim Van Verth6bdfebe2018-09-17 11:46:50 -0400757 // it's possible that the previous point is coincident with the new one now
758 if (duplicate_pt(fPathPolygon[fPathPolygon.count() - 1], pSanitized)) {
759 fPathPolygon.pop();
760 }
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400761 }
762 }
763
Jim Van Verthd737ab92018-09-10 15:19:01 -0400764 fPathPolygon.push_back(pSanitized);
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400765}
766
Brian Salomonaff27a22017-02-06 15:47:44 -0500767void SkBaseShadowTessellator::handleLine(const SkMatrix& m, SkPoint* p) {
Jim Van Vertha84898d2017-02-06 13:38:23 -0500768 m.mapPoints(p, 1);
Jim Van Verthcdaf6612018-06-05 15:21:13 -0400769
Jim Van Vertha84898d2017-02-06 13:38:23 -0500770 this->handleLine(*p);
771}
772
Brian Salomonaff27a22017-02-06 15:47:44 -0500773void SkBaseShadowTessellator::handleQuad(const SkPoint pts[3]) {
Jim Van Vertha84898d2017-02-06 13:38:23 -0500774#if SK_SUPPORT_GPU
Jim Van Vertha947e292018-02-26 13:54:34 -0500775 // check for degeneracy
776 SkVector v0 = pts[1] - pts[0];
777 SkVector v1 = pts[2] - pts[0];
778 if (SkScalarNearlyZero(v0.cross(v1))) {
779 return;
780 }
Jim Van Vertha84898d2017-02-06 13:38:23 -0500781 // TODO: Pull PathUtils out of Ganesh?
782 int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
Mike Kleincc9856c2018-04-19 09:18:33 -0400783 fPointBuffer.setCount(maxCount);
Jim Van Vertha84898d2017-02-06 13:38:23 -0500784 SkPoint* target = fPointBuffer.begin();
785 int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
786 kQuadTolerance, &target, maxCount);
787 fPointBuffer.setCount(count);
788 for (int i = 0; i < count; i++) {
789 this->handleLine(fPointBuffer[i]);
790 }
791#else
792 // for now, just to draw something
793 this->handleLine(pts[1]);
794 this->handleLine(pts[2]);
795#endif
796}
797
Brian Salomonaff27a22017-02-06 15:47:44 -0500798void SkBaseShadowTessellator::handleQuad(const SkMatrix& m, SkPoint pts[3]) {
Jim Van Vertha84898d2017-02-06 13:38:23 -0500799 m.mapPoints(pts, 3);
800 this->handleQuad(pts);
801}
802
Brian Salomonaff27a22017-02-06 15:47:44 -0500803void SkBaseShadowTessellator::handleCubic(const SkMatrix& m, SkPoint pts[4]) {
Jim Van Vertha84898d2017-02-06 13:38:23 -0500804 m.mapPoints(pts, 4);
805#if SK_SUPPORT_GPU
806 // TODO: Pull PathUtils out of Ganesh?
807 int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
Mike Kleincc9856c2018-04-19 09:18:33 -0400808 fPointBuffer.setCount(maxCount);
Jim Van Vertha84898d2017-02-06 13:38:23 -0500809 SkPoint* target = fPointBuffer.begin();
810 int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
811 kCubicTolerance, &target, maxCount);
812 fPointBuffer.setCount(count);
813 for (int i = 0; i < count; i++) {
814 this->handleLine(fPointBuffer[i]);
815 }
816#else
817 // for now, just to draw something
818 this->handleLine(pts[1]);
819 this->handleLine(pts[2]);
820 this->handleLine(pts[3]);
821#endif
822}
823
Brian Salomonaff27a22017-02-06 15:47:44 -0500824void SkBaseShadowTessellator::handleConic(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
Jim Van Verthda965502017-04-11 15:29:14 -0400825 if (m.hasPerspective()) {
826 w = SkConic::TransformW(pts, w, m);
827 }
Jim Van Vertha84898d2017-02-06 13:38:23 -0500828 m.mapPoints(pts, 3);
829 SkAutoConicToQuads quadder;
830 const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
831 SkPoint lastPoint = *(quads++);
832 int count = quadder.countQuads();
833 for (int i = 0; i < count; ++i) {
834 SkPoint quadPts[3];
835 quadPts[0] = lastPoint;
836 quadPts[1] = quads[0];
837 quadPts[2] = i == count - 1 ? pts[2] : quads[1];
838 this->handleQuad(quadPts);
839 lastPoint = quadPts[2];
840 quads += 2;
841 }
842}
843
Jim Van Verthd737ab92018-09-10 15:19:01 -0400844bool SkBaseShadowTessellator::addArc(const SkVector& nextNormal, SkScalar offset, bool finishArc) {
Jim Van Vertha84898d2017-02-06 13:38:23 -0500845 // fill in fan from previous quad
846 SkScalar rotSin, rotCos;
847 int numSteps;
Jim Van Verthd737ab92018-09-10 15:19:01 -0400848 if (!SkComputeRadialSteps(fPrevOutset, nextNormal, offset, &rotSin, &rotCos, &numSteps)) {
Jim Van Verth061cc212018-07-11 14:09:09 -0400849 // recover as best we can
850 numSteps = 0;
851 }
Jim Van Verth76387852017-05-16 16:55:16 -0400852 SkVector prevNormal = fPrevOutset;
Jim Van Verthe7e1d9d2017-05-01 16:06:48 -0400853 for (int i = 0; i < numSteps-1; ++i) {
Jim Van Verthda965502017-04-11 15:29:14 -0400854 SkVector currNormal;
855 currNormal.fX = prevNormal.fX*rotCos - prevNormal.fY*rotSin;
856 currNormal.fY = prevNormal.fY*rotCos + prevNormal.fX*rotSin;
Jim Van Verthd737ab92018-09-10 15:19:01 -0400857 fPositions.push_back(fPrevPoint + currNormal);
Jim Van Verthfb186392018-09-11 11:37:46 -0400858 fColors.push_back(kPenumbraColor);
Jim Van Verth872da6b2018-04-10 11:24:11 -0400859 this->appendTriangle(fPrevUmbraIndex, fPositions.count() - 1, fPositions.count() - 2);
Jim Van Vertha84898d2017-02-06 13:38:23 -0500860
Jim Van Verthda965502017-04-11 15:29:14 -0400861 prevNormal = currNormal;
Jim Van Vertha84898d2017-02-06 13:38:23 -0500862 }
Jim Van Verthe7e1d9d2017-05-01 16:06:48 -0400863 if (finishArc && numSteps) {
Jim Van Verthd737ab92018-09-10 15:19:01 -0400864 fPositions.push_back(fPrevPoint + nextNormal);
Jim Van Verthfb186392018-09-11 11:37:46 -0400865 fColors.push_back(kPenumbraColor);
Jim Van Verth872da6b2018-04-10 11:24:11 -0400866 this->appendTriangle(fPrevUmbraIndex, fPositions.count() - 1, fPositions.count() - 2);
Jim Van Verthda965502017-04-11 15:29:14 -0400867 }
Jim Van Verth76387852017-05-16 16:55:16 -0400868 fPrevOutset = nextNormal;
Jim Van Verthe7e1d9d2017-05-01 16:06:48 -0400869
870 return (numSteps > 0);
Jim Van Vertha84898d2017-02-06 13:38:23 -0500871}
872
Jim Van Verth872da6b2018-04-10 11:24:11 -0400873void SkBaseShadowTessellator::appendTriangle(uint16_t index0, uint16_t index1, uint16_t index2) {
874 auto indices = fIndices.append(3);
875
876 indices[0] = index0;
877 indices[1] = index1;
878 indices[2] = index2;
879}
880
881void SkBaseShadowTessellator::appendQuad(uint16_t index0, uint16_t index1,
882 uint16_t index2, uint16_t index3) {
883 auto indices = fIndices.append(6);
884
885 indices[0] = index0;
886 indices[1] = index1;
887 indices[2] = index2;
888
889 indices[3] = index2;
890 indices[4] = index1;
891 indices[5] = index3;
892}
893
Jim Van Vertha84898d2017-02-06 13:38:23 -0500894//////////////////////////////////////////////////////////////////////////////////////////////////
895
Brian Salomonaff27a22017-02-06 15:47:44 -0500896class SkAmbientShadowTessellator : public SkBaseShadowTessellator {
Jim Van Vertha84898d2017-02-06 13:38:23 -0500897public:
898 SkAmbientShadowTessellator(const SkPath& path, const SkMatrix& ctm,
Jim Van Verthe308a122017-05-08 14:19:30 -0400899 const SkPoint3& zPlaneParams, bool transparent);
Jim Van Vertha84898d2017-02-06 13:38:23 -0500900
901private:
Jim Van Verth3645bb02018-06-26 14:58:58 -0400902 bool computePathPolygon(const SkPath& path, const SkMatrix& ctm);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400903
John Stiles7571f9e2020-09-02 22:42:33 -0400904 using INHERITED = SkBaseShadowTessellator;
Jim Van Vertha84898d2017-02-06 13:38:23 -0500905};
906
Jim Van Verthefe3ded2017-01-30 13:11:45 -0500907SkAmbientShadowTessellator::SkAmbientShadowTessellator(const SkPath& path,
Jim Van Vertha84898d2017-02-06 13:38:23 -0500908 const SkMatrix& ctm,
Jim Van Verthe308a122017-05-08 14:19:30 -0400909 const SkPoint3& zPlaneParams,
Jim Van Verthbce74962017-01-25 09:39:46 -0500910 bool transparent)
Jim Van Vertha5ef3972019-05-01 13:28:07 -0400911 : INHERITED(zPlaneParams, path.getBounds(), transparent) {
Jim Van Verthda965502017-04-11 15:29:14 -0400912 // Set base colors
Jim Van Vertha5ef3972019-05-01 13:28:07 -0400913 auto baseZ = heightFunc(fPathBounds.centerX(), fPathBounds.centerY());
Jim Van Verthb4366552017-03-27 14:25:29 -0400914 // umbraColor is the interior value, penumbraColor the exterior value.
Jim Van Verthfb186392018-09-11 11:37:46 -0400915 auto outset = SkDrawShadowMetrics::AmbientBlurRadius(baseZ);
916 auto inset = outset * SkDrawShadowMetrics::AmbientRecipAlpha(baseZ) - outset;
Brian Osman788b9162020-02-07 10:36:46 -0500917 inset = SkTPin(inset, 0.0f, std::min(path.getBounds().width(),
Brian Osmanaba642c2020-02-06 12:52:25 -0500918 path.getBounds().height()));
Jim Van Verthda965502017-04-11 15:29:14 -0400919
Jim Van Verth3645bb02018-06-26 14:58:58 -0400920 if (!this->computePathPolygon(path, ctm)) {
921 return;
922 }
923 if (fPathPolygon.count() < 3 || !SkScalarIsFinite(fArea)) {
924 fSucceeded = true; // We don't want to try to blur these cases, so we will
925 // return an empty SkVertices instead.
926 return;
927 }
928
Jim Van Verthbce74962017-01-25 09:39:46 -0500929 // Outer ring: 3*numPts
930 // Middle ring: numPts
931 fPositions.setReserve(4 * path.countPoints());
932 fColors.setReserve(4 * path.countPoints());
933 // Outer ring: 12*numPts
934 // Middle ring: 0
935 fIndices.setReserve(12 * path.countPoints());
936
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400937 if (fIsConvex) {
Jim Van Verthfb186392018-09-11 11:37:46 -0400938 fSucceeded = this->computeConvexShadow(inset, outset, false);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400939 } else {
Jim Van Verthfb186392018-09-11 11:37:46 -0400940 fSucceeded = this->computeConcaveShadow(inset, outset);
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400941 }
942}
943
Jim Van Verth3645bb02018-06-26 14:58:58 -0400944bool SkAmbientShadowTessellator::computePathPolygon(const SkPath& path, const SkMatrix& ctm) {
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400945 fPathPolygon.setReserve(path.countPoints());
946
947 // walk around the path, tessellate and generate outer ring
948 // if original path is transparent, will accumulate sum of points for centroid
949 SkPath::Iter iter(path, true);
950 SkPoint pts[4];
951 SkPath::Verb verb;
Jim Van Verth3645bb02018-06-26 14:58:58 -0400952 bool verbSeen = false;
953 bool closeSeen = false;
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400954 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
Jim Van Verth3645bb02018-06-26 14:58:58 -0400955 if (closeSeen) {
956 return false;
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400957 }
Jim Van Verth3645bb02018-06-26 14:58:58 -0400958 switch (verb) {
959 case SkPath::kLine_Verb:
960 this->handleLine(ctm, &pts[1]);
961 break;
962 case SkPath::kQuad_Verb:
963 this->handleQuad(ctm, pts);
964 break;
965 case SkPath::kCubic_Verb:
966 this->handleCubic(ctm, pts);
967 break;
968 case SkPath::kConic_Verb:
969 this->handleConic(ctm, pts, iter.conicWeight());
970 break;
971 case SkPath::kMove_Verb:
972 if (verbSeen) {
973 return false;
974 }
975 break;
976 case SkPath::kClose_Verb:
977 case SkPath::kDone_Verb:
978 closeSeen = true;
979 break;
980 }
981 verbSeen = true;
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400982 }
983
984 this->finishPathPolygon();
Jim Van Verth3645bb02018-06-26 14:58:58 -0400985 return true;
Jim Van Verth8760e2f2018-06-12 14:21:38 -0400986}
987
Jim Van Verth91af7272017-01-27 14:15:54 -0500988///////////////////////////////////////////////////////////////////////////////////////////////////
989
Brian Salomonaff27a22017-02-06 15:47:44 -0500990class SkSpotShadowTessellator : public SkBaseShadowTessellator {
Brian Salomon958fbc42017-01-30 17:01:28 -0500991public:
Jim Van Vertha84898d2017-02-06 13:38:23 -0500992 SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
Jim Van Verthe308a122017-05-08 14:19:30 -0400993 const SkPoint3& zPlaneParams, const SkPoint3& lightPos,
Jim Van Verth63f03542020-12-16 11:56:11 -0500994 SkScalar lightRadius, bool transparent, bool directional);
Brian Salomon958fbc42017-01-30 17:01:28 -0500995
Brian Salomon958fbc42017-01-30 17:01:28 -0500996private:
Jim Van Verth3645bb02018-06-26 14:58:58 -0400997 bool computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm,
Jim Van Verthda965502017-04-11 15:29:14 -0400998 const SkMatrix& shadowTransform);
Jim Van Verthf507c282018-05-11 10:48:20 -0400999 void addToClip(const SkVector& nextPoint);
Jim Van Verthda965502017-04-11 15:29:14 -04001000
John Stiles7571f9e2020-09-02 22:42:33 -04001001 using INHERITED = SkBaseShadowTessellator;
Brian Salomon958fbc42017-01-30 17:01:28 -05001002};
1003
Jim Van Vertha84898d2017-02-06 13:38:23 -05001004SkSpotShadowTessellator::SkSpotShadowTessellator(const SkPath& path, const SkMatrix& ctm,
Jim Van Verthe308a122017-05-08 14:19:30 -04001005 const SkPoint3& zPlaneParams,
Jim Van Verthb4366552017-03-27 14:25:29 -04001006 const SkPoint3& lightPos, SkScalar lightRadius,
Jim Van Verth63f03542020-12-16 11:56:11 -05001007 bool transparent, bool directional)
Jim Van Vertha5ef3972019-05-01 13:28:07 -04001008 : INHERITED(zPlaneParams, path.getBounds(), transparent) {
Jim Van Verthda965502017-04-11 15:29:14 -04001009
Jim Van Verth1af03d42017-07-31 09:34:58 -04001010 // Compute the blur radius, scale and translation for the spot shadow.
Jim Van Verthda965502017-04-11 15:29:14 -04001011 SkMatrix shadowTransform;
Jim Van Verth3a039d52018-09-14 17:14:47 -04001012 SkScalar outset;
Jim Van Verth63f03542020-12-16 11:56:11 -05001013 if (!SkDrawShadowMetrics::GetSpotShadowTransform(lightPos, lightRadius, ctm, zPlaneParams,
1014 path.getBounds(), directional,
Jim Van Verth3a039d52018-09-14 17:14:47 -04001015 &shadowTransform, &outset)) {
1016 return;
Jim Van Verthda965502017-04-11 15:29:14 -04001017 }
Jim Van Verthd737ab92018-09-10 15:19:01 -04001018 SkScalar inset = outset;
Jim Van Verthb4366552017-03-27 14:25:29 -04001019
Brian Salomonab664fa2017-03-24 16:07:20 +00001020 // compute rough clip bounds for umbra, plus offset polygon, plus centroid
Jim Van Verth3645bb02018-06-26 14:58:58 -04001021 if (!this->computeClipAndPathPolygons(path, ctm, shadowTransform)) {
1022 return;
1023 }
1024 if (fClipPolygon.count() < 3 || fPathPolygon.count() < 3 || !SkScalarIsFinite(fArea)) {
1025 fSucceeded = true; // We don't want to try to blur these cases, so we will
1026 // return an empty SkVertices instead.
Brian Salomon66085ed2017-02-02 15:39:34 -05001027 return;
1028 }
Brian Salomon66085ed2017-02-02 15:39:34 -05001029
Jim Van Verthd737ab92018-09-10 15:19:01 -04001030 // TODO: calculate these reserves better
1031 // Penumbra ring: 3*numPts
1032 // Umbra ring: numPts
1033 // Inner ring: numPts
1034 fPositions.setReserve(5 * path.countPoints());
1035 fColors.setReserve(5 * path.countPoints());
1036 // Penumbra ring: 12*numPts
1037 // Umbra ring: 3*numPts
1038 fIndices.setReserve(15 * path.countPoints());
Jim Van Verthf507c282018-05-11 10:48:20 -04001039
Jim Van Verthf507c282018-05-11 10:48:20 -04001040 if (fIsConvex) {
Jim Van Verthd737ab92018-09-10 15:19:01 -04001041 fSucceeded = this->computeConvexShadow(inset, outset, true);
Jim Van Verth872da6b2018-04-10 11:24:11 -04001042 } else {
Jim Van Verthd737ab92018-09-10 15:19:01 -04001043 fSucceeded = this->computeConcaveShadow(inset, outset);
Jim Van Verth8760e2f2018-06-12 14:21:38 -04001044 }
1045
1046 if (!fSucceeded) {
Jim Van Verthf507c282018-05-11 10:48:20 -04001047 return;
Jim Van Verth91af7272017-01-27 14:15:54 -05001048 }
Jim Van Verthda965502017-04-11 15:29:14 -04001049
Brian Salomon0dda9cb2017-02-03 10:33:25 -05001050 fSucceeded = true;
Jim Van Verth91af7272017-01-27 14:15:54 -05001051}
1052
Jim Van Verth3645bb02018-06-26 14:58:58 -04001053bool SkSpotShadowTessellator::computeClipAndPathPolygons(const SkPath& path, const SkMatrix& ctm,
Jim Van Verthda965502017-04-11 15:29:14 -04001054 const SkMatrix& shadowTransform) {
Brian Salomonab664fa2017-03-24 16:07:20 +00001055
1056 fPathPolygon.setReserve(path.countPoints());
Jim Van Verth3645bb02018-06-26 14:58:58 -04001057 fClipPolygon.setReserve(path.countPoints());
Brian Salomonab664fa2017-03-24 16:07:20 +00001058
1059 // Walk around the path and compute clip polygon and path polygon.
1060 // Will also accumulate sum of areas for centroid.
1061 // For Bezier curves, we compute additional interior points on curve.
Jim Van Verth91af7272017-01-27 14:15:54 -05001062 SkPath::Iter iter(path, true);
1063 SkPoint pts[4];
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001064 SkPoint clipPts[4];
Jim Van Verth91af7272017-01-27 14:15:54 -05001065 SkPath::Verb verb;
1066
Brian Salomon66085ed2017-02-02 15:39:34 -05001067 // coefficients to compute cubic Bezier at t = 5/16
Brian Salomonab664fa2017-03-24 16:07:20 +00001068 static constexpr SkScalar kA = 0.32495117187f;
1069 static constexpr SkScalar kB = 0.44311523437f;
1070 static constexpr SkScalar kC = 0.20141601562f;
1071 static constexpr SkScalar kD = 0.03051757812f;
Brian Salomon66085ed2017-02-02 15:39:34 -05001072
1073 SkPoint curvePoint;
1074 SkScalar w;
Jim Van Verth3645bb02018-06-26 14:58:58 -04001075 bool closeSeen = false;
1076 bool verbSeen = false;
Jim Van Verth91af7272017-01-27 14:15:54 -05001077 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
Jim Van Verth3645bb02018-06-26 14:58:58 -04001078 if (closeSeen) {
1079 return false;
1080 }
Jim Van Verth91af7272017-01-27 14:15:54 -05001081 switch (verb) {
Jim Van Verth91af7272017-01-27 14:15:54 -05001082 case SkPath::kLine_Verb:
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001083 ctm.mapPoints(clipPts, &pts[1], 1);
1084 this->addToClip(clipPts[0]);
Jim Van Verthcdaf6612018-06-05 15:21:13 -04001085 this->handleLine(shadowTransform, &pts[1]);
Jim Van Verth91af7272017-01-27 14:15:54 -05001086 break;
1087 case SkPath::kQuad_Verb:
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001088 ctm.mapPoints(clipPts, pts, 3);
Brian Salomon66085ed2017-02-02 15:39:34 -05001089 // point at t = 1/2
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001090 curvePoint.fX = 0.25f*clipPts[0].fX + 0.5f*clipPts[1].fX + 0.25f*clipPts[2].fX;
1091 curvePoint.fY = 0.25f*clipPts[0].fY + 0.5f*clipPts[1].fY + 0.25f*clipPts[2].fY;
Jim Van Verthf507c282018-05-11 10:48:20 -04001092 this->addToClip(curvePoint);
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001093 this->addToClip(clipPts[2]);
Brian Salomonab664fa2017-03-24 16:07:20 +00001094 this->handleQuad(shadowTransform, pts);
Jim Van Verth91af7272017-01-27 14:15:54 -05001095 break;
1096 case SkPath::kConic_Verb:
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001097 ctm.mapPoints(clipPts, pts, 3);
Brian Salomon66085ed2017-02-02 15:39:34 -05001098 w = iter.conicWeight();
Jim Van Vertha84898d2017-02-06 13:38:23 -05001099 // point at t = 1/2
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001100 curvePoint.fX = 0.25f*clipPts[0].fX + w*0.5f*clipPts[1].fX + 0.25f*clipPts[2].fX;
1101 curvePoint.fY = 0.25f*clipPts[0].fY + w*0.5f*clipPts[1].fY + 0.25f*clipPts[2].fY;
Brian Salomon66085ed2017-02-02 15:39:34 -05001102 curvePoint *= SkScalarInvert(0.5f + 0.5f*w);
Jim Van Verthf507c282018-05-11 10:48:20 -04001103 this->addToClip(curvePoint);
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001104 this->addToClip(clipPts[2]);
Brian Salomonab664fa2017-03-24 16:07:20 +00001105 this->handleConic(shadowTransform, pts, w);
Jim Van Verth91af7272017-01-27 14:15:54 -05001106 break;
1107 case SkPath::kCubic_Verb:
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001108 ctm.mapPoints(clipPts, pts, 4);
Brian Salomon66085ed2017-02-02 15:39:34 -05001109 // point at t = 5/16
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001110 curvePoint.fX = kA*clipPts[0].fX + kB*clipPts[1].fX
1111 + kC*clipPts[2].fX + kD*clipPts[3].fX;
1112 curvePoint.fY = kA*clipPts[0].fY + kB*clipPts[1].fY
1113 + kC*clipPts[2].fY + kD*clipPts[3].fY;
Jim Van Verthf507c282018-05-11 10:48:20 -04001114 this->addToClip(curvePoint);
Brian Salomon66085ed2017-02-02 15:39:34 -05001115 // point at t = 11/16
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001116 curvePoint.fX = kD*clipPts[0].fX + kC*clipPts[1].fX
1117 + kB*clipPts[2].fX + kA*clipPts[3].fX;
1118 curvePoint.fY = kD*clipPts[0].fY + kC*clipPts[1].fY
1119 + kB*clipPts[2].fY + kA*clipPts[3].fY;
Jim Van Verthf507c282018-05-11 10:48:20 -04001120 this->addToClip(curvePoint);
Jim Van Verth0b7645f2018-08-31 12:36:52 -04001121 this->addToClip(clipPts[3]);
Brian Salomonab664fa2017-03-24 16:07:20 +00001122 this->handleCubic(shadowTransform, pts);
Jim Van Verth91af7272017-01-27 14:15:54 -05001123 break;
Brian Salomonab664fa2017-03-24 16:07:20 +00001124 case SkPath::kMove_Verb:
Jim Van Verth3645bb02018-06-26 14:58:58 -04001125 if (verbSeen) {
1126 return false;
1127 }
1128 break;
Jim Van Verth91af7272017-01-27 14:15:54 -05001129 case SkPath::kClose_Verb:
Brian Salomonab664fa2017-03-24 16:07:20 +00001130 case SkPath::kDone_Verb:
Jim Van Verth3645bb02018-06-26 14:58:58 -04001131 closeSeen = true;
Jim Van Verth91af7272017-01-27 14:15:54 -05001132 break;
1133 default:
1134 SkDEBUGFAIL("unknown verb");
1135 }
Jim Van Verth3645bb02018-06-26 14:58:58 -04001136 verbSeen = true;
Jim Van Verth91af7272017-01-27 14:15:54 -05001137 }
1138
Jim Van Verthcdaf6612018-06-05 15:21:13 -04001139 this->finishPathPolygon();
Jim Van Verth3645bb02018-06-26 14:58:58 -04001140 return true;
Brian Salomon66085ed2017-02-02 15:39:34 -05001141}
1142
Jim Van Verthd737ab92018-09-10 15:19:01 -04001143void SkSpotShadowTessellator::addToClip(const SkPoint& point) {
1144 if (fClipPolygon.isEmpty() || !duplicate_pt(point, fClipPolygon[fClipPolygon.count() - 1])) {
1145 fClipPolygon.push_back(point);
Brian Salomon66085ed2017-02-02 15:39:34 -05001146 }
Jim Van Verth91af7272017-01-27 14:15:54 -05001147}
Brian Salomon958fbc42017-01-30 17:01:28 -05001148
1149///////////////////////////////////////////////////////////////////////////////////////////////////
1150
Brian Salomonaff27a22017-02-06 15:47:44 -05001151sk_sp<SkVertices> SkShadowTessellator::MakeAmbient(const SkPath& path, const SkMatrix& ctm,
Jim Van Verthe308a122017-05-08 14:19:30 -04001152 const SkPoint3& zPlane, bool transparent) {
Mike Reed27575e82018-05-17 10:11:31 -04001153 if (!ctm.mapRect(path.getBounds()).isFinite() || !zPlane.isFinite()) {
Mike Reed9d5c6742018-03-06 10:31:27 -05001154 return nullptr;
1155 }
Jim Van Verthe308a122017-05-08 14:19:30 -04001156 SkAmbientShadowTessellator ambientTess(path, ctm, zPlane, transparent);
Brian Salomonaff27a22017-02-06 15:47:44 -05001157 return ambientTess.releaseVertices();
Brian Salomon958fbc42017-01-30 17:01:28 -05001158}
1159
Brian Salomonaff27a22017-02-06 15:47:44 -05001160sk_sp<SkVertices> SkShadowTessellator::MakeSpot(const SkPath& path, const SkMatrix& ctm,
Jim Van Verthe308a122017-05-08 14:19:30 -04001161 const SkPoint3& zPlane, const SkPoint3& lightPos,
Jim Van Verth63f03542020-12-16 11:56:11 -05001162 SkScalar lightRadius, bool transparent,
1163 bool directional) {
Mike Reed27575e82018-05-17 10:11:31 -04001164 if (!ctm.mapRect(path.getBounds()).isFinite() || !zPlane.isFinite() ||
Jim Van Verth1989c492018-05-31 13:15:16 -04001165 !lightPos.isFinite() || !(lightPos.fZ >= SK_ScalarNearlyZero) ||
1166 !SkScalarIsFinite(lightRadius) || !(lightRadius >= SK_ScalarNearlyZero)) {
Mike Reed9d5c6742018-03-06 10:31:27 -05001167 return nullptr;
1168 }
Jim Van Verth63f03542020-12-16 11:56:11 -05001169 SkSpotShadowTessellator spotTess(path, ctm, zPlane, lightPos, lightRadius, transparent,
1170 directional);
Brian Salomonaff27a22017-02-06 15:47:44 -05001171 return spotTess.releaseVertices();
Brian Salomon958fbc42017-01-30 17:01:28 -05001172}