blob: 00f275dd3be29d278f9326511dfe9ee6622bce23 [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 Dalton330cfa42021-01-27 18:24:48 -0700207void* GrTriangulator::emitMonotonePoly(const MonotonePoly* monotonePoly, void* data,
208 BreadcrumbTriangleList* breadcrumbList) const {
Chris Dalton93c2d812021-01-11 19:51:59 -0700209 SkASSERT(monotonePoly->fWinding != 0);
Chris Dalton9a4904f2021-01-07 19:10:14 -0700210 Edge* e = monotonePoly->fFirstEdge;
Chris Dalton5045de32021-01-07 19:09:01 -0700211 VertexList vertices;
212 vertices.append(e->fTop);
213 int count = 1;
214 while (e != nullptr) {
Chris Dalton9a4904f2021-01-07 19:10:14 -0700215 if (kRight_Side == monotonePoly->fSide) {
Chris Dalton5045de32021-01-07 19:09:01 -0700216 vertices.append(e->fBottom);
217 e = e->fRightPolyNext;
218 } else {
219 vertices.prepend(e->fBottom);
220 e = e->fLeftPolyNext;
Chris Dalton17ce8c52021-01-07 18:08:46 -0700221 }
Chris Dalton5045de32021-01-07 19:09:01 -0700222 count++;
223 }
224 Vertex* first = vertices.fHead;
225 Vertex* v = first->fNext;
226 while (v != vertices.fTail) {
227 SkASSERT(v && v->fPrev && v->fNext);
228 Vertex* prev = v->fPrev;
229 Vertex* curr = v;
230 Vertex* next = v->fNext;
231 if (count == 3) {
Chris Dalton330cfa42021-01-27 18:24:48 -0700232 return this->emitTriangle(prev, curr, next, monotonePoly->fWinding, data,
233 breadcrumbList);
Chris Dalton5045de32021-01-07 19:09:01 -0700234 }
235 double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX;
236 double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY;
237 double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX;
238 double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY;
239 if (ax * by - ay * bx >= 0.0) {
Chris Dalton330cfa42021-01-27 18:24:48 -0700240 data = this->emitTriangle(prev, curr, next, monotonePoly->fWinding, data,
241 breadcrumbList);
Chris Dalton5045de32021-01-07 19:09:01 -0700242 v->fPrev->fNext = v->fNext;
243 v->fNext->fPrev = v->fPrev;
244 count--;
245 if (v->fPrev == first) {
Chris Dalton17ce8c52021-01-07 18:08:46 -0700246 v = v->fNext;
Chris Daltond60c9192021-01-07 18:30:08 +0000247 } else {
Chris Dalton5045de32021-01-07 19:09:01 -0700248 v = v->fPrev;
Chris Daltond60c9192021-01-07 18:30:08 +0000249 }
Chris Dalton5045de32021-01-07 19:09:01 -0700250 } else {
251 v = v->fNext;
Chris Daltond60c9192021-01-07 18:30:08 +0000252 }
Chris Dalton75887a22021-01-06 00:23:13 -0700253 }
Chris Dalton5045de32021-01-07 19:09:01 -0700254 return data;
255}
256
Chris Dalton9a4904f2021-01-07 19:10:14 -0700257void* GrTriangulator::emitTriangle(Vertex* prev, Vertex* curr, Vertex* next, int winding,
Chris Dalton330cfa42021-01-27 18:24:48 -0700258 void* data, BreadcrumbTriangleList* breadcrumbList) const {
Chris Dalton93c2d812021-01-11 19:51:59 -0700259 if (winding > 0) {
Chris Dalton5045de32021-01-07 19:09:01 -0700260 // Ensure our triangles always wind in the same direction as if the path had been
261 // triangulated as a simple fan (a la red book).
262 std::swap(prev, next);
263 }
Chris Dalton330cfa42021-01-27 18:24:48 -0700264 if (breadcrumbList && abs(winding) > 1 &&
Chris Dalton68b8bd52021-01-14 10:48:02 -0700265 fPath.getFillType() == SkPathFillType::kWinding) {
266 // The first winding count will come from the actual triangle we emit. The remaining counts
267 // come from the breadcrumb triangle.
Chris Dalton330cfa42021-01-27 18:24:48 -0700268 breadcrumbList->prepend(fAlloc, prev->fPoint, curr->fPoint, next->fPoint, abs(winding) - 1);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700269 }
Chris Dalton93c2d812021-01-11 19:51:59 -0700270 return emit_triangle(prev, curr, next, fEmitCoverage, data);
Chris Dalton5045de32021-01-07 19:09:01 -0700271}
272
Chris Dalton8a42b092021-01-21 22:09:26 -0700273Poly* GrTriangulator::Poly::addEdge(Edge* e, Side side, SkArenaAlloc* alloc) {
Chris Dalton5045de32021-01-07 19:09:01 -0700274 TESS_LOG("addEdge (%g -> %g) to poly %d, %s side\n",
275 e->fTop->fID, e->fBottom->fID, fID, side == kLeft_Side ? "left" : "right");
276 Poly* partner = fPartner;
277 Poly* poly = this;
278 if (side == kRight_Side) {
279 if (e->fUsedInRightPoly) {
280 return this;
Chris Daltond60c9192021-01-07 18:30:08 +0000281 }
Chris Dalton5045de32021-01-07 19:09:01 -0700282 } else {
283 if (e->fUsedInLeftPoly) {
284 return this;
Chris Daltond60c9192021-01-07 18:30:08 +0000285 }
Chris Dalton5045de32021-01-07 19:09:01 -0700286 }
287 if (partner) {
288 fPartner = partner->fPartner = nullptr;
289 }
290 if (!fTail) {
Chris Dalton8a42b092021-01-21 22:09:26 -0700291 fHead = fTail = alloc->make<MonotonePoly>(e, side, fWinding);
Chris Dalton5045de32021-01-07 19:09:01 -0700292 fCount += 2;
293 } else if (e->fBottom == fTail->fLastEdge->fBottom) {
294 return poly;
295 } else if (side == fTail->fSide) {
296 fTail->addEdge(e);
297 fCount++;
298 } else {
Chris Dalton8a42b092021-01-21 22:09:26 -0700299 e = alloc->make<Edge>(fTail->fLastEdge->fBottom, e->fBottom, 1, EdgeType::kInner);
Chris Dalton5045de32021-01-07 19:09:01 -0700300 fTail->addEdge(e);
301 fCount++;
302 if (partner) {
303 partner->addEdge(e, side, alloc);
304 poly = partner;
305 } else {
Chris Dalton8a42b092021-01-21 22:09:26 -0700306 MonotonePoly* m = alloc->make<MonotonePoly>(e, side, fWinding);
Chris Dalton5045de32021-01-07 19:09:01 -0700307 m->fPrev = fTail;
308 fTail->fNext = m;
309 fTail = m;
310 }
311 }
312 return poly;
313}
Chris Dalton330cfa42021-01-27 18:24:48 -0700314void* GrTriangulator::emitPoly(const Poly* poly, void *data,
315 BreadcrumbTriangleList* breadcrumbList) const {
Chris Dalton9a4904f2021-01-07 19:10:14 -0700316 if (poly->fCount < 3) {
ethannicholase9709e82016-01-07 13:34:16 -0800317 return data;
318 }
Chris Dalton5045de32021-01-07 19:09:01 -0700319 TESS_LOG("emit() %d, size %d\n", fID, fCount);
Chris Dalton9a4904f2021-01-07 19:10:14 -0700320 for (MonotonePoly* m = poly->fHead; m != nullptr; m = m->fNext) {
Chris Dalton330cfa42021-01-27 18:24:48 -0700321 data = this->emitMonotonePoly(m, data, breadcrumbList);
Chris Dalton5045de32021-01-07 19:09:01 -0700322 }
323 return data;
324}
ethannicholase9709e82016-01-07 13:34:16 -0800325
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700326static bool coincident(const SkPoint& a, const SkPoint& b) {
ethannicholase9709e82016-01-07 13:34:16 -0800327 return a == b;
328}
329
Chris Dalton330cfa42021-01-27 18:24:48 -0700330Poly* GrTriangulator::makePoly(Poly** head, Vertex* v, int winding) const {
Chris Dalton8a42b092021-01-21 22:09:26 -0700331 Poly* poly = fAlloc->make<Poly>(v, winding);
ethannicholase9709e82016-01-07 13:34:16 -0800332 poly->fNext = *head;
333 *head = poly;
334 return poly;
335}
336
Chris Dalton330cfa42021-01-27 18:24:48 -0700337void GrTriangulator::appendPointToContour(const SkPoint& p, VertexList* contour) const {
Chris Dalton8a42b092021-01-21 22:09:26 -0700338 Vertex* v = fAlloc->make<Vertex>(p, 255);
Chris Dalton5045de32021-01-07 19:09:01 -0700339#if TRIANGULATOR_LOGGING
ethannicholase9709e82016-01-07 13:34:16 -0800340 static float gID = 0.0f;
341 v->fID = gID++;
342#endif
Stephen White3a9aab92017-03-07 14:07:18 -0500343 contour->append(v);
ethannicholase9709e82016-01-07 13:34:16 -0800344}
345
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700346static SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u) {
Stephen White36e4f062017-03-27 16:11:31 -0400347 SkQuadCoeff quad(pts);
348 SkPoint p0 = to_point(quad.eval(t - 0.5f * u));
349 SkPoint mid = to_point(quad.eval(t));
350 SkPoint p1 = to_point(quad.eval(t + 0.5f * u));
Stephen Whitee3a0be72017-06-12 11:43:18 -0400351 if (!p0.isFinite() || !mid.isFinite() || !p1.isFinite()) {
352 return 0;
353 }
Cary Clarkdf429f32017-11-08 11:44:31 -0500354 return SkPointPriv::DistanceToLineSegmentBetweenSqd(mid, p0, p1);
Stephen White36e4f062017-03-27 16:11:31 -0400355}
356
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700357void GrTriangulator::appendQuadraticToContour(const SkPoint pts[3], SkScalar toleranceSqd,
Chris Dalton330cfa42021-01-27 18:24:48 -0700358 VertexList* contour) const {
Stephen White36e4f062017-03-27 16:11:31 -0400359 SkQuadCoeff quad(pts);
360 Sk2s aa = quad.fA * quad.fA;
361 SkScalar denom = 2.0f * (aa[0] + aa[1]);
362 Sk2s ab = quad.fA * quad.fB;
363 SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f;
364 int nPoints = 1;
Stephen Whitee40c3612018-01-09 11:49:08 -0500365 SkScalar u = 1.0f;
Stephen White36e4f062017-03-27 16:11:31 -0400366 // Test possible subdivision values only at the point of maximum curvature.
367 // If it passes the flatness metric there, it'll pass everywhere.
Stephen Whitee40c3612018-01-09 11:49:08 -0500368 while (nPoints < GrPathUtils::kMaxPointsPerCurve) {
Stephen White36e4f062017-03-27 16:11:31 -0400369 u = 1.0f / nPoints;
370 if (quad_error_at(pts, t, u) < toleranceSqd) {
371 break;
372 }
373 nPoints++;
ethannicholase9709e82016-01-07 13:34:16 -0800374 }
Stephen White36e4f062017-03-27 16:11:31 -0400375 for (int j = 1; j <= nPoints; j++) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700376 this->appendPointToContour(to_point(quad.eval(j * u)), contour);
Stephen White36e4f062017-03-27 16:11:31 -0400377 }
ethannicholase9709e82016-01-07 13:34:16 -0800378}
379
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700380void GrTriangulator::generateCubicPoints(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
381 const SkPoint& p3, SkScalar tolSqd, VertexList* contour,
Chris Dalton330cfa42021-01-27 18:24:48 -0700382 int pointsLeft) const {
Cary Clarkdf429f32017-11-08 11:44:31 -0500383 SkScalar d1 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p1, p0, p3);
384 SkScalar d2 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p2, p0, p3);
ethannicholase9709e82016-01-07 13:34:16 -0800385 if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) ||
386 !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700387 this->appendPointToContour(p3, contour);
Stephen White3a9aab92017-03-07 14:07:18 -0500388 return;
ethannicholase9709e82016-01-07 13:34:16 -0800389 }
390 const SkPoint q[] = {
391 { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
392 { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
393 { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
394 };
395 const SkPoint r[] = {
396 { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
397 { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
398 };
399 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
400 pointsLeft >>= 1;
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700401 this->generateCubicPoints(p0, q[0], r[0], s, tolSqd, contour, pointsLeft);
402 this->generateCubicPoints(s, r[1], q[2], p3, tolSqd, contour, pointsLeft);
ethannicholase9709e82016-01-07 13:34:16 -0800403}
404
405// Stage 1: convert the input path to a set of linear contours (linked list of Vertices).
406
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700407void GrTriangulator::pathToContours(float tolerance, const SkRect& clipBounds,
Chris Dalton330cfa42021-01-27 18:24:48 -0700408 VertexList* contours, bool* isLinear) const {
ethannicholase9709e82016-01-07 13:34:16 -0800409 SkScalar toleranceSqd = tolerance * tolerance;
Chris Dalton7156db22020-05-07 22:06:28 +0000410 SkPoint pts[4];
Chris Dalton37d16f12021-01-20 18:32:48 -0700411 *isLinear = true;
Stephen White3a9aab92017-03-07 14:07:18 -0500412 VertexList* contour = contours;
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700413 SkPath::Iter iter(fPath, false);
414 if (fPath.isInverseFillType()) {
ethannicholase9709e82016-01-07 13:34:16 -0800415 SkPoint quad[4];
416 clipBounds.toQuad(quad);
senorblanco7ab96e92016-10-12 06:47:44 -0700417 for (int i = 3; i >= 0; i--) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700418 this->appendPointToContour(quad[i], contours);
ethannicholase9709e82016-01-07 13:34:16 -0800419 }
Stephen White3a9aab92017-03-07 14:07:18 -0500420 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800421 }
422 SkAutoConicToQuads converter;
Chris Dalton7156db22020-05-07 22:06:28 +0000423 SkPath::Verb verb;
424 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
ethannicholase9709e82016-01-07 13:34:16 -0800425 switch (verb) {
Chris Dalton7156db22020-05-07 22:06:28 +0000426 case SkPath::kConic_Verb: {
Chris Dalton37d16f12021-01-20 18:32:48 -0700427 *isLinear = false;
Chris Dalton57115c02021-01-12 18:12:18 -0700428 if (toleranceSqd == 0) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700429 this->appendPointToContour(pts[2], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700430 break;
431 }
Chris Dalton7156db22020-05-07 22:06:28 +0000432 SkScalar weight = iter.conicWeight();
433 const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd);
ethannicholase9709e82016-01-07 13:34:16 -0800434 for (int i = 0; i < converter.countQuads(); ++i) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700435 this->appendQuadraticToContour(quadPts, toleranceSqd, contour);
ethannicholase9709e82016-01-07 13:34:16 -0800436 quadPts += 2;
437 }
ethannicholase9709e82016-01-07 13:34:16 -0800438 break;
439 }
Chris Dalton7156db22020-05-07 22:06:28 +0000440 case SkPath::kMove_Verb:
Stephen White3a9aab92017-03-07 14:07:18 -0500441 if (contour->fHead) {
442 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800443 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700444 this->appendPointToContour(pts[0], contour);
ethannicholase9709e82016-01-07 13:34:16 -0800445 break;
Chris Dalton7156db22020-05-07 22:06:28 +0000446 case SkPath::kLine_Verb: {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700447 this->appendPointToContour(pts[1], contour);
ethannicholase9709e82016-01-07 13:34:16 -0800448 break;
449 }
Chris Dalton7156db22020-05-07 22:06:28 +0000450 case SkPath::kQuad_Verb: {
Chris Dalton37d16f12021-01-20 18:32:48 -0700451 *isLinear = false;
Chris Dalton57115c02021-01-12 18:12:18 -0700452 if (toleranceSqd == 0) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700453 this->appendPointToContour(pts[2], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700454 break;
455 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700456 this->appendQuadraticToContour(pts, toleranceSqd, contour);
ethannicholase9709e82016-01-07 13:34:16 -0800457 break;
458 }
Chris Dalton7156db22020-05-07 22:06:28 +0000459 case SkPath::kCubic_Verb: {
Chris Dalton37d16f12021-01-20 18:32:48 -0700460 *isLinear = false;
Chris Dalton57115c02021-01-12 18:12:18 -0700461 if (toleranceSqd == 0) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700462 this->appendPointToContour(pts[3], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700463 break;
464 }
ethannicholase9709e82016-01-07 13:34:16 -0800465 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700466 this->generateCubicPoints(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour,
467 pointsLeft);
ethannicholase9709e82016-01-07 13:34:16 -0800468 break;
469 }
Chris Dalton7156db22020-05-07 22:06:28 +0000470 case SkPath::kClose_Verb:
471 case SkPath::kDone_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800472 break;
473 }
474 }
475}
476
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700477static inline bool apply_fill_type(SkPathFillType fillType, int winding) {
ethannicholase9709e82016-01-07 13:34:16 -0800478 switch (fillType) {
Mike Reed7d34dc72019-11-26 12:17:17 -0500479 case SkPathFillType::kWinding:
ethannicholase9709e82016-01-07 13:34:16 -0800480 return winding != 0;
Mike Reed7d34dc72019-11-26 12:17:17 -0500481 case SkPathFillType::kEvenOdd:
ethannicholase9709e82016-01-07 13:34:16 -0800482 return (winding & 1) != 0;
Mike Reed7d34dc72019-11-26 12:17:17 -0500483 case SkPathFillType::kInverseWinding:
senorblanco7ab96e92016-10-12 06:47:44 -0700484 return winding == 1;
Mike Reed7d34dc72019-11-26 12:17:17 -0500485 case SkPathFillType::kInverseEvenOdd:
ethannicholase9709e82016-01-07 13:34:16 -0800486 return (winding & 1) == 1;
487 default:
488 SkASSERT(false);
489 return false;
490 }
491}
492
Chris Dalton330cfa42021-01-27 18:24:48 -0700493bool GrTriangulator::applyFillType(int winding) const {
Chris Dalton47114db2021-01-06 00:35:20 -0700494 return apply_fill_type(fPath.getFillType(), winding);
495}
496
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700497static inline bool apply_fill_type(SkPathFillType fillType, Poly* poly) {
Stephen White49789062017-02-21 10:35:49 -0500498 return poly && apply_fill_type(fillType, poly->fWinding);
499}
500
Chris Dalton330cfa42021-01-27 18:24:48 -0700501Edge* GrTriangulator::makeEdge(Vertex* prev, Vertex* next, EdgeType type,
502 const Comparator& c) const {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700503 SkASSERT(prev->fPoint != next->fPoint);
Stephen White2f4686f2017-01-03 16:20:01 -0500504 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
ethannicholase9709e82016-01-07 13:34:16 -0800505 Vertex* top = winding < 0 ? next : prev;
506 Vertex* bottom = winding < 0 ? prev : next;
Chris Dalton8a42b092021-01-21 22:09:26 -0700507 return fAlloc->make<Edge>(top, bottom, winding, type);
ethannicholase9709e82016-01-07 13:34:16 -0800508}
509
Chris Dalton24472af2021-01-11 20:05:00 -0700510void EdgeList::insert(Edge* edge, Edge* prev) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400511 TESS_LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
Chris Dalton24472af2021-01-11 20:05:00 -0700512 SkASSERT(!this->contains(edge));
513 Edge* next = prev ? prev->fRight : fHead;
514 this->insert(edge, prev, next);
ethannicholase9709e82016-01-07 13:34:16 -0800515}
516
Chris Dalton47114db2021-01-06 00:35:20 -0700517void GrTriangulator::FindEnclosingEdges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) {
Stephen White90732fd2017-03-02 16:16:33 -0500518 if (v->fFirstEdgeAbove && v->fLastEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -0800519 *left = v->fFirstEdgeAbove->fLeft;
520 *right = v->fLastEdgeAbove->fRight;
521 return;
522 }
523 Edge* next = nullptr;
524 Edge* prev;
525 for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) {
526 if (prev->isLeftOf(v)) {
527 break;
528 }
529 next = prev;
530 }
531 *left = prev;
532 *right = next;
ethannicholase9709e82016-01-07 13:34:16 -0800533}
534
Chris Dalton24472af2021-01-11 20:05:00 -0700535void GrTriangulator::Edge::insertAbove(Vertex* v, const Comparator& c) {
536 if (fTop->fPoint == fBottom->fPoint ||
537 c.sweep_lt(fBottom->fPoint, fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800538 return;
539 }
Chris Dalton24472af2021-01-11 20:05:00 -0700540 TESS_LOG("insert edge (%g -> %g) above vertex %g\n", fTop->fID, fBottom->fID, v->fID);
ethannicholase9709e82016-01-07 13:34:16 -0800541 Edge* prev = nullptr;
542 Edge* next;
Chris Daltond60c9192021-01-07 18:30:08 +0000543 for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -0700544 if (next->isRightOf(fTop)) {
ethannicholase9709e82016-01-07 13:34:16 -0800545 break;
546 }
547 prev = next;
548 }
senorblancoe6eaa322016-03-08 09:06:44 -0800549 list_insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
Chris Dalton24472af2021-01-11 20:05:00 -0700550 this, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove);
ethannicholase9709e82016-01-07 13:34:16 -0800551}
552
Chris Dalton24472af2021-01-11 20:05:00 -0700553void GrTriangulator::Edge::insertBelow(Vertex* v, const Comparator& c) {
554 if (fTop->fPoint == fBottom->fPoint ||
555 c.sweep_lt(fBottom->fPoint, fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800556 return;
557 }
Chris Dalton24472af2021-01-11 20:05:00 -0700558 TESS_LOG("insert edge (%g -> %g) below vertex %g\n", fTop->fID, fBottom->fID, v->fID);
ethannicholase9709e82016-01-07 13:34:16 -0800559 Edge* prev = nullptr;
560 Edge* next;
Chris Daltond60c9192021-01-07 18:30:08 +0000561 for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -0700562 if (next->isRightOf(fBottom)) {
ethannicholase9709e82016-01-07 13:34:16 -0800563 break;
564 }
565 prev = next;
566 }
senorblancoe6eaa322016-03-08 09:06:44 -0800567 list_insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
Chris Dalton24472af2021-01-11 20:05:00 -0700568 this, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow);
ethannicholase9709e82016-01-07 13:34:16 -0800569}
570
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700571static void remove_edge_above(Edge* edge) {
Stephen White7b376942018-05-22 11:51:32 -0400572 SkASSERT(edge->fTop && edge->fBottom);
Brian Salomon120e7d62019-09-11 10:29:22 -0400573 TESS_LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
574 edge->fBottom->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800575 list_remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800576 edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove);
577}
578
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700579static void remove_edge_below(Edge* edge) {
Stephen White7b376942018-05-22 11:51:32 -0400580 SkASSERT(edge->fTop && edge->fBottom);
Brian Salomon120e7d62019-09-11 10:29:22 -0400581 TESS_LOG("removing edge (%g -> %g) below vertex %g\n",
582 edge->fTop->fID, edge->fBottom->fID, edge->fTop->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800583 list_remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800584 edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow);
585}
586
Chris Dalton24472af2021-01-11 20:05:00 -0700587void GrTriangulator::Edge::disconnect() {
588 remove_edge_above(this);
589 remove_edge_below(this);
Stephen Whitee7a364d2017-01-11 16:19:26 -0500590}
591
Chris Dalton811dc6a2021-01-07 16:40:32 -0700592static void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, const Comparator& c) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400593 if (!current || *current == dst || c.sweep_lt((*current)->fPoint, dst->fPoint)) {
594 return;
595 }
596 Vertex* v = *current;
Brian Salomon120e7d62019-09-11 10:29:22 -0400597 TESS_LOG("rewinding active edges from vertex %g to vertex %g\n", v->fID, dst->fID);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400598 while (v != dst) {
599 v = v->fPrev;
600 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -0700601 activeEdges->remove(e);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400602 }
603 Edge* leftEdge = v->fLeftEnclosingEdge;
604 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -0700605 activeEdges->insert(e, leftEdge);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400606 leftEdge = e;
Stephen Whitec03e6982020-02-06 16:32:14 -0500607 Vertex* top = e->fTop;
608 if (c.sweep_lt(top->fPoint, dst->fPoint) &&
609 ((top->fLeftEnclosingEdge && !top->fLeftEnclosingEdge->isLeftOf(e->fTop)) ||
610 (top->fRightEnclosingEdge && !top->fRightEnclosingEdge->isRightOf(e->fTop)))) {
611 dst = top;
612 }
Stephen White3b5a3fa2017-06-06 14:51:19 -0400613 }
614 }
615 *current = v;
616}
617
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700618static void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700619 const Comparator& c) {
Stephen Whitec03e6982020-02-06 16:32:14 -0500620 if (!activeEdges || !current) {
621 return;
622 }
623 Vertex* top = edge->fTop;
624 Vertex* bottom = edge->fBottom;
625 if (edge->fLeft) {
626 Vertex* leftTop = edge->fLeft->fTop;
627 Vertex* leftBottom = edge->fLeft->fBottom;
628 if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
629 rewind(activeEdges, current, leftTop, c);
630 } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
631 rewind(activeEdges, current, top, c);
632 } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
633 !edge->fLeft->isLeftOf(bottom)) {
634 rewind(activeEdges, current, leftTop, c);
635 } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
636 rewind(activeEdges, current, top, c);
637 }
638 }
639 if (edge->fRight) {
640 Vertex* rightTop = edge->fRight->fTop;
641 Vertex* rightBottom = edge->fRight->fBottom;
642 if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
643 rewind(activeEdges, current, rightTop, c);
644 } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
645 rewind(activeEdges, current, top, c);
646 } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
647 !edge->fRight->isRightOf(bottom)) {
648 rewind(activeEdges, current, rightTop, c);
649 } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
650 !edge->isLeftOf(rightBottom)) {
651 rewind(activeEdges, current, top, c);
652 }
653 }
654}
655
Chris Dalton68b8bd52021-01-14 10:48:02 -0700656void GrTriangulator::setTop(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
Chris Dalton330cfa42021-01-27 18:24:48 -0700657 const Comparator& c, BreadcrumbTriangleList* breadcrumbList) const {
ethannicholase9709e82016-01-07 13:34:16 -0800658 remove_edge_below(edge);
Chris Dalton330cfa42021-01-27 18:24:48 -0700659 if (breadcrumbList) {
660 breadcrumbList->prepend(fAlloc, edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
661 edge->fWinding);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700662 }
ethannicholase9709e82016-01-07 13:34:16 -0800663 edge->fTop = v;
664 edge->recompute();
Chris Dalton24472af2021-01-11 20:05:00 -0700665 edge->insertBelow(v, c);
Stephen Whitec03e6982020-02-06 16:32:14 -0500666 rewind_if_necessary(edge, activeEdges, current, c);
Chris Dalton330cfa42021-01-27 18:24:48 -0700667 this->mergeCollinearEdges(edge, activeEdges, current, c, breadcrumbList);
ethannicholase9709e82016-01-07 13:34:16 -0800668}
669
Chris Dalton68b8bd52021-01-14 10:48:02 -0700670void GrTriangulator::setBottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
Chris Dalton330cfa42021-01-27 18:24:48 -0700671 const Comparator& c, BreadcrumbTriangleList* breadcrumbList) const {
ethannicholase9709e82016-01-07 13:34:16 -0800672 remove_edge_above(edge);
Chris Dalton330cfa42021-01-27 18:24:48 -0700673 if (breadcrumbList) {
674 breadcrumbList->prepend(fAlloc, edge->fTop->fPoint, edge->fBottom->fPoint, v->fPoint,
675 edge->fWinding);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700676 }
ethannicholase9709e82016-01-07 13:34:16 -0800677 edge->fBottom = v;
678 edge->recompute();
Chris Dalton24472af2021-01-11 20:05:00 -0700679 edge->insertAbove(v, c);
Stephen Whitec03e6982020-02-06 16:32:14 -0500680 rewind_if_necessary(edge, activeEdges, current, c);
Chris Dalton330cfa42021-01-27 18:24:48 -0700681 this->mergeCollinearEdges(edge, activeEdges, current, c, breadcrumbList);
ethannicholase9709e82016-01-07 13:34:16 -0800682}
683
Chris Dalton68b8bd52021-01-14 10:48:02 -0700684void GrTriangulator::mergeEdgesAbove(Edge* edge, Edge* other, EdgeList* activeEdges,
Chris Dalton330cfa42021-01-27 18:24:48 -0700685 Vertex** current, const Comparator& c,
686 BreadcrumbTriangleList* breadcrumbList) const {
ethannicholase9709e82016-01-07 13:34:16 -0800687 if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400688 TESS_LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
689 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
690 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
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 Dalton24472af2021-01-11 20:05:00 -0700693 edge->disconnect();
Stephen Whiteec79c392018-05-18 11:49:21 -0400694 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -0800695 } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400696 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800697 other->fWinding += edge->fWinding;
Chris Dalton330cfa42021-01-27 18:24:48 -0700698 this->setBottom(edge, other->fTop, activeEdges, current, c, breadcrumbList);
ethannicholase9709e82016-01-07 13:34:16 -0800699 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400700 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800701 edge->fWinding += other->fWinding;
Chris Dalton330cfa42021-01-27 18:24:48 -0700702 this->setBottom(other, edge->fTop, activeEdges, current, c, breadcrumbList);
ethannicholase9709e82016-01-07 13:34:16 -0800703 }
704}
705
Chris Dalton68b8bd52021-01-14 10:48:02 -0700706void GrTriangulator::mergeEdgesBelow(Edge* edge, Edge* other, EdgeList* activeEdges,
Chris Dalton330cfa42021-01-27 18:24:48 -0700707 Vertex** current, const Comparator& c,
708 BreadcrumbTriangleList* breadcrumbList) const {
ethannicholase9709e82016-01-07 13:34:16 -0800709 if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400710 TESS_LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
711 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
712 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400713 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800714 other->fWinding += edge->fWinding;
Chris Dalton24472af2021-01-11 20:05:00 -0700715 edge->disconnect();
Stephen Whiteec79c392018-05-18 11:49:21 -0400716 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -0800717 } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400718 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800719 edge->fWinding += other->fWinding;
Chris Dalton330cfa42021-01-27 18:24:48 -0700720 this->setTop(other, edge->fBottom, activeEdges, current, c, breadcrumbList);
ethannicholase9709e82016-01-07 13:34:16 -0800721 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400722 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800723 other->fWinding += edge->fWinding;
Chris Dalton330cfa42021-01-27 18:24:48 -0700724 this->setTop(edge, other->fBottom, activeEdges, current, c, breadcrumbList);
ethannicholase9709e82016-01-07 13:34:16 -0800725 }
726}
727
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700728static bool top_collinear(Edge* left, Edge* right) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400729 if (!left || !right) {
730 return false;
731 }
732 return left->fTop->fPoint == right->fTop->fPoint ||
733 !left->isLeftOf(right->fTop) || !right->isRightOf(left->fTop);
734}
735
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700736static bool bottom_collinear(Edge* left, Edge* right) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400737 if (!left || !right) {
738 return false;
739 }
740 return left->fBottom->fPoint == right->fBottom->fPoint ||
741 !left->isLeftOf(right->fBottom) || !right->isRightOf(left->fBottom);
742}
743
Chris Dalton68b8bd52021-01-14 10:48:02 -0700744void GrTriangulator::mergeCollinearEdges(Edge* edge, EdgeList* activeEdges, Vertex** current,
Chris Dalton330cfa42021-01-27 18:24:48 -0700745 const Comparator& c,
746 BreadcrumbTriangleList* breadcrumbList) const {
Stephen White6eca90f2017-05-25 14:47:11 -0400747 for (;;) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400748 if (top_collinear(edge->fPrevEdgeAbove, edge)) {
Chris Dalton330cfa42021-01-27 18:24:48 -0700749 this->mergeEdgesAbove(edge->fPrevEdgeAbove, edge, activeEdges, current, c,
750 breadcrumbList);
Stephen Whited26b4d82018-07-26 10:02:27 -0400751 } else if (top_collinear(edge, edge->fNextEdgeAbove)) {
Chris Dalton330cfa42021-01-27 18:24:48 -0700752 this->mergeEdgesAbove(edge->fNextEdgeAbove, edge, activeEdges, current, c,
753 breadcrumbList);
Stephen Whited26b4d82018-07-26 10:02:27 -0400754 } else if (bottom_collinear(edge->fPrevEdgeBelow, edge)) {
Chris Dalton330cfa42021-01-27 18:24:48 -0700755 this->mergeEdgesBelow(edge->fPrevEdgeBelow, edge, activeEdges, current, c,
756 breadcrumbList);
Stephen Whited26b4d82018-07-26 10:02:27 -0400757 } else if (bottom_collinear(edge, edge->fNextEdgeBelow)) {
Chris Dalton330cfa42021-01-27 18:24:48 -0700758 this->mergeEdgesBelow(edge->fNextEdgeBelow, edge, activeEdges, current, c,
759 breadcrumbList);
Stephen White6eca90f2017-05-25 14:47:11 -0400760 } else {
761 break;
762 }
ethannicholase9709e82016-01-07 13:34:16 -0800763 }
Stephen Whited26b4d82018-07-26 10:02:27 -0400764 SkASSERT(!top_collinear(edge->fPrevEdgeAbove, edge));
765 SkASSERT(!top_collinear(edge, edge->fNextEdgeAbove));
766 SkASSERT(!bottom_collinear(edge->fPrevEdgeBelow, edge));
767 SkASSERT(!bottom_collinear(edge, edge->fNextEdgeBelow));
ethannicholase9709e82016-01-07 13:34:16 -0800768}
769
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700770bool GrTriangulator::splitEdge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
Chris Dalton330cfa42021-01-27 18:24:48 -0700771 const Comparator& c, BreadcrumbTriangleList* breadcrumbList) const {
Stephen Whiteec79c392018-05-18 11:49:21 -0400772 if (!edge->fTop || !edge->fBottom || v == edge->fTop || v == edge->fBottom) {
Stephen White89042d52018-06-08 12:18:22 -0400773 return false;
Stephen White0cb31672017-06-08 14:41:01 -0400774 }
Brian Salomon120e7d62019-09-11 10:29:22 -0400775 TESS_LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
776 edge->fTop->fID, edge->fBottom->fID, v->fID, v->fPoint.fX, v->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400777 Vertex* top;
778 Vertex* bottom;
Stephen White531a48e2018-06-01 09:49:39 -0400779 int winding = edge->fWinding;
ethannicholase9709e82016-01-07 13:34:16 -0800780 if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400781 top = v;
782 bottom = edge->fTop;
Chris Dalton330cfa42021-01-27 18:24:48 -0700783 this->setTop(edge, v, activeEdges, current, c, breadcrumbList);
Stephen Whitee30cf802017-02-27 11:37:55 -0500784 } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400785 top = edge->fBottom;
786 bottom = v;
Chris Dalton330cfa42021-01-27 18:24:48 -0700787 this->setBottom(edge, v, activeEdges, current, c, breadcrumbList);
ethannicholase9709e82016-01-07 13:34:16 -0800788 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400789 top = v;
790 bottom = edge->fBottom;
Chris Dalton330cfa42021-01-27 18:24:48 -0700791 this->setBottom(edge, v, activeEdges, current, c, breadcrumbList);
ethannicholase9709e82016-01-07 13:34:16 -0800792 }
Chris Dalton8a42b092021-01-21 22:09:26 -0700793 Edge* newEdge = fAlloc->make<Edge>(top, bottom, winding, edge->fType);
Chris Dalton24472af2021-01-11 20:05:00 -0700794 newEdge->insertBelow(top, c);
795 newEdge->insertAbove(bottom, c);
Chris Dalton330cfa42021-01-27 18:24:48 -0700796 this->mergeCollinearEdges(newEdge, activeEdges, current, c, breadcrumbList);
Stephen White89042d52018-06-08 12:18:22 -0400797 return true;
798}
799
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700800bool GrTriangulator::intersectEdgePair(Edge* left, Edge* right, EdgeList* activeEdges,
Chris Dalton330cfa42021-01-27 18:24:48 -0700801 Vertex** current, const Comparator& c,
802 BreadcrumbTriangleList* breadcrumbList) const {
Stephen White89042d52018-06-08 12:18:22 -0400803 if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) {
804 return false;
805 }
Stephen White1c5fd182018-07-12 15:54:05 -0400806 if (left->fTop == right->fTop || left->fBottom == right->fBottom) {
807 return false;
808 }
Stephen White89042d52018-06-08 12:18:22 -0400809 if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
810 if (!left->isLeftOf(right->fTop)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400811 rewind(activeEdges, current, right->fTop, c);
Chris Dalton330cfa42021-01-27 18:24:48 -0700812 return this->splitEdge(left, right->fTop, activeEdges, current, c, breadcrumbList);
Stephen White89042d52018-06-08 12:18:22 -0400813 }
814 } else {
815 if (!right->isRightOf(left->fTop)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400816 rewind(activeEdges, current, left->fTop, c);
Chris Dalton330cfa42021-01-27 18:24:48 -0700817 return this->splitEdge(right, left->fTop, activeEdges, current, c, breadcrumbList);
Stephen White89042d52018-06-08 12:18:22 -0400818 }
819 }
820 if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
821 if (!left->isLeftOf(right->fBottom)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400822 rewind(activeEdges, current, right->fBottom, c);
Chris Dalton330cfa42021-01-27 18:24:48 -0700823 return this->splitEdge(left, right->fBottom, activeEdges, current, c, breadcrumbList);
Stephen White89042d52018-06-08 12:18:22 -0400824 }
825 } else {
826 if (!right->isRightOf(left->fBottom)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400827 rewind(activeEdges, current, left->fBottom, c);
Chris Dalton330cfa42021-01-27 18:24:48 -0700828 return this->splitEdge(right, left->fBottom, activeEdges, current, c, breadcrumbList);
Stephen White89042d52018-06-08 12:18:22 -0400829 }
830 }
831 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800832}
833
Chris Dalton7cf3add2021-01-11 18:33:28 -0700834Edge* GrTriangulator::makeConnectingEdge(Vertex* prev, Vertex* next, EdgeType type,
Chris Dalton330cfa42021-01-27 18:24:48 -0700835 const Comparator& c,
836 BreadcrumbTriangleList* breadcrumbList,
837 int windingScale) const {
Stephen Whitee260c462017-12-19 18:09:54 -0500838 if (!prev || !next || prev->fPoint == next->fPoint) {
839 return nullptr;
840 }
Chris Dalton7cf3add2021-01-11 18:33:28 -0700841 Edge* edge = this->makeEdge(prev, next, type, c);
Chris Dalton24472af2021-01-11 20:05:00 -0700842 edge->insertBelow(edge->fTop, c);
843 edge->insertAbove(edge->fBottom, c);
Chris Dalton7cf3add2021-01-11 18:33:28 -0700844 edge->fWinding *= windingScale;
Chris Dalton330cfa42021-01-27 18:24:48 -0700845 this->mergeCollinearEdges(edge, nullptr, nullptr, c, breadcrumbList);
senorblancof57372d2016-08-31 10:36:19 -0700846 return edge;
847}
848
Chris Dalton68b8bd52021-01-14 10:48:02 -0700849void GrTriangulator::mergeVertices(Vertex* src, Vertex* dst, VertexList* mesh,
Chris Dalton330cfa42021-01-27 18:24:48 -0700850 const Comparator& c,
851 BreadcrumbTriangleList* breadcrumbList) const {
Brian Salomon120e7d62019-09-11 10:29:22 -0400852 TESS_LOG("found coincident verts at %g, %g; merging %g into %g\n",
853 src->fPoint.fX, src->fPoint.fY, src->fID, dst->fID);
Brian Osman788b9162020-02-07 10:36:46 -0500854 dst->fAlpha = std::max(src->fAlpha, dst->fAlpha);
Stephen Whitebda29c02017-03-13 15:10:13 -0400855 if (src->fPartner) {
856 src->fPartner->fPartner = dst;
857 }
Stephen White7b376942018-05-22 11:51:32 -0400858 while (Edge* edge = src->fFirstEdgeAbove) {
Chris Dalton330cfa42021-01-27 18:24:48 -0700859 this->setBottom(edge, dst, nullptr, nullptr, c, breadcrumbList);
ethannicholase9709e82016-01-07 13:34:16 -0800860 }
Stephen White7b376942018-05-22 11:51:32 -0400861 while (Edge* edge = src->fFirstEdgeBelow) {
Chris Dalton330cfa42021-01-27 18:24:48 -0700862 this->setTop(edge, dst, nullptr, nullptr, c, breadcrumbList);
ethannicholase9709e82016-01-07 13:34:16 -0800863 }
Stephen Whitebf6137e2017-01-04 15:43:26 -0500864 mesh->remove(src);
Stephen Whitec4dbc372019-05-22 10:50:14 -0400865 dst->fSynthetic = true;
ethannicholase9709e82016-01-07 13:34:16 -0800866}
867
Chris Dalton7cf3add2021-01-11 18:33:28 -0700868Vertex* GrTriangulator::makeSortedVertex(const SkPoint& p, uint8_t alpha, VertexList* mesh,
Chris Dalton330cfa42021-01-27 18:24:48 -0700869 Vertex* reference, const Comparator& c) const {
Stephen White95152e12017-12-18 10:52:44 -0500870 Vertex* prevV = reference;
871 while (prevV && c.sweep_lt(p, prevV->fPoint)) {
872 prevV = prevV->fPrev;
873 }
874 Vertex* nextV = prevV ? prevV->fNext : mesh->fHead;
875 while (nextV && c.sweep_lt(nextV->fPoint, p)) {
876 prevV = nextV;
877 nextV = nextV->fNext;
878 }
879 Vertex* v;
880 if (prevV && coincident(prevV->fPoint, p)) {
881 v = prevV;
882 } else if (nextV && coincident(nextV->fPoint, p)) {
883 v = nextV;
884 } else {
Chris Dalton8a42b092021-01-21 22:09:26 -0700885 v = fAlloc->make<Vertex>(p, alpha);
Chris Dalton5045de32021-01-07 19:09:01 -0700886#if TRIANGULATOR_LOGGING
Stephen White95152e12017-12-18 10:52:44 -0500887 if (!prevV) {
888 v->fID = mesh->fHead->fID - 1.0f;
889 } else if (!nextV) {
890 v->fID = mesh->fTail->fID + 1.0f;
891 } else {
892 v->fID = (prevV->fID + nextV->fID) * 0.5f;
893 }
894#endif
895 mesh->insert(v, prevV, nextV);
896 }
897 return v;
898}
899
Stephen White53a02982018-05-30 22:47:46 -0400900// If an edge's top and bottom points differ only by 1/2 machine epsilon in the primary
901// sort criterion, it may not be possible to split correctly, since there is no point which is
902// below the top and above the bottom. This function detects that case.
Chris Dalton811dc6a2021-01-07 16:40:32 -0700903static bool nearly_flat(const Comparator& c, Edge* edge) {
Stephen White53a02982018-05-30 22:47:46 -0400904 SkPoint diff = edge->fBottom->fPoint - edge->fTop->fPoint;
905 float primaryDiff = c.fDirection == Comparator::Direction::kHorizontal ? diff.fX : diff.fY;
Stephen White13f3d8d2018-06-22 10:19:20 -0400906 return fabs(primaryDiff) < std::numeric_limits<float>::epsilon() && primaryDiff != 0.0f;
Stephen White53a02982018-05-30 22:47:46 -0400907}
908
Chris Dalton811dc6a2021-01-07 16:40:32 -0700909static SkPoint clamp(SkPoint p, SkPoint min, SkPoint max, const Comparator& c) {
Stephen Whitee62999f2018-06-05 18:45:07 -0400910 if (c.sweep_lt(p, min)) {
911 return min;
912 } else if (c.sweep_lt(max, p)) {
913 return max;
914 } else {
915 return p;
916 }
917}
918
Chris Dalton330cfa42021-01-27 18:24:48 -0700919void GrTriangulator::computeBisector(Edge* edge1, Edge* edge2, Vertex* v) const {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700920 SkASSERT(fEmitCoverage); // Edge-AA only!
Stephen Whitec4dbc372019-05-22 10:50:14 -0400921 Line line1 = edge1->fLine;
922 Line line2 = edge2->fLine;
923 line1.normalize();
924 line2.normalize();
925 double cosAngle = line1.fA * line2.fA + line1.fB * line2.fB;
926 if (cosAngle > 0.999) {
927 return;
928 }
929 line1.fC += edge1->fWinding > 0 ? -1 : 1;
930 line2.fC += edge2->fWinding > 0 ? -1 : 1;
931 SkPoint p;
932 if (line1.intersect(line2, &p)) {
Chris Dalton17ce8c52021-01-07 18:08:46 -0700933 uint8_t alpha = edge1->fType == EdgeType::kOuter ? 255 : 0;
Chris Dalton8a42b092021-01-21 22:09:26 -0700934 v->fPartner = fAlloc->make<Vertex>(p, alpha);
Brian Salomon120e7d62019-09-11 10:29:22 -0400935 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 -0400936 }
937}
938
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700939bool GrTriangulator::checkForIntersection(Edge* left, Edge* right, EdgeList* activeEdges,
Chris Dalton330cfa42021-01-27 18:24:48 -0700940 Vertex** current, VertexList* mesh, const Comparator& c,
941 BreadcrumbTriangleList* breadcrumbList) const {
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400942 if (!left || !right) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400943 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800944 }
Stephen White56158ae2017-01-30 14:31:31 -0500945 SkPoint p;
946 uint8_t alpha;
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400947 if (left->intersect(*right, &p, &alpha) && p.isFinite()) {
Ravi Mistrybfe95982018-05-29 18:19:07 +0000948 Vertex* v;
Brian Salomon120e7d62019-09-11 10:29:22 -0400949 TESS_LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400950 Vertex* top = *current;
951 // If the intersection point is above the current vertex, rewind to the vertex above the
952 // intersection.
Stephen White0cb31672017-06-08 14:41:01 -0400953 while (top && c.sweep_lt(p, top->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400954 top = top->fPrev;
955 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400956 if (!nearly_flat(c, left)) {
957 p = clamp(p, left->fTop->fPoint, left->fBottom->fPoint, c);
Stephen Whitee62999f2018-06-05 18:45:07 -0400958 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400959 if (!nearly_flat(c, right)) {
960 p = clamp(p, right->fTop->fPoint, right->fBottom->fPoint, c);
Stephen Whitee62999f2018-06-05 18:45:07 -0400961 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400962 if (p == left->fTop->fPoint) {
963 v = left->fTop;
964 } else if (p == left->fBottom->fPoint) {
965 v = left->fBottom;
966 } else if (p == right->fTop->fPoint) {
967 v = right->fTop;
968 } else if (p == right->fBottom->fPoint) {
969 v = right->fBottom;
Ravi Mistrybfe95982018-05-29 18:19:07 +0000970 } else {
Chris Dalton7cf3add2021-01-11 18:33:28 -0700971 v = this->makeSortedVertex(p, alpha, mesh, top, c);
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400972 if (left->fTop->fPartner) {
Chris Dalton68b8bd52021-01-14 10:48:02 -0700973 SkASSERT(fEmitCoverage); // Edge-AA only!
Stephen Whitec4dbc372019-05-22 10:50:14 -0400974 v->fSynthetic = true;
Chris Dalton7cf3add2021-01-11 18:33:28 -0700975 this->computeBisector(left, right, v);
Stephen Whitee260c462017-12-19 18:09:54 -0500976 }
ethannicholase9709e82016-01-07 13:34:16 -0800977 }
Stephen White0cb31672017-06-08 14:41:01 -0400978 rewind(activeEdges, current, top ? top : v, c);
Chris Dalton330cfa42021-01-27 18:24:48 -0700979 this->splitEdge(left, v, activeEdges, current, c, breadcrumbList);
980 this->splitEdge(right, v, activeEdges, current, c, breadcrumbList);
Brian Osman788b9162020-02-07 10:36:46 -0500981 v->fAlpha = std::max(v->fAlpha, alpha);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400982 return true;
ethannicholase9709e82016-01-07 13:34:16 -0800983 }
Chris Dalton330cfa42021-01-27 18:24:48 -0700984 return this->intersectEdgePair(left, right, activeEdges, current, c, breadcrumbList);
ethannicholase9709e82016-01-07 13:34:16 -0800985}
986
Chris Dalton330cfa42021-01-27 18:24:48 -0700987void GrTriangulator::sanitizeContours(VertexList* contours, int contourCnt) const {
Stephen White3a9aab92017-03-07 14:07:18 -0500988 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
989 SkASSERT(contour->fHead);
990 Vertex* prev = contour->fTail;
Chris Dalton854ee852021-01-05 15:12:59 -0700991 if (fRoundVerticesToQuarterPixel) {
Stephen White3a9aab92017-03-07 14:07:18 -0500992 round(&prev->fPoint);
Stephen White5926f2d2017-02-13 13:55:42 -0500993 }
Stephen White3a9aab92017-03-07 14:07:18 -0500994 for (Vertex* v = contour->fHead; v;) {
Chris Dalton854ee852021-01-05 15:12:59 -0700995 if (fRoundVerticesToQuarterPixel) {
senorblancof57372d2016-08-31 10:36:19 -0700996 round(&v->fPoint);
997 }
Stephen White3a9aab92017-03-07 14:07:18 -0500998 Vertex* next = v->fNext;
Stephen White3de40f82018-06-28 09:36:49 -0400999 Vertex* nextWrap = next ? next : contour->fHead;
Stephen White3a9aab92017-03-07 14:07:18 -05001000 if (coincident(prev->fPoint, v->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001001 TESS_LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001002 contour->remove(v);
Stephen White73e7f802017-08-23 13:56:07 -04001003 } else if (!v->fPoint.isFinite()) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001004 TESS_LOG("vertex %g,%g non-finite; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White73e7f802017-08-23 13:56:07 -04001005 contour->remove(v);
Chris Dalton854ee852021-01-05 15:12:59 -07001006 } else if (fCullCollinearVertices &&
Chris Dalton6ccc0322020-01-29 11:38:16 -07001007 Line(prev->fPoint, nextWrap->fPoint).dist(v->fPoint) == 0.0) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001008 TESS_LOG("vertex %g,%g collinear; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White06768ca2018-05-25 14:50:56 -04001009 contour->remove(v);
1010 } else {
1011 prev = v;
ethannicholase9709e82016-01-07 13:34:16 -08001012 }
Stephen White3a9aab92017-03-07 14:07:18 -05001013 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001014 }
1015 }
1016}
1017
Chris Dalton330cfa42021-01-27 18:24:48 -07001018bool GrTriangulator::mergeCoincidentVertices(VertexList* mesh, const Comparator& c,
1019 BreadcrumbTriangleList* breadcrumbList) const {
Stephen Whitebda29c02017-03-13 15:10:13 -04001020 if (!mesh->fHead) {
Stephen Whitee260c462017-12-19 18:09:54 -05001021 return false;
Stephen Whitebda29c02017-03-13 15:10:13 -04001022 }
Stephen Whitee260c462017-12-19 18:09:54 -05001023 bool merged = false;
1024 for (Vertex* v = mesh->fHead->fNext; v;) {
1025 Vertex* next = v->fNext;
ethannicholase9709e82016-01-07 13:34:16 -08001026 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) {
1027 v->fPoint = v->fPrev->fPoint;
1028 }
1029 if (coincident(v->fPrev->fPoint, v->fPoint)) {
Chris Dalton330cfa42021-01-27 18:24:48 -07001030 this->mergeVertices(v, v->fPrev, mesh, c, breadcrumbList);
Stephen Whitee260c462017-12-19 18:09:54 -05001031 merged = true;
ethannicholase9709e82016-01-07 13:34:16 -08001032 }
Stephen Whitee260c462017-12-19 18:09:54 -05001033 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001034 }
Stephen Whitee260c462017-12-19 18:09:54 -05001035 return merged;
ethannicholase9709e82016-01-07 13:34:16 -08001036}
1037
1038// Stage 2: convert the contours to a mesh of edges connecting the vertices.
1039
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001040void GrTriangulator::buildEdges(VertexList* contours, int contourCnt, VertexList* mesh,
Chris Dalton330cfa42021-01-27 18:24:48 -07001041 const Comparator& c, BreadcrumbTriangleList* breadcrumbList) const {
Stephen White3a9aab92017-03-07 14:07:18 -05001042 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1043 Vertex* prev = contour->fTail;
1044 for (Vertex* v = contour->fHead; v;) {
1045 Vertex* next = v->fNext;
Chris Dalton330cfa42021-01-27 18:24:48 -07001046 this->makeConnectingEdge(prev, v, EdgeType::kInner, c, breadcrumbList);
Stephen White3a9aab92017-03-07 14:07:18 -05001047 mesh->append(v);
ethannicholase9709e82016-01-07 13:34:16 -08001048 prev = v;
Stephen White3a9aab92017-03-07 14:07:18 -05001049 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001050 }
1051 }
ethannicholase9709e82016-01-07 13:34:16 -08001052}
1053
Stephen Whitebda29c02017-03-13 15:10:13 -04001054template <CompareFunc sweep_lt>
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001055static void sorted_merge(VertexList* front, VertexList* back, VertexList* result) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001056 Vertex* a = front->fHead;
1057 Vertex* b = back->fHead;
1058 while (a && b) {
1059 if (sweep_lt(a->fPoint, b->fPoint)) {
1060 front->remove(a);
1061 result->append(a);
1062 a = front->fHead;
1063 } else {
1064 back->remove(b);
1065 result->append(b);
1066 b = back->fHead;
1067 }
1068 }
1069 result->append(*front);
1070 result->append(*back);
1071}
1072
Chris Dalton47114db2021-01-06 00:35:20 -07001073void GrTriangulator::SortedMerge(VertexList* front, VertexList* back, VertexList* result,
1074 const Comparator& c) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001075 if (c.fDirection == Comparator::Direction::kHorizontal) {
1076 sorted_merge<sweep_lt_horiz>(front, back, result);
1077 } else {
1078 sorted_merge<sweep_lt_vert>(front, back, result);
1079 }
Chris Dalton5045de32021-01-07 19:09:01 -07001080#if TRIANGULATOR_LOGGING
Stephen White3b5a3fa2017-06-06 14:51:19 -04001081 float id = 0.0f;
1082 for (Vertex* v = result->fHead; v; v = v->fNext) {
1083 v->fID = id++;
1084 }
1085#endif
Stephen Whitebda29c02017-03-13 15:10:13 -04001086}
1087
ethannicholase9709e82016-01-07 13:34:16 -08001088// Stage 3: sort the vertices by increasing sweep direction.
1089
Stephen White16a40cb2017-02-23 11:10:01 -05001090template <CompareFunc sweep_lt>
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001091static void merge_sort(VertexList* vertices) {
Stephen White16a40cb2017-02-23 11:10:01 -05001092 Vertex* slow = vertices->fHead;
1093 if (!slow) {
ethannicholase9709e82016-01-07 13:34:16 -08001094 return;
1095 }
Stephen White16a40cb2017-02-23 11:10:01 -05001096 Vertex* fast = slow->fNext;
1097 if (!fast) {
1098 return;
1099 }
1100 do {
1101 fast = fast->fNext;
1102 if (fast) {
1103 fast = fast->fNext;
1104 slow = slow->fNext;
1105 }
1106 } while (fast);
1107 VertexList front(vertices->fHead, slow);
1108 VertexList back(slow->fNext, vertices->fTail);
1109 front.fTail->fNext = back.fHead->fPrev = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001110
Stephen White16a40cb2017-02-23 11:10:01 -05001111 merge_sort<sweep_lt>(&front);
1112 merge_sort<sweep_lt>(&back);
ethannicholase9709e82016-01-07 13:34:16 -08001113
Stephen White16a40cb2017-02-23 11:10:01 -05001114 vertices->fHead = vertices->fTail = nullptr;
Stephen Whitebda29c02017-03-13 15:10:13 -04001115 sorted_merge<sweep_lt>(&front, &back, vertices);
ethannicholase9709e82016-01-07 13:34:16 -08001116}
1117
Chris Dalton5045de32021-01-07 19:09:01 -07001118#if TRIANGULATOR_LOGGING
Chris Dalton330cfa42021-01-27 18:24:48 -07001119void VertexList::dump() const {
Chris Dalton24472af2021-01-11 20:05:00 -07001120 for (Vertex* v = fHead; v; v = v->fNext) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001121 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 -05001122 if (Vertex* p = v->fPartner) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001123 TESS_LOG(", partner %g (%g, %g) alpha %d\n",
1124 p->fID, p->fPoint.fX, p->fPoint.fY, p->fAlpha);
Stephen White95152e12017-12-18 10:52:44 -05001125 } else {
Brian Salomon120e7d62019-09-11 10:29:22 -04001126 TESS_LOG(", null partner\n");
Stephen White95152e12017-12-18 10:52:44 -05001127 }
1128 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001129 TESS_LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
Stephen White95152e12017-12-18 10:52:44 -05001130 }
1131 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001132 TESS_LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
Stephen White95152e12017-12-18 10:52:44 -05001133 }
1134 }
Chris Daltond60c9192021-01-07 18:30:08 +00001135}
Chris Dalton7cf3add2021-01-11 18:33:28 -07001136#endif
Stephen White95152e12017-12-18 10:52:44 -05001137
Stephen White89042d52018-06-08 12:18:22 -04001138#ifdef SK_DEBUG
Chris Dalton811dc6a2021-01-07 16:40:32 -07001139static void validate_edge_pair(Edge* left, Edge* right, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -04001140 if (!left || !right) {
1141 return;
1142 }
1143 if (left->fTop == right->fTop) {
1144 SkASSERT(left->isLeftOf(right->fBottom));
1145 SkASSERT(right->isRightOf(left->fBottom));
1146 } else if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
1147 SkASSERT(left->isLeftOf(right->fTop));
1148 } else {
1149 SkASSERT(right->isRightOf(left->fTop));
1150 }
1151 if (left->fBottom == right->fBottom) {
1152 SkASSERT(left->isLeftOf(right->fTop));
1153 SkASSERT(right->isRightOf(left->fTop));
1154 } else if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
1155 SkASSERT(left->isLeftOf(right->fBottom));
1156 } else {
1157 SkASSERT(right->isRightOf(left->fBottom));
1158 }
1159}
1160
Chris Dalton811dc6a2021-01-07 16:40:32 -07001161static void validate_edge_list(EdgeList* edges, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -04001162 Edge* left = edges->fHead;
1163 if (!left) {
1164 return;
1165 }
1166 for (Edge* right = left->fRight; right; right = right->fRight) {
1167 validate_edge_pair(left, right, c);
1168 left = right;
1169 }
1170}
1171#endif
1172
ethannicholase9709e82016-01-07 13:34:16 -08001173// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges.
1174
Chris Dalton330cfa42021-01-27 18:24:48 -07001175GrTriangulator::SimplifyResult GrTriangulator::simplify(
1176 VertexList* mesh, const Comparator& c, BreadcrumbTriangleList* breadcrumbList) const {
Brian Salomon120e7d62019-09-11 10:29:22 -04001177 TESS_LOG("simplifying complex polygons\n");
ethannicholase9709e82016-01-07 13:34:16 -08001178 EdgeList activeEdges;
Chris Dalton6ccc0322020-01-29 11:38:16 -07001179 auto result = SimplifyResult::kAlreadySimple;
Stephen White0cb31672017-06-08 14:41:01 -04001180 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
Chris Dalton24472af2021-01-11 20:05:00 -07001181 if (!v->isConnected()) {
ethannicholase9709e82016-01-07 13:34:16 -08001182 continue;
1183 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001184 Edge* leftEnclosingEdge;
1185 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001186 bool restartChecks;
1187 do {
Brian Salomon120e7d62019-09-11 10:29:22 -04001188 TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n",
1189 v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001190 restartChecks = false;
Chris Dalton47114db2021-01-06 00:35:20 -07001191 FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001192 v->fLeftEnclosingEdge = leftEnclosingEdge;
1193 v->fRightEnclosingEdge = rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001194 if (v->fFirstEdgeBelow) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001195 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001196 if (this->checkForIntersection(
Chris Dalton330cfa42021-01-27 18:24:48 -07001197 leftEnclosingEdge, edge, &activeEdges, &v, mesh, c, breadcrumbList) ||
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001198 this->checkForIntersection(
Chris Dalton330cfa42021-01-27 18:24:48 -07001199 edge, rightEnclosingEdge, &activeEdges, &v, mesh, c, breadcrumbList)) {
Chris Dalton57115c02021-01-12 18:12:18 -07001200 if (fDisallowSelfIntersection) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001201 return SimplifyResult::kAbort;
1202 }
1203 result = SimplifyResult::kFoundSelfIntersection;
ethannicholase9709e82016-01-07 13:34:16 -08001204 restartChecks = true;
1205 break;
1206 }
1207 }
1208 } else {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001209 if (this->checkForIntersection(leftEnclosingEdge, rightEnclosingEdge, &activeEdges,
Chris Dalton330cfa42021-01-27 18:24:48 -07001210 &v, mesh, c, breadcrumbList)) {
Chris Dalton57115c02021-01-12 18:12:18 -07001211 if (fDisallowSelfIntersection) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001212 return SimplifyResult::kAbort;
1213 }
1214 result = SimplifyResult::kFoundSelfIntersection;
ethannicholase9709e82016-01-07 13:34:16 -08001215 restartChecks = true;
1216 }
1217
1218 }
1219 } while (restartChecks);
Stephen White89042d52018-06-08 12:18:22 -04001220#ifdef SK_DEBUG
1221 validate_edge_list(&activeEdges, c);
1222#endif
ethannicholase9709e82016-01-07 13:34:16 -08001223 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -07001224 activeEdges.remove(e);
ethannicholase9709e82016-01-07 13:34:16 -08001225 }
1226 Edge* leftEdge = leftEnclosingEdge;
1227 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -07001228 activeEdges.insert(e, leftEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001229 leftEdge = e;
1230 }
ethannicholase9709e82016-01-07 13:34:16 -08001231 }
Stephen Whitee260c462017-12-19 18:09:54 -05001232 SkASSERT(!activeEdges.fHead && !activeEdges.fTail);
Chris Dalton6ccc0322020-01-29 11:38:16 -07001233 return result;
ethannicholase9709e82016-01-07 13:34:16 -08001234}
1235
1236// Stage 5: Tessellate the simplified mesh into monotone polygons.
1237
Chris Dalton330cfa42021-01-27 18:24:48 -07001238Poly* GrTriangulator::tessellate(const VertexList& vertices, const Comparator&) const {
Brian Salomon120e7d62019-09-11 10:29:22 -04001239 TESS_LOG("\ntessellating simple polygons\n");
Chris Dalton6ccc0322020-01-29 11:38:16 -07001240 int maxWindMagnitude = std::numeric_limits<int>::max();
Chris Dalton57115c02021-01-12 18:12:18 -07001241 if (fDisallowSelfIntersection && !SkPathFillType_IsEvenOdd(fPath.getFillType())) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001242 maxWindMagnitude = 1;
1243 }
ethannicholase9709e82016-01-07 13:34:16 -08001244 EdgeList activeEdges;
1245 Poly* polys = nullptr;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001246 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
Chris Dalton24472af2021-01-11 20:05:00 -07001247 if (!v->isConnected()) {
ethannicholase9709e82016-01-07 13:34:16 -08001248 continue;
1249 }
Chris Dalton5045de32021-01-07 19:09:01 -07001250#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001251 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 -08001252#endif
Stephen White8a0bfc52017-02-21 15:24:13 -05001253 Edge* leftEnclosingEdge;
1254 Edge* rightEnclosingEdge;
Chris Dalton47114db2021-01-06 00:35:20 -07001255 FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White8a0bfc52017-02-21 15:24:13 -05001256 Poly* leftPoly;
1257 Poly* rightPoly;
ethannicholase9709e82016-01-07 13:34:16 -08001258 if (v->fFirstEdgeAbove) {
1259 leftPoly = v->fFirstEdgeAbove->fLeftPoly;
1260 rightPoly = v->fLastEdgeAbove->fRightPoly;
1261 } else {
1262 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr;
1263 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr;
1264 }
Chris Dalton5045de32021-01-07 19:09:01 -07001265#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001266 TESS_LOG("edges above:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001267 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001268 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1269 e->fTop->fID, e->fBottom->fID,
1270 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1271 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001272 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001273 TESS_LOG("edges below:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001274 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001275 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1276 e->fTop->fID, e->fBottom->fID,
1277 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1278 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001279 }
1280#endif
1281 if (v->fFirstEdgeAbove) {
1282 if (leftPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001283 leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, kRight_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001284 }
1285 if (rightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001286 rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001287 }
1288 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -08001289 Edge* rightEdge = e->fNextEdgeAbove;
Chris Dalton24472af2021-01-11 20:05:00 -07001290 activeEdges.remove(e);
Stephen White8a0bfc52017-02-21 15:24:13 -05001291 if (e->fRightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001292 e->fRightPoly->addEdge(e, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001293 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001294 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001295 rightEdge->fLeftPoly->addEdge(e, kRight_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001296 }
1297 }
Chris Dalton24472af2021-01-11 20:05:00 -07001298 activeEdges.remove(v->fLastEdgeAbove);
ethannicholase9709e82016-01-07 13:34:16 -08001299 if (!v->fFirstEdgeBelow) {
1300 if (leftPoly && rightPoly && leftPoly != rightPoly) {
1301 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr);
1302 rightPoly->fPartner = leftPoly;
1303 leftPoly->fPartner = rightPoly;
1304 }
1305 }
1306 }
1307 if (v->fFirstEdgeBelow) {
1308 if (!v->fFirstEdgeAbove) {
senorblanco93e3fff2016-06-07 12:36:00 -07001309 if (leftPoly && rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001310 if (leftPoly == rightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001311 if (leftPoly->fTail && leftPoly->fTail->fSide == kLeft_Side) {
Chris Dalton7cf3add2021-01-11 18:33:28 -07001312 leftPoly = this->makePoly(&polys, leftPoly->lastVertex(),
1313 leftPoly->fWinding);
senorblanco531237e2016-06-02 11:36:48 -07001314 leftEnclosingEdge->fRightPoly = leftPoly;
1315 } else {
Chris Dalton7cf3add2021-01-11 18:33:28 -07001316 rightPoly = this->makePoly(&polys, rightPoly->lastVertex(),
1317 rightPoly->fWinding);
senorblanco531237e2016-06-02 11:36:48 -07001318 rightEnclosingEdge->fLeftPoly = rightPoly;
1319 }
ethannicholase9709e82016-01-07 13:34:16 -08001320 }
Chris Dalton8a42b092021-01-21 22:09:26 -07001321 Edge* join = fAlloc->make<Edge>(leftPoly->lastVertex(), v, 1,
Chris Dalton17ce8c52021-01-07 18:08:46 -07001322 EdgeType::kInner);
1323 leftPoly = leftPoly->addEdge(join, kRight_Side, fAlloc);
1324 rightPoly = rightPoly->addEdge(join, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001325 }
1326 }
1327 Edge* leftEdge = v->fFirstEdgeBelow;
1328 leftEdge->fLeftPoly = leftPoly;
Chris Dalton24472af2021-01-11 20:05:00 -07001329 activeEdges.insert(leftEdge, leftEnclosingEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001330 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge;
1331 rightEdge = rightEdge->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -07001332 activeEdges.insert(rightEdge, leftEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001333 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0;
1334 winding += leftEdge->fWinding;
1335 if (winding != 0) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001336 if (abs(winding) > maxWindMagnitude) {
1337 return nullptr; // We can't have weighted wind in kSimpleInnerPolygons mode
1338 }
Chris Dalton7cf3add2021-01-11 18:33:28 -07001339 Poly* poly = this->makePoly(&polys, v, winding);
ethannicholase9709e82016-01-07 13:34:16 -08001340 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly;
1341 }
1342 leftEdge = rightEdge;
1343 }
1344 v->fLastEdgeBelow->fRightPoly = rightPoly;
1345 }
Chris Dalton5045de32021-01-07 19:09:01 -07001346#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001347 TESS_LOG("\nactive edges:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001348 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001349 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1350 e->fTop->fID, e->fBottom->fID,
1351 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1352 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001353 }
1354#endif
1355 }
1356 return polys;
1357}
1358
Stephen Whitebda29c02017-03-13 15:10:13 -04001359// This is a driver function that calls stages 2-5 in turn.
ethannicholase9709e82016-01-07 13:34:16 -08001360
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001361void GrTriangulator::contoursToMesh(VertexList* contours, int contourCnt, VertexList* mesh,
Chris Dalton330cfa42021-01-27 18:24:48 -07001362 const Comparator& c,
1363 BreadcrumbTriangleList* breadcrumbList) const {
Chris Dalton5045de32021-01-07 19:09:01 -07001364#if TRIANGULATOR_LOGGING
ethannicholase9709e82016-01-07 13:34:16 -08001365 for (int i = 0; i < contourCnt; ++i) {
Stephen White3a9aab92017-03-07 14:07:18 -05001366 Vertex* v = contours[i].fHead;
ethannicholase9709e82016-01-07 13:34:16 -08001367 SkASSERT(v);
Brian Salomon120e7d62019-09-11 10:29:22 -04001368 TESS_LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001369 for (v = v->fNext; v; v = v->fNext) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001370 TESS_LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
ethannicholase9709e82016-01-07 13:34:16 -08001371 }
1372 }
1373#endif
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001374 this->sanitizeContours(contours, contourCnt);
Chris Dalton330cfa42021-01-27 18:24:48 -07001375 this->buildEdges(contours, contourCnt, mesh, c, breadcrumbList);
senorblancof57372d2016-08-31 10:36:19 -07001376}
1377
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001378void GrTriangulator::SortMesh(VertexList* vertices, const Comparator& c) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001379 if (!vertices || !vertices->fHead) {
Stephen White2f4686f2017-01-03 16:20:01 -05001380 return;
ethannicholase9709e82016-01-07 13:34:16 -08001381 }
1382
1383 // Sort vertices in Y (secondarily in X).
Stephen White16a40cb2017-02-23 11:10:01 -05001384 if (c.fDirection == Comparator::Direction::kHorizontal) {
1385 merge_sort<sweep_lt_horiz>(vertices);
1386 } else {
1387 merge_sort<sweep_lt_vert>(vertices);
1388 }
Chris Dalton5045de32021-01-07 19:09:01 -07001389#if TRIANGULATOR_LOGGING
Stephen White2e2cb9b2017-01-09 13:11:18 -05001390 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001391 static float gID = 0.0f;
1392 v->fID = gID++;
1393 }
1394#endif
Stephen White2f4686f2017-01-03 16:20:01 -05001395}
1396
Chris Dalton330cfa42021-01-27 18:24:48 -07001397Poly* GrTriangulator::contoursToPolys(VertexList* contours, int contourCnt,
1398 BreadcrumbTriangleList* breadcrumbList) const {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001399 const SkRect& pathBounds = fPath.getBounds();
Stephen White16a40cb2017-02-23 11:10:01 -05001400 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
1401 : Comparator::Direction::kVertical);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001402 VertexList mesh;
Chris Dalton330cfa42021-01-27 18:24:48 -07001403 this->contoursToMesh(contours, contourCnt, &mesh, c, breadcrumbList);
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001404 SortMesh(&mesh, c);
Chris Dalton330cfa42021-01-27 18:24:48 -07001405 this->mergeCoincidentVertices(&mesh, c, breadcrumbList);
1406 if (SimplifyResult::kAbort == this->simplify(&mesh, c, breadcrumbList)) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001407 return nullptr;
1408 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001409 TESS_LOG("\nsimplified mesh:\n");
Chris Dalton7cf3add2021-01-11 18:33:28 -07001410 DUMP_MESH(mesh);
Chris Dalton93c2d812021-01-11 19:51:59 -07001411 return this->tessellate(mesh, c);
Chris Dalton7cf3add2021-01-11 18:33:28 -07001412}
1413
senorblancof57372d2016-08-31 10:36:19 -07001414// Stage 6: Triangulate the monotone polygons into a vertex buffer.
Chris Dalton330cfa42021-01-27 18:24:48 -07001415void* GrTriangulator::polysToTriangles(Poly* polys, void* data,
1416 BreadcrumbTriangleList* breadcrumbList,
1417 SkPathFillType overrideFillType) const {
senorblancof57372d2016-08-31 10:36:19 -07001418 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001419 if (apply_fill_type(overrideFillType, poly)) {
Chris Dalton330cfa42021-01-27 18:24:48 -07001420 data = this->emitPoly(poly, data, breadcrumbList);
senorblancof57372d2016-08-31 10:36:19 -07001421 }
1422 }
1423 return data;
ethannicholase9709e82016-01-07 13:34:16 -08001424}
1425
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001426static int get_contour_count(const SkPath& path, SkScalar tolerance) {
Chris Daltonc71b3d42020-01-08 21:29:59 -07001427 // We could theoretically be more aggressive about not counting empty contours, but we need to
1428 // actually match the exact number of contour linked lists the tessellator will create later on.
1429 int contourCnt = 1;
1430 bool hasPoints = false;
1431
Chris Dalton7156db22020-05-07 22:06:28 +00001432 SkPath::Iter iter(path, false);
1433 SkPath::Verb verb;
1434 SkPoint pts[4];
Chris Daltonc71b3d42020-01-08 21:29:59 -07001435 bool first = true;
Chris Dalton7156db22020-05-07 22:06:28 +00001436 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
Chris Daltonc71b3d42020-01-08 21:29:59 -07001437 switch (verb) {
Chris Dalton7156db22020-05-07 22:06:28 +00001438 case SkPath::kMove_Verb:
Chris Daltonc71b3d42020-01-08 21:29:59 -07001439 if (!first) {
1440 ++contourCnt;
1441 }
John Stiles30212b72020-06-11 17:55:07 -04001442 [[fallthrough]];
Chris Dalton7156db22020-05-07 22:06:28 +00001443 case SkPath::kLine_Verb:
1444 case SkPath::kConic_Verb:
1445 case SkPath::kQuad_Verb:
1446 case SkPath::kCubic_Verb:
Chris Daltonc71b3d42020-01-08 21:29:59 -07001447 hasPoints = true;
John Stiles30212b72020-06-11 17:55:07 -04001448 break;
Chris Daltonc71b3d42020-01-08 21:29:59 -07001449 default:
1450 break;
1451 }
1452 first = false;
1453 }
1454 if (!hasPoints) {
Stephen White11f65e02017-02-16 19:00:39 -05001455 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001456 }
Stephen White11f65e02017-02-16 19:00:39 -05001457 return contourCnt;
ethannicholase9709e82016-01-07 13:34:16 -08001458}
1459
Chris Dalton330cfa42021-01-27 18:24:48 -07001460Poly* GrTriangulator::pathToPolys(float tolerance, const SkRect& clipBounds,
1461 BreadcrumbTriangleList* breadcrumbList, bool* isLinear) const {
Chris Daltond5384792021-01-20 15:43:24 -07001462 int contourCnt = get_contour_count(fPath, tolerance);
1463 if (contourCnt <= 0) {
Chris Dalton37d16f12021-01-20 18:32:48 -07001464 *isLinear = true;
Chris Daltond5384792021-01-20 15:43:24 -07001465 return nullptr;
1466 }
1467
1468 if (SkPathFillType_IsInverse(fPath.getFillType())) {
1469 contourCnt++;
1470 }
1471 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
1472
Chris Dalton37d16f12021-01-20 18:32:48 -07001473 this->pathToContours(tolerance, clipBounds, contours.get(), isLinear);
Chris Dalton330cfa42021-01-27 18:24:48 -07001474 return this->contoursToPolys(contours.get(), contourCnt, breadcrumbList);
Chris Daltond5384792021-01-20 15:43:24 -07001475}
1476
1477int64_t GrTriangulator::CountPoints(Poly* polys, SkPathFillType overrideFillType) {
Greg Danield5b45932018-06-07 13:15:10 -04001478 int64_t count = 0;
ethannicholase9709e82016-01-07 13:34:16 -08001479 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton93c2d812021-01-11 19:51:59 -07001480 if (apply_fill_type(overrideFillType, poly) && poly->fCount >= 3) {
Chris Dalton17dc4182020-03-25 16:18:16 -06001481 count += (poly->fCount - 2) * (TRIANGULATOR_WIREFRAME ? 6 : 3);
ethannicholase9709e82016-01-07 13:34:16 -08001482 }
1483 }
1484 return count;
1485}
1486
ethannicholase9709e82016-01-07 13:34:16 -08001487// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1488
Chris Dalton330cfa42021-01-27 18:24:48 -07001489int GrTriangulator::polysToTriangles(Poly* polys, GrEagerVertexAllocator* vertexAllocator,
1490 BreadcrumbTriangleList* breadcrumbList) const {
Chris Daltond5384792021-01-20 15:43:24 -07001491 int64_t count64 = CountPoints(polys, fPath.getFillType());
Greg Danield5b45932018-06-07 13:15:10 -04001492 if (0 == count64 || count64 > SK_MaxS32) {
Stephen Whiteff60b172017-05-05 15:54:52 -04001493 return 0;
1494 }
Greg Danield5b45932018-06-07 13:15:10 -04001495 int count = count64;
ethannicholase9709e82016-01-07 13:34:16 -08001496
Chris Dalton854ee852021-01-05 15:12:59 -07001497 size_t vertexStride = sizeof(SkPoint);
1498 if (fEmitCoverage) {
1499 vertexStride += sizeof(float);
1500 }
Chris Daltond081dce2020-01-23 12:09:04 -07001501 void* verts = vertexAllocator->lock(vertexStride, count);
senorblanco6599eff2016-03-10 08:38:45 -08001502 if (!verts) {
ethannicholase9709e82016-01-07 13:34:16 -08001503 SkDebugf("Could not allocate vertices\n");
1504 return 0;
1505 }
senorblancof57372d2016-08-31 10:36:19 -07001506
Brian Salomon120e7d62019-09-11 10:29:22 -04001507 TESS_LOG("emitting %d verts\n", count);
Chris Dalton330cfa42021-01-27 18:24:48 -07001508 void* end = this->polysToTriangles(polys, verts, breadcrumbList, fPath.getFillType());
Brian Osman80879d42019-01-07 16:15:27 -05001509
senorblancof57372d2016-08-31 10:36:19 -07001510 int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
Chris Daltond081dce2020-01-23 12:09:04 -07001511 / vertexStride);
ethannicholase9709e82016-01-07 13:34:16 -08001512 SkASSERT(actualCount <= count);
senorblanco6599eff2016-03-10 08:38:45 -08001513 vertexAllocator->unlock(actualCount);
ethannicholase9709e82016-01-07 13:34:16 -08001514 return actualCount;
1515}
1516
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001517int GrTriangulator::PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
1518 WindingVertex** verts) {
Chris Dalton8a42b092021-01-21 22:09:26 -07001519 SkArenaAlloc alloc(kArenaDefaultChunkSize);
1520 GrTriangulator triangulator(path, &alloc);
Chris Dalton37d16f12021-01-20 18:32:48 -07001521 bool isLinear;
Chris Dalton330cfa42021-01-27 18:24:48 -07001522 Poly* polys = triangulator.pathToPolys(tolerance, clipBounds, nullptr, &isLinear);
Chris Daltond5384792021-01-20 15:43:24 -07001523 int64_t count64 = CountPoints(polys, path.getFillType());
Greg Danield5b45932018-06-07 13:15:10 -04001524 if (0 == count64 || count64 > SK_MaxS32) {
ethannicholase9709e82016-01-07 13:34:16 -08001525 *verts = nullptr;
1526 return 0;
1527 }
Greg Danield5b45932018-06-07 13:15:10 -04001528 int count = count64;
ethannicholase9709e82016-01-07 13:34:16 -08001529
Chris Dalton17dc4182020-03-25 16:18:16 -06001530 *verts = new WindingVertex[count];
1531 WindingVertex* vertsEnd = *verts;
ethannicholase9709e82016-01-07 13:34:16 -08001532 SkPoint* points = new SkPoint[count];
1533 SkPoint* pointsEnd = points;
1534 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton93c2d812021-01-11 19:51:59 -07001535 if (apply_fill_type(path.getFillType(), poly)) {
ethannicholase9709e82016-01-07 13:34:16 -08001536 SkPoint* start = pointsEnd;
Chris Dalton330cfa42021-01-27 18:24:48 -07001537 pointsEnd = static_cast<SkPoint*>(triangulator.emitPoly(poly, pointsEnd, nullptr));
ethannicholase9709e82016-01-07 13:34:16 -08001538 while (start != pointsEnd) {
1539 vertsEnd->fPos = *start;
1540 vertsEnd->fWinding = poly->fWinding;
1541 ++start;
1542 ++vertsEnd;
1543 }
1544 }
1545 }
1546 int actualCount = static_cast<int>(vertsEnd - *verts);
1547 SkASSERT(actualCount <= count);
1548 SkASSERT(pointsEnd - points == actualCount);
1549 delete[] points;
1550 return actualCount;
1551}