blob: 71f2349e9d8f4c2aa1199cfc4d1c3db6b84a2727 [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 Dalton0879da02021-01-29 13:57:25 -0700207void* GrTriangulator::emitMonotonePoly(const MonotonePoly* monotonePoly, void* data) const {
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 Dalton0879da02021-01-29 13:57:25 -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 Dalton0879da02021-01-29 13:57:25 -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,
Chris Dalton0879da02021-01-29 13:57:25 -0700255 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 Dalton0879da02021-01-29 13:57:25 -0700261 if (fCollectBreadcrumbTriangles && abs(winding) > 1 &&
Chris Dalton68b8bd52021-01-14 10:48:02 -0700262 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.
Chris Dalton0879da02021-01-29 13:57:25 -0700265 fBreadcrumbList.append(fAlloc, prev->fPoint, curr->fPoint, next->fPoint, abs(winding) - 1);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700266 }
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 Dalton0879da02021-01-29 13:57:25 -0700311void* GrTriangulator::emitPoly(const Poly* poly, void *data) const {
Chris Dalton9a4904f2021-01-07 19:10:14 -0700312 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) {
Chris Dalton0879da02021-01-29 13:57:25 -0700317 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 Dalton330cfa42021-01-27 18:24:48 -0700326Poly* GrTriangulator::makePoly(Poly** head, Vertex* v, int winding) const {
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 Dalton330cfa42021-01-27 18:24:48 -0700333void GrTriangulator::appendPointToContour(const SkPoint& p, VertexList* contour) const {
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,
Chris Dalton330cfa42021-01-27 18:24:48 -0700354 VertexList* contour) const {
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,
Chris Dalton330cfa42021-01-27 18:24:48 -0700378 int pointsLeft) const {
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 Dalton330cfa42021-01-27 18:24:48 -0700404 VertexList* contours, bool* isLinear) const {
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 Dalton330cfa42021-01-27 18:24:48 -0700489bool GrTriangulator::applyFillType(int winding) const {
Chris Dalton47114db2021-01-06 00:35:20 -0700490 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 Dalton330cfa42021-01-27 18:24:48 -0700497Edge* GrTriangulator::makeEdge(Vertex* prev, Vertex* next, EdgeType type,
498 const Comparator& c) const {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700499 SkASSERT(prev->fPoint != next->fPoint);
Stephen White2f4686f2017-01-03 16:20:01 -0500500 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
ethannicholase9709e82016-01-07 13:34:16 -0800501 Vertex* top = winding < 0 ? next : prev;
502 Vertex* bottom = winding < 0 ? prev : next;
Chris Dalton8a42b092021-01-21 22:09:26 -0700503 return fAlloc->make<Edge>(top, bottom, winding, type);
ethannicholase9709e82016-01-07 13:34:16 -0800504}
505
Chris Dalton24472af2021-01-11 20:05:00 -0700506void EdgeList::insert(Edge* edge, Edge* prev) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400507 TESS_LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
Chris Dalton24472af2021-01-11 20:05:00 -0700508 SkASSERT(!this->contains(edge));
509 Edge* next = prev ? prev->fRight : fHead;
510 this->insert(edge, prev, next);
ethannicholase9709e82016-01-07 13:34:16 -0800511}
512
Chris Dalton47114db2021-01-06 00:35:20 -0700513void GrTriangulator::FindEnclosingEdges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) {
Stephen White90732fd2017-03-02 16:16:33 -0500514 if (v->fFirstEdgeAbove && v->fLastEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -0800515 *left = v->fFirstEdgeAbove->fLeft;
516 *right = v->fLastEdgeAbove->fRight;
517 return;
518 }
519 Edge* next = nullptr;
520 Edge* prev;
521 for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) {
522 if (prev->isLeftOf(v)) {
523 break;
524 }
525 next = prev;
526 }
527 *left = prev;
528 *right = next;
ethannicholase9709e82016-01-07 13:34:16 -0800529}
530
Chris Dalton24472af2021-01-11 20:05:00 -0700531void GrTriangulator::Edge::insertAbove(Vertex* v, const Comparator& c) {
532 if (fTop->fPoint == fBottom->fPoint ||
533 c.sweep_lt(fBottom->fPoint, fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800534 return;
535 }
Chris Dalton24472af2021-01-11 20:05:00 -0700536 TESS_LOG("insert edge (%g -> %g) above vertex %g\n", fTop->fID, fBottom->fID, v->fID);
ethannicholase9709e82016-01-07 13:34:16 -0800537 Edge* prev = nullptr;
538 Edge* next;
Chris Daltond60c9192021-01-07 18:30:08 +0000539 for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -0700540 if (next->isRightOf(fTop)) {
ethannicholase9709e82016-01-07 13:34:16 -0800541 break;
542 }
543 prev = next;
544 }
senorblancoe6eaa322016-03-08 09:06:44 -0800545 list_insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
Chris Dalton24472af2021-01-11 20:05:00 -0700546 this, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove);
ethannicholase9709e82016-01-07 13:34:16 -0800547}
548
Chris Dalton24472af2021-01-11 20:05:00 -0700549void GrTriangulator::Edge::insertBelow(Vertex* v, const Comparator& c) {
550 if (fTop->fPoint == fBottom->fPoint ||
551 c.sweep_lt(fBottom->fPoint, fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800552 return;
553 }
Chris Dalton24472af2021-01-11 20:05:00 -0700554 TESS_LOG("insert edge (%g -> %g) below vertex %g\n", fTop->fID, fBottom->fID, v->fID);
ethannicholase9709e82016-01-07 13:34:16 -0800555 Edge* prev = nullptr;
556 Edge* next;
Chris Daltond60c9192021-01-07 18:30:08 +0000557 for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -0700558 if (next->isRightOf(fBottom)) {
ethannicholase9709e82016-01-07 13:34:16 -0800559 break;
560 }
561 prev = next;
562 }
senorblancoe6eaa322016-03-08 09:06:44 -0800563 list_insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
Chris Dalton24472af2021-01-11 20:05:00 -0700564 this, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow);
ethannicholase9709e82016-01-07 13:34:16 -0800565}
566
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700567static void remove_edge_above(Edge* edge) {
Stephen White7b376942018-05-22 11:51:32 -0400568 SkASSERT(edge->fTop && edge->fBottom);
Brian Salomon120e7d62019-09-11 10:29:22 -0400569 TESS_LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
570 edge->fBottom->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800571 list_remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800572 edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove);
573}
574
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700575static void remove_edge_below(Edge* edge) {
Stephen White7b376942018-05-22 11:51:32 -0400576 SkASSERT(edge->fTop && edge->fBottom);
Brian Salomon120e7d62019-09-11 10:29:22 -0400577 TESS_LOG("removing edge (%g -> %g) below vertex %g\n",
578 edge->fTop->fID, edge->fBottom->fID, edge->fTop->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800579 list_remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800580 edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow);
581}
582
Chris Dalton24472af2021-01-11 20:05:00 -0700583void GrTriangulator::Edge::disconnect() {
584 remove_edge_above(this);
585 remove_edge_below(this);
Stephen Whitee7a364d2017-01-11 16:19:26 -0500586}
587
Chris Dalton811dc6a2021-01-07 16:40:32 -0700588static void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, const Comparator& c) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400589 if (!current || *current == dst || c.sweep_lt((*current)->fPoint, dst->fPoint)) {
590 return;
591 }
592 Vertex* v = *current;
Brian Salomon120e7d62019-09-11 10:29:22 -0400593 TESS_LOG("rewinding active edges from vertex %g to vertex %g\n", v->fID, dst->fID);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400594 while (v != dst) {
595 v = v->fPrev;
596 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -0700597 activeEdges->remove(e);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400598 }
599 Edge* leftEdge = v->fLeftEnclosingEdge;
600 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -0700601 activeEdges->insert(e, leftEdge);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400602 leftEdge = e;
Stephen Whitec03e6982020-02-06 16:32:14 -0500603 Vertex* top = e->fTop;
604 if (c.sweep_lt(top->fPoint, dst->fPoint) &&
605 ((top->fLeftEnclosingEdge && !top->fLeftEnclosingEdge->isLeftOf(e->fTop)) ||
606 (top->fRightEnclosingEdge && !top->fRightEnclosingEdge->isRightOf(e->fTop)))) {
607 dst = top;
608 }
Stephen White3b5a3fa2017-06-06 14:51:19 -0400609 }
610 }
611 *current = v;
612}
613
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700614static void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700615 const Comparator& c) {
Stephen Whitec03e6982020-02-06 16:32:14 -0500616 if (!activeEdges || !current) {
617 return;
618 }
619 Vertex* top = edge->fTop;
620 Vertex* bottom = edge->fBottom;
621 if (edge->fLeft) {
622 Vertex* leftTop = edge->fLeft->fTop;
623 Vertex* leftBottom = edge->fLeft->fBottom;
624 if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
625 rewind(activeEdges, current, leftTop, c);
626 } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
627 rewind(activeEdges, current, top, c);
628 } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
629 !edge->fLeft->isLeftOf(bottom)) {
630 rewind(activeEdges, current, leftTop, c);
631 } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
632 rewind(activeEdges, current, top, c);
633 }
634 }
635 if (edge->fRight) {
636 Vertex* rightTop = edge->fRight->fTop;
637 Vertex* rightBottom = edge->fRight->fBottom;
638 if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
639 rewind(activeEdges, current, rightTop, c);
640 } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
641 rewind(activeEdges, current, top, c);
642 } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
643 !edge->fRight->isRightOf(bottom)) {
644 rewind(activeEdges, current, rightTop, c);
645 } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
646 !edge->isLeftOf(rightBottom)) {
647 rewind(activeEdges, current, top, c);
648 }
649 }
650}
651
Chris Dalton68b8bd52021-01-14 10:48:02 -0700652void GrTriangulator::setTop(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
Chris Dalton0879da02021-01-29 13:57:25 -0700653 const Comparator& c) const {
ethannicholase9709e82016-01-07 13:34:16 -0800654 remove_edge_below(edge);
Chris Dalton0879da02021-01-29 13:57:25 -0700655 if (fCollectBreadcrumbTriangles) {
656 fBreadcrumbList.append(fAlloc, edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
657 edge->fWinding);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700658 }
ethannicholase9709e82016-01-07 13:34:16 -0800659 edge->fTop = v;
660 edge->recompute();
Chris Dalton24472af2021-01-11 20:05:00 -0700661 edge->insertBelow(v, c);
Stephen Whitec03e6982020-02-06 16:32:14 -0500662 rewind_if_necessary(edge, activeEdges, current, c);
Chris Dalton0879da02021-01-29 13:57:25 -0700663 this->mergeCollinearEdges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800664}
665
Chris Dalton68b8bd52021-01-14 10:48:02 -0700666void GrTriangulator::setBottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
Chris Dalton0879da02021-01-29 13:57:25 -0700667 const Comparator& c) const {
ethannicholase9709e82016-01-07 13:34:16 -0800668 remove_edge_above(edge);
Chris Dalton0879da02021-01-29 13:57:25 -0700669 if (fCollectBreadcrumbTriangles) {
670 fBreadcrumbList.append(fAlloc, edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
671 edge->fWinding);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700672 }
ethannicholase9709e82016-01-07 13:34:16 -0800673 edge->fBottom = v;
674 edge->recompute();
Chris Dalton24472af2021-01-11 20:05:00 -0700675 edge->insertAbove(v, c);
Stephen Whitec03e6982020-02-06 16:32:14 -0500676 rewind_if_necessary(edge, activeEdges, current, c);
Chris Dalton0879da02021-01-29 13:57:25 -0700677 this->mergeCollinearEdges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800678}
679
Chris Dalton68b8bd52021-01-14 10:48:02 -0700680void GrTriangulator::mergeEdgesAbove(Edge* edge, Edge* other, EdgeList* activeEdges,
Chris Dalton0879da02021-01-29 13:57:25 -0700681 Vertex** current, const Comparator& c) const {
ethannicholase9709e82016-01-07 13:34:16 -0800682 if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400683 TESS_LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
684 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
685 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400686 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800687 other->fWinding += edge->fWinding;
Chris Dalton24472af2021-01-11 20:05:00 -0700688 edge->disconnect();
Stephen Whiteec79c392018-05-18 11:49:21 -0400689 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -0800690 } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400691 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800692 other->fWinding += edge->fWinding;
Chris Dalton0879da02021-01-29 13:57:25 -0700693 this->setBottom(edge, other->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800694 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400695 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800696 edge->fWinding += other->fWinding;
Chris Dalton0879da02021-01-29 13:57:25 -0700697 this->setBottom(other, edge->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800698 }
699}
700
Chris Dalton68b8bd52021-01-14 10:48:02 -0700701void GrTriangulator::mergeEdgesBelow(Edge* edge, Edge* other, EdgeList* activeEdges,
Chris Dalton0879da02021-01-29 13:57:25 -0700702 Vertex** current, const Comparator& c) const {
ethannicholase9709e82016-01-07 13:34:16 -0800703 if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400704 TESS_LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
705 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
706 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400707 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800708 other->fWinding += edge->fWinding;
Chris Dalton24472af2021-01-11 20:05:00 -0700709 edge->disconnect();
Stephen Whiteec79c392018-05-18 11:49:21 -0400710 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -0800711 } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400712 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800713 edge->fWinding += other->fWinding;
Chris Dalton0879da02021-01-29 13:57:25 -0700714 this->setTop(other, edge->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800715 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400716 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800717 other->fWinding += edge->fWinding;
Chris Dalton0879da02021-01-29 13:57:25 -0700718 this->setTop(edge, other->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800719 }
720}
721
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700722static bool top_collinear(Edge* left, Edge* right) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400723 if (!left || !right) {
724 return false;
725 }
726 return left->fTop->fPoint == right->fTop->fPoint ||
727 !left->isLeftOf(right->fTop) || !right->isRightOf(left->fTop);
728}
729
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700730static bool bottom_collinear(Edge* left, Edge* right) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400731 if (!left || !right) {
732 return false;
733 }
734 return left->fBottom->fPoint == right->fBottom->fPoint ||
735 !left->isLeftOf(right->fBottom) || !right->isRightOf(left->fBottom);
736}
737
Chris Dalton68b8bd52021-01-14 10:48:02 -0700738void GrTriangulator::mergeCollinearEdges(Edge* edge, EdgeList* activeEdges, Vertex** current,
Chris Dalton0879da02021-01-29 13:57:25 -0700739 const Comparator& c) const {
Stephen White6eca90f2017-05-25 14:47:11 -0400740 for (;;) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400741 if (top_collinear(edge->fPrevEdgeAbove, edge)) {
Chris Dalton0879da02021-01-29 13:57:25 -0700742 this->mergeEdgesAbove(edge->fPrevEdgeAbove, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400743 } else if (top_collinear(edge, edge->fNextEdgeAbove)) {
Chris Dalton0879da02021-01-29 13:57:25 -0700744 this->mergeEdgesAbove(edge->fNextEdgeAbove, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400745 } else if (bottom_collinear(edge->fPrevEdgeBelow, edge)) {
Chris Dalton0879da02021-01-29 13:57:25 -0700746 this->mergeEdgesBelow(edge->fPrevEdgeBelow, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400747 } else if (bottom_collinear(edge, edge->fNextEdgeBelow)) {
Chris Dalton0879da02021-01-29 13:57:25 -0700748 this->mergeEdgesBelow(edge->fNextEdgeBelow, edge, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -0400749 } else {
750 break;
751 }
ethannicholase9709e82016-01-07 13:34:16 -0800752 }
Stephen Whited26b4d82018-07-26 10:02:27 -0400753 SkASSERT(!top_collinear(edge->fPrevEdgeAbove, edge));
754 SkASSERT(!top_collinear(edge, edge->fNextEdgeAbove));
755 SkASSERT(!bottom_collinear(edge->fPrevEdgeBelow, edge));
756 SkASSERT(!bottom_collinear(edge, edge->fNextEdgeBelow));
ethannicholase9709e82016-01-07 13:34:16 -0800757}
758
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700759bool GrTriangulator::splitEdge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
Chris Dalton0879da02021-01-29 13:57:25 -0700760 const Comparator& c) const {
Stephen Whiteec79c392018-05-18 11:49:21 -0400761 if (!edge->fTop || !edge->fBottom || v == edge->fTop || v == edge->fBottom) {
Stephen White89042d52018-06-08 12:18:22 -0400762 return false;
Stephen White0cb31672017-06-08 14:41:01 -0400763 }
Brian Salomon120e7d62019-09-11 10:29:22 -0400764 TESS_LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
765 edge->fTop->fID, edge->fBottom->fID, v->fID, v->fPoint.fX, v->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400766 Vertex* top;
767 Vertex* bottom;
Stephen White531a48e2018-06-01 09:49:39 -0400768 int winding = edge->fWinding;
ethannicholase9709e82016-01-07 13:34:16 -0800769 if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400770 top = v;
771 bottom = edge->fTop;
Chris Dalton0879da02021-01-29 13:57:25 -0700772 this->setTop(edge, v, activeEdges, current, c);
Stephen Whitee30cf802017-02-27 11:37:55 -0500773 } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400774 top = edge->fBottom;
775 bottom = v;
Chris Dalton0879da02021-01-29 13:57:25 -0700776 this->setBottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800777 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400778 top = v;
779 bottom = edge->fBottom;
Chris Dalton0879da02021-01-29 13:57:25 -0700780 this->setBottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800781 }
Chris Dalton8a42b092021-01-21 22:09:26 -0700782 Edge* newEdge = fAlloc->make<Edge>(top, bottom, winding, edge->fType);
Chris Dalton24472af2021-01-11 20:05:00 -0700783 newEdge->insertBelow(top, c);
784 newEdge->insertAbove(bottom, c);
Chris Dalton0879da02021-01-29 13:57:25 -0700785 this->mergeCollinearEdges(newEdge, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400786 return true;
787}
788
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700789bool GrTriangulator::intersectEdgePair(Edge* left, Edge* right, EdgeList* activeEdges,
Chris Dalton0879da02021-01-29 13:57:25 -0700790 Vertex** current, const Comparator& c) const {
Stephen White89042d52018-06-08 12:18:22 -0400791 if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) {
792 return false;
793 }
Stephen White1c5fd182018-07-12 15:54:05 -0400794 if (left->fTop == right->fTop || left->fBottom == right->fBottom) {
795 return false;
796 }
Stephen White89042d52018-06-08 12:18:22 -0400797 if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
798 if (!left->isLeftOf(right->fTop)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400799 rewind(activeEdges, current, right->fTop, c);
Chris Dalton0879da02021-01-29 13:57:25 -0700800 return this->splitEdge(left, right->fTop, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400801 }
802 } else {
803 if (!right->isRightOf(left->fTop)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400804 rewind(activeEdges, current, left->fTop, c);
Chris Dalton0879da02021-01-29 13:57:25 -0700805 return this->splitEdge(right, left->fTop, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400806 }
807 }
808 if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
809 if (!left->isLeftOf(right->fBottom)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400810 rewind(activeEdges, current, right->fBottom, c);
Chris Dalton0879da02021-01-29 13:57:25 -0700811 return this->splitEdge(left, right->fBottom, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400812 }
813 } else {
814 if (!right->isRightOf(left->fBottom)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400815 rewind(activeEdges, current, left->fBottom, c);
Chris Dalton0879da02021-01-29 13:57:25 -0700816 return this->splitEdge(right, left->fBottom, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400817 }
818 }
819 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800820}
821
Chris Dalton7cf3add2021-01-11 18:33:28 -0700822Edge* GrTriangulator::makeConnectingEdge(Vertex* prev, Vertex* next, EdgeType type,
Chris Dalton0879da02021-01-29 13:57:25 -0700823 const Comparator& c, int windingScale) const {
Stephen Whitee260c462017-12-19 18:09:54 -0500824 if (!prev || !next || prev->fPoint == next->fPoint) {
825 return nullptr;
826 }
Chris Dalton7cf3add2021-01-11 18:33:28 -0700827 Edge* edge = this->makeEdge(prev, next, type, c);
Chris Dalton24472af2021-01-11 20:05:00 -0700828 edge->insertBelow(edge->fTop, c);
829 edge->insertAbove(edge->fBottom, c);
Chris Dalton7cf3add2021-01-11 18:33:28 -0700830 edge->fWinding *= windingScale;
Chris Dalton0879da02021-01-29 13:57:25 -0700831 this->mergeCollinearEdges(edge, nullptr, nullptr, c);
senorblancof57372d2016-08-31 10:36:19 -0700832 return edge;
833}
834
Chris Dalton68b8bd52021-01-14 10:48:02 -0700835void GrTriangulator::mergeVertices(Vertex* src, Vertex* dst, VertexList* mesh,
Chris Dalton0879da02021-01-29 13:57:25 -0700836 const Comparator& c) const {
Brian Salomon120e7d62019-09-11 10:29:22 -0400837 TESS_LOG("found coincident verts at %g, %g; merging %g into %g\n",
838 src->fPoint.fX, src->fPoint.fY, src->fID, dst->fID);
Brian Osman788b9162020-02-07 10:36:46 -0500839 dst->fAlpha = std::max(src->fAlpha, dst->fAlpha);
Stephen Whitebda29c02017-03-13 15:10:13 -0400840 if (src->fPartner) {
841 src->fPartner->fPartner = dst;
842 }
Stephen White7b376942018-05-22 11:51:32 -0400843 while (Edge* edge = src->fFirstEdgeAbove) {
Chris Dalton0879da02021-01-29 13:57:25 -0700844 this->setBottom(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -0800845 }
Stephen White7b376942018-05-22 11:51:32 -0400846 while (Edge* edge = src->fFirstEdgeBelow) {
Chris Dalton0879da02021-01-29 13:57:25 -0700847 this->setTop(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -0800848 }
Stephen Whitebf6137e2017-01-04 15:43:26 -0500849 mesh->remove(src);
Stephen Whitec4dbc372019-05-22 10:50:14 -0400850 dst->fSynthetic = true;
ethannicholase9709e82016-01-07 13:34:16 -0800851}
852
Chris Dalton7cf3add2021-01-11 18:33:28 -0700853Vertex* GrTriangulator::makeSortedVertex(const SkPoint& p, uint8_t alpha, VertexList* mesh,
Chris Dalton330cfa42021-01-27 18:24:48 -0700854 Vertex* reference, const Comparator& c) const {
Stephen White95152e12017-12-18 10:52:44 -0500855 Vertex* prevV = reference;
856 while (prevV && c.sweep_lt(p, prevV->fPoint)) {
857 prevV = prevV->fPrev;
858 }
859 Vertex* nextV = prevV ? prevV->fNext : mesh->fHead;
860 while (nextV && c.sweep_lt(nextV->fPoint, p)) {
861 prevV = nextV;
862 nextV = nextV->fNext;
863 }
864 Vertex* v;
865 if (prevV && coincident(prevV->fPoint, p)) {
866 v = prevV;
867 } else if (nextV && coincident(nextV->fPoint, p)) {
868 v = nextV;
869 } else {
Chris Dalton8a42b092021-01-21 22:09:26 -0700870 v = fAlloc->make<Vertex>(p, alpha);
Chris Dalton5045de32021-01-07 19:09:01 -0700871#if TRIANGULATOR_LOGGING
Stephen White95152e12017-12-18 10:52:44 -0500872 if (!prevV) {
873 v->fID = mesh->fHead->fID - 1.0f;
874 } else if (!nextV) {
875 v->fID = mesh->fTail->fID + 1.0f;
876 } else {
877 v->fID = (prevV->fID + nextV->fID) * 0.5f;
878 }
879#endif
880 mesh->insert(v, prevV, nextV);
881 }
882 return v;
883}
884
Stephen White53a02982018-05-30 22:47:46 -0400885// If an edge's top and bottom points differ only by 1/2 machine epsilon in the primary
886// sort criterion, it may not be possible to split correctly, since there is no point which is
887// below the top and above the bottom. This function detects that case.
Chris Dalton811dc6a2021-01-07 16:40:32 -0700888static bool nearly_flat(const Comparator& c, Edge* edge) {
Stephen White53a02982018-05-30 22:47:46 -0400889 SkPoint diff = edge->fBottom->fPoint - edge->fTop->fPoint;
890 float primaryDiff = c.fDirection == Comparator::Direction::kHorizontal ? diff.fX : diff.fY;
Stephen White13f3d8d2018-06-22 10:19:20 -0400891 return fabs(primaryDiff) < std::numeric_limits<float>::epsilon() && primaryDiff != 0.0f;
Stephen White53a02982018-05-30 22:47:46 -0400892}
893
Chris Dalton811dc6a2021-01-07 16:40:32 -0700894static SkPoint clamp(SkPoint p, SkPoint min, SkPoint max, const Comparator& c) {
Stephen Whitee62999f2018-06-05 18:45:07 -0400895 if (c.sweep_lt(p, min)) {
896 return min;
897 } else if (c.sweep_lt(max, p)) {
898 return max;
899 } else {
900 return p;
901 }
902}
903
Chris Dalton330cfa42021-01-27 18:24:48 -0700904void GrTriangulator::computeBisector(Edge* edge1, Edge* edge2, Vertex* v) const {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700905 SkASSERT(fEmitCoverage); // Edge-AA only!
Stephen Whitec4dbc372019-05-22 10:50:14 -0400906 Line line1 = edge1->fLine;
907 Line line2 = edge2->fLine;
908 line1.normalize();
909 line2.normalize();
910 double cosAngle = line1.fA * line2.fA + line1.fB * line2.fB;
911 if (cosAngle > 0.999) {
912 return;
913 }
914 line1.fC += edge1->fWinding > 0 ? -1 : 1;
915 line2.fC += edge2->fWinding > 0 ? -1 : 1;
916 SkPoint p;
917 if (line1.intersect(line2, &p)) {
Chris Dalton17ce8c52021-01-07 18:08:46 -0700918 uint8_t alpha = edge1->fType == EdgeType::kOuter ? 255 : 0;
Chris Dalton8a42b092021-01-21 22:09:26 -0700919 v->fPartner = fAlloc->make<Vertex>(p, alpha);
Brian Salomon120e7d62019-09-11 10:29:22 -0400920 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 -0400921 }
922}
923
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700924bool GrTriangulator::checkForIntersection(Edge* left, Edge* right, EdgeList* activeEdges,
Chris Dalton0879da02021-01-29 13:57:25 -0700925 Vertex** current, VertexList* mesh,
926 const Comparator& c) const {
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400927 if (!left || !right) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400928 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800929 }
Stephen White56158ae2017-01-30 14:31:31 -0500930 SkPoint p;
931 uint8_t alpha;
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400932 if (left->intersect(*right, &p, &alpha) && p.isFinite()) {
Ravi Mistrybfe95982018-05-29 18:19:07 +0000933 Vertex* v;
Brian Salomon120e7d62019-09-11 10:29:22 -0400934 TESS_LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400935 Vertex* top = *current;
936 // If the intersection point is above the current vertex, rewind to the vertex above the
937 // intersection.
Stephen White0cb31672017-06-08 14:41:01 -0400938 while (top && c.sweep_lt(p, top->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400939 top = top->fPrev;
940 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400941 if (!nearly_flat(c, left)) {
942 p = clamp(p, left->fTop->fPoint, left->fBottom->fPoint, c);
Stephen Whitee62999f2018-06-05 18:45:07 -0400943 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400944 if (!nearly_flat(c, right)) {
945 p = clamp(p, right->fTop->fPoint, right->fBottom->fPoint, c);
Stephen Whitee62999f2018-06-05 18:45:07 -0400946 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400947 if (p == left->fTop->fPoint) {
948 v = left->fTop;
949 } else if (p == left->fBottom->fPoint) {
950 v = left->fBottom;
951 } else if (p == right->fTop->fPoint) {
952 v = right->fTop;
953 } else if (p == right->fBottom->fPoint) {
954 v = right->fBottom;
Ravi Mistrybfe95982018-05-29 18:19:07 +0000955 } else {
Chris Dalton7cf3add2021-01-11 18:33:28 -0700956 v = this->makeSortedVertex(p, alpha, mesh, top, c);
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400957 if (left->fTop->fPartner) {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700958 SkASSERT(fEmitCoverage); // Edge-AA only!
Stephen Whitec4dbc372019-05-22 10:50:14 -0400959 v->fSynthetic = true;
Chris Dalton7cf3add2021-01-11 18:33:28 -0700960 this->computeBisector(left, right, v);
Stephen Whitee260c462017-12-19 18:09:54 -0500961 }
ethannicholase9709e82016-01-07 13:34:16 -0800962 }
Stephen White0cb31672017-06-08 14:41:01 -0400963 rewind(activeEdges, current, top ? top : v, c);
Chris Dalton0879da02021-01-29 13:57:25 -0700964 this->splitEdge(left, v, activeEdges, current, c);
965 this->splitEdge(right, v, activeEdges, current, c);
Brian Osman788b9162020-02-07 10:36:46 -0500966 v->fAlpha = std::max(v->fAlpha, alpha);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400967 return true;
ethannicholase9709e82016-01-07 13:34:16 -0800968 }
Chris Dalton0879da02021-01-29 13:57:25 -0700969 return this->intersectEdgePair(left, right, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800970}
971
Chris Dalton330cfa42021-01-27 18:24:48 -0700972void GrTriangulator::sanitizeContours(VertexList* contours, int contourCnt) const {
Stephen White3a9aab92017-03-07 14:07:18 -0500973 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
974 SkASSERT(contour->fHead);
975 Vertex* prev = contour->fTail;
Chris Dalton854ee852021-01-05 15:12:59 -0700976 if (fRoundVerticesToQuarterPixel) {
Stephen White3a9aab92017-03-07 14:07:18 -0500977 round(&prev->fPoint);
Stephen White5926f2d2017-02-13 13:55:42 -0500978 }
Stephen White3a9aab92017-03-07 14:07:18 -0500979 for (Vertex* v = contour->fHead; v;) {
Chris Dalton854ee852021-01-05 15:12:59 -0700980 if (fRoundVerticesToQuarterPixel) {
senorblancof57372d2016-08-31 10:36:19 -0700981 round(&v->fPoint);
982 }
Stephen White3a9aab92017-03-07 14:07:18 -0500983 Vertex* next = v->fNext;
Stephen White3de40f82018-06-28 09:36:49 -0400984 Vertex* nextWrap = next ? next : contour->fHead;
Stephen White3a9aab92017-03-07 14:07:18 -0500985 if (coincident(prev->fPoint, v->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400986 TESS_LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -0500987 contour->remove(v);
Stephen White73e7f802017-08-23 13:56:07 -0400988 } else if (!v->fPoint.isFinite()) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400989 TESS_LOG("vertex %g,%g non-finite; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White73e7f802017-08-23 13:56:07 -0400990 contour->remove(v);
Chris Dalton0879da02021-01-29 13:57:25 -0700991 } else if (!fPreserveCollinearVertices &&
Chris Dalton6ccc0322020-01-29 11:38:16 -0700992 Line(prev->fPoint, nextWrap->fPoint).dist(v->fPoint) == 0.0) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400993 TESS_LOG("vertex %g,%g collinear; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White06768ca2018-05-25 14:50:56 -0400994 contour->remove(v);
995 } else {
996 prev = v;
ethannicholase9709e82016-01-07 13:34:16 -0800997 }
Stephen White3a9aab92017-03-07 14:07:18 -0500998 v = next;
ethannicholase9709e82016-01-07 13:34:16 -0800999 }
1000 }
1001}
1002
Chris Dalton0879da02021-01-29 13:57:25 -07001003bool GrTriangulator::mergeCoincidentVertices(VertexList* mesh, const Comparator& c) const {
Stephen Whitebda29c02017-03-13 15:10:13 -04001004 if (!mesh->fHead) {
Stephen Whitee260c462017-12-19 18:09:54 -05001005 return false;
Stephen Whitebda29c02017-03-13 15:10:13 -04001006 }
Stephen Whitee260c462017-12-19 18:09:54 -05001007 bool merged = false;
1008 for (Vertex* v = mesh->fHead->fNext; v;) {
1009 Vertex* next = v->fNext;
ethannicholase9709e82016-01-07 13:34:16 -08001010 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) {
1011 v->fPoint = v->fPrev->fPoint;
1012 }
1013 if (coincident(v->fPrev->fPoint, v->fPoint)) {
Chris Dalton0879da02021-01-29 13:57:25 -07001014 this->mergeVertices(v, v->fPrev, mesh, c);
Stephen Whitee260c462017-12-19 18:09:54 -05001015 merged = true;
ethannicholase9709e82016-01-07 13:34:16 -08001016 }
Stephen Whitee260c462017-12-19 18:09:54 -05001017 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001018 }
Stephen Whitee260c462017-12-19 18:09:54 -05001019 return merged;
ethannicholase9709e82016-01-07 13:34:16 -08001020}
1021
1022// Stage 2: convert the contours to a mesh of edges connecting the vertices.
1023
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001024void GrTriangulator::buildEdges(VertexList* contours, int contourCnt, VertexList* mesh,
Chris Dalton0879da02021-01-29 13:57:25 -07001025 const Comparator& c) const {
Stephen White3a9aab92017-03-07 14:07:18 -05001026 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1027 Vertex* prev = contour->fTail;
1028 for (Vertex* v = contour->fHead; v;) {
1029 Vertex* next = v->fNext;
Chris Dalton0879da02021-01-29 13:57:25 -07001030 this->makeConnectingEdge(prev, v, EdgeType::kInner, c);
Stephen White3a9aab92017-03-07 14:07:18 -05001031 mesh->append(v);
ethannicholase9709e82016-01-07 13:34:16 -08001032 prev = v;
Stephen White3a9aab92017-03-07 14:07:18 -05001033 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001034 }
1035 }
ethannicholase9709e82016-01-07 13:34:16 -08001036}
1037
Stephen Whitebda29c02017-03-13 15:10:13 -04001038template <CompareFunc sweep_lt>
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001039static void sorted_merge(VertexList* front, VertexList* back, VertexList* result) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001040 Vertex* a = front->fHead;
1041 Vertex* b = back->fHead;
1042 while (a && b) {
1043 if (sweep_lt(a->fPoint, b->fPoint)) {
1044 front->remove(a);
1045 result->append(a);
1046 a = front->fHead;
1047 } else {
1048 back->remove(b);
1049 result->append(b);
1050 b = back->fHead;
1051 }
1052 }
1053 result->append(*front);
1054 result->append(*back);
1055}
1056
Chris Dalton47114db2021-01-06 00:35:20 -07001057void GrTriangulator::SortedMerge(VertexList* front, VertexList* back, VertexList* result,
1058 const Comparator& c) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001059 if (c.fDirection == Comparator::Direction::kHorizontal) {
1060 sorted_merge<sweep_lt_horiz>(front, back, result);
1061 } else {
1062 sorted_merge<sweep_lt_vert>(front, back, result);
1063 }
Chris Dalton5045de32021-01-07 19:09:01 -07001064#if TRIANGULATOR_LOGGING
Stephen White3b5a3fa2017-06-06 14:51:19 -04001065 float id = 0.0f;
1066 for (Vertex* v = result->fHead; v; v = v->fNext) {
1067 v->fID = id++;
1068 }
1069#endif
Stephen Whitebda29c02017-03-13 15:10:13 -04001070}
1071
ethannicholase9709e82016-01-07 13:34:16 -08001072// Stage 3: sort the vertices by increasing sweep direction.
1073
Stephen White16a40cb2017-02-23 11:10:01 -05001074template <CompareFunc sweep_lt>
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001075static void merge_sort(VertexList* vertices) {
Stephen White16a40cb2017-02-23 11:10:01 -05001076 Vertex* slow = vertices->fHead;
1077 if (!slow) {
ethannicholase9709e82016-01-07 13:34:16 -08001078 return;
1079 }
Stephen White16a40cb2017-02-23 11:10:01 -05001080 Vertex* fast = slow->fNext;
1081 if (!fast) {
1082 return;
1083 }
1084 do {
1085 fast = fast->fNext;
1086 if (fast) {
1087 fast = fast->fNext;
1088 slow = slow->fNext;
1089 }
1090 } while (fast);
1091 VertexList front(vertices->fHead, slow);
1092 VertexList back(slow->fNext, vertices->fTail);
1093 front.fTail->fNext = back.fHead->fPrev = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001094
Stephen White16a40cb2017-02-23 11:10:01 -05001095 merge_sort<sweep_lt>(&front);
1096 merge_sort<sweep_lt>(&back);
ethannicholase9709e82016-01-07 13:34:16 -08001097
Stephen White16a40cb2017-02-23 11:10:01 -05001098 vertices->fHead = vertices->fTail = nullptr;
Stephen Whitebda29c02017-03-13 15:10:13 -04001099 sorted_merge<sweep_lt>(&front, &back, vertices);
ethannicholase9709e82016-01-07 13:34:16 -08001100}
1101
Chris Dalton5045de32021-01-07 19:09:01 -07001102#if TRIANGULATOR_LOGGING
Chris Dalton330cfa42021-01-27 18:24:48 -07001103void VertexList::dump() const {
Chris Dalton24472af2021-01-11 20:05:00 -07001104 for (Vertex* v = fHead; v; v = v->fNext) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001105 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 -05001106 if (Vertex* p = v->fPartner) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001107 TESS_LOG(", partner %g (%g, %g) alpha %d\n",
1108 p->fID, p->fPoint.fX, p->fPoint.fY, p->fAlpha);
Stephen White95152e12017-12-18 10:52:44 -05001109 } else {
Brian Salomon120e7d62019-09-11 10:29:22 -04001110 TESS_LOG(", null partner\n");
Stephen White95152e12017-12-18 10:52:44 -05001111 }
1112 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001113 TESS_LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
Stephen White95152e12017-12-18 10:52:44 -05001114 }
1115 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001116 TESS_LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
Stephen White95152e12017-12-18 10:52:44 -05001117 }
1118 }
Chris Daltond60c9192021-01-07 18:30:08 +00001119}
Chris Dalton7cf3add2021-01-11 18:33:28 -07001120#endif
Stephen White95152e12017-12-18 10:52:44 -05001121
Stephen White89042d52018-06-08 12:18:22 -04001122#ifdef SK_DEBUG
Chris Dalton811dc6a2021-01-07 16:40:32 -07001123static void validate_edge_pair(Edge* left, Edge* right, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -04001124 if (!left || !right) {
1125 return;
1126 }
1127 if (left->fTop == right->fTop) {
1128 SkASSERT(left->isLeftOf(right->fBottom));
1129 SkASSERT(right->isRightOf(left->fBottom));
1130 } else if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
1131 SkASSERT(left->isLeftOf(right->fTop));
1132 } else {
1133 SkASSERT(right->isRightOf(left->fTop));
1134 }
1135 if (left->fBottom == right->fBottom) {
1136 SkASSERT(left->isLeftOf(right->fTop));
1137 SkASSERT(right->isRightOf(left->fTop));
1138 } else if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
1139 SkASSERT(left->isLeftOf(right->fBottom));
1140 } else {
1141 SkASSERT(right->isRightOf(left->fBottom));
1142 }
1143}
1144
Chris Dalton811dc6a2021-01-07 16:40:32 -07001145static void validate_edge_list(EdgeList* edges, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -04001146 Edge* left = edges->fHead;
1147 if (!left) {
1148 return;
1149 }
1150 for (Edge* right = left->fRight; right; right = right->fRight) {
1151 validate_edge_pair(left, right, c);
1152 left = right;
1153 }
1154}
1155#endif
1156
ethannicholase9709e82016-01-07 13:34:16 -08001157// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges.
1158
Chris Dalton0879da02021-01-29 13:57:25 -07001159GrTriangulator::SimplifyResult GrTriangulator::simplify(VertexList* mesh,
1160 const Comparator& c) const {
Brian Salomon120e7d62019-09-11 10:29:22 -04001161 TESS_LOG("simplifying complex polygons\n");
ethannicholase9709e82016-01-07 13:34:16 -08001162 EdgeList activeEdges;
Chris Dalton6ccc0322020-01-29 11:38:16 -07001163 auto result = SimplifyResult::kAlreadySimple;
Stephen White0cb31672017-06-08 14:41:01 -04001164 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
Chris Dalton24472af2021-01-11 20:05:00 -07001165 if (!v->isConnected()) {
ethannicholase9709e82016-01-07 13:34:16 -08001166 continue;
1167 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001168 Edge* leftEnclosingEdge;
1169 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001170 bool restartChecks;
1171 do {
Brian Salomon120e7d62019-09-11 10:29:22 -04001172 TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n",
1173 v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001174 restartChecks = false;
Chris Dalton47114db2021-01-06 00:35:20 -07001175 FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001176 v->fLeftEnclosingEdge = leftEnclosingEdge;
1177 v->fRightEnclosingEdge = rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001178 if (v->fFirstEdgeBelow) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001179 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001180 if (this->checkForIntersection(
Chris Dalton0879da02021-01-29 13:57:25 -07001181 leftEnclosingEdge, edge, &activeEdges, &v, mesh, c) ||
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001182 this->checkForIntersection(
Chris Dalton0879da02021-01-29 13:57:25 -07001183 edge, rightEnclosingEdge, &activeEdges, &v, mesh, c)) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001184 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,
Chris Dalton0879da02021-01-29 13:57:25 -07001191 &v, mesh, c)) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001192 result = SimplifyResult::kFoundSelfIntersection;
ethannicholase9709e82016-01-07 13:34:16 -08001193 restartChecks = true;
1194 }
1195
1196 }
1197 } while (restartChecks);
Stephen White89042d52018-06-08 12:18:22 -04001198#ifdef SK_DEBUG
1199 validate_edge_list(&activeEdges, c);
1200#endif
ethannicholase9709e82016-01-07 13:34:16 -08001201 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -07001202 activeEdges.remove(e);
ethannicholase9709e82016-01-07 13:34:16 -08001203 }
1204 Edge* leftEdge = leftEnclosingEdge;
1205 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -07001206 activeEdges.insert(e, leftEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001207 leftEdge = e;
1208 }
ethannicholase9709e82016-01-07 13:34:16 -08001209 }
Stephen Whitee260c462017-12-19 18:09:54 -05001210 SkASSERT(!activeEdges.fHead && !activeEdges.fTail);
Chris Dalton6ccc0322020-01-29 11:38:16 -07001211 return result;
ethannicholase9709e82016-01-07 13:34:16 -08001212}
1213
1214// Stage 5: Tessellate the simplified mesh into monotone polygons.
1215
Chris Dalton330cfa42021-01-27 18:24:48 -07001216Poly* GrTriangulator::tessellate(const VertexList& vertices, const Comparator&) const {
Brian Salomon120e7d62019-09-11 10:29:22 -04001217 TESS_LOG("\ntessellating simple polygons\n");
ethannicholase9709e82016-01-07 13:34:16 -08001218 EdgeList activeEdges;
1219 Poly* polys = nullptr;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001220 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
Chris Dalton24472af2021-01-11 20:05:00 -07001221 if (!v->isConnected()) {
ethannicholase9709e82016-01-07 13:34:16 -08001222 continue;
1223 }
Chris Dalton5045de32021-01-07 19:09:01 -07001224#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001225 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 -08001226#endif
Stephen White8a0bfc52017-02-21 15:24:13 -05001227 Edge* leftEnclosingEdge;
1228 Edge* rightEnclosingEdge;
Chris Dalton47114db2021-01-06 00:35:20 -07001229 FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White8a0bfc52017-02-21 15:24:13 -05001230 Poly* leftPoly;
1231 Poly* rightPoly;
ethannicholase9709e82016-01-07 13:34:16 -08001232 if (v->fFirstEdgeAbove) {
1233 leftPoly = v->fFirstEdgeAbove->fLeftPoly;
1234 rightPoly = v->fLastEdgeAbove->fRightPoly;
1235 } else {
1236 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr;
1237 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr;
1238 }
Chris Dalton5045de32021-01-07 19:09:01 -07001239#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001240 TESS_LOG("edges above:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001241 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001242 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1243 e->fTop->fID, e->fBottom->fID,
1244 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1245 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001246 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001247 TESS_LOG("edges below:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001248 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
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 }
1254#endif
1255 if (v->fFirstEdgeAbove) {
1256 if (leftPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001257 leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, kRight_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001258 }
1259 if (rightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001260 rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001261 }
1262 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -08001263 Edge* rightEdge = e->fNextEdgeAbove;
Chris Dalton24472af2021-01-11 20:05:00 -07001264 activeEdges.remove(e);
Stephen White8a0bfc52017-02-21 15:24:13 -05001265 if (e->fRightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001266 e->fRightPoly->addEdge(e, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001267 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001268 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001269 rightEdge->fLeftPoly->addEdge(e, kRight_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001270 }
1271 }
Chris Dalton24472af2021-01-11 20:05:00 -07001272 activeEdges.remove(v->fLastEdgeAbove);
ethannicholase9709e82016-01-07 13:34:16 -08001273 if (!v->fFirstEdgeBelow) {
1274 if (leftPoly && rightPoly && leftPoly != rightPoly) {
1275 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr);
1276 rightPoly->fPartner = leftPoly;
1277 leftPoly->fPartner = rightPoly;
1278 }
1279 }
1280 }
1281 if (v->fFirstEdgeBelow) {
1282 if (!v->fFirstEdgeAbove) {
senorblanco93e3fff2016-06-07 12:36:00 -07001283 if (leftPoly && rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001284 if (leftPoly == rightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001285 if (leftPoly->fTail && leftPoly->fTail->fSide == kLeft_Side) {
Chris Dalton7cf3add2021-01-11 18:33:28 -07001286 leftPoly = this->makePoly(&polys, leftPoly->lastVertex(),
1287 leftPoly->fWinding);
senorblanco531237e2016-06-02 11:36:48 -07001288 leftEnclosingEdge->fRightPoly = leftPoly;
1289 } else {
Chris Dalton7cf3add2021-01-11 18:33:28 -07001290 rightPoly = this->makePoly(&polys, rightPoly->lastVertex(),
1291 rightPoly->fWinding);
senorblanco531237e2016-06-02 11:36:48 -07001292 rightEnclosingEdge->fLeftPoly = rightPoly;
1293 }
ethannicholase9709e82016-01-07 13:34:16 -08001294 }
Chris Dalton8a42b092021-01-21 22:09:26 -07001295 Edge* join = fAlloc->make<Edge>(leftPoly->lastVertex(), v, 1,
Chris Dalton17ce8c52021-01-07 18:08:46 -07001296 EdgeType::kInner);
1297 leftPoly = leftPoly->addEdge(join, kRight_Side, fAlloc);
1298 rightPoly = rightPoly->addEdge(join, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001299 }
1300 }
1301 Edge* leftEdge = v->fFirstEdgeBelow;
1302 leftEdge->fLeftPoly = leftPoly;
Chris Dalton24472af2021-01-11 20:05:00 -07001303 activeEdges.insert(leftEdge, leftEnclosingEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001304 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge;
1305 rightEdge = rightEdge->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -07001306 activeEdges.insert(rightEdge, leftEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001307 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0;
1308 winding += leftEdge->fWinding;
1309 if (winding != 0) {
Chris Dalton7cf3add2021-01-11 18:33:28 -07001310 Poly* poly = this->makePoly(&polys, v, winding);
ethannicholase9709e82016-01-07 13:34:16 -08001311 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly;
1312 }
1313 leftEdge = rightEdge;
1314 }
1315 v->fLastEdgeBelow->fRightPoly = rightPoly;
1316 }
Chris Dalton5045de32021-01-07 19:09:01 -07001317#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001318 TESS_LOG("\nactive edges:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001319 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001320 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1321 e->fTop->fID, e->fBottom->fID,
1322 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1323 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001324 }
1325#endif
1326 }
1327 return polys;
1328}
1329
Stephen Whitebda29c02017-03-13 15:10:13 -04001330// This is a driver function that calls stages 2-5 in turn.
ethannicholase9709e82016-01-07 13:34:16 -08001331
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001332void GrTriangulator::contoursToMesh(VertexList* contours, int contourCnt, VertexList* mesh,
Chris Dalton0879da02021-01-29 13:57:25 -07001333 const Comparator& c) const {
Chris Dalton5045de32021-01-07 19:09:01 -07001334#if TRIANGULATOR_LOGGING
ethannicholase9709e82016-01-07 13:34:16 -08001335 for (int i = 0; i < contourCnt; ++i) {
Stephen White3a9aab92017-03-07 14:07:18 -05001336 Vertex* v = contours[i].fHead;
ethannicholase9709e82016-01-07 13:34:16 -08001337 SkASSERT(v);
Brian Salomon120e7d62019-09-11 10:29:22 -04001338 TESS_LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001339 for (v = v->fNext; v; v = v->fNext) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001340 TESS_LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
ethannicholase9709e82016-01-07 13:34:16 -08001341 }
1342 }
1343#endif
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001344 this->sanitizeContours(contours, contourCnt);
Chris Dalton0879da02021-01-29 13:57:25 -07001345 this->buildEdges(contours, contourCnt, mesh, c);
senorblancof57372d2016-08-31 10:36:19 -07001346}
1347
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001348void GrTriangulator::SortMesh(VertexList* vertices, const Comparator& c) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001349 if (!vertices || !vertices->fHead) {
Stephen White2f4686f2017-01-03 16:20:01 -05001350 return;
ethannicholase9709e82016-01-07 13:34:16 -08001351 }
1352
1353 // Sort vertices in Y (secondarily in X).
Stephen White16a40cb2017-02-23 11:10:01 -05001354 if (c.fDirection == Comparator::Direction::kHorizontal) {
1355 merge_sort<sweep_lt_horiz>(vertices);
1356 } else {
1357 merge_sort<sweep_lt_vert>(vertices);
1358 }
Chris Dalton5045de32021-01-07 19:09:01 -07001359#if TRIANGULATOR_LOGGING
Stephen White2e2cb9b2017-01-09 13:11:18 -05001360 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001361 static float gID = 0.0f;
1362 v->fID = gID++;
1363 }
1364#endif
Stephen White2f4686f2017-01-03 16:20:01 -05001365}
1366
Chris Dalton0879da02021-01-29 13:57:25 -07001367Poly* GrTriangulator::contoursToPolys(VertexList* contours, int contourCnt) const {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001368 const SkRect& pathBounds = fPath.getBounds();
Stephen White16a40cb2017-02-23 11:10:01 -05001369 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
1370 : Comparator::Direction::kVertical);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001371 VertexList mesh;
Chris Dalton0879da02021-01-29 13:57:25 -07001372 this->contoursToMesh(contours, contourCnt, &mesh, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001373 SortMesh(&mesh, c);
Chris Dalton0879da02021-01-29 13:57:25 -07001374 this->mergeCoincidentVertices(&mesh, c);
1375 this->simplify(&mesh, c);
Brian Salomon120e7d62019-09-11 10:29:22 -04001376 TESS_LOG("\nsimplified mesh:\n");
Chris Dalton7cf3add2021-01-11 18:33:28 -07001377 DUMP_MESH(mesh);
Chris Dalton93c2d812021-01-11 19:51:59 -07001378 return this->tessellate(mesh, c);
Chris Dalton7cf3add2021-01-11 18:33:28 -07001379}
1380
senorblancof57372d2016-08-31 10:36:19 -07001381// Stage 6: Triangulate the monotone polygons into a vertex buffer.
Chris Dalton330cfa42021-01-27 18:24:48 -07001382void* GrTriangulator::polysToTriangles(Poly* polys, void* data,
Chris Dalton330cfa42021-01-27 18:24:48 -07001383 SkPathFillType overrideFillType) const {
senorblancof57372d2016-08-31 10:36:19 -07001384 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001385 if (apply_fill_type(overrideFillType, poly)) {
Chris Dalton0879da02021-01-29 13:57:25 -07001386 data = this->emitPoly(poly, data);
senorblancof57372d2016-08-31 10:36:19 -07001387 }
1388 }
1389 return data;
ethannicholase9709e82016-01-07 13:34:16 -08001390}
1391
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001392static int get_contour_count(const SkPath& path, SkScalar tolerance) {
Chris Daltonc71b3d42020-01-08 21:29:59 -07001393 // We could theoretically be more aggressive about not counting empty contours, but we need to
1394 // actually match the exact number of contour linked lists the tessellator will create later on.
1395 int contourCnt = 1;
1396 bool hasPoints = false;
1397
Chris Dalton7156db22020-05-07 22:06:28 +00001398 SkPath::Iter iter(path, false);
1399 SkPath::Verb verb;
1400 SkPoint pts[4];
Chris Daltonc71b3d42020-01-08 21:29:59 -07001401 bool first = true;
Chris Dalton7156db22020-05-07 22:06:28 +00001402 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
Chris Daltonc71b3d42020-01-08 21:29:59 -07001403 switch (verb) {
Chris Dalton7156db22020-05-07 22:06:28 +00001404 case SkPath::kMove_Verb:
Chris Daltonc71b3d42020-01-08 21:29:59 -07001405 if (!first) {
1406 ++contourCnt;
1407 }
John Stiles30212b72020-06-11 17:55:07 -04001408 [[fallthrough]];
Chris Dalton7156db22020-05-07 22:06:28 +00001409 case SkPath::kLine_Verb:
1410 case SkPath::kConic_Verb:
1411 case SkPath::kQuad_Verb:
1412 case SkPath::kCubic_Verb:
Chris Daltonc71b3d42020-01-08 21:29:59 -07001413 hasPoints = true;
John Stiles30212b72020-06-11 17:55:07 -04001414 break;
Chris Daltonc71b3d42020-01-08 21:29:59 -07001415 default:
1416 break;
1417 }
1418 first = false;
1419 }
1420 if (!hasPoints) {
Stephen White11f65e02017-02-16 19:00:39 -05001421 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001422 }
Stephen White11f65e02017-02-16 19:00:39 -05001423 return contourCnt;
ethannicholase9709e82016-01-07 13:34:16 -08001424}
1425
Chris Dalton0879da02021-01-29 13:57:25 -07001426Poly* GrTriangulator::pathToPolys(float tolerance, const SkRect& clipBounds, bool* isLinear) const {
Chris Daltond5384792021-01-20 15:43:24 -07001427 int contourCnt = get_contour_count(fPath, tolerance);
1428 if (contourCnt <= 0) {
Chris Dalton37d16f12021-01-20 18:32:48 -07001429 *isLinear = true;
Chris Daltond5384792021-01-20 15:43:24 -07001430 return nullptr;
1431 }
1432
1433 if (SkPathFillType_IsInverse(fPath.getFillType())) {
1434 contourCnt++;
1435 }
1436 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
1437
Chris Dalton37d16f12021-01-20 18:32:48 -07001438 this->pathToContours(tolerance, clipBounds, contours.get(), isLinear);
Chris Dalton0879da02021-01-29 13:57:25 -07001439 return this->contoursToPolys(contours.get(), contourCnt);
Chris Daltond5384792021-01-20 15:43:24 -07001440}
1441
1442int64_t GrTriangulator::CountPoints(Poly* polys, SkPathFillType overrideFillType) {
Greg Danield5b45932018-06-07 13:15:10 -04001443 int64_t count = 0;
ethannicholase9709e82016-01-07 13:34:16 -08001444 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton93c2d812021-01-11 19:51:59 -07001445 if (apply_fill_type(overrideFillType, poly) && poly->fCount >= 3) {
Chris Dalton17dc4182020-03-25 16:18:16 -06001446 count += (poly->fCount - 2) * (TRIANGULATOR_WIREFRAME ? 6 : 3);
ethannicholase9709e82016-01-07 13:34:16 -08001447 }
1448 }
1449 return count;
1450}
1451
ethannicholase9709e82016-01-07 13:34:16 -08001452// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1453
Chris Dalton0879da02021-01-29 13:57:25 -07001454int GrTriangulator::polysToTriangles(Poly* polys, GrEagerVertexAllocator* vertexAllocator) const {
Chris Daltond5384792021-01-20 15:43:24 -07001455 int64_t count64 = CountPoints(polys, fPath.getFillType());
Greg Danield5b45932018-06-07 13:15:10 -04001456 if (0 == count64 || count64 > SK_MaxS32) {
Stephen Whiteff60b172017-05-05 15:54:52 -04001457 return 0;
1458 }
Greg Danield5b45932018-06-07 13:15:10 -04001459 int count = count64;
ethannicholase9709e82016-01-07 13:34:16 -08001460
Chris Dalton854ee852021-01-05 15:12:59 -07001461 size_t vertexStride = sizeof(SkPoint);
1462 if (fEmitCoverage) {
1463 vertexStride += sizeof(float);
1464 }
Chris Daltond081dce2020-01-23 12:09:04 -07001465 void* verts = vertexAllocator->lock(vertexStride, count);
senorblanco6599eff2016-03-10 08:38:45 -08001466 if (!verts) {
ethannicholase9709e82016-01-07 13:34:16 -08001467 SkDebugf("Could not allocate vertices\n");
1468 return 0;
1469 }
senorblancof57372d2016-08-31 10:36:19 -07001470
Brian Salomon120e7d62019-09-11 10:29:22 -04001471 TESS_LOG("emitting %d verts\n", count);
Chris Dalton0879da02021-01-29 13:57:25 -07001472 void* end = this->polysToTriangles(polys, verts, fPath.getFillType());
Brian Osman80879d42019-01-07 16:15:27 -05001473
senorblancof57372d2016-08-31 10:36:19 -07001474 int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
Chris Daltond081dce2020-01-23 12:09:04 -07001475 / vertexStride);
ethannicholase9709e82016-01-07 13:34:16 -08001476 SkASSERT(actualCount <= count);
senorblanco6599eff2016-03-10 08:38:45 -08001477 vertexAllocator->unlock(actualCount);
ethannicholase9709e82016-01-07 13:34:16 -08001478 return actualCount;
1479}
1480
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001481int GrTriangulator::PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
1482 WindingVertex** verts) {
Chris Dalton8a42b092021-01-21 22:09:26 -07001483 SkArenaAlloc alloc(kArenaDefaultChunkSize);
1484 GrTriangulator triangulator(path, &alloc);
Chris Dalton37d16f12021-01-20 18:32:48 -07001485 bool isLinear;
Chris Dalton0879da02021-01-29 13:57:25 -07001486 Poly* polys = triangulator.pathToPolys(tolerance, clipBounds, &isLinear);
Chris Daltond5384792021-01-20 15:43:24 -07001487 int64_t count64 = CountPoints(polys, path.getFillType());
Greg Danield5b45932018-06-07 13:15:10 -04001488 if (0 == count64 || count64 > SK_MaxS32) {
ethannicholase9709e82016-01-07 13:34:16 -08001489 *verts = nullptr;
1490 return 0;
1491 }
Greg Danield5b45932018-06-07 13:15:10 -04001492 int count = count64;
ethannicholase9709e82016-01-07 13:34:16 -08001493
Chris Dalton17dc4182020-03-25 16:18:16 -06001494 *verts = new WindingVertex[count];
1495 WindingVertex* vertsEnd = *verts;
ethannicholase9709e82016-01-07 13:34:16 -08001496 SkPoint* points = new SkPoint[count];
1497 SkPoint* pointsEnd = points;
1498 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton93c2d812021-01-11 19:51:59 -07001499 if (apply_fill_type(path.getFillType(), poly)) {
ethannicholase9709e82016-01-07 13:34:16 -08001500 SkPoint* start = pointsEnd;
Chris Dalton0879da02021-01-29 13:57:25 -07001501 pointsEnd = static_cast<SkPoint*>(triangulator.emitPoly(poly, pointsEnd));
ethannicholase9709e82016-01-07 13:34:16 -08001502 while (start != pointsEnd) {
1503 vertsEnd->fPos = *start;
1504 vertsEnd->fWinding = poly->fWinding;
1505 ++start;
1506 ++vertsEnd;
1507 }
1508 }
1509 }
1510 int actualCount = static_cast<int>(vertsEnd - *verts);
1511 SkASSERT(actualCount <= count);
1512 SkASSERT(pointsEnd - points == actualCount);
1513 delete[] points;
1514 return actualCount;
1515}