blob: 94a1eacafc7e1aaf5a87be98086c883115b967b7 [file] [log] [blame]
ethannicholase9709e82016-01-07 13:34:16 -08001/*
2 * Copyright 2015 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
Chris Dalton17dc4182020-03-25 16:18:16 -06008#include "src/gpu/GrTriangulator.h"
ethannicholase9709e82016-01-07 13:34:16 -08009
Chris Daltond081dce2020-01-23 12:09:04 -070010#include "src/gpu/GrEagerVertexAllocator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/gpu/GrVertexWriter.h"
Michael Ludwig663afe52019-06-03 16:46:19 -040012#include "src/gpu/geometry/GrPathUtils.h"
Chris Daltond60c9192021-01-07 18:30:08 +000013
14#include "src/core/SkGeometry.h"
15#include "src/core/SkPointPriv.h"
16
Stephen White94b7e542018-01-04 14:01:10 -050017#include <algorithm>
ethannicholase9709e82016-01-07 13:34:16 -080018
Chris Daltond60c9192021-01-07 18:30:08 +000019
Chris Dalton5045de32021-01-07 19:09:01 -070020#if TRIANGULATOR_LOGGING
Chris Daltond60c9192021-01-07 18:30:08 +000021#define TESS_LOG printf
Chris Dalton24472af2021-01-11 20:05:00 -070022#define DUMP_MESH(M) (M).dump()
ethannicholase9709e82016-01-07 13:34:16 -080023#else
Brian Salomon120e7d62019-09-11 10:29:22 -040024#define TESS_LOG(...)
Chris Dalton7cf3add2021-01-11 18:33:28 -070025#define DUMP_MESH(M)
ethannicholase9709e82016-01-07 13:34:16 -080026#endif
27
Chris Dalton17ce8c52021-01-07 18:08:46 -070028using EdgeType = GrTriangulator::EdgeType;
Chris Dalton57ea1fc2021-01-05 13:37:44 -070029using Vertex = GrTriangulator::Vertex;
30using VertexList = GrTriangulator::VertexList;
Chris Dalton17ce8c52021-01-07 18:08:46 -070031using Line = GrTriangulator::Line;
Chris Dalton57ea1fc2021-01-05 13:37:44 -070032using Edge = GrTriangulator::Edge;
33using EdgeList = GrTriangulator::EdgeList;
34using Poly = GrTriangulator::Poly;
Chris Dalton17ce8c52021-01-07 18:08:46 -070035using MonotonePoly = GrTriangulator::MonotonePoly;
Chris Dalton57ea1fc2021-01-05 13:37:44 -070036using Comparator = GrTriangulator::Comparator;
ethannicholase9709e82016-01-07 13:34:16 -080037
38template <class T, T* T::*Prev, T* T::*Next>
Chris Dalton57ea1fc2021-01-05 13:37:44 -070039static void list_insert(T* t, T* prev, T* next, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -080040 t->*Prev = prev;
41 t->*Next = next;
42 if (prev) {
43 prev->*Next = t;
44 } else if (head) {
45 *head = t;
46 }
47 if (next) {
48 next->*Prev = t;
49 } else if (tail) {
50 *tail = t;
51 }
52}
53
54template <class T, T* T::*Prev, T* T::*Next>
Chris Dalton57ea1fc2021-01-05 13:37:44 -070055static void list_remove(T* t, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -080056 if (t->*Prev) {
57 t->*Prev->*Next = t->*Next;
58 } else if (head) {
59 *head = t->*Next;
60 }
61 if (t->*Next) {
62 t->*Next->*Prev = t->*Prev;
63 } else if (tail) {
64 *tail = t->*Prev;
65 }
66 t->*Prev = t->*Next = nullptr;
67}
68
ethannicholase9709e82016-01-07 13:34:16 -080069typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b);
70
Chris Dalton57ea1fc2021-01-05 13:37:44 -070071static bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -050072 return a.fX < b.fX || (a.fX == b.fX && a.fY > b.fY);
ethannicholase9709e82016-01-07 13:34:16 -080073}
74
Chris Dalton57ea1fc2021-01-05 13:37:44 -070075static bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -050076 return a.fY < b.fY || (a.fY == b.fY && a.fX < b.fX);
ethannicholase9709e82016-01-07 13:34:16 -080077}
78
Chris Dalton5045de32021-01-07 19:09:01 -070079bool GrTriangulator::Comparator::sweep_lt(const SkPoint& a, const SkPoint& b) const {
80 return fDirection == Direction::kHorizontal ? sweep_lt_horiz(a, b) : sweep_lt_vert(a, b);
81}
Stephen White16a40cb2017-02-23 11:10:01 -050082
Chris Daltond60c9192021-01-07 18:30:08 +000083static inline void* emit_vertex(Vertex* v, bool emitCoverage, void* data) {
Brian Osmanf9aabff2018-11-13 16:11:38 -050084 GrVertexWriter verts{data};
85 verts.write(v->fPoint);
86
Brian Osman80879d42019-01-07 16:15:27 -050087 if (emitCoverage) {
88 verts.write(GrNormalizeByteToFloat(v->fAlpha));
89 }
Brian Osman0995fd52019-01-09 09:52:25 -050090
Brian Osmanf9aabff2018-11-13 16:11:38 -050091 return verts.fPtr;
ethannicholase9709e82016-01-07 13:34:16 -080092}
93
Chris Daltond60c9192021-01-07 18:30:08 +000094static void* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, bool emitCoverage, void* data) {
Brian Salomon120e7d62019-09-11 10:29:22 -040095 TESS_LOG("emit_triangle %g (%g, %g) %d\n", v0->fID, v0->fPoint.fX, v0->fPoint.fY, v0->fAlpha);
96 TESS_LOG(" %g (%g, %g) %d\n", v1->fID, v1->fPoint.fX, v1->fPoint.fY, v1->fAlpha);
97 TESS_LOG(" %g (%g, %g) %d\n", v2->fID, v2->fPoint.fX, v2->fPoint.fY, v2->fAlpha);
senorblancof57372d2016-08-31 10:36:19 -070098#if TESSELLATOR_WIREFRAME
Brian Osman0995fd52019-01-09 09:52:25 -050099 data = emit_vertex(v0, emitCoverage, data);
100 data = emit_vertex(v1, emitCoverage, data);
101 data = emit_vertex(v1, emitCoverage, data);
102 data = emit_vertex(v2, emitCoverage, data);
103 data = emit_vertex(v2, emitCoverage, data);
104 data = emit_vertex(v0, emitCoverage, data);
ethannicholase9709e82016-01-07 13:34:16 -0800105#else
Brian Osman0995fd52019-01-09 09:52:25 -0500106 data = emit_vertex(v0, emitCoverage, data);
107 data = emit_vertex(v1, emitCoverage, data);
108 data = emit_vertex(v2, emitCoverage, data);
ethannicholase9709e82016-01-07 13:34:16 -0800109#endif
110 return data;
111}
112
Chris Dalton5045de32021-01-07 19:09:01 -0700113void GrTriangulator::VertexList::insert(Vertex* v, Vertex* prev, Vertex* next) {
114 list_insert<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, prev, next, &fHead, &fTail);
115}
116
117void GrTriangulator::VertexList::remove(Vertex* v) {
118 list_remove<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, &fHead, &fTail);
119}
senorblancoe6eaa322016-03-08 09:06:44 -0800120
senorblancof57372d2016-08-31 10:36:19 -0700121// Round to nearest quarter-pixel. This is used for screenspace tessellation.
122
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700123static inline void round(SkPoint* p) {
senorblancof57372d2016-08-31 10:36:19 -0700124 p->fX = SkScalarRoundToScalar(p->fX * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
125 p->fY = SkScalarRoundToScalar(p->fY * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
126}
127
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700128static inline SkScalar double_to_clamped_scalar(double d) {
Stephen White94b7e542018-01-04 14:01:10 -0500129 return SkDoubleToScalar(std::min((double) SK_ScalarMax, std::max(d, (double) -SK_ScalarMax)));
130}
131
Chris Dalton5045de32021-01-07 19:09:01 -0700132bool GrTriangulator::Line::intersect(const Line& other, SkPoint* point) const {
133 double denom = fA * other.fB - fB * other.fA;
134 if (denom == 0.0) {
135 return false;
senorblanco49df8d12016-10-07 08:36:56 -0700136 }
Chris Dalton5045de32021-01-07 19:09:01 -0700137 double scale = 1.0 / denom;
138 point->fX = double_to_clamped_scalar((fB * other.fC - other.fB * fC) * scale);
139 point->fY = double_to_clamped_scalar((other.fA * fC - fA * other.fC) * scale);
140 round(point);
141 return point->isFinite();
142}
Chris Daltond60c9192021-01-07 18:30:08 +0000143
Chris Dalton5045de32021-01-07 19:09:01 -0700144bool GrTriangulator::Edge::intersect(const Edge& other, SkPoint* p, uint8_t* alpha) const {
145 TESS_LOG("intersecting %g -> %g with %g -> %g\n",
146 fTop->fID, fBottom->fID, other.fTop->fID, other.fBottom->fID);
147 if (fTop == other.fTop || fBottom == other.fBottom) {
148 return false;
Chris Daltond60c9192021-01-07 18:30:08 +0000149 }
Chris Dalton5045de32021-01-07 19:09:01 -0700150 double denom = fLine.fA * other.fLine.fB - fLine.fB * other.fLine.fA;
151 if (denom == 0.0) {
152 return false;
Chris Daltond60c9192021-01-07 18:30:08 +0000153 }
Chris Dalton5045de32021-01-07 19:09:01 -0700154 double dx = static_cast<double>(other.fTop->fPoint.fX) - fTop->fPoint.fX;
155 double dy = static_cast<double>(other.fTop->fPoint.fY) - fTop->fPoint.fY;
156 double sNumer = dy * other.fLine.fB + dx * other.fLine.fA;
157 double tNumer = dy * fLine.fB + dx * fLine.fA;
158 // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early.
159 // This saves us doing the divide below unless absolutely necessary.
160 if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom)
161 : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNumer < denom)) {
162 return false;
Chris Daltond60c9192021-01-07 18:30:08 +0000163 }
Chris Dalton5045de32021-01-07 19:09:01 -0700164 double s = sNumer / denom;
165 SkASSERT(s >= 0.0 && s <= 1.0);
166 p->fX = SkDoubleToScalar(fTop->fPoint.fX - s * fLine.fB);
167 p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fLine.fA);
168 if (alpha) {
169 if (fType == EdgeType::kConnector) {
170 *alpha = (1.0 - s) * fTop->fAlpha + s * fBottom->fAlpha;
171 } else if (other.fType == EdgeType::kConnector) {
172 double t = tNumer / denom;
173 *alpha = (1.0 - t) * other.fTop->fAlpha + t * other.fBottom->fAlpha;
174 } else if (fType == EdgeType::kOuter && other.fType == EdgeType::kOuter) {
175 *alpha = 0;
176 } else {
177 *alpha = 255;
178 }
Chris Daltond60c9192021-01-07 18:30:08 +0000179 }
Chris Dalton5045de32021-01-07 19:09:01 -0700180 return true;
181}
senorblancof57372d2016-08-31 10:36:19 -0700182
Chris Dalton5045de32021-01-07 19:09:01 -0700183void GrTriangulator::EdgeList::insert(Edge* edge, Edge* prev, Edge* next) {
184 list_insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &fHead, &fTail);
185}
Chris Dalton24472af2021-01-11 20:05:00 -0700186
Chris Dalton5045de32021-01-07 19:09:01 -0700187void GrTriangulator::EdgeList::remove(Edge* edge) {
Chris Dalton24472af2021-01-11 20:05:00 -0700188 TESS_LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
189 SkASSERT(this->contains(edge));
Chris Dalton5045de32021-01-07 19:09:01 -0700190 list_remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &fHead, &fTail);
191}
ethannicholase9709e82016-01-07 13:34:16 -0800192
Chris Dalton5045de32021-01-07 19:09:01 -0700193void GrTriangulator::MonotonePoly::addEdge(Edge* edge) {
194 if (fSide == kRight_Side) {
195 SkASSERT(!edge->fUsedInRightPoly);
196 list_insert<Edge, &Edge::fRightPolyPrev, &Edge::fRightPolyNext>(
197 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
198 edge->fUsedInRightPoly = true;
199 } else {
200 SkASSERT(!edge->fUsedInLeftPoly);
201 list_insert<Edge, &Edge::fLeftPolyPrev, &Edge::fLeftPolyNext>(
202 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
203 edge->fUsedInLeftPoly = true;
Chris Dalton17ce8c52021-01-07 18:08:46 -0700204 }
Chris Dalton5045de32021-01-07 19:09:01 -0700205}
Chris Dalton17ce8c52021-01-07 18:08:46 -0700206
Chris Dalton9a4904f2021-01-07 19:10:14 -0700207void* GrTriangulator::emitMonotonePoly(const MonotonePoly* monotonePoly, void* data) {
Chris Dalton93c2d812021-01-11 19:51:59 -0700208 SkASSERT(monotonePoly->fWinding != 0);
Chris Dalton9a4904f2021-01-07 19:10:14 -0700209 Edge* e = monotonePoly->fFirstEdge;
Chris Dalton5045de32021-01-07 19:09:01 -0700210 VertexList vertices;
211 vertices.append(e->fTop);
212 int count = 1;
213 while (e != nullptr) {
Chris Dalton9a4904f2021-01-07 19:10:14 -0700214 if (kRight_Side == monotonePoly->fSide) {
Chris Dalton5045de32021-01-07 19:09:01 -0700215 vertices.append(e->fBottom);
216 e = e->fRightPolyNext;
217 } else {
218 vertices.prepend(e->fBottom);
219 e = e->fLeftPolyNext;
Chris Dalton17ce8c52021-01-07 18:08:46 -0700220 }
Chris Dalton5045de32021-01-07 19:09:01 -0700221 count++;
222 }
223 Vertex* first = vertices.fHead;
224 Vertex* v = first->fNext;
225 while (v != vertices.fTail) {
226 SkASSERT(v && v->fPrev && v->fNext);
227 Vertex* prev = v->fPrev;
228 Vertex* curr = v;
229 Vertex* next = v->fNext;
230 if (count == 3) {
Chris Dalton9a4904f2021-01-07 19:10:14 -0700231 return this->emitTriangle(prev, curr, next, monotonePoly->fWinding, data);
Chris Dalton5045de32021-01-07 19:09:01 -0700232 }
233 double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX;
234 double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY;
235 double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX;
236 double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY;
237 if (ax * by - ay * bx >= 0.0) {
Chris Dalton9a4904f2021-01-07 19:10:14 -0700238 data = this->emitTriangle(prev, curr, next, monotonePoly->fWinding, data);
Chris Dalton5045de32021-01-07 19:09:01 -0700239 v->fPrev->fNext = v->fNext;
240 v->fNext->fPrev = v->fPrev;
241 count--;
242 if (v->fPrev == first) {
Chris Dalton17ce8c52021-01-07 18:08:46 -0700243 v = v->fNext;
Chris Daltond60c9192021-01-07 18:30:08 +0000244 } else {
Chris Dalton5045de32021-01-07 19:09:01 -0700245 v = v->fPrev;
Chris Daltond60c9192021-01-07 18:30:08 +0000246 }
Chris Dalton5045de32021-01-07 19:09:01 -0700247 } else {
248 v = v->fNext;
Chris Daltond60c9192021-01-07 18:30:08 +0000249 }
Chris Dalton75887a22021-01-06 00:23:13 -0700250 }
Chris Dalton5045de32021-01-07 19:09:01 -0700251 return data;
252}
253
Chris Dalton9a4904f2021-01-07 19:10:14 -0700254void* GrTriangulator::emitTriangle(Vertex* prev, Vertex* curr, Vertex* next, int winding,
255 void* data) const {
Chris Dalton93c2d812021-01-11 19:51:59 -0700256 if (winding > 0) {
Chris Dalton5045de32021-01-07 19:09:01 -0700257 // Ensure our triangles always wind in the same direction as if the path had been
258 // triangulated as a simple fan (a la red book).
259 std::swap(prev, next);
260 }
Chris Dalton68b8bd52021-01-14 10:48:02 -0700261 if (fBreadcrumbTriangles && abs(winding) > 1 &&
262 fPath.getFillType() == SkPathFillType::kWinding) {
263 // The first winding count will come from the actual triangle we emit. The remaining counts
264 // come from the breadcrumb triangle.
265 fBreadcrumbTriangles->push(prev->fPoint, curr->fPoint, next->fPoint, abs(winding) - 1);
266 }
Chris Dalton93c2d812021-01-11 19:51:59 -0700267 return emit_triangle(prev, curr, next, fEmitCoverage, data);
Chris Dalton5045de32021-01-07 19:09:01 -0700268}
269
Chris Dalton8a42b092021-01-21 22:09:26 -0700270Poly* GrTriangulator::Poly::addEdge(Edge* e, Side side, SkArenaAlloc* alloc) {
Chris Dalton5045de32021-01-07 19:09:01 -0700271 TESS_LOG("addEdge (%g -> %g) to poly %d, %s side\n",
272 e->fTop->fID, e->fBottom->fID, fID, side == kLeft_Side ? "left" : "right");
273 Poly* partner = fPartner;
274 Poly* poly = this;
275 if (side == kRight_Side) {
276 if (e->fUsedInRightPoly) {
277 return this;
Chris Daltond60c9192021-01-07 18:30:08 +0000278 }
Chris Dalton5045de32021-01-07 19:09:01 -0700279 } else {
280 if (e->fUsedInLeftPoly) {
281 return this;
Chris Daltond60c9192021-01-07 18:30:08 +0000282 }
Chris Dalton5045de32021-01-07 19:09:01 -0700283 }
284 if (partner) {
285 fPartner = partner->fPartner = nullptr;
286 }
287 if (!fTail) {
Chris Dalton8a42b092021-01-21 22:09:26 -0700288 fHead = fTail = alloc->make<MonotonePoly>(e, side, fWinding);
Chris Dalton5045de32021-01-07 19:09:01 -0700289 fCount += 2;
290 } else if (e->fBottom == fTail->fLastEdge->fBottom) {
291 return poly;
292 } else if (side == fTail->fSide) {
293 fTail->addEdge(e);
294 fCount++;
295 } else {
Chris Dalton8a42b092021-01-21 22:09:26 -0700296 e = alloc->make<Edge>(fTail->fLastEdge->fBottom, e->fBottom, 1, EdgeType::kInner);
Chris Dalton5045de32021-01-07 19:09:01 -0700297 fTail->addEdge(e);
298 fCount++;
299 if (partner) {
300 partner->addEdge(e, side, alloc);
301 poly = partner;
302 } else {
Chris Dalton8a42b092021-01-21 22:09:26 -0700303 MonotonePoly* m = alloc->make<MonotonePoly>(e, side, fWinding);
Chris Dalton5045de32021-01-07 19:09:01 -0700304 m->fPrev = fTail;
305 fTail->fNext = m;
306 fTail = m;
307 }
308 }
309 return poly;
310}
Chris Dalton9a4904f2021-01-07 19:10:14 -0700311void* GrTriangulator::emitPoly(const Poly* poly, void *data) {
312 if (poly->fCount < 3) {
ethannicholase9709e82016-01-07 13:34:16 -0800313 return data;
314 }
Chris Dalton5045de32021-01-07 19:09:01 -0700315 TESS_LOG("emit() %d, size %d\n", fID, fCount);
Chris Dalton9a4904f2021-01-07 19:10:14 -0700316 for (MonotonePoly* m = poly->fHead; m != nullptr; m = m->fNext) {
317 data = this->emitMonotonePoly(m, data);
Chris Dalton5045de32021-01-07 19:09:01 -0700318 }
319 return data;
320}
ethannicholase9709e82016-01-07 13:34:16 -0800321
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700322static bool coincident(const SkPoint& a, const SkPoint& b) {
ethannicholase9709e82016-01-07 13:34:16 -0800323 return a == b;
324}
325
Chris Dalton7cf3add2021-01-11 18:33:28 -0700326Poly* GrTriangulator::makePoly(Poly** head, Vertex* v, int winding) {
Chris Dalton8a42b092021-01-21 22:09:26 -0700327 Poly* poly = fAlloc->make<Poly>(v, winding);
ethannicholase9709e82016-01-07 13:34:16 -0800328 poly->fNext = *head;
329 *head = poly;
330 return poly;
331}
332
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700333void GrTriangulator::appendPointToContour(const SkPoint& p, VertexList* contour) {
Chris Dalton8a42b092021-01-21 22:09:26 -0700334 Vertex* v = fAlloc->make<Vertex>(p, 255);
Chris Dalton5045de32021-01-07 19:09:01 -0700335#if TRIANGULATOR_LOGGING
ethannicholase9709e82016-01-07 13:34:16 -0800336 static float gID = 0.0f;
337 v->fID = gID++;
338#endif
Stephen White3a9aab92017-03-07 14:07:18 -0500339 contour->append(v);
ethannicholase9709e82016-01-07 13:34:16 -0800340}
341
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700342static SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u) {
Stephen White36e4f062017-03-27 16:11:31 -0400343 SkQuadCoeff quad(pts);
344 SkPoint p0 = to_point(quad.eval(t - 0.5f * u));
345 SkPoint mid = to_point(quad.eval(t));
346 SkPoint p1 = to_point(quad.eval(t + 0.5f * u));
Stephen Whitee3a0be72017-06-12 11:43:18 -0400347 if (!p0.isFinite() || !mid.isFinite() || !p1.isFinite()) {
348 return 0;
349 }
Cary Clarkdf429f32017-11-08 11:44:31 -0500350 return SkPointPriv::DistanceToLineSegmentBetweenSqd(mid, p0, p1);
Stephen White36e4f062017-03-27 16:11:31 -0400351}
352
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700353void GrTriangulator::appendQuadraticToContour(const SkPoint pts[3], SkScalar toleranceSqd,
354 VertexList* contour) {
Stephen White36e4f062017-03-27 16:11:31 -0400355 SkQuadCoeff quad(pts);
356 Sk2s aa = quad.fA * quad.fA;
357 SkScalar denom = 2.0f * (aa[0] + aa[1]);
358 Sk2s ab = quad.fA * quad.fB;
359 SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f;
360 int nPoints = 1;
Stephen Whitee40c3612018-01-09 11:49:08 -0500361 SkScalar u = 1.0f;
Stephen White36e4f062017-03-27 16:11:31 -0400362 // Test possible subdivision values only at the point of maximum curvature.
363 // If it passes the flatness metric there, it'll pass everywhere.
Stephen Whitee40c3612018-01-09 11:49:08 -0500364 while (nPoints < GrPathUtils::kMaxPointsPerCurve) {
Stephen White36e4f062017-03-27 16:11:31 -0400365 u = 1.0f / nPoints;
366 if (quad_error_at(pts, t, u) < toleranceSqd) {
367 break;
368 }
369 nPoints++;
ethannicholase9709e82016-01-07 13:34:16 -0800370 }
Stephen White36e4f062017-03-27 16:11:31 -0400371 for (int j = 1; j <= nPoints; j++) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700372 this->appendPointToContour(to_point(quad.eval(j * u)), contour);
Stephen White36e4f062017-03-27 16:11:31 -0400373 }
ethannicholase9709e82016-01-07 13:34:16 -0800374}
375
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700376void GrTriangulator::generateCubicPoints(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
377 const SkPoint& p3, SkScalar tolSqd, VertexList* contour,
378 int pointsLeft) {
Cary Clarkdf429f32017-11-08 11:44:31 -0500379 SkScalar d1 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p1, p0, p3);
380 SkScalar d2 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p2, p0, p3);
ethannicholase9709e82016-01-07 13:34:16 -0800381 if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) ||
382 !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700383 this->appendPointToContour(p3, contour);
Stephen White3a9aab92017-03-07 14:07:18 -0500384 return;
ethannicholase9709e82016-01-07 13:34:16 -0800385 }
386 const SkPoint q[] = {
387 { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
388 { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
389 { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
390 };
391 const SkPoint r[] = {
392 { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
393 { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
394 };
395 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
396 pointsLeft >>= 1;
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700397 this->generateCubicPoints(p0, q[0], r[0], s, tolSqd, contour, pointsLeft);
398 this->generateCubicPoints(s, r[1], q[2], p3, tolSqd, contour, pointsLeft);
ethannicholase9709e82016-01-07 13:34:16 -0800399}
400
401// Stage 1: convert the input path to a set of linear contours (linked list of Vertices).
402
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700403void GrTriangulator::pathToContours(float tolerance, const SkRect& clipBounds,
Chris Dalton37d16f12021-01-20 18:32:48 -0700404 VertexList* contours, bool* isLinear) {
ethannicholase9709e82016-01-07 13:34:16 -0800405 SkScalar toleranceSqd = tolerance * tolerance;
Chris Dalton7156db22020-05-07 22:06:28 +0000406 SkPoint pts[4];
Chris Dalton37d16f12021-01-20 18:32:48 -0700407 *isLinear = true;
Stephen White3a9aab92017-03-07 14:07:18 -0500408 VertexList* contour = contours;
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700409 SkPath::Iter iter(fPath, false);
410 if (fPath.isInverseFillType()) {
ethannicholase9709e82016-01-07 13:34:16 -0800411 SkPoint quad[4];
412 clipBounds.toQuad(quad);
senorblanco7ab96e92016-10-12 06:47:44 -0700413 for (int i = 3; i >= 0; i--) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700414 this->appendPointToContour(quad[i], contours);
ethannicholase9709e82016-01-07 13:34:16 -0800415 }
Stephen White3a9aab92017-03-07 14:07:18 -0500416 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800417 }
418 SkAutoConicToQuads converter;
Chris Dalton7156db22020-05-07 22:06:28 +0000419 SkPath::Verb verb;
420 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
ethannicholase9709e82016-01-07 13:34:16 -0800421 switch (verb) {
Chris Dalton7156db22020-05-07 22:06:28 +0000422 case SkPath::kConic_Verb: {
Chris Dalton37d16f12021-01-20 18:32:48 -0700423 *isLinear = false;
Chris Dalton57115c02021-01-12 18:12:18 -0700424 if (toleranceSqd == 0) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700425 this->appendPointToContour(pts[2], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700426 break;
427 }
Chris Dalton7156db22020-05-07 22:06:28 +0000428 SkScalar weight = iter.conicWeight();
429 const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd);
ethannicholase9709e82016-01-07 13:34:16 -0800430 for (int i = 0; i < converter.countQuads(); ++i) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700431 this->appendQuadraticToContour(quadPts, toleranceSqd, contour);
ethannicholase9709e82016-01-07 13:34:16 -0800432 quadPts += 2;
433 }
ethannicholase9709e82016-01-07 13:34:16 -0800434 break;
435 }
Chris Dalton7156db22020-05-07 22:06:28 +0000436 case SkPath::kMove_Verb:
Stephen White3a9aab92017-03-07 14:07:18 -0500437 if (contour->fHead) {
438 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800439 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700440 this->appendPointToContour(pts[0], contour);
ethannicholase9709e82016-01-07 13:34:16 -0800441 break;
Chris Dalton7156db22020-05-07 22:06:28 +0000442 case SkPath::kLine_Verb: {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700443 this->appendPointToContour(pts[1], contour);
ethannicholase9709e82016-01-07 13:34:16 -0800444 break;
445 }
Chris Dalton7156db22020-05-07 22:06:28 +0000446 case SkPath::kQuad_Verb: {
Chris Dalton37d16f12021-01-20 18:32:48 -0700447 *isLinear = false;
Chris Dalton57115c02021-01-12 18:12:18 -0700448 if (toleranceSqd == 0) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700449 this->appendPointToContour(pts[2], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700450 break;
451 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700452 this->appendQuadraticToContour(pts, toleranceSqd, contour);
ethannicholase9709e82016-01-07 13:34:16 -0800453 break;
454 }
Chris Dalton7156db22020-05-07 22:06:28 +0000455 case SkPath::kCubic_Verb: {
Chris Dalton37d16f12021-01-20 18:32:48 -0700456 *isLinear = false;
Chris Dalton57115c02021-01-12 18:12:18 -0700457 if (toleranceSqd == 0) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700458 this->appendPointToContour(pts[3], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700459 break;
460 }
ethannicholase9709e82016-01-07 13:34:16 -0800461 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700462 this->generateCubicPoints(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour,
463 pointsLeft);
ethannicholase9709e82016-01-07 13:34:16 -0800464 break;
465 }
Chris Dalton7156db22020-05-07 22:06:28 +0000466 case SkPath::kClose_Verb:
467 case SkPath::kDone_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800468 break;
469 }
470 }
471}
472
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700473static inline bool apply_fill_type(SkPathFillType fillType, int winding) {
ethannicholase9709e82016-01-07 13:34:16 -0800474 switch (fillType) {
Mike Reed7d34dc72019-11-26 12:17:17 -0500475 case SkPathFillType::kWinding:
ethannicholase9709e82016-01-07 13:34:16 -0800476 return winding != 0;
Mike Reed7d34dc72019-11-26 12:17:17 -0500477 case SkPathFillType::kEvenOdd:
ethannicholase9709e82016-01-07 13:34:16 -0800478 return (winding & 1) != 0;
Mike Reed7d34dc72019-11-26 12:17:17 -0500479 case SkPathFillType::kInverseWinding:
senorblanco7ab96e92016-10-12 06:47:44 -0700480 return winding == 1;
Mike Reed7d34dc72019-11-26 12:17:17 -0500481 case SkPathFillType::kInverseEvenOdd:
ethannicholase9709e82016-01-07 13:34:16 -0800482 return (winding & 1) == 1;
483 default:
484 SkASSERT(false);
485 return false;
486 }
487}
488
Chris Dalton47114db2021-01-06 00:35:20 -0700489bool GrTriangulator::applyFillType(int winding) {
490 return apply_fill_type(fPath.getFillType(), winding);
491}
492
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700493static inline bool apply_fill_type(SkPathFillType fillType, Poly* poly) {
Stephen White49789062017-02-21 10:35:49 -0500494 return poly && apply_fill_type(fillType, poly->fWinding);
495}
496
Chris Dalton7cf3add2021-01-11 18:33:28 -0700497Edge* GrTriangulator::makeEdge(Vertex* prev, Vertex* next, EdgeType type, const Comparator& c) {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700498 SkASSERT(prev->fPoint != next->fPoint);
Stephen White2f4686f2017-01-03 16:20:01 -0500499 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
ethannicholase9709e82016-01-07 13:34:16 -0800500 Vertex* top = winding < 0 ? next : prev;
501 Vertex* bottom = winding < 0 ? prev : next;
Chris Dalton8a42b092021-01-21 22:09:26 -0700502 return fAlloc->make<Edge>(top, bottom, winding, type);
ethannicholase9709e82016-01-07 13:34:16 -0800503}
504
Chris Dalton24472af2021-01-11 20:05:00 -0700505void EdgeList::insert(Edge* edge, Edge* prev) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400506 TESS_LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
Chris Dalton24472af2021-01-11 20:05:00 -0700507 SkASSERT(!this->contains(edge));
508 Edge* next = prev ? prev->fRight : fHead;
509 this->insert(edge, prev, next);
ethannicholase9709e82016-01-07 13:34:16 -0800510}
511
Chris Dalton47114db2021-01-06 00:35:20 -0700512void GrTriangulator::FindEnclosingEdges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) {
Stephen White90732fd2017-03-02 16:16:33 -0500513 if (v->fFirstEdgeAbove && v->fLastEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -0800514 *left = v->fFirstEdgeAbove->fLeft;
515 *right = v->fLastEdgeAbove->fRight;
516 return;
517 }
518 Edge* next = nullptr;
519 Edge* prev;
520 for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) {
521 if (prev->isLeftOf(v)) {
522 break;
523 }
524 next = prev;
525 }
526 *left = prev;
527 *right = next;
ethannicholase9709e82016-01-07 13:34:16 -0800528}
529
Chris Dalton24472af2021-01-11 20:05:00 -0700530void GrTriangulator::Edge::insertAbove(Vertex* v, const Comparator& c) {
531 if (fTop->fPoint == fBottom->fPoint ||
532 c.sweep_lt(fBottom->fPoint, fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800533 return;
534 }
Chris Dalton24472af2021-01-11 20:05:00 -0700535 TESS_LOG("insert edge (%g -> %g) above vertex %g\n", fTop->fID, fBottom->fID, v->fID);
ethannicholase9709e82016-01-07 13:34:16 -0800536 Edge* prev = nullptr;
537 Edge* next;
Chris Daltond60c9192021-01-07 18:30:08 +0000538 for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -0700539 if (next->isRightOf(fTop)) {
ethannicholase9709e82016-01-07 13:34:16 -0800540 break;
541 }
542 prev = next;
543 }
senorblancoe6eaa322016-03-08 09:06:44 -0800544 list_insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
Chris Dalton24472af2021-01-11 20:05:00 -0700545 this, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove);
ethannicholase9709e82016-01-07 13:34:16 -0800546}
547
Chris Dalton24472af2021-01-11 20:05:00 -0700548void GrTriangulator::Edge::insertBelow(Vertex* v, const Comparator& c) {
549 if (fTop->fPoint == fBottom->fPoint ||
550 c.sweep_lt(fBottom->fPoint, fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800551 return;
552 }
Chris Dalton24472af2021-01-11 20:05:00 -0700553 TESS_LOG("insert edge (%g -> %g) below vertex %g\n", fTop->fID, fBottom->fID, v->fID);
ethannicholase9709e82016-01-07 13:34:16 -0800554 Edge* prev = nullptr;
555 Edge* next;
Chris Daltond60c9192021-01-07 18:30:08 +0000556 for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -0700557 if (next->isRightOf(fBottom)) {
ethannicholase9709e82016-01-07 13:34:16 -0800558 break;
559 }
560 prev = next;
561 }
senorblancoe6eaa322016-03-08 09:06:44 -0800562 list_insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
Chris Dalton24472af2021-01-11 20:05:00 -0700563 this, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow);
ethannicholase9709e82016-01-07 13:34:16 -0800564}
565
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700566static void remove_edge_above(Edge* edge) {
Stephen White7b376942018-05-22 11:51:32 -0400567 SkASSERT(edge->fTop && edge->fBottom);
Brian Salomon120e7d62019-09-11 10:29:22 -0400568 TESS_LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
569 edge->fBottom->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800570 list_remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800571 edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove);
572}
573
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700574static void remove_edge_below(Edge* edge) {
Stephen White7b376942018-05-22 11:51:32 -0400575 SkASSERT(edge->fTop && edge->fBottom);
Brian Salomon120e7d62019-09-11 10:29:22 -0400576 TESS_LOG("removing edge (%g -> %g) below vertex %g\n",
577 edge->fTop->fID, edge->fBottom->fID, edge->fTop->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800578 list_remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800579 edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow);
580}
581
Chris Dalton24472af2021-01-11 20:05:00 -0700582void GrTriangulator::Edge::disconnect() {
583 remove_edge_above(this);
584 remove_edge_below(this);
Stephen Whitee7a364d2017-01-11 16:19:26 -0500585}
586
Chris Dalton811dc6a2021-01-07 16:40:32 -0700587static void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, const Comparator& c) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400588 if (!current || *current == dst || c.sweep_lt((*current)->fPoint, dst->fPoint)) {
589 return;
590 }
591 Vertex* v = *current;
Brian Salomon120e7d62019-09-11 10:29:22 -0400592 TESS_LOG("rewinding active edges from vertex %g to vertex %g\n", v->fID, dst->fID);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400593 while (v != dst) {
594 v = v->fPrev;
595 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -0700596 activeEdges->remove(e);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400597 }
598 Edge* leftEdge = v->fLeftEnclosingEdge;
599 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -0700600 activeEdges->insert(e, leftEdge);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400601 leftEdge = e;
Stephen Whitec03e6982020-02-06 16:32:14 -0500602 Vertex* top = e->fTop;
603 if (c.sweep_lt(top->fPoint, dst->fPoint) &&
604 ((top->fLeftEnclosingEdge && !top->fLeftEnclosingEdge->isLeftOf(e->fTop)) ||
605 (top->fRightEnclosingEdge && !top->fRightEnclosingEdge->isRightOf(e->fTop)))) {
606 dst = top;
607 }
Stephen White3b5a3fa2017-06-06 14:51:19 -0400608 }
609 }
610 *current = v;
611}
612
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700613static void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700614 const Comparator& c) {
Stephen Whitec03e6982020-02-06 16:32:14 -0500615 if (!activeEdges || !current) {
616 return;
617 }
618 Vertex* top = edge->fTop;
619 Vertex* bottom = edge->fBottom;
620 if (edge->fLeft) {
621 Vertex* leftTop = edge->fLeft->fTop;
622 Vertex* leftBottom = edge->fLeft->fBottom;
623 if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
624 rewind(activeEdges, current, leftTop, c);
625 } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
626 rewind(activeEdges, current, top, c);
627 } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
628 !edge->fLeft->isLeftOf(bottom)) {
629 rewind(activeEdges, current, leftTop, c);
630 } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
631 rewind(activeEdges, current, top, c);
632 }
633 }
634 if (edge->fRight) {
635 Vertex* rightTop = edge->fRight->fTop;
636 Vertex* rightBottom = edge->fRight->fBottom;
637 if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
638 rewind(activeEdges, current, rightTop, c);
639 } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
640 rewind(activeEdges, current, top, c);
641 } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
642 !edge->fRight->isRightOf(bottom)) {
643 rewind(activeEdges, current, rightTop, c);
644 } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
645 !edge->isLeftOf(rightBottom)) {
646 rewind(activeEdges, current, top, c);
647 }
648 }
649}
650
Chris Dalton68b8bd52021-01-14 10:48:02 -0700651void GrTriangulator::setTop(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
652 const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800653 remove_edge_below(edge);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700654 if (fBreadcrumbTriangles) {
655 fBreadcrumbTriangles->push(edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
656 edge->fWinding);
657 }
ethannicholase9709e82016-01-07 13:34:16 -0800658 edge->fTop = v;
659 edge->recompute();
Chris Dalton24472af2021-01-11 20:05:00 -0700660 edge->insertBelow(v, c);
Stephen Whitec03e6982020-02-06 16:32:14 -0500661 rewind_if_necessary(edge, activeEdges, current, c);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700662 this->mergeCollinearEdges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800663}
664
Chris Dalton68b8bd52021-01-14 10:48:02 -0700665void GrTriangulator::setBottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
666 const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800667 remove_edge_above(edge);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700668 if (fBreadcrumbTriangles) {
669 fBreadcrumbTriangles->push(edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
670 edge->fWinding);
671 }
ethannicholase9709e82016-01-07 13:34:16 -0800672 edge->fBottom = v;
673 edge->recompute();
Chris Dalton24472af2021-01-11 20:05:00 -0700674 edge->insertAbove(v, c);
Stephen Whitec03e6982020-02-06 16:32:14 -0500675 rewind_if_necessary(edge, activeEdges, current, c);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700676 this->mergeCollinearEdges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800677}
678
Chris Dalton68b8bd52021-01-14 10:48:02 -0700679void GrTriangulator::mergeEdgesAbove(Edge* edge, Edge* other, EdgeList* activeEdges,
680 Vertex** current, const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800681 if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400682 TESS_LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
683 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
684 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400685 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800686 other->fWinding += edge->fWinding;
Chris Dalton24472af2021-01-11 20:05:00 -0700687 edge->disconnect();
Stephen Whiteec79c392018-05-18 11:49:21 -0400688 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -0800689 } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400690 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800691 other->fWinding += edge->fWinding;
Chris Dalton68b8bd52021-01-14 10:48:02 -0700692 this->setBottom(edge, other->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800693 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400694 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800695 edge->fWinding += other->fWinding;
Chris Dalton68b8bd52021-01-14 10:48:02 -0700696 this->setBottom(other, edge->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800697 }
698}
699
Chris Dalton68b8bd52021-01-14 10:48:02 -0700700void GrTriangulator::mergeEdgesBelow(Edge* edge, Edge* other, EdgeList* activeEdges,
701 Vertex** current, const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800702 if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400703 TESS_LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
704 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
705 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400706 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800707 other->fWinding += edge->fWinding;
Chris Dalton24472af2021-01-11 20:05:00 -0700708 edge->disconnect();
Stephen Whiteec79c392018-05-18 11:49:21 -0400709 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -0800710 } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400711 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800712 edge->fWinding += other->fWinding;
Chris Dalton68b8bd52021-01-14 10:48:02 -0700713 this->setTop(other, edge->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800714 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400715 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800716 other->fWinding += edge->fWinding;
Chris Dalton68b8bd52021-01-14 10:48:02 -0700717 this->setTop(edge, other->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800718 }
719}
720
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700721static bool top_collinear(Edge* left, Edge* right) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400722 if (!left || !right) {
723 return false;
724 }
725 return left->fTop->fPoint == right->fTop->fPoint ||
726 !left->isLeftOf(right->fTop) || !right->isRightOf(left->fTop);
727}
728
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700729static bool bottom_collinear(Edge* left, Edge* right) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400730 if (!left || !right) {
731 return false;
732 }
733 return left->fBottom->fPoint == right->fBottom->fPoint ||
734 !left->isLeftOf(right->fBottom) || !right->isRightOf(left->fBottom);
735}
736
Chris Dalton68b8bd52021-01-14 10:48:02 -0700737void GrTriangulator::mergeCollinearEdges(Edge* edge, EdgeList* activeEdges, Vertex** current,
738 const Comparator& c) {
Stephen White6eca90f2017-05-25 14:47:11 -0400739 for (;;) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400740 if (top_collinear(edge->fPrevEdgeAbove, edge)) {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700741 this->mergeEdgesAbove(edge->fPrevEdgeAbove, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400742 } else if (top_collinear(edge, edge->fNextEdgeAbove)) {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700743 this->mergeEdgesAbove(edge->fNextEdgeAbove, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400744 } else if (bottom_collinear(edge->fPrevEdgeBelow, edge)) {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700745 this->mergeEdgesBelow(edge->fPrevEdgeBelow, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400746 } else if (bottom_collinear(edge, edge->fNextEdgeBelow)) {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700747 this->mergeEdgesBelow(edge->fNextEdgeBelow, edge, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -0400748 } else {
749 break;
750 }
ethannicholase9709e82016-01-07 13:34:16 -0800751 }
Stephen Whited26b4d82018-07-26 10:02:27 -0400752 SkASSERT(!top_collinear(edge->fPrevEdgeAbove, edge));
753 SkASSERT(!top_collinear(edge, edge->fNextEdgeAbove));
754 SkASSERT(!bottom_collinear(edge->fPrevEdgeBelow, edge));
755 SkASSERT(!bottom_collinear(edge, edge->fNextEdgeBelow));
ethannicholase9709e82016-01-07 13:34:16 -0800756}
757
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700758bool GrTriangulator::splitEdge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700759 const Comparator& c) {
Stephen Whiteec79c392018-05-18 11:49:21 -0400760 if (!edge->fTop || !edge->fBottom || v == edge->fTop || v == edge->fBottom) {
Stephen White89042d52018-06-08 12:18:22 -0400761 return false;
Stephen White0cb31672017-06-08 14:41:01 -0400762 }
Brian Salomon120e7d62019-09-11 10:29:22 -0400763 TESS_LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
764 edge->fTop->fID, edge->fBottom->fID, v->fID, v->fPoint.fX, v->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400765 Vertex* top;
766 Vertex* bottom;
Stephen White531a48e2018-06-01 09:49:39 -0400767 int winding = edge->fWinding;
ethannicholase9709e82016-01-07 13:34:16 -0800768 if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400769 top = v;
770 bottom = edge->fTop;
Chris Dalton68b8bd52021-01-14 10:48:02 -0700771 this->setTop(edge, v, activeEdges, current, c);
Stephen Whitee30cf802017-02-27 11:37:55 -0500772 } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400773 top = edge->fBottom;
774 bottom = v;
Chris Dalton68b8bd52021-01-14 10:48:02 -0700775 this->setBottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800776 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400777 top = v;
778 bottom = edge->fBottom;
Chris Dalton68b8bd52021-01-14 10:48:02 -0700779 this->setBottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800780 }
Chris Dalton8a42b092021-01-21 22:09:26 -0700781 Edge* newEdge = fAlloc->make<Edge>(top, bottom, winding, edge->fType);
Chris Dalton24472af2021-01-11 20:05:00 -0700782 newEdge->insertBelow(top, c);
783 newEdge->insertAbove(bottom, c);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700784 this->mergeCollinearEdges(newEdge, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400785 return true;
786}
787
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700788bool GrTriangulator::intersectEdgePair(Edge* left, Edge* right, EdgeList* activeEdges,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700789 Vertex** current, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -0400790 if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) {
791 return false;
792 }
Stephen White1c5fd182018-07-12 15:54:05 -0400793 if (left->fTop == right->fTop || left->fBottom == right->fBottom) {
794 return false;
795 }
Stephen White89042d52018-06-08 12:18:22 -0400796 if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
797 if (!left->isLeftOf(right->fTop)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400798 rewind(activeEdges, current, right->fTop, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700799 return this->splitEdge(left, right->fTop, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400800 }
801 } else {
802 if (!right->isRightOf(left->fTop)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400803 rewind(activeEdges, current, left->fTop, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700804 return this->splitEdge(right, left->fTop, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400805 }
806 }
807 if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
808 if (!left->isLeftOf(right->fBottom)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400809 rewind(activeEdges, current, right->fBottom, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700810 return this->splitEdge(left, right->fBottom, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400811 }
812 } else {
813 if (!right->isRightOf(left->fBottom)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400814 rewind(activeEdges, current, left->fBottom, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700815 return this->splitEdge(right, left->fBottom, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400816 }
817 }
818 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800819}
820
Chris Dalton7cf3add2021-01-11 18:33:28 -0700821Edge* GrTriangulator::makeConnectingEdge(Vertex* prev, Vertex* next, EdgeType type,
822 const Comparator& c, int windingScale) {
Stephen Whitee260c462017-12-19 18:09:54 -0500823 if (!prev || !next || prev->fPoint == next->fPoint) {
824 return nullptr;
825 }
Chris Dalton7cf3add2021-01-11 18:33:28 -0700826 Edge* edge = this->makeEdge(prev, next, type, c);
Chris Dalton24472af2021-01-11 20:05:00 -0700827 edge->insertBelow(edge->fTop, c);
828 edge->insertAbove(edge->fBottom, c);
Chris Dalton7cf3add2021-01-11 18:33:28 -0700829 edge->fWinding *= windingScale;
Chris Dalton68b8bd52021-01-14 10:48:02 -0700830 this->mergeCollinearEdges(edge, nullptr, nullptr, c);
senorblancof57372d2016-08-31 10:36:19 -0700831 return edge;
832}
833
Chris Dalton68b8bd52021-01-14 10:48:02 -0700834void GrTriangulator::mergeVertices(Vertex* src, Vertex* dst, VertexList* mesh,
835 const Comparator& c) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400836 TESS_LOG("found coincident verts at %g, %g; merging %g into %g\n",
837 src->fPoint.fX, src->fPoint.fY, src->fID, dst->fID);
Brian Osman788b9162020-02-07 10:36:46 -0500838 dst->fAlpha = std::max(src->fAlpha, dst->fAlpha);
Stephen Whitebda29c02017-03-13 15:10:13 -0400839 if (src->fPartner) {
840 src->fPartner->fPartner = dst;
841 }
Stephen White7b376942018-05-22 11:51:32 -0400842 while (Edge* edge = src->fFirstEdgeAbove) {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700843 this->setBottom(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -0800844 }
Stephen White7b376942018-05-22 11:51:32 -0400845 while (Edge* edge = src->fFirstEdgeBelow) {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700846 this->setTop(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -0800847 }
Stephen Whitebf6137e2017-01-04 15:43:26 -0500848 mesh->remove(src);
Stephen Whitec4dbc372019-05-22 10:50:14 -0400849 dst->fSynthetic = true;
ethannicholase9709e82016-01-07 13:34:16 -0800850}
851
Chris Dalton7cf3add2021-01-11 18:33:28 -0700852Vertex* GrTriangulator::makeSortedVertex(const SkPoint& p, uint8_t alpha, VertexList* mesh,
853 Vertex* reference, const Comparator& c) {
Stephen White95152e12017-12-18 10:52:44 -0500854 Vertex* prevV = reference;
855 while (prevV && c.sweep_lt(p, prevV->fPoint)) {
856 prevV = prevV->fPrev;
857 }
858 Vertex* nextV = prevV ? prevV->fNext : mesh->fHead;
859 while (nextV && c.sweep_lt(nextV->fPoint, p)) {
860 prevV = nextV;
861 nextV = nextV->fNext;
862 }
863 Vertex* v;
864 if (prevV && coincident(prevV->fPoint, p)) {
865 v = prevV;
866 } else if (nextV && coincident(nextV->fPoint, p)) {
867 v = nextV;
868 } else {
Chris Dalton8a42b092021-01-21 22:09:26 -0700869 v = fAlloc->make<Vertex>(p, alpha);
Chris Dalton5045de32021-01-07 19:09:01 -0700870#if TRIANGULATOR_LOGGING
Stephen White95152e12017-12-18 10:52:44 -0500871 if (!prevV) {
872 v->fID = mesh->fHead->fID - 1.0f;
873 } else if (!nextV) {
874 v->fID = mesh->fTail->fID + 1.0f;
875 } else {
876 v->fID = (prevV->fID + nextV->fID) * 0.5f;
877 }
878#endif
879 mesh->insert(v, prevV, nextV);
880 }
881 return v;
882}
883
Stephen White53a02982018-05-30 22:47:46 -0400884// If an edge's top and bottom points differ only by 1/2 machine epsilon in the primary
885// sort criterion, it may not be possible to split correctly, since there is no point which is
886// below the top and above the bottom. This function detects that case.
Chris Dalton811dc6a2021-01-07 16:40:32 -0700887static bool nearly_flat(const Comparator& c, Edge* edge) {
Stephen White53a02982018-05-30 22:47:46 -0400888 SkPoint diff = edge->fBottom->fPoint - edge->fTop->fPoint;
889 float primaryDiff = c.fDirection == Comparator::Direction::kHorizontal ? diff.fX : diff.fY;
Stephen White13f3d8d2018-06-22 10:19:20 -0400890 return fabs(primaryDiff) < std::numeric_limits<float>::epsilon() && primaryDiff != 0.0f;
Stephen White53a02982018-05-30 22:47:46 -0400891}
892
Chris Dalton811dc6a2021-01-07 16:40:32 -0700893static SkPoint clamp(SkPoint p, SkPoint min, SkPoint max, const Comparator& c) {
Stephen Whitee62999f2018-06-05 18:45:07 -0400894 if (c.sweep_lt(p, min)) {
895 return min;
896 } else if (c.sweep_lt(max, p)) {
897 return max;
898 } else {
899 return p;
900 }
901}
902
Chris Dalton7cf3add2021-01-11 18:33:28 -0700903void GrTriangulator::computeBisector(Edge* edge1, Edge* edge2, Vertex* v) {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700904 SkASSERT(fEmitCoverage); // Edge-AA only!
Stephen Whitec4dbc372019-05-22 10:50:14 -0400905 Line line1 = edge1->fLine;
906 Line line2 = edge2->fLine;
907 line1.normalize();
908 line2.normalize();
909 double cosAngle = line1.fA * line2.fA + line1.fB * line2.fB;
910 if (cosAngle > 0.999) {
911 return;
912 }
913 line1.fC += edge1->fWinding > 0 ? -1 : 1;
914 line2.fC += edge2->fWinding > 0 ? -1 : 1;
915 SkPoint p;
916 if (line1.intersect(line2, &p)) {
Chris Dalton17ce8c52021-01-07 18:08:46 -0700917 uint8_t alpha = edge1->fType == EdgeType::kOuter ? 255 : 0;
Chris Dalton8a42b092021-01-21 22:09:26 -0700918 v->fPartner = fAlloc->make<Vertex>(p, alpha);
Brian Salomon120e7d62019-09-11 10:29:22 -0400919 TESS_LOG("computed bisector (%g,%g) alpha %d for vertex %g\n", p.fX, p.fY, alpha, v->fID);
Stephen Whitec4dbc372019-05-22 10:50:14 -0400920 }
921}
922
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700923bool GrTriangulator::checkForIntersection(Edge* left, Edge* right, EdgeList* activeEdges,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700924 Vertex** current, VertexList* mesh, const Comparator& c) {
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400925 if (!left || !right) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400926 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800927 }
Stephen White56158ae2017-01-30 14:31:31 -0500928 SkPoint p;
929 uint8_t alpha;
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400930 if (left->intersect(*right, &p, &alpha) && p.isFinite()) {
Ravi Mistrybfe95982018-05-29 18:19:07 +0000931 Vertex* v;
Brian Salomon120e7d62019-09-11 10:29:22 -0400932 TESS_LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400933 Vertex* top = *current;
934 // If the intersection point is above the current vertex, rewind to the vertex above the
935 // intersection.
Stephen White0cb31672017-06-08 14:41:01 -0400936 while (top && c.sweep_lt(p, top->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400937 top = top->fPrev;
938 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400939 if (!nearly_flat(c, left)) {
940 p = clamp(p, left->fTop->fPoint, left->fBottom->fPoint, c);
Stephen Whitee62999f2018-06-05 18:45:07 -0400941 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400942 if (!nearly_flat(c, right)) {
943 p = clamp(p, right->fTop->fPoint, right->fBottom->fPoint, c);
Stephen Whitee62999f2018-06-05 18:45:07 -0400944 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400945 if (p == left->fTop->fPoint) {
946 v = left->fTop;
947 } else if (p == left->fBottom->fPoint) {
948 v = left->fBottom;
949 } else if (p == right->fTop->fPoint) {
950 v = right->fTop;
951 } else if (p == right->fBottom->fPoint) {
952 v = right->fBottom;
Ravi Mistrybfe95982018-05-29 18:19:07 +0000953 } else {
Chris Dalton7cf3add2021-01-11 18:33:28 -0700954 v = this->makeSortedVertex(p, alpha, mesh, top, c);
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400955 if (left->fTop->fPartner) {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700956 SkASSERT(fEmitCoverage); // Edge-AA only!
Stephen Whitec4dbc372019-05-22 10:50:14 -0400957 v->fSynthetic = true;
Chris Dalton7cf3add2021-01-11 18:33:28 -0700958 this->computeBisector(left, right, v);
Stephen Whitee260c462017-12-19 18:09:54 -0500959 }
ethannicholase9709e82016-01-07 13:34:16 -0800960 }
Stephen White0cb31672017-06-08 14:41:01 -0400961 rewind(activeEdges, current, top ? top : v, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700962 this->splitEdge(left, v, activeEdges, current, c);
963 this->splitEdge(right, v, activeEdges, current, c);
Brian Osman788b9162020-02-07 10:36:46 -0500964 v->fAlpha = std::max(v->fAlpha, alpha);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400965 return true;
ethannicholase9709e82016-01-07 13:34:16 -0800966 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700967 return this->intersectEdgePair(left, right, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800968}
969
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700970void GrTriangulator::sanitizeContours(VertexList* contours, int contourCnt) {
Stephen White3a9aab92017-03-07 14:07:18 -0500971 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
972 SkASSERT(contour->fHead);
973 Vertex* prev = contour->fTail;
Chris Dalton854ee852021-01-05 15:12:59 -0700974 if (fRoundVerticesToQuarterPixel) {
Stephen White3a9aab92017-03-07 14:07:18 -0500975 round(&prev->fPoint);
Stephen White5926f2d2017-02-13 13:55:42 -0500976 }
Stephen White3a9aab92017-03-07 14:07:18 -0500977 for (Vertex* v = contour->fHead; v;) {
Chris Dalton854ee852021-01-05 15:12:59 -0700978 if (fRoundVerticesToQuarterPixel) {
senorblancof57372d2016-08-31 10:36:19 -0700979 round(&v->fPoint);
980 }
Stephen White3a9aab92017-03-07 14:07:18 -0500981 Vertex* next = v->fNext;
Stephen White3de40f82018-06-28 09:36:49 -0400982 Vertex* nextWrap = next ? next : contour->fHead;
Stephen White3a9aab92017-03-07 14:07:18 -0500983 if (coincident(prev->fPoint, v->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400984 TESS_LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -0500985 contour->remove(v);
Stephen White73e7f802017-08-23 13:56:07 -0400986 } else if (!v->fPoint.isFinite()) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400987 TESS_LOG("vertex %g,%g non-finite; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White73e7f802017-08-23 13:56:07 -0400988 contour->remove(v);
Chris Dalton854ee852021-01-05 15:12:59 -0700989 } else if (fCullCollinearVertices &&
Chris Dalton6ccc0322020-01-29 11:38:16 -0700990 Line(prev->fPoint, nextWrap->fPoint).dist(v->fPoint) == 0.0) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400991 TESS_LOG("vertex %g,%g collinear; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White06768ca2018-05-25 14:50:56 -0400992 contour->remove(v);
993 } else {
994 prev = v;
ethannicholase9709e82016-01-07 13:34:16 -0800995 }
Stephen White3a9aab92017-03-07 14:07:18 -0500996 v = next;
ethannicholase9709e82016-01-07 13:34:16 -0800997 }
998 }
999}
1000
Chris Dalton811dc6a2021-01-07 16:40:32 -07001001bool GrTriangulator::mergeCoincidentVertices(VertexList* mesh, const Comparator& c) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001002 if (!mesh->fHead) {
Stephen Whitee260c462017-12-19 18:09:54 -05001003 return false;
Stephen Whitebda29c02017-03-13 15:10:13 -04001004 }
Stephen Whitee260c462017-12-19 18:09:54 -05001005 bool merged = false;
1006 for (Vertex* v = mesh->fHead->fNext; v;) {
1007 Vertex* next = v->fNext;
ethannicholase9709e82016-01-07 13:34:16 -08001008 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) {
1009 v->fPoint = v->fPrev->fPoint;
1010 }
1011 if (coincident(v->fPrev->fPoint, v->fPoint)) {
Chris Dalton68b8bd52021-01-14 10:48:02 -07001012 this->mergeVertices(v, v->fPrev, mesh, c);
Stephen Whitee260c462017-12-19 18:09:54 -05001013 merged = true;
ethannicholase9709e82016-01-07 13:34:16 -08001014 }
Stephen Whitee260c462017-12-19 18:09:54 -05001015 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001016 }
Stephen Whitee260c462017-12-19 18:09:54 -05001017 return merged;
ethannicholase9709e82016-01-07 13:34:16 -08001018}
1019
1020// Stage 2: convert the contours to a mesh of edges connecting the vertices.
1021
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001022void GrTriangulator::buildEdges(VertexList* contours, int contourCnt, VertexList* mesh,
Chris Dalton811dc6a2021-01-07 16:40:32 -07001023 const Comparator& c) {
Stephen White3a9aab92017-03-07 14:07:18 -05001024 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1025 Vertex* prev = contour->fTail;
1026 for (Vertex* v = contour->fHead; v;) {
1027 Vertex* next = v->fNext;
Chris Dalton7cf3add2021-01-11 18:33:28 -07001028 this->makeConnectingEdge(prev, v, EdgeType::kInner, c);
Stephen White3a9aab92017-03-07 14:07:18 -05001029 mesh->append(v);
ethannicholase9709e82016-01-07 13:34:16 -08001030 prev = v;
Stephen White3a9aab92017-03-07 14:07:18 -05001031 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001032 }
1033 }
ethannicholase9709e82016-01-07 13:34:16 -08001034}
1035
Stephen Whitebda29c02017-03-13 15:10:13 -04001036template <CompareFunc sweep_lt>
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001037static void sorted_merge(VertexList* front, VertexList* back, VertexList* result) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001038 Vertex* a = front->fHead;
1039 Vertex* b = back->fHead;
1040 while (a && b) {
1041 if (sweep_lt(a->fPoint, b->fPoint)) {
1042 front->remove(a);
1043 result->append(a);
1044 a = front->fHead;
1045 } else {
1046 back->remove(b);
1047 result->append(b);
1048 b = back->fHead;
1049 }
1050 }
1051 result->append(*front);
1052 result->append(*back);
1053}
1054
Chris Dalton47114db2021-01-06 00:35:20 -07001055void GrTriangulator::SortedMerge(VertexList* front, VertexList* back, VertexList* result,
1056 const Comparator& c) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001057 if (c.fDirection == Comparator::Direction::kHorizontal) {
1058 sorted_merge<sweep_lt_horiz>(front, back, result);
1059 } else {
1060 sorted_merge<sweep_lt_vert>(front, back, result);
1061 }
Chris Dalton5045de32021-01-07 19:09:01 -07001062#if TRIANGULATOR_LOGGING
Stephen White3b5a3fa2017-06-06 14:51:19 -04001063 float id = 0.0f;
1064 for (Vertex* v = result->fHead; v; v = v->fNext) {
1065 v->fID = id++;
1066 }
1067#endif
Stephen Whitebda29c02017-03-13 15:10:13 -04001068}
1069
ethannicholase9709e82016-01-07 13:34:16 -08001070// Stage 3: sort the vertices by increasing sweep direction.
1071
Stephen White16a40cb2017-02-23 11:10:01 -05001072template <CompareFunc sweep_lt>
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001073static void merge_sort(VertexList* vertices) {
Stephen White16a40cb2017-02-23 11:10:01 -05001074 Vertex* slow = vertices->fHead;
1075 if (!slow) {
ethannicholase9709e82016-01-07 13:34:16 -08001076 return;
1077 }
Stephen White16a40cb2017-02-23 11:10:01 -05001078 Vertex* fast = slow->fNext;
1079 if (!fast) {
1080 return;
1081 }
1082 do {
1083 fast = fast->fNext;
1084 if (fast) {
1085 fast = fast->fNext;
1086 slow = slow->fNext;
1087 }
1088 } while (fast);
1089 VertexList front(vertices->fHead, slow);
1090 VertexList back(slow->fNext, vertices->fTail);
1091 front.fTail->fNext = back.fHead->fPrev = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001092
Stephen White16a40cb2017-02-23 11:10:01 -05001093 merge_sort<sweep_lt>(&front);
1094 merge_sort<sweep_lt>(&back);
ethannicholase9709e82016-01-07 13:34:16 -08001095
Stephen White16a40cb2017-02-23 11:10:01 -05001096 vertices->fHead = vertices->fTail = nullptr;
Stephen Whitebda29c02017-03-13 15:10:13 -04001097 sorted_merge<sweep_lt>(&front, &back, vertices);
ethannicholase9709e82016-01-07 13:34:16 -08001098}
1099
Chris Dalton5045de32021-01-07 19:09:01 -07001100#if TRIANGULATOR_LOGGING
Chris Dalton24472af2021-01-11 20:05:00 -07001101void VertexList::dump() {
1102 for (Vertex* v = fHead; v; v = v->fNext) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001103 TESS_LOG("vertex %g (%g, %g) alpha %d", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
Stephen White95152e12017-12-18 10:52:44 -05001104 if (Vertex* p = v->fPartner) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001105 TESS_LOG(", partner %g (%g, %g) alpha %d\n",
1106 p->fID, p->fPoint.fX, p->fPoint.fY, p->fAlpha);
Stephen White95152e12017-12-18 10:52:44 -05001107 } else {
Brian Salomon120e7d62019-09-11 10:29:22 -04001108 TESS_LOG(", null partner\n");
Stephen White95152e12017-12-18 10:52:44 -05001109 }
1110 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001111 TESS_LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
Stephen White95152e12017-12-18 10:52:44 -05001112 }
1113 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001114 TESS_LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
Stephen White95152e12017-12-18 10:52:44 -05001115 }
1116 }
Chris Daltond60c9192021-01-07 18:30:08 +00001117}
Chris Dalton7cf3add2021-01-11 18:33:28 -07001118#endif
Stephen White95152e12017-12-18 10:52:44 -05001119
Stephen White89042d52018-06-08 12:18:22 -04001120#ifdef SK_DEBUG
Chris Dalton811dc6a2021-01-07 16:40:32 -07001121static void validate_edge_pair(Edge* left, Edge* right, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -04001122 if (!left || !right) {
1123 return;
1124 }
1125 if (left->fTop == right->fTop) {
1126 SkASSERT(left->isLeftOf(right->fBottom));
1127 SkASSERT(right->isRightOf(left->fBottom));
1128 } else if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
1129 SkASSERT(left->isLeftOf(right->fTop));
1130 } else {
1131 SkASSERT(right->isRightOf(left->fTop));
1132 }
1133 if (left->fBottom == right->fBottom) {
1134 SkASSERT(left->isLeftOf(right->fTop));
1135 SkASSERT(right->isRightOf(left->fTop));
1136 } else if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
1137 SkASSERT(left->isLeftOf(right->fBottom));
1138 } else {
1139 SkASSERT(right->isRightOf(left->fBottom));
1140 }
1141}
1142
Chris Dalton811dc6a2021-01-07 16:40:32 -07001143static void validate_edge_list(EdgeList* edges, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -04001144 Edge* left = edges->fHead;
1145 if (!left) {
1146 return;
1147 }
1148 for (Edge* right = left->fRight; right; right = right->fRight) {
1149 validate_edge_pair(left, right, c);
1150 left = right;
1151 }
1152}
1153#endif
1154
ethannicholase9709e82016-01-07 13:34:16 -08001155// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges.
1156
Chris Dalton811dc6a2021-01-07 16:40:32 -07001157GrTriangulator::SimplifyResult GrTriangulator::simplify(VertexList* mesh, const Comparator& c) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001158 TESS_LOG("simplifying complex polygons\n");
ethannicholase9709e82016-01-07 13:34:16 -08001159 EdgeList activeEdges;
Chris Dalton6ccc0322020-01-29 11:38:16 -07001160 auto result = SimplifyResult::kAlreadySimple;
Stephen White0cb31672017-06-08 14:41:01 -04001161 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
Chris Dalton24472af2021-01-11 20:05:00 -07001162 if (!v->isConnected()) {
ethannicholase9709e82016-01-07 13:34:16 -08001163 continue;
1164 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001165 Edge* leftEnclosingEdge;
1166 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001167 bool restartChecks;
1168 do {
Brian Salomon120e7d62019-09-11 10:29:22 -04001169 TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n",
1170 v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001171 restartChecks = false;
Chris Dalton47114db2021-01-06 00:35:20 -07001172 FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001173 v->fLeftEnclosingEdge = leftEnclosingEdge;
1174 v->fRightEnclosingEdge = rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001175 if (v->fFirstEdgeBelow) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001176 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001177 if (this->checkForIntersection(
1178 leftEnclosingEdge, edge, &activeEdges, &v, mesh, c) ||
1179 this->checkForIntersection(
1180 edge, rightEnclosingEdge, &activeEdges, &v, mesh, c)) {
Chris Dalton57115c02021-01-12 18:12:18 -07001181 if (fDisallowSelfIntersection) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001182 return SimplifyResult::kAbort;
1183 }
1184 result = SimplifyResult::kFoundSelfIntersection;
ethannicholase9709e82016-01-07 13:34:16 -08001185 restartChecks = true;
1186 break;
1187 }
1188 }
1189 } else {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001190 if (this->checkForIntersection(leftEnclosingEdge, rightEnclosingEdge, &activeEdges,
1191 &v, mesh, c)) {
Chris Dalton57115c02021-01-12 18:12:18 -07001192 if (fDisallowSelfIntersection) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001193 return SimplifyResult::kAbort;
1194 }
1195 result = SimplifyResult::kFoundSelfIntersection;
ethannicholase9709e82016-01-07 13:34:16 -08001196 restartChecks = true;
1197 }
1198
1199 }
1200 } while (restartChecks);
Stephen White89042d52018-06-08 12:18:22 -04001201#ifdef SK_DEBUG
1202 validate_edge_list(&activeEdges, c);
1203#endif
ethannicholase9709e82016-01-07 13:34:16 -08001204 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -07001205 activeEdges.remove(e);
ethannicholase9709e82016-01-07 13:34:16 -08001206 }
1207 Edge* leftEdge = leftEnclosingEdge;
1208 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -07001209 activeEdges.insert(e, leftEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001210 leftEdge = e;
1211 }
ethannicholase9709e82016-01-07 13:34:16 -08001212 }
Stephen Whitee260c462017-12-19 18:09:54 -05001213 SkASSERT(!activeEdges.fHead && !activeEdges.fTail);
Chris Dalton6ccc0322020-01-29 11:38:16 -07001214 return result;
ethannicholase9709e82016-01-07 13:34:16 -08001215}
1216
1217// Stage 5: Tessellate the simplified mesh into monotone polygons.
1218
Chris Dalton93c2d812021-01-11 19:51:59 -07001219Poly* GrTriangulator::tessellate(const VertexList& vertices, const Comparator&) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001220 TESS_LOG("\ntessellating simple polygons\n");
Chris Dalton6ccc0322020-01-29 11:38:16 -07001221 int maxWindMagnitude = std::numeric_limits<int>::max();
Chris Dalton57115c02021-01-12 18:12:18 -07001222 if (fDisallowSelfIntersection && !SkPathFillType_IsEvenOdd(fPath.getFillType())) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001223 maxWindMagnitude = 1;
1224 }
ethannicholase9709e82016-01-07 13:34:16 -08001225 EdgeList activeEdges;
1226 Poly* polys = nullptr;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001227 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
Chris Dalton24472af2021-01-11 20:05:00 -07001228 if (!v->isConnected()) {
ethannicholase9709e82016-01-07 13:34:16 -08001229 continue;
1230 }
Chris Dalton5045de32021-01-07 19:09:01 -07001231#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001232 TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001233#endif
Stephen White8a0bfc52017-02-21 15:24:13 -05001234 Edge* leftEnclosingEdge;
1235 Edge* rightEnclosingEdge;
Chris Dalton47114db2021-01-06 00:35:20 -07001236 FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White8a0bfc52017-02-21 15:24:13 -05001237 Poly* leftPoly;
1238 Poly* rightPoly;
ethannicholase9709e82016-01-07 13:34:16 -08001239 if (v->fFirstEdgeAbove) {
1240 leftPoly = v->fFirstEdgeAbove->fLeftPoly;
1241 rightPoly = v->fLastEdgeAbove->fRightPoly;
1242 } else {
1243 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr;
1244 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr;
1245 }
Chris Dalton5045de32021-01-07 19:09:01 -07001246#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001247 TESS_LOG("edges above:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001248 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001249 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1250 e->fTop->fID, e->fBottom->fID,
1251 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1252 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001253 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001254 TESS_LOG("edges below:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001255 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001256 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1257 e->fTop->fID, e->fBottom->fID,
1258 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1259 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001260 }
1261#endif
1262 if (v->fFirstEdgeAbove) {
1263 if (leftPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001264 leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, kRight_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001265 }
1266 if (rightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001267 rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001268 }
1269 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -08001270 Edge* rightEdge = e->fNextEdgeAbove;
Chris Dalton24472af2021-01-11 20:05:00 -07001271 activeEdges.remove(e);
Stephen White8a0bfc52017-02-21 15:24:13 -05001272 if (e->fRightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001273 e->fRightPoly->addEdge(e, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001274 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001275 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001276 rightEdge->fLeftPoly->addEdge(e, kRight_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001277 }
1278 }
Chris Dalton24472af2021-01-11 20:05:00 -07001279 activeEdges.remove(v->fLastEdgeAbove);
ethannicholase9709e82016-01-07 13:34:16 -08001280 if (!v->fFirstEdgeBelow) {
1281 if (leftPoly && rightPoly && leftPoly != rightPoly) {
1282 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr);
1283 rightPoly->fPartner = leftPoly;
1284 leftPoly->fPartner = rightPoly;
1285 }
1286 }
1287 }
1288 if (v->fFirstEdgeBelow) {
1289 if (!v->fFirstEdgeAbove) {
senorblanco93e3fff2016-06-07 12:36:00 -07001290 if (leftPoly && rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001291 if (leftPoly == rightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001292 if (leftPoly->fTail && leftPoly->fTail->fSide == kLeft_Side) {
Chris Dalton7cf3add2021-01-11 18:33:28 -07001293 leftPoly = this->makePoly(&polys, leftPoly->lastVertex(),
1294 leftPoly->fWinding);
senorblanco531237e2016-06-02 11:36:48 -07001295 leftEnclosingEdge->fRightPoly = leftPoly;
1296 } else {
Chris Dalton7cf3add2021-01-11 18:33:28 -07001297 rightPoly = this->makePoly(&polys, rightPoly->lastVertex(),
1298 rightPoly->fWinding);
senorblanco531237e2016-06-02 11:36:48 -07001299 rightEnclosingEdge->fLeftPoly = rightPoly;
1300 }
ethannicholase9709e82016-01-07 13:34:16 -08001301 }
Chris Dalton8a42b092021-01-21 22:09:26 -07001302 Edge* join = fAlloc->make<Edge>(leftPoly->lastVertex(), v, 1,
Chris Dalton17ce8c52021-01-07 18:08:46 -07001303 EdgeType::kInner);
1304 leftPoly = leftPoly->addEdge(join, kRight_Side, fAlloc);
1305 rightPoly = rightPoly->addEdge(join, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001306 }
1307 }
1308 Edge* leftEdge = v->fFirstEdgeBelow;
1309 leftEdge->fLeftPoly = leftPoly;
Chris Dalton24472af2021-01-11 20:05:00 -07001310 activeEdges.insert(leftEdge, leftEnclosingEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001311 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge;
1312 rightEdge = rightEdge->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -07001313 activeEdges.insert(rightEdge, leftEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001314 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0;
1315 winding += leftEdge->fWinding;
1316 if (winding != 0) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001317 if (abs(winding) > maxWindMagnitude) {
1318 return nullptr; // We can't have weighted wind in kSimpleInnerPolygons mode
1319 }
Chris Dalton7cf3add2021-01-11 18:33:28 -07001320 Poly* poly = this->makePoly(&polys, v, winding);
ethannicholase9709e82016-01-07 13:34:16 -08001321 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly;
1322 }
1323 leftEdge = rightEdge;
1324 }
1325 v->fLastEdgeBelow->fRightPoly = rightPoly;
1326 }
Chris Dalton5045de32021-01-07 19:09:01 -07001327#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001328 TESS_LOG("\nactive edges:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001329 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001330 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1331 e->fTop->fID, e->fBottom->fID,
1332 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1333 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001334 }
1335#endif
1336 }
1337 return polys;
1338}
1339
Stephen Whitebda29c02017-03-13 15:10:13 -04001340// This is a driver function that calls stages 2-5 in turn.
ethannicholase9709e82016-01-07 13:34:16 -08001341
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001342void GrTriangulator::contoursToMesh(VertexList* contours, int contourCnt, VertexList* mesh,
Chris Dalton811dc6a2021-01-07 16:40:32 -07001343 const Comparator& c) {
Chris Dalton5045de32021-01-07 19:09:01 -07001344#if TRIANGULATOR_LOGGING
ethannicholase9709e82016-01-07 13:34:16 -08001345 for (int i = 0; i < contourCnt; ++i) {
Stephen White3a9aab92017-03-07 14:07:18 -05001346 Vertex* v = contours[i].fHead;
ethannicholase9709e82016-01-07 13:34:16 -08001347 SkASSERT(v);
Brian Salomon120e7d62019-09-11 10:29:22 -04001348 TESS_LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001349 for (v = v->fNext; v; v = v->fNext) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001350 TESS_LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
ethannicholase9709e82016-01-07 13:34:16 -08001351 }
1352 }
1353#endif
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001354 this->sanitizeContours(contours, contourCnt);
1355 this->buildEdges(contours, contourCnt, mesh, c);
senorblancof57372d2016-08-31 10:36:19 -07001356}
1357
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001358void GrTriangulator::SortMesh(VertexList* vertices, const Comparator& c) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001359 if (!vertices || !vertices->fHead) {
Stephen White2f4686f2017-01-03 16:20:01 -05001360 return;
ethannicholase9709e82016-01-07 13:34:16 -08001361 }
1362
1363 // Sort vertices in Y (secondarily in X).
Stephen White16a40cb2017-02-23 11:10:01 -05001364 if (c.fDirection == Comparator::Direction::kHorizontal) {
1365 merge_sort<sweep_lt_horiz>(vertices);
1366 } else {
1367 merge_sort<sweep_lt_vert>(vertices);
1368 }
Chris Dalton5045de32021-01-07 19:09:01 -07001369#if TRIANGULATOR_LOGGING
Stephen White2e2cb9b2017-01-09 13:11:18 -05001370 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001371 static float gID = 0.0f;
1372 v->fID = gID++;
1373 }
1374#endif
Stephen White2f4686f2017-01-03 16:20:01 -05001375}
1376
Chris Dalton93c2d812021-01-11 19:51:59 -07001377Poly* GrTriangulator::contoursToPolys(VertexList* contours, int contourCnt) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001378 const SkRect& pathBounds = fPath.getBounds();
Stephen White16a40cb2017-02-23 11:10:01 -05001379 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
1380 : Comparator::Direction::kVertical);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001381 VertexList mesh;
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001382 this->contoursToMesh(contours, contourCnt, &mesh, c);
1383 SortMesh(&mesh, c);
1384 this->mergeCoincidentVertices(&mesh, c);
1385 if (SimplifyResult::kAbort == this->simplify(&mesh, c)) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001386 return nullptr;
1387 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001388 TESS_LOG("\nsimplified mesh:\n");
Chris Dalton7cf3add2021-01-11 18:33:28 -07001389 DUMP_MESH(mesh);
Chris Dalton93c2d812021-01-11 19:51:59 -07001390 return this->tessellate(mesh, c);
Chris Dalton7cf3add2021-01-11 18:33:28 -07001391}
1392
senorblancof57372d2016-08-31 10:36:19 -07001393// Stage 6: Triangulate the monotone polygons into a vertex buffer.
Chris Daltond5384792021-01-20 15:43:24 -07001394void* GrTriangulator::polysToTriangles(Poly* polys, void* data, SkPathFillType overrideFillType) {
senorblancof57372d2016-08-31 10:36:19 -07001395 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001396 if (apply_fill_type(overrideFillType, poly)) {
Chris Dalton9a4904f2021-01-07 19:10:14 -07001397 data = this->emitPoly(poly, data);
senorblancof57372d2016-08-31 10:36:19 -07001398 }
1399 }
1400 return data;
ethannicholase9709e82016-01-07 13:34:16 -08001401}
1402
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001403static int get_contour_count(const SkPath& path, SkScalar tolerance) {
Chris Daltonc71b3d42020-01-08 21:29:59 -07001404 // We could theoretically be more aggressive about not counting empty contours, but we need to
1405 // actually match the exact number of contour linked lists the tessellator will create later on.
1406 int contourCnt = 1;
1407 bool hasPoints = false;
1408
Chris Dalton7156db22020-05-07 22:06:28 +00001409 SkPath::Iter iter(path, false);
1410 SkPath::Verb verb;
1411 SkPoint pts[4];
Chris Daltonc71b3d42020-01-08 21:29:59 -07001412 bool first = true;
Chris Dalton7156db22020-05-07 22:06:28 +00001413 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
Chris Daltonc71b3d42020-01-08 21:29:59 -07001414 switch (verb) {
Chris Dalton7156db22020-05-07 22:06:28 +00001415 case SkPath::kMove_Verb:
Chris Daltonc71b3d42020-01-08 21:29:59 -07001416 if (!first) {
1417 ++contourCnt;
1418 }
John Stiles30212b72020-06-11 17:55:07 -04001419 [[fallthrough]];
Chris Dalton7156db22020-05-07 22:06:28 +00001420 case SkPath::kLine_Verb:
1421 case SkPath::kConic_Verb:
1422 case SkPath::kQuad_Verb:
1423 case SkPath::kCubic_Verb:
Chris Daltonc71b3d42020-01-08 21:29:59 -07001424 hasPoints = true;
John Stiles30212b72020-06-11 17:55:07 -04001425 break;
Chris Daltonc71b3d42020-01-08 21:29:59 -07001426 default:
1427 break;
1428 }
1429 first = false;
1430 }
1431 if (!hasPoints) {
Stephen White11f65e02017-02-16 19:00:39 -05001432 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001433 }
Stephen White11f65e02017-02-16 19:00:39 -05001434 return contourCnt;
ethannicholase9709e82016-01-07 13:34:16 -08001435}
1436
Chris Dalton37d16f12021-01-20 18:32:48 -07001437Poly* GrTriangulator::pathToPolys(float tolerance, const SkRect& clipBounds, bool* isLinear) {
Chris Daltond5384792021-01-20 15:43:24 -07001438 int contourCnt = get_contour_count(fPath, tolerance);
1439 if (contourCnt <= 0) {
Chris Dalton37d16f12021-01-20 18:32:48 -07001440 *isLinear = true;
Chris Daltond5384792021-01-20 15:43:24 -07001441 return nullptr;
1442 }
1443
1444 if (SkPathFillType_IsInverse(fPath.getFillType())) {
1445 contourCnt++;
1446 }
1447 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
1448
Chris Dalton37d16f12021-01-20 18:32:48 -07001449 this->pathToContours(tolerance, clipBounds, contours.get(), isLinear);
Chris Daltond5384792021-01-20 15:43:24 -07001450 return this->contoursToPolys(contours.get(), contourCnt);
1451}
1452
1453int64_t GrTriangulator::CountPoints(Poly* polys, SkPathFillType overrideFillType) {
Greg Danield5b45932018-06-07 13:15:10 -04001454 int64_t count = 0;
ethannicholase9709e82016-01-07 13:34:16 -08001455 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton93c2d812021-01-11 19:51:59 -07001456 if (apply_fill_type(overrideFillType, poly) && poly->fCount >= 3) {
Chris Dalton17dc4182020-03-25 16:18:16 -06001457 count += (poly->fCount - 2) * (TRIANGULATOR_WIREFRAME ? 6 : 3);
ethannicholase9709e82016-01-07 13:34:16 -08001458 }
1459 }
1460 return count;
1461}
1462
ethannicholase9709e82016-01-07 13:34:16 -08001463// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1464
Chris Daltond5384792021-01-20 15:43:24 -07001465int GrTriangulator::polysToTriangles(Poly* polys, GrEagerVertexAllocator* vertexAllocator) {
1466 int64_t count64 = CountPoints(polys, fPath.getFillType());
Greg Danield5b45932018-06-07 13:15:10 -04001467 if (0 == count64 || count64 > SK_MaxS32) {
Stephen Whiteff60b172017-05-05 15:54:52 -04001468 return 0;
1469 }
Greg Danield5b45932018-06-07 13:15:10 -04001470 int count = count64;
ethannicholase9709e82016-01-07 13:34:16 -08001471
Chris Dalton854ee852021-01-05 15:12:59 -07001472 size_t vertexStride = sizeof(SkPoint);
1473 if (fEmitCoverage) {
1474 vertexStride += sizeof(float);
1475 }
Chris Daltond081dce2020-01-23 12:09:04 -07001476 void* verts = vertexAllocator->lock(vertexStride, count);
senorblanco6599eff2016-03-10 08:38:45 -08001477 if (!verts) {
ethannicholase9709e82016-01-07 13:34:16 -08001478 SkDebugf("Could not allocate vertices\n");
1479 return 0;
1480 }
senorblancof57372d2016-08-31 10:36:19 -07001481
Brian Salomon120e7d62019-09-11 10:29:22 -04001482 TESS_LOG("emitting %d verts\n", count);
Chris Daltond5384792021-01-20 15:43:24 -07001483 void* end = this->polysToTriangles(polys, verts, fPath.getFillType());
Brian Osman80879d42019-01-07 16:15:27 -05001484
senorblancof57372d2016-08-31 10:36:19 -07001485 int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
Chris Daltond081dce2020-01-23 12:09:04 -07001486 / vertexStride);
ethannicholase9709e82016-01-07 13:34:16 -08001487 SkASSERT(actualCount <= count);
senorblanco6599eff2016-03-10 08:38:45 -08001488 vertexAllocator->unlock(actualCount);
ethannicholase9709e82016-01-07 13:34:16 -08001489 return actualCount;
1490}
1491
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001492int GrTriangulator::PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
1493 WindingVertex** verts) {
Chris Dalton8a42b092021-01-21 22:09:26 -07001494 SkArenaAlloc alloc(kArenaDefaultChunkSize);
1495 GrTriangulator triangulator(path, &alloc);
Chris Dalton37d16f12021-01-20 18:32:48 -07001496 bool isLinear;
1497 Poly* polys = triangulator.pathToPolys(tolerance, clipBounds, &isLinear);
Chris Daltond5384792021-01-20 15:43:24 -07001498 int64_t count64 = CountPoints(polys, path.getFillType());
Greg Danield5b45932018-06-07 13:15:10 -04001499 if (0 == count64 || count64 > SK_MaxS32) {
ethannicholase9709e82016-01-07 13:34:16 -08001500 *verts = nullptr;
1501 return 0;
1502 }
Greg Danield5b45932018-06-07 13:15:10 -04001503 int count = count64;
ethannicholase9709e82016-01-07 13:34:16 -08001504
Chris Dalton17dc4182020-03-25 16:18:16 -06001505 *verts = new WindingVertex[count];
1506 WindingVertex* vertsEnd = *verts;
ethannicholase9709e82016-01-07 13:34:16 -08001507 SkPoint* points = new SkPoint[count];
1508 SkPoint* pointsEnd = points;
1509 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton93c2d812021-01-11 19:51:59 -07001510 if (apply_fill_type(path.getFillType(), poly)) {
ethannicholase9709e82016-01-07 13:34:16 -08001511 SkPoint* start = pointsEnd;
Chris Dalton9a4904f2021-01-07 19:10:14 -07001512 pointsEnd = static_cast<SkPoint*>(triangulator.emitPoly(poly, pointsEnd));
ethannicholase9709e82016-01-07 13:34:16 -08001513 while (start != pointsEnd) {
1514 vertsEnd->fPos = *start;
1515 vertsEnd->fWinding = poly->fWinding;
1516 ++start;
1517 ++vertsEnd;
1518 }
1519 }
1520 }
1521 int actualCount = static_cast<int>(vertsEnd - *verts);
1522 SkASSERT(actualCount <= count);
1523 SkASSERT(pointsEnd - points == actualCount);
1524 delete[] points;
1525 return actualCount;
1526}