blob: a9d897ab98ce402c6ea0ce907b9d11ef8ba9c15d [file] [log] [blame]
ethannicholase9709e82016-01-07 13:34:16 -08001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Chris Dalton17dc4182020-03-25 16:18:16 -06008#include "src/gpu/GrTriangulator.h"
ethannicholase9709e82016-01-07 13:34:16 -08009
Chris Daltond081dce2020-01-23 12:09:04 -070010#include "src/gpu/GrEagerVertexAllocator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/gpu/GrVertexWriter.h"
Michael Ludwig663afe52019-06-03 16:46:19 -040012#include "src/gpu/geometry/GrPathUtils.h"
Chris Daltond60c9192021-01-07 18:30:08 +000013
14#include "src/core/SkGeometry.h"
15#include "src/core/SkPointPriv.h"
16
Stephen White94b7e542018-01-04 14:01:10 -050017#include <algorithm>
ethannicholase9709e82016-01-07 13:34:16 -080018
Chris Daltond60c9192021-01-07 18:30:08 +000019
Chris Dalton5045de32021-01-07 19:09:01 -070020#if TRIANGULATOR_LOGGING
Chris Daltond60c9192021-01-07 18:30:08 +000021#define TESS_LOG printf
Chris Dalton24472af2021-01-11 20:05:00 -070022#define DUMP_MESH(M) (M).dump()
ethannicholase9709e82016-01-07 13:34:16 -080023#else
Brian Salomon120e7d62019-09-11 10:29:22 -040024#define TESS_LOG(...)
Chris Dalton7cf3add2021-01-11 18:33:28 -070025#define DUMP_MESH(M)
ethannicholase9709e82016-01-07 13:34:16 -080026#endif
27
Chris Dalton17ce8c52021-01-07 18:08:46 -070028using EdgeType = GrTriangulator::EdgeType;
Chris Dalton57ea1fc2021-01-05 13:37:44 -070029using Vertex = GrTriangulator::Vertex;
30using VertexList = GrTriangulator::VertexList;
Chris Dalton17ce8c52021-01-07 18:08:46 -070031using Line = GrTriangulator::Line;
Chris Dalton57ea1fc2021-01-05 13:37:44 -070032using Edge = GrTriangulator::Edge;
33using EdgeList = GrTriangulator::EdgeList;
34using Poly = GrTriangulator::Poly;
Chris Dalton17ce8c52021-01-07 18:08:46 -070035using MonotonePoly = GrTriangulator::MonotonePoly;
Chris Dalton57ea1fc2021-01-05 13:37:44 -070036using Comparator = GrTriangulator::Comparator;
ethannicholase9709e82016-01-07 13:34:16 -080037
38template <class T, T* T::*Prev, T* T::*Next>
Chris Dalton57ea1fc2021-01-05 13:37:44 -070039static void list_insert(T* t, T* prev, T* next, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -080040 t->*Prev = prev;
41 t->*Next = next;
42 if (prev) {
43 prev->*Next = t;
44 } else if (head) {
45 *head = t;
46 }
47 if (next) {
48 next->*Prev = t;
49 } else if (tail) {
50 *tail = t;
51 }
52}
53
54template <class T, T* T::*Prev, T* T::*Next>
Chris Dalton57ea1fc2021-01-05 13:37:44 -070055static void list_remove(T* t, T** head, T** tail) {
ethannicholase9709e82016-01-07 13:34:16 -080056 if (t->*Prev) {
57 t->*Prev->*Next = t->*Next;
58 } else if (head) {
59 *head = t->*Next;
60 }
61 if (t->*Next) {
62 t->*Next->*Prev = t->*Prev;
63 } else if (tail) {
64 *tail = t->*Prev;
65 }
66 t->*Prev = t->*Next = nullptr;
67}
68
ethannicholase9709e82016-01-07 13:34:16 -080069typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b);
70
Chris Dalton57ea1fc2021-01-05 13:37:44 -070071static bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -050072 return a.fX < b.fX || (a.fX == b.fX && a.fY > b.fY);
ethannicholase9709e82016-01-07 13:34:16 -080073}
74
Chris Dalton57ea1fc2021-01-05 13:37:44 -070075static bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) {
Stephen White16a40cb2017-02-23 11:10:01 -050076 return a.fY < b.fY || (a.fY == b.fY && a.fX < b.fX);
ethannicholase9709e82016-01-07 13:34:16 -080077}
78
Chris Dalton5045de32021-01-07 19:09:01 -070079bool GrTriangulator::Comparator::sweep_lt(const SkPoint& a, const SkPoint& b) const {
80 return fDirection == Direction::kHorizontal ? sweep_lt_horiz(a, b) : sweep_lt_vert(a, b);
81}
Stephen White16a40cb2017-02-23 11:10:01 -050082
Chris Daltond60c9192021-01-07 18:30:08 +000083static inline void* emit_vertex(Vertex* v, bool emitCoverage, void* data) {
Brian Osmanf9aabff2018-11-13 16:11:38 -050084 GrVertexWriter verts{data};
85 verts.write(v->fPoint);
86
Brian Osman80879d42019-01-07 16:15:27 -050087 if (emitCoverage) {
88 verts.write(GrNormalizeByteToFloat(v->fAlpha));
89 }
Brian Osman0995fd52019-01-09 09:52:25 -050090
Brian Osmanf9aabff2018-11-13 16:11:38 -050091 return verts.fPtr;
ethannicholase9709e82016-01-07 13:34:16 -080092}
93
Chris Daltond60c9192021-01-07 18:30:08 +000094static void* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, bool emitCoverage, void* data) {
Brian Salomon120e7d62019-09-11 10:29:22 -040095 TESS_LOG("emit_triangle %g (%g, %g) %d\n", v0->fID, v0->fPoint.fX, v0->fPoint.fY, v0->fAlpha);
96 TESS_LOG(" %g (%g, %g) %d\n", v1->fID, v1->fPoint.fX, v1->fPoint.fY, v1->fAlpha);
97 TESS_LOG(" %g (%g, %g) %d\n", v2->fID, v2->fPoint.fX, v2->fPoint.fY, v2->fAlpha);
senorblancof57372d2016-08-31 10:36:19 -070098#if TESSELLATOR_WIREFRAME
Brian Osman0995fd52019-01-09 09:52:25 -050099 data = emit_vertex(v0, emitCoverage, data);
100 data = emit_vertex(v1, emitCoverage, data);
101 data = emit_vertex(v1, emitCoverage, data);
102 data = emit_vertex(v2, emitCoverage, data);
103 data = emit_vertex(v2, emitCoverage, data);
104 data = emit_vertex(v0, emitCoverage, data);
ethannicholase9709e82016-01-07 13:34:16 -0800105#else
Brian Osman0995fd52019-01-09 09:52:25 -0500106 data = emit_vertex(v0, emitCoverage, data);
107 data = emit_vertex(v1, emitCoverage, data);
108 data = emit_vertex(v2, emitCoverage, data);
ethannicholase9709e82016-01-07 13:34:16 -0800109#endif
110 return data;
111}
112
Chris Dalton5045de32021-01-07 19:09:01 -0700113void GrTriangulator::VertexList::insert(Vertex* v, Vertex* prev, Vertex* next) {
114 list_insert<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, prev, next, &fHead, &fTail);
115}
116
117void GrTriangulator::VertexList::remove(Vertex* v) {
118 list_remove<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, &fHead, &fTail);
119}
senorblancoe6eaa322016-03-08 09:06:44 -0800120
senorblancof57372d2016-08-31 10:36:19 -0700121// Round to nearest quarter-pixel. This is used for screenspace tessellation.
122
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700123static inline void round(SkPoint* p) {
senorblancof57372d2016-08-31 10:36:19 -0700124 p->fX = SkScalarRoundToScalar(p->fX * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
125 p->fY = SkScalarRoundToScalar(p->fY * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f);
126}
127
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700128static inline SkScalar double_to_clamped_scalar(double d) {
Stephen White94b7e542018-01-04 14:01:10 -0500129 return SkDoubleToScalar(std::min((double) SK_ScalarMax, std::max(d, (double) -SK_ScalarMax)));
130}
131
Chris Dalton5045de32021-01-07 19:09:01 -0700132bool GrTriangulator::Line::intersect(const Line& other, SkPoint* point) const {
133 double denom = fA * other.fB - fB * other.fA;
134 if (denom == 0.0) {
135 return false;
senorblanco49df8d12016-10-07 08:36:56 -0700136 }
Chris Dalton5045de32021-01-07 19:09:01 -0700137 double scale = 1.0 / denom;
138 point->fX = double_to_clamped_scalar((fB * other.fC - other.fB * fC) * scale);
139 point->fY = double_to_clamped_scalar((other.fA * fC - fA * other.fC) * scale);
140 round(point);
141 return point->isFinite();
142}
Chris Daltond60c9192021-01-07 18:30:08 +0000143
Chris Dalton5045de32021-01-07 19:09:01 -0700144bool GrTriangulator::Edge::intersect(const Edge& other, SkPoint* p, uint8_t* alpha) const {
145 TESS_LOG("intersecting %g -> %g with %g -> %g\n",
146 fTop->fID, fBottom->fID, other.fTop->fID, other.fBottom->fID);
147 if (fTop == other.fTop || fBottom == other.fBottom) {
148 return false;
Chris Daltond60c9192021-01-07 18:30:08 +0000149 }
Chris Dalton5045de32021-01-07 19:09:01 -0700150 double denom = fLine.fA * other.fLine.fB - fLine.fB * other.fLine.fA;
151 if (denom == 0.0) {
152 return false;
Chris Daltond60c9192021-01-07 18:30:08 +0000153 }
Chris Dalton5045de32021-01-07 19:09:01 -0700154 double dx = static_cast<double>(other.fTop->fPoint.fX) - fTop->fPoint.fX;
155 double dy = static_cast<double>(other.fTop->fPoint.fY) - fTop->fPoint.fY;
156 double sNumer = dy * other.fLine.fB + dx * other.fLine.fA;
157 double tNumer = dy * fLine.fB + dx * fLine.fA;
158 // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early.
159 // This saves us doing the divide below unless absolutely necessary.
160 if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom)
161 : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNumer < denom)) {
162 return false;
Chris Daltond60c9192021-01-07 18:30:08 +0000163 }
Chris Dalton5045de32021-01-07 19:09:01 -0700164 double s = sNumer / denom;
165 SkASSERT(s >= 0.0 && s <= 1.0);
166 p->fX = SkDoubleToScalar(fTop->fPoint.fX - s * fLine.fB);
167 p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fLine.fA);
168 if (alpha) {
169 if (fType == EdgeType::kConnector) {
170 *alpha = (1.0 - s) * fTop->fAlpha + s * fBottom->fAlpha;
171 } else if (other.fType == EdgeType::kConnector) {
172 double t = tNumer / denom;
173 *alpha = (1.0 - t) * other.fTop->fAlpha + t * other.fBottom->fAlpha;
174 } else if (fType == EdgeType::kOuter && other.fType == EdgeType::kOuter) {
175 *alpha = 0;
176 } else {
177 *alpha = 255;
178 }
Chris Daltond60c9192021-01-07 18:30:08 +0000179 }
Chris Dalton5045de32021-01-07 19:09:01 -0700180 return true;
181}
senorblancof57372d2016-08-31 10:36:19 -0700182
Chris Dalton5045de32021-01-07 19:09:01 -0700183void GrTriangulator::EdgeList::insert(Edge* edge, Edge* prev, Edge* next) {
184 list_insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &fHead, &fTail);
185}
Chris Dalton24472af2021-01-11 20:05:00 -0700186
Chris Dalton5045de32021-01-07 19:09:01 -0700187void GrTriangulator::EdgeList::remove(Edge* edge) {
Chris Dalton24472af2021-01-11 20:05:00 -0700188 TESS_LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
189 SkASSERT(this->contains(edge));
Chris Dalton5045de32021-01-07 19:09:01 -0700190 list_remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &fHead, &fTail);
191}
ethannicholase9709e82016-01-07 13:34:16 -0800192
Chris Dalton5045de32021-01-07 19:09:01 -0700193void GrTriangulator::MonotonePoly::addEdge(Edge* edge) {
194 if (fSide == kRight_Side) {
195 SkASSERT(!edge->fUsedInRightPoly);
196 list_insert<Edge, &Edge::fRightPolyPrev, &Edge::fRightPolyNext>(
197 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
198 edge->fUsedInRightPoly = true;
199 } else {
200 SkASSERT(!edge->fUsedInLeftPoly);
201 list_insert<Edge, &Edge::fLeftPolyPrev, &Edge::fLeftPolyNext>(
202 edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge);
203 edge->fUsedInLeftPoly = true;
Chris Dalton17ce8c52021-01-07 18:08:46 -0700204 }
Chris Dalton5045de32021-01-07 19:09:01 -0700205}
Chris Dalton17ce8c52021-01-07 18:08:46 -0700206
Chris Dalton9a4904f2021-01-07 19:10:14 -0700207void* GrTriangulator::emitMonotonePoly(const MonotonePoly* monotonePoly, void* data) {
Chris Dalton93c2d812021-01-11 19:51:59 -0700208 SkASSERT(monotonePoly->fWinding != 0);
Chris Dalton9a4904f2021-01-07 19:10:14 -0700209 Edge* e = monotonePoly->fFirstEdge;
Chris Dalton5045de32021-01-07 19:09:01 -0700210 VertexList vertices;
211 vertices.append(e->fTop);
212 int count = 1;
213 while (e != nullptr) {
Chris Dalton9a4904f2021-01-07 19:10:14 -0700214 if (kRight_Side == monotonePoly->fSide) {
Chris Dalton5045de32021-01-07 19:09:01 -0700215 vertices.append(e->fBottom);
216 e = e->fRightPolyNext;
217 } else {
218 vertices.prepend(e->fBottom);
219 e = e->fLeftPolyNext;
Chris Dalton17ce8c52021-01-07 18:08:46 -0700220 }
Chris Dalton5045de32021-01-07 19:09:01 -0700221 count++;
222 }
223 Vertex* first = vertices.fHead;
224 Vertex* v = first->fNext;
225 while (v != vertices.fTail) {
226 SkASSERT(v && v->fPrev && v->fNext);
227 Vertex* prev = v->fPrev;
228 Vertex* curr = v;
229 Vertex* next = v->fNext;
230 if (count == 3) {
Chris Dalton9a4904f2021-01-07 19:10:14 -0700231 return this->emitTriangle(prev, curr, next, monotonePoly->fWinding, data);
Chris Dalton5045de32021-01-07 19:09:01 -0700232 }
233 double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX;
234 double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY;
235 double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX;
236 double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY;
237 if (ax * by - ay * bx >= 0.0) {
Chris Dalton9a4904f2021-01-07 19:10:14 -0700238 data = this->emitTriangle(prev, curr, next, monotonePoly->fWinding, data);
Chris Dalton5045de32021-01-07 19:09:01 -0700239 v->fPrev->fNext = v->fNext;
240 v->fNext->fPrev = v->fPrev;
241 count--;
242 if (v->fPrev == first) {
Chris Dalton17ce8c52021-01-07 18:08:46 -0700243 v = v->fNext;
Chris Daltond60c9192021-01-07 18:30:08 +0000244 } else {
Chris Dalton5045de32021-01-07 19:09:01 -0700245 v = v->fPrev;
Chris Daltond60c9192021-01-07 18:30:08 +0000246 }
Chris Dalton5045de32021-01-07 19:09:01 -0700247 } else {
248 v = v->fNext;
Chris Daltond60c9192021-01-07 18:30:08 +0000249 }
Chris Dalton75887a22021-01-06 00:23:13 -0700250 }
Chris Dalton5045de32021-01-07 19:09:01 -0700251 return data;
252}
253
Chris Dalton9a4904f2021-01-07 19:10:14 -0700254void* GrTriangulator::emitTriangle(Vertex* prev, Vertex* curr, Vertex* next, int winding,
255 void* data) const {
Chris Dalton93c2d812021-01-11 19:51:59 -0700256 if (winding > 0) {
Chris Dalton5045de32021-01-07 19:09:01 -0700257 // Ensure our triangles always wind in the same direction as if the path had been
258 // triangulated as a simple fan (a la red book).
259 std::swap(prev, next);
260 }
Chris Dalton93c2d812021-01-11 19:51:59 -0700261 return emit_triangle(prev, curr, next, fEmitCoverage, data);
Chris Dalton5045de32021-01-07 19:09:01 -0700262}
263
264Poly* GrTriangulator::Poly::addEdge(Edge* e, Side side, SkArenaAlloc& alloc) {
265 TESS_LOG("addEdge (%g -> %g) to poly %d, %s side\n",
266 e->fTop->fID, e->fBottom->fID, fID, side == kLeft_Side ? "left" : "right");
267 Poly* partner = fPartner;
268 Poly* poly = this;
269 if (side == kRight_Side) {
270 if (e->fUsedInRightPoly) {
271 return this;
Chris Daltond60c9192021-01-07 18:30:08 +0000272 }
Chris Dalton5045de32021-01-07 19:09:01 -0700273 } else {
274 if (e->fUsedInLeftPoly) {
275 return this;
Chris Daltond60c9192021-01-07 18:30:08 +0000276 }
Chris Dalton5045de32021-01-07 19:09:01 -0700277 }
278 if (partner) {
279 fPartner = partner->fPartner = nullptr;
280 }
281 if (!fTail) {
282 fHead = fTail = alloc.make<MonotonePoly>(e, side, fWinding);
283 fCount += 2;
284 } else if (e->fBottom == fTail->fLastEdge->fBottom) {
285 return poly;
286 } else if (side == fTail->fSide) {
287 fTail->addEdge(e);
288 fCount++;
289 } else {
290 e = alloc.make<Edge>(fTail->fLastEdge->fBottom, e->fBottom, 1, EdgeType::kInner);
291 fTail->addEdge(e);
292 fCount++;
293 if (partner) {
294 partner->addEdge(e, side, alloc);
295 poly = partner;
296 } else {
297 MonotonePoly* m = alloc.make<MonotonePoly>(e, side, fWinding);
298 m->fPrev = fTail;
299 fTail->fNext = m;
300 fTail = m;
301 }
302 }
303 return poly;
304}
Chris Dalton9a4904f2021-01-07 19:10:14 -0700305void* GrTriangulator::emitPoly(const Poly* poly, void *data) {
306 if (poly->fCount < 3) {
ethannicholase9709e82016-01-07 13:34:16 -0800307 return data;
308 }
Chris Dalton5045de32021-01-07 19:09:01 -0700309 TESS_LOG("emit() %d, size %d\n", fID, fCount);
Chris Dalton9a4904f2021-01-07 19:10:14 -0700310 for (MonotonePoly* m = poly->fHead; m != nullptr; m = m->fNext) {
311 data = this->emitMonotonePoly(m, data);
Chris Dalton5045de32021-01-07 19:09:01 -0700312 }
313 return data;
314}
ethannicholase9709e82016-01-07 13:34:16 -0800315
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700316static bool coincident(const SkPoint& a, const SkPoint& b) {
ethannicholase9709e82016-01-07 13:34:16 -0800317 return a == b;
318}
319
Chris Dalton7cf3add2021-01-11 18:33:28 -0700320Poly* GrTriangulator::makePoly(Poly** head, Vertex* v, int winding) {
321 Poly* poly = fAlloc.make<Poly>(v, winding);
ethannicholase9709e82016-01-07 13:34:16 -0800322 poly->fNext = *head;
323 *head = poly;
324 return poly;
325}
326
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700327void GrTriangulator::appendPointToContour(const SkPoint& p, VertexList* contour) {
328 Vertex* v = fAlloc.make<Vertex>(p, 255);
Chris Dalton5045de32021-01-07 19:09:01 -0700329#if TRIANGULATOR_LOGGING
ethannicholase9709e82016-01-07 13:34:16 -0800330 static float gID = 0.0f;
331 v->fID = gID++;
332#endif
Stephen White3a9aab92017-03-07 14:07:18 -0500333 contour->append(v);
ethannicholase9709e82016-01-07 13:34:16 -0800334}
335
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700336static SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u) {
Stephen White36e4f062017-03-27 16:11:31 -0400337 SkQuadCoeff quad(pts);
338 SkPoint p0 = to_point(quad.eval(t - 0.5f * u));
339 SkPoint mid = to_point(quad.eval(t));
340 SkPoint p1 = to_point(quad.eval(t + 0.5f * u));
Stephen Whitee3a0be72017-06-12 11:43:18 -0400341 if (!p0.isFinite() || !mid.isFinite() || !p1.isFinite()) {
342 return 0;
343 }
Cary Clarkdf429f32017-11-08 11:44:31 -0500344 return SkPointPriv::DistanceToLineSegmentBetweenSqd(mid, p0, p1);
Stephen White36e4f062017-03-27 16:11:31 -0400345}
346
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700347void GrTriangulator::appendQuadraticToContour(const SkPoint pts[3], SkScalar toleranceSqd,
348 VertexList* contour) {
Stephen White36e4f062017-03-27 16:11:31 -0400349 SkQuadCoeff quad(pts);
350 Sk2s aa = quad.fA * quad.fA;
351 SkScalar denom = 2.0f * (aa[0] + aa[1]);
352 Sk2s ab = quad.fA * quad.fB;
353 SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f;
354 int nPoints = 1;
Stephen Whitee40c3612018-01-09 11:49:08 -0500355 SkScalar u = 1.0f;
Stephen White36e4f062017-03-27 16:11:31 -0400356 // Test possible subdivision values only at the point of maximum curvature.
357 // If it passes the flatness metric there, it'll pass everywhere.
Stephen Whitee40c3612018-01-09 11:49:08 -0500358 while (nPoints < GrPathUtils::kMaxPointsPerCurve) {
Stephen White36e4f062017-03-27 16:11:31 -0400359 u = 1.0f / nPoints;
360 if (quad_error_at(pts, t, u) < toleranceSqd) {
361 break;
362 }
363 nPoints++;
ethannicholase9709e82016-01-07 13:34:16 -0800364 }
Stephen White36e4f062017-03-27 16:11:31 -0400365 for (int j = 1; j <= nPoints; j++) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700366 this->appendPointToContour(to_point(quad.eval(j * u)), contour);
Stephen White36e4f062017-03-27 16:11:31 -0400367 }
ethannicholase9709e82016-01-07 13:34:16 -0800368}
369
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700370void GrTriangulator::generateCubicPoints(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2,
371 const SkPoint& p3, SkScalar tolSqd, VertexList* contour,
372 int pointsLeft) {
Cary Clarkdf429f32017-11-08 11:44:31 -0500373 SkScalar d1 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p1, p0, p3);
374 SkScalar d2 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p2, p0, p3);
ethannicholase9709e82016-01-07 13:34:16 -0800375 if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) ||
376 !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700377 this->appendPointToContour(p3, contour);
Stephen White3a9aab92017-03-07 14:07:18 -0500378 return;
ethannicholase9709e82016-01-07 13:34:16 -0800379 }
380 const SkPoint q[] = {
381 { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) },
382 { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) },
383 { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) }
384 };
385 const SkPoint r[] = {
386 { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) },
387 { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) }
388 };
389 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) };
390 pointsLeft >>= 1;
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700391 this->generateCubicPoints(p0, q[0], r[0], s, tolSqd, contour, pointsLeft);
392 this->generateCubicPoints(s, r[1], q[2], p3, tolSqd, contour, pointsLeft);
ethannicholase9709e82016-01-07 13:34:16 -0800393}
394
395// Stage 1: convert the input path to a set of linear contours (linked list of Vertices).
396
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700397void GrTriangulator::pathToContours(float tolerance, const SkRect& clipBounds,
398 VertexList* contours) {
ethannicholase9709e82016-01-07 13:34:16 -0800399 SkScalar toleranceSqd = tolerance * tolerance;
Chris Dalton7156db22020-05-07 22:06:28 +0000400 SkPoint pts[4];
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700401 fIsLinear = true;
Stephen White3a9aab92017-03-07 14:07:18 -0500402 VertexList* contour = contours;
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700403 SkPath::Iter iter(fPath, false);
404 if (fPath.isInverseFillType()) {
ethannicholase9709e82016-01-07 13:34:16 -0800405 SkPoint quad[4];
406 clipBounds.toQuad(quad);
senorblanco7ab96e92016-10-12 06:47:44 -0700407 for (int i = 3; i >= 0; i--) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700408 this->appendPointToContour(quad[i], contours);
ethannicholase9709e82016-01-07 13:34:16 -0800409 }
Stephen White3a9aab92017-03-07 14:07:18 -0500410 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800411 }
412 SkAutoConicToQuads converter;
Chris Dalton7156db22020-05-07 22:06:28 +0000413 SkPath::Verb verb;
414 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
ethannicholase9709e82016-01-07 13:34:16 -0800415 switch (verb) {
Chris Dalton7156db22020-05-07 22:06:28 +0000416 case SkPath::kConic_Verb: {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700417 fIsLinear = false;
Chris Dalton854ee852021-01-05 15:12:59 -0700418 if (fSimpleInnerPolygons) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700419 this->appendPointToContour(pts[2], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700420 break;
421 }
Chris Dalton7156db22020-05-07 22:06:28 +0000422 SkScalar weight = iter.conicWeight();
423 const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd);
ethannicholase9709e82016-01-07 13:34:16 -0800424 for (int i = 0; i < converter.countQuads(); ++i) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700425 this->appendQuadraticToContour(quadPts, toleranceSqd, contour);
ethannicholase9709e82016-01-07 13:34:16 -0800426 quadPts += 2;
427 }
ethannicholase9709e82016-01-07 13:34:16 -0800428 break;
429 }
Chris Dalton7156db22020-05-07 22:06:28 +0000430 case SkPath::kMove_Verb:
Stephen White3a9aab92017-03-07 14:07:18 -0500431 if (contour->fHead) {
432 contour++;
ethannicholase9709e82016-01-07 13:34:16 -0800433 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700434 this->appendPointToContour(pts[0], contour);
ethannicholase9709e82016-01-07 13:34:16 -0800435 break;
Chris Dalton7156db22020-05-07 22:06:28 +0000436 case SkPath::kLine_Verb: {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700437 this->appendPointToContour(pts[1], contour);
ethannicholase9709e82016-01-07 13:34:16 -0800438 break;
439 }
Chris Dalton7156db22020-05-07 22:06:28 +0000440 case SkPath::kQuad_Verb: {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700441 fIsLinear = false;
Chris Dalton854ee852021-01-05 15:12:59 -0700442 if (fSimpleInnerPolygons) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700443 this->appendPointToContour(pts[2], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700444 break;
445 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700446 this->appendQuadraticToContour(pts, toleranceSqd, contour);
ethannicholase9709e82016-01-07 13:34:16 -0800447 break;
448 }
Chris Dalton7156db22020-05-07 22:06:28 +0000449 case SkPath::kCubic_Verb: {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700450 fIsLinear = false;
Chris Dalton854ee852021-01-05 15:12:59 -0700451 if (fSimpleInnerPolygons) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700452 this->appendPointToContour(pts[3], contour);
Chris Dalton6ccc0322020-01-29 11:38:16 -0700453 break;
454 }
ethannicholase9709e82016-01-07 13:34:16 -0800455 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700456 this->generateCubicPoints(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour,
457 pointsLeft);
ethannicholase9709e82016-01-07 13:34:16 -0800458 break;
459 }
Chris Dalton7156db22020-05-07 22:06:28 +0000460 case SkPath::kClose_Verb:
461 case SkPath::kDone_Verb:
ethannicholase9709e82016-01-07 13:34:16 -0800462 break;
463 }
464 }
465}
466
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700467static inline bool apply_fill_type(SkPathFillType fillType, int winding) {
ethannicholase9709e82016-01-07 13:34:16 -0800468 switch (fillType) {
Mike Reed7d34dc72019-11-26 12:17:17 -0500469 case SkPathFillType::kWinding:
ethannicholase9709e82016-01-07 13:34:16 -0800470 return winding != 0;
Mike Reed7d34dc72019-11-26 12:17:17 -0500471 case SkPathFillType::kEvenOdd:
ethannicholase9709e82016-01-07 13:34:16 -0800472 return (winding & 1) != 0;
Mike Reed7d34dc72019-11-26 12:17:17 -0500473 case SkPathFillType::kInverseWinding:
senorblanco7ab96e92016-10-12 06:47:44 -0700474 return winding == 1;
Mike Reed7d34dc72019-11-26 12:17:17 -0500475 case SkPathFillType::kInverseEvenOdd:
ethannicholase9709e82016-01-07 13:34:16 -0800476 return (winding & 1) == 1;
477 default:
478 SkASSERT(false);
479 return false;
480 }
481}
482
Chris Dalton47114db2021-01-06 00:35:20 -0700483bool GrTriangulator::applyFillType(int winding) {
484 return apply_fill_type(fPath.getFillType(), winding);
485}
486
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700487static inline bool apply_fill_type(SkPathFillType fillType, Poly* poly) {
Stephen White49789062017-02-21 10:35:49 -0500488 return poly && apply_fill_type(fillType, poly->fWinding);
489}
490
Chris Dalton7cf3add2021-01-11 18:33:28 -0700491Edge* GrTriangulator::makeEdge(Vertex* prev, Vertex* next, EdgeType type, const Comparator& c) {
Stephen White2f4686f2017-01-03 16:20:01 -0500492 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
ethannicholase9709e82016-01-07 13:34:16 -0800493 Vertex* top = winding < 0 ? next : prev;
494 Vertex* bottom = winding < 0 ? prev : next;
Chris Dalton7cf3add2021-01-11 18:33:28 -0700495 return fAlloc.make<Edge>(top, bottom, winding, type);
ethannicholase9709e82016-01-07 13:34:16 -0800496}
497
Chris Dalton24472af2021-01-11 20:05:00 -0700498void EdgeList::insert(Edge* edge, Edge* prev) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400499 TESS_LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID);
Chris Dalton24472af2021-01-11 20:05:00 -0700500 SkASSERT(!this->contains(edge));
501 Edge* next = prev ? prev->fRight : fHead;
502 this->insert(edge, prev, next);
ethannicholase9709e82016-01-07 13:34:16 -0800503}
504
Chris Dalton47114db2021-01-06 00:35:20 -0700505void GrTriangulator::FindEnclosingEdges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) {
Stephen White90732fd2017-03-02 16:16:33 -0500506 if (v->fFirstEdgeAbove && v->fLastEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -0800507 *left = v->fFirstEdgeAbove->fLeft;
508 *right = v->fLastEdgeAbove->fRight;
509 return;
510 }
511 Edge* next = nullptr;
512 Edge* prev;
513 for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) {
514 if (prev->isLeftOf(v)) {
515 break;
516 }
517 next = prev;
518 }
519 *left = prev;
520 *right = next;
ethannicholase9709e82016-01-07 13:34:16 -0800521}
522
Chris Dalton24472af2021-01-11 20:05:00 -0700523void GrTriangulator::Edge::insertAbove(Vertex* v, const Comparator& c) {
524 if (fTop->fPoint == fBottom->fPoint ||
525 c.sweep_lt(fBottom->fPoint, fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800526 return;
527 }
Chris Dalton24472af2021-01-11 20:05:00 -0700528 TESS_LOG("insert edge (%g -> %g) above vertex %g\n", fTop->fID, fBottom->fID, v->fID);
ethannicholase9709e82016-01-07 13:34:16 -0800529 Edge* prev = nullptr;
530 Edge* next;
Chris Daltond60c9192021-01-07 18:30:08 +0000531 for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -0700532 if (next->isRightOf(fTop)) {
ethannicholase9709e82016-01-07 13:34:16 -0800533 break;
534 }
535 prev = next;
536 }
senorblancoe6eaa322016-03-08 09:06:44 -0800537 list_insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
Chris Dalton24472af2021-01-11 20:05:00 -0700538 this, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove);
ethannicholase9709e82016-01-07 13:34:16 -0800539}
540
Chris Dalton24472af2021-01-11 20:05:00 -0700541void GrTriangulator::Edge::insertBelow(Vertex* v, const Comparator& c) {
542 if (fTop->fPoint == fBottom->fPoint ||
543 c.sweep_lt(fBottom->fPoint, fTop->fPoint)) {
ethannicholase9709e82016-01-07 13:34:16 -0800544 return;
545 }
Chris Dalton24472af2021-01-11 20:05:00 -0700546 TESS_LOG("insert edge (%g -> %g) below vertex %g\n", fTop->fID, fBottom->fID, v->fID);
ethannicholase9709e82016-01-07 13:34:16 -0800547 Edge* prev = nullptr;
548 Edge* next;
Chris Daltond60c9192021-01-07 18:30:08 +0000549 for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -0700550 if (next->isRightOf(fBottom)) {
ethannicholase9709e82016-01-07 13:34:16 -0800551 break;
552 }
553 prev = next;
554 }
senorblancoe6eaa322016-03-08 09:06:44 -0800555 list_insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
Chris Dalton24472af2021-01-11 20:05:00 -0700556 this, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow);
ethannicholase9709e82016-01-07 13:34:16 -0800557}
558
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700559static void remove_edge_above(Edge* edge) {
Stephen White7b376942018-05-22 11:51:32 -0400560 SkASSERT(edge->fTop && edge->fBottom);
Brian Salomon120e7d62019-09-11 10:29:22 -0400561 TESS_LOG("removing edge (%g -> %g) above vertex %g\n", edge->fTop->fID, edge->fBottom->fID,
562 edge->fBottom->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800563 list_remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>(
ethannicholase9709e82016-01-07 13:34:16 -0800564 edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove);
565}
566
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700567static void remove_edge_below(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) below vertex %g\n",
570 edge->fTop->fID, edge->fBottom->fID, edge->fTop->fID);
senorblancoe6eaa322016-03-08 09:06:44 -0800571 list_remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>(
ethannicholase9709e82016-01-07 13:34:16 -0800572 edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow);
573}
574
Chris Dalton24472af2021-01-11 20:05:00 -0700575void GrTriangulator::Edge::disconnect() {
576 remove_edge_above(this);
577 remove_edge_below(this);
Stephen Whitee7a364d2017-01-11 16:19:26 -0500578}
579
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700580static void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700581 const Comparator& c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400582
Chris Dalton811dc6a2021-01-07 16:40:32 -0700583static void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, const Comparator& c) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400584 if (!current || *current == dst || c.sweep_lt((*current)->fPoint, dst->fPoint)) {
585 return;
586 }
587 Vertex* v = *current;
Brian Salomon120e7d62019-09-11 10:29:22 -0400588 TESS_LOG("rewinding active edges from vertex %g to vertex %g\n", v->fID, dst->fID);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400589 while (v != dst) {
590 v = v->fPrev;
591 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -0700592 activeEdges->remove(e);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400593 }
594 Edge* leftEdge = v->fLeftEnclosingEdge;
595 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -0700596 activeEdges->insert(e, leftEdge);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400597 leftEdge = e;
Stephen Whitec03e6982020-02-06 16:32:14 -0500598 Vertex* top = e->fTop;
599 if (c.sweep_lt(top->fPoint, dst->fPoint) &&
600 ((top->fLeftEnclosingEdge && !top->fLeftEnclosingEdge->isLeftOf(e->fTop)) ||
601 (top->fRightEnclosingEdge && !top->fRightEnclosingEdge->isRightOf(e->fTop)))) {
602 dst = top;
603 }
Stephen White3b5a3fa2017-06-06 14:51:19 -0400604 }
605 }
606 *current = v;
607}
608
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700609static void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700610 const Comparator& c) {
Stephen Whitec03e6982020-02-06 16:32:14 -0500611 if (!activeEdges || !current) {
612 return;
613 }
614 Vertex* top = edge->fTop;
615 Vertex* bottom = edge->fBottom;
616 if (edge->fLeft) {
617 Vertex* leftTop = edge->fLeft->fTop;
618 Vertex* leftBottom = edge->fLeft->fBottom;
619 if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) {
620 rewind(activeEdges, current, leftTop, c);
621 } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) {
622 rewind(activeEdges, current, top, c);
623 } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) &&
624 !edge->fLeft->isLeftOf(bottom)) {
625 rewind(activeEdges, current, leftTop, c);
626 } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) {
627 rewind(activeEdges, current, top, c);
628 }
629 }
630 if (edge->fRight) {
631 Vertex* rightTop = edge->fRight->fTop;
632 Vertex* rightBottom = edge->fRight->fBottom;
633 if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) {
634 rewind(activeEdges, current, rightTop, c);
635 } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) {
636 rewind(activeEdges, current, top, c);
637 } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) &&
638 !edge->fRight->isRightOf(bottom)) {
639 rewind(activeEdges, current, rightTop, c);
640 } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) &&
641 !edge->isLeftOf(rightBottom)) {
642 rewind(activeEdges, current, top, c);
643 }
644 }
645}
646
Chris Dalton811dc6a2021-01-07 16:40:32 -0700647static void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
648 const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800649 remove_edge_below(edge);
650 edge->fTop = v;
651 edge->recompute();
Chris Dalton24472af2021-01-11 20:05:00 -0700652 edge->insertBelow(v, c);
Stephen Whitec03e6982020-02-06 16:32:14 -0500653 rewind_if_necessary(edge, activeEdges, current, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400654 merge_collinear_edges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800655}
656
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700657static void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700658 const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800659 remove_edge_above(edge);
660 edge->fBottom = v;
661 edge->recompute();
Chris Dalton24472af2021-01-11 20:05:00 -0700662 edge->insertAbove(v, c);
Stephen Whitec03e6982020-02-06 16:32:14 -0500663 rewind_if_necessary(edge, activeEdges, current, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400664 merge_collinear_edges(edge, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800665}
666
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700667static void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700668 const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800669 if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400670 TESS_LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n",
671 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
672 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400673 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800674 other->fWinding += edge->fWinding;
Chris Dalton24472af2021-01-11 20:05:00 -0700675 edge->disconnect();
Stephen Whiteec79c392018-05-18 11:49:21 -0400676 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -0800677 } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400678 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800679 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400680 set_bottom(edge, other->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800681 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400682 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800683 edge->fWinding += other->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400684 set_bottom(other, edge->fTop, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800685 }
686}
687
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700688static void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700689 const Comparator& c) {
ethannicholase9709e82016-01-07 13:34:16 -0800690 if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400691 TESS_LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n",
692 edge->fTop->fPoint.fX, edge->fTop->fPoint.fY,
693 edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400694 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800695 other->fWinding += edge->fWinding;
Chris Dalton24472af2021-01-11 20:05:00 -0700696 edge->disconnect();
Stephen Whiteec79c392018-05-18 11:49:21 -0400697 edge->fTop = edge->fBottom = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -0800698 } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400699 rewind(activeEdges, current, other->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800700 edge->fWinding += other->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400701 set_top(other, edge->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800702 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400703 rewind(activeEdges, current, edge->fTop, c);
ethannicholase9709e82016-01-07 13:34:16 -0800704 other->fWinding += edge->fWinding;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400705 set_top(edge, other->fBottom, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800706 }
707}
708
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700709static bool top_collinear(Edge* left, Edge* right) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400710 if (!left || !right) {
711 return false;
712 }
713 return left->fTop->fPoint == right->fTop->fPoint ||
714 !left->isLeftOf(right->fTop) || !right->isRightOf(left->fTop);
715}
716
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700717static bool bottom_collinear(Edge* left, Edge* right) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400718 if (!left || !right) {
719 return false;
720 }
721 return left->fBottom->fPoint == right->fBottom->fPoint ||
722 !left->isLeftOf(right->fBottom) || !right->isRightOf(left->fBottom);
723}
724
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700725static void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700726 const Comparator& c) {
Stephen White6eca90f2017-05-25 14:47:11 -0400727 for (;;) {
Stephen Whited26b4d82018-07-26 10:02:27 -0400728 if (top_collinear(edge->fPrevEdgeAbove, edge)) {
Stephen White24289e02018-06-29 17:02:21 -0400729 merge_edges_above(edge->fPrevEdgeAbove, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400730 } else if (top_collinear(edge, edge->fNextEdgeAbove)) {
Stephen White24289e02018-06-29 17:02:21 -0400731 merge_edges_above(edge->fNextEdgeAbove, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400732 } else if (bottom_collinear(edge->fPrevEdgeBelow, edge)) {
Stephen White24289e02018-06-29 17:02:21 -0400733 merge_edges_below(edge->fPrevEdgeBelow, edge, activeEdges, current, c);
Stephen Whited26b4d82018-07-26 10:02:27 -0400734 } else if (bottom_collinear(edge, edge->fNextEdgeBelow)) {
Stephen White24289e02018-06-29 17:02:21 -0400735 merge_edges_below(edge->fNextEdgeBelow, edge, activeEdges, current, c);
Stephen White6eca90f2017-05-25 14:47:11 -0400736 } else {
737 break;
738 }
ethannicholase9709e82016-01-07 13:34:16 -0800739 }
Stephen Whited26b4d82018-07-26 10:02:27 -0400740 SkASSERT(!top_collinear(edge->fPrevEdgeAbove, edge));
741 SkASSERT(!top_collinear(edge, edge->fNextEdgeAbove));
742 SkASSERT(!bottom_collinear(edge->fPrevEdgeBelow, edge));
743 SkASSERT(!bottom_collinear(edge, edge->fNextEdgeBelow));
ethannicholase9709e82016-01-07 13:34:16 -0800744}
745
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700746bool GrTriangulator::splitEdge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700747 const Comparator& c) {
Stephen Whiteec79c392018-05-18 11:49:21 -0400748 if (!edge->fTop || !edge->fBottom || v == edge->fTop || v == edge->fBottom) {
Stephen White89042d52018-06-08 12:18:22 -0400749 return false;
Stephen White0cb31672017-06-08 14:41:01 -0400750 }
Brian Salomon120e7d62019-09-11 10:29:22 -0400751 TESS_LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n",
752 edge->fTop->fID, edge->fBottom->fID, v->fID, v->fPoint.fX, v->fPoint.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400753 Vertex* top;
754 Vertex* bottom;
Stephen White531a48e2018-06-01 09:49:39 -0400755 int winding = edge->fWinding;
ethannicholase9709e82016-01-07 13:34:16 -0800756 if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400757 top = v;
758 bottom = edge->fTop;
759 set_top(edge, v, activeEdges, current, c);
Stephen Whitee30cf802017-02-27 11:37:55 -0500760 } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400761 top = edge->fBottom;
762 bottom = v;
763 set_bottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800764 } else {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400765 top = v;
766 bottom = edge->fBottom;
767 set_bottom(edge, v, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800768 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700769 Edge* newEdge = fAlloc.make<Edge>(top, bottom, winding, edge->fType);
Chris Dalton24472af2021-01-11 20:05:00 -0700770 newEdge->insertBelow(top, c);
771 newEdge->insertAbove(bottom, c);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400772 merge_collinear_edges(newEdge, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400773 return true;
774}
775
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700776bool GrTriangulator::intersectEdgePair(Edge* left, Edge* right, EdgeList* activeEdges,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700777 Vertex** current, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -0400778 if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) {
779 return false;
780 }
Stephen White1c5fd182018-07-12 15:54:05 -0400781 if (left->fTop == right->fTop || left->fBottom == right->fBottom) {
782 return false;
783 }
Stephen White89042d52018-06-08 12:18:22 -0400784 if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
785 if (!left->isLeftOf(right->fTop)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400786 rewind(activeEdges, current, right->fTop, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700787 return this->splitEdge(left, right->fTop, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400788 }
789 } else {
790 if (!right->isRightOf(left->fTop)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400791 rewind(activeEdges, current, left->fTop, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700792 return this->splitEdge(right, left->fTop, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400793 }
794 }
795 if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
796 if (!left->isLeftOf(right->fBottom)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400797 rewind(activeEdges, current, right->fBottom, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700798 return this->splitEdge(left, right->fBottom, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400799 }
800 } else {
801 if (!right->isRightOf(left->fBottom)) {
Stephen White1c5fd182018-07-12 15:54:05 -0400802 rewind(activeEdges, current, left->fBottom, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700803 return this->splitEdge(right, left->fBottom, activeEdges, current, c);
Stephen White89042d52018-06-08 12:18:22 -0400804 }
805 }
806 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800807}
808
Chris Dalton7cf3add2021-01-11 18:33:28 -0700809Edge* GrTriangulator::makeConnectingEdge(Vertex* prev, Vertex* next, EdgeType type,
810 const Comparator& c, int windingScale) {
Stephen Whitee260c462017-12-19 18:09:54 -0500811 if (!prev || !next || prev->fPoint == next->fPoint) {
812 return nullptr;
813 }
Chris Dalton7cf3add2021-01-11 18:33:28 -0700814 Edge* edge = this->makeEdge(prev, next, type, c);
Chris Dalton24472af2021-01-11 20:05:00 -0700815 edge->insertBelow(edge->fTop, c);
816 edge->insertAbove(edge->fBottom, c);
Chris Dalton7cf3add2021-01-11 18:33:28 -0700817 edge->fWinding *= windingScale;
Stephen White3b5a3fa2017-06-06 14:51:19 -0400818 merge_collinear_edges(edge, nullptr, nullptr, c);
senorblancof57372d2016-08-31 10:36:19 -0700819 return edge;
820}
821
Chris Dalton811dc6a2021-01-07 16:40:32 -0700822static void merge_vertices(Vertex* src, Vertex* dst, VertexList* mesh, const Comparator& c) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400823 TESS_LOG("found coincident verts at %g, %g; merging %g into %g\n",
824 src->fPoint.fX, src->fPoint.fY, src->fID, dst->fID);
Brian Osman788b9162020-02-07 10:36:46 -0500825 dst->fAlpha = std::max(src->fAlpha, dst->fAlpha);
Stephen Whitebda29c02017-03-13 15:10:13 -0400826 if (src->fPartner) {
827 src->fPartner->fPartner = dst;
828 }
Stephen White7b376942018-05-22 11:51:32 -0400829 while (Edge* edge = src->fFirstEdgeAbove) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400830 set_bottom(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -0800831 }
Stephen White7b376942018-05-22 11:51:32 -0400832 while (Edge* edge = src->fFirstEdgeBelow) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400833 set_top(edge, dst, nullptr, nullptr, c);
ethannicholase9709e82016-01-07 13:34:16 -0800834 }
Stephen Whitebf6137e2017-01-04 15:43:26 -0500835 mesh->remove(src);
Stephen Whitec4dbc372019-05-22 10:50:14 -0400836 dst->fSynthetic = true;
ethannicholase9709e82016-01-07 13:34:16 -0800837}
838
Chris Dalton7cf3add2021-01-11 18:33:28 -0700839Vertex* GrTriangulator::makeSortedVertex(const SkPoint& p, uint8_t alpha, VertexList* mesh,
840 Vertex* reference, const Comparator& c) {
Stephen White95152e12017-12-18 10:52:44 -0500841 Vertex* prevV = reference;
842 while (prevV && c.sweep_lt(p, prevV->fPoint)) {
843 prevV = prevV->fPrev;
844 }
845 Vertex* nextV = prevV ? prevV->fNext : mesh->fHead;
846 while (nextV && c.sweep_lt(nextV->fPoint, p)) {
847 prevV = nextV;
848 nextV = nextV->fNext;
849 }
850 Vertex* v;
851 if (prevV && coincident(prevV->fPoint, p)) {
852 v = prevV;
853 } else if (nextV && coincident(nextV->fPoint, p)) {
854 v = nextV;
855 } else {
Chris Dalton7cf3add2021-01-11 18:33:28 -0700856 v = fAlloc.make<Vertex>(p, alpha);
Chris Dalton5045de32021-01-07 19:09:01 -0700857#if TRIANGULATOR_LOGGING
Stephen White95152e12017-12-18 10:52:44 -0500858 if (!prevV) {
859 v->fID = mesh->fHead->fID - 1.0f;
860 } else if (!nextV) {
861 v->fID = mesh->fTail->fID + 1.0f;
862 } else {
863 v->fID = (prevV->fID + nextV->fID) * 0.5f;
864 }
865#endif
866 mesh->insert(v, prevV, nextV);
867 }
868 return v;
869}
870
Stephen White53a02982018-05-30 22:47:46 -0400871// If an edge's top and bottom points differ only by 1/2 machine epsilon in the primary
872// sort criterion, it may not be possible to split correctly, since there is no point which is
873// below the top and above the bottom. This function detects that case.
Chris Dalton811dc6a2021-01-07 16:40:32 -0700874static bool nearly_flat(const Comparator& c, Edge* edge) {
Stephen White53a02982018-05-30 22:47:46 -0400875 SkPoint diff = edge->fBottom->fPoint - edge->fTop->fPoint;
876 float primaryDiff = c.fDirection == Comparator::Direction::kHorizontal ? diff.fX : diff.fY;
Stephen White13f3d8d2018-06-22 10:19:20 -0400877 return fabs(primaryDiff) < std::numeric_limits<float>::epsilon() && primaryDiff != 0.0f;
Stephen White53a02982018-05-30 22:47:46 -0400878}
879
Chris Dalton811dc6a2021-01-07 16:40:32 -0700880static SkPoint clamp(SkPoint p, SkPoint min, SkPoint max, const Comparator& c) {
Stephen Whitee62999f2018-06-05 18:45:07 -0400881 if (c.sweep_lt(p, min)) {
882 return min;
883 } else if (c.sweep_lt(max, p)) {
884 return max;
885 } else {
886 return p;
887 }
888}
889
Chris Dalton7cf3add2021-01-11 18:33:28 -0700890void GrTriangulator::computeBisector(Edge* edge1, Edge* edge2, Vertex* v) {
Stephen Whitec4dbc372019-05-22 10:50:14 -0400891 Line line1 = edge1->fLine;
892 Line line2 = edge2->fLine;
893 line1.normalize();
894 line2.normalize();
895 double cosAngle = line1.fA * line2.fA + line1.fB * line2.fB;
896 if (cosAngle > 0.999) {
897 return;
898 }
899 line1.fC += edge1->fWinding > 0 ? -1 : 1;
900 line2.fC += edge2->fWinding > 0 ? -1 : 1;
901 SkPoint p;
902 if (line1.intersect(line2, &p)) {
Chris Dalton17ce8c52021-01-07 18:08:46 -0700903 uint8_t alpha = edge1->fType == EdgeType::kOuter ? 255 : 0;
Chris Dalton7cf3add2021-01-11 18:33:28 -0700904 v->fPartner = fAlloc.make<Vertex>(p, alpha);
Brian Salomon120e7d62019-09-11 10:29:22 -0400905 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 -0400906 }
907}
908
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700909bool GrTriangulator::checkForIntersection(Edge* left, Edge* right, EdgeList* activeEdges,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700910 Vertex** current, VertexList* mesh, const Comparator& c) {
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400911 if (!left || !right) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400912 return false;
ethannicholase9709e82016-01-07 13:34:16 -0800913 }
Stephen White56158ae2017-01-30 14:31:31 -0500914 SkPoint p;
915 uint8_t alpha;
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400916 if (left->intersect(*right, &p, &alpha) && p.isFinite()) {
Ravi Mistrybfe95982018-05-29 18:19:07 +0000917 Vertex* v;
Brian Salomon120e7d62019-09-11 10:29:22 -0400918 TESS_LOG("found intersection, pt is %g, %g\n", p.fX, p.fY);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400919 Vertex* top = *current;
920 // If the intersection point is above the current vertex, rewind to the vertex above the
921 // intersection.
Stephen White0cb31672017-06-08 14:41:01 -0400922 while (top && c.sweep_lt(p, top->fPoint)) {
Stephen White3b5a3fa2017-06-06 14:51:19 -0400923 top = top->fPrev;
924 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400925 if (!nearly_flat(c, left)) {
926 p = clamp(p, left->fTop->fPoint, left->fBottom->fPoint, c);
Stephen Whitee62999f2018-06-05 18:45:07 -0400927 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400928 if (!nearly_flat(c, right)) {
929 p = clamp(p, right->fTop->fPoint, right->fBottom->fPoint, c);
Stephen Whitee62999f2018-06-05 18:45:07 -0400930 }
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400931 if (p == left->fTop->fPoint) {
932 v = left->fTop;
933 } else if (p == left->fBottom->fPoint) {
934 v = left->fBottom;
935 } else if (p == right->fTop->fPoint) {
936 v = right->fTop;
937 } else if (p == right->fBottom->fPoint) {
938 v = right->fBottom;
Ravi Mistrybfe95982018-05-29 18:19:07 +0000939 } else {
Chris Dalton7cf3add2021-01-11 18:33:28 -0700940 v = this->makeSortedVertex(p, alpha, mesh, top, c);
Stephen Whiteb141fcb2018-06-14 10:15:47 -0400941 if (left->fTop->fPartner) {
Stephen Whitec4dbc372019-05-22 10:50:14 -0400942 v->fSynthetic = true;
Chris Dalton7cf3add2021-01-11 18:33:28 -0700943 this->computeBisector(left, right, v);
Stephen Whitee260c462017-12-19 18:09:54 -0500944 }
ethannicholase9709e82016-01-07 13:34:16 -0800945 }
Stephen White0cb31672017-06-08 14:41:01 -0400946 rewind(activeEdges, current, top ? top : v, c);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700947 this->splitEdge(left, v, activeEdges, current, c);
948 this->splitEdge(right, v, activeEdges, current, c);
Brian Osman788b9162020-02-07 10:36:46 -0500949 v->fAlpha = std::max(v->fAlpha, alpha);
Stephen White3b5a3fa2017-06-06 14:51:19 -0400950 return true;
ethannicholase9709e82016-01-07 13:34:16 -0800951 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700952 return this->intersectEdgePair(left, right, activeEdges, current, c);
ethannicholase9709e82016-01-07 13:34:16 -0800953}
954
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700955void GrTriangulator::sanitizeContours(VertexList* contours, int contourCnt) {
Stephen White3a9aab92017-03-07 14:07:18 -0500956 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
957 SkASSERT(contour->fHead);
958 Vertex* prev = contour->fTail;
Chris Dalton854ee852021-01-05 15:12:59 -0700959 if (fRoundVerticesToQuarterPixel) {
Stephen White3a9aab92017-03-07 14:07:18 -0500960 round(&prev->fPoint);
Stephen White5926f2d2017-02-13 13:55:42 -0500961 }
Stephen White3a9aab92017-03-07 14:07:18 -0500962 for (Vertex* v = contour->fHead; v;) {
Chris Dalton854ee852021-01-05 15:12:59 -0700963 if (fRoundVerticesToQuarterPixel) {
senorblancof57372d2016-08-31 10:36:19 -0700964 round(&v->fPoint);
965 }
Stephen White3a9aab92017-03-07 14:07:18 -0500966 Vertex* next = v->fNext;
Stephen White3de40f82018-06-28 09:36:49 -0400967 Vertex* nextWrap = next ? next : contour->fHead;
Stephen White3a9aab92017-03-07 14:07:18 -0500968 if (coincident(prev->fPoint, v->fPoint)) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400969 TESS_LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -0500970 contour->remove(v);
Stephen White73e7f802017-08-23 13:56:07 -0400971 } else if (!v->fPoint.isFinite()) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400972 TESS_LOG("vertex %g,%g non-finite; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White73e7f802017-08-23 13:56:07 -0400973 contour->remove(v);
Chris Dalton854ee852021-01-05 15:12:59 -0700974 } else if (fCullCollinearVertices &&
Chris Dalton6ccc0322020-01-29 11:38:16 -0700975 Line(prev->fPoint, nextWrap->fPoint).dist(v->fPoint) == 0.0) {
Brian Salomon120e7d62019-09-11 10:29:22 -0400976 TESS_LOG("vertex %g,%g collinear; removing\n", v->fPoint.fX, v->fPoint.fY);
Stephen White06768ca2018-05-25 14:50:56 -0400977 contour->remove(v);
978 } else {
979 prev = v;
ethannicholase9709e82016-01-07 13:34:16 -0800980 }
Stephen White3a9aab92017-03-07 14:07:18 -0500981 v = next;
ethannicholase9709e82016-01-07 13:34:16 -0800982 }
983 }
984}
985
Chris Dalton811dc6a2021-01-07 16:40:32 -0700986bool GrTriangulator::mergeCoincidentVertices(VertexList* mesh, const Comparator& c) {
Stephen Whitebda29c02017-03-13 15:10:13 -0400987 if (!mesh->fHead) {
Stephen Whitee260c462017-12-19 18:09:54 -0500988 return false;
Stephen Whitebda29c02017-03-13 15:10:13 -0400989 }
Stephen Whitee260c462017-12-19 18:09:54 -0500990 bool merged = false;
991 for (Vertex* v = mesh->fHead->fNext; v;) {
992 Vertex* next = v->fNext;
ethannicholase9709e82016-01-07 13:34:16 -0800993 if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) {
994 v->fPoint = v->fPrev->fPoint;
995 }
996 if (coincident(v->fPrev->fPoint, v->fPoint)) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700997 merge_vertices(v, v->fPrev, mesh, c);
Stephen Whitee260c462017-12-19 18:09:54 -0500998 merged = true;
ethannicholase9709e82016-01-07 13:34:16 -0800999 }
Stephen Whitee260c462017-12-19 18:09:54 -05001000 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001001 }
Stephen Whitee260c462017-12-19 18:09:54 -05001002 return merged;
ethannicholase9709e82016-01-07 13:34:16 -08001003}
1004
1005// Stage 2: convert the contours to a mesh of edges connecting the vertices.
1006
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001007void GrTriangulator::buildEdges(VertexList* contours, int contourCnt, VertexList* mesh,
Chris Dalton811dc6a2021-01-07 16:40:32 -07001008 const Comparator& c) {
Stephen White3a9aab92017-03-07 14:07:18 -05001009 for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) {
1010 Vertex* prev = contour->fTail;
1011 for (Vertex* v = contour->fHead; v;) {
1012 Vertex* next = v->fNext;
Chris Dalton7cf3add2021-01-11 18:33:28 -07001013 this->makeConnectingEdge(prev, v, EdgeType::kInner, c);
Stephen White3a9aab92017-03-07 14:07:18 -05001014 mesh->append(v);
ethannicholase9709e82016-01-07 13:34:16 -08001015 prev = v;
Stephen White3a9aab92017-03-07 14:07:18 -05001016 v = next;
ethannicholase9709e82016-01-07 13:34:16 -08001017 }
1018 }
ethannicholase9709e82016-01-07 13:34:16 -08001019}
1020
Stephen Whitebda29c02017-03-13 15:10:13 -04001021template <CompareFunc sweep_lt>
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001022static void sorted_merge(VertexList* front, VertexList* back, VertexList* result) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001023 Vertex* a = front->fHead;
1024 Vertex* b = back->fHead;
1025 while (a && b) {
1026 if (sweep_lt(a->fPoint, b->fPoint)) {
1027 front->remove(a);
1028 result->append(a);
1029 a = front->fHead;
1030 } else {
1031 back->remove(b);
1032 result->append(b);
1033 b = back->fHead;
1034 }
1035 }
1036 result->append(*front);
1037 result->append(*back);
1038}
1039
Chris Dalton47114db2021-01-06 00:35:20 -07001040void GrTriangulator::SortedMerge(VertexList* front, VertexList* back, VertexList* result,
1041 const Comparator& c) {
Stephen Whitebda29c02017-03-13 15:10:13 -04001042 if (c.fDirection == Comparator::Direction::kHorizontal) {
1043 sorted_merge<sweep_lt_horiz>(front, back, result);
1044 } else {
1045 sorted_merge<sweep_lt_vert>(front, back, result);
1046 }
Chris Dalton5045de32021-01-07 19:09:01 -07001047#if TRIANGULATOR_LOGGING
Stephen White3b5a3fa2017-06-06 14:51:19 -04001048 float id = 0.0f;
1049 for (Vertex* v = result->fHead; v; v = v->fNext) {
1050 v->fID = id++;
1051 }
1052#endif
Stephen Whitebda29c02017-03-13 15:10:13 -04001053}
1054
ethannicholase9709e82016-01-07 13:34:16 -08001055// Stage 3: sort the vertices by increasing sweep direction.
1056
Stephen White16a40cb2017-02-23 11:10:01 -05001057template <CompareFunc sweep_lt>
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001058static void merge_sort(VertexList* vertices) {
Stephen White16a40cb2017-02-23 11:10:01 -05001059 Vertex* slow = vertices->fHead;
1060 if (!slow) {
ethannicholase9709e82016-01-07 13:34:16 -08001061 return;
1062 }
Stephen White16a40cb2017-02-23 11:10:01 -05001063 Vertex* fast = slow->fNext;
1064 if (!fast) {
1065 return;
1066 }
1067 do {
1068 fast = fast->fNext;
1069 if (fast) {
1070 fast = fast->fNext;
1071 slow = slow->fNext;
1072 }
1073 } while (fast);
1074 VertexList front(vertices->fHead, slow);
1075 VertexList back(slow->fNext, vertices->fTail);
1076 front.fTail->fNext = back.fHead->fPrev = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001077
Stephen White16a40cb2017-02-23 11:10:01 -05001078 merge_sort<sweep_lt>(&front);
1079 merge_sort<sweep_lt>(&back);
ethannicholase9709e82016-01-07 13:34:16 -08001080
Stephen White16a40cb2017-02-23 11:10:01 -05001081 vertices->fHead = vertices->fTail = nullptr;
Stephen Whitebda29c02017-03-13 15:10:13 -04001082 sorted_merge<sweep_lt>(&front, &back, vertices);
ethannicholase9709e82016-01-07 13:34:16 -08001083}
1084
Chris Dalton5045de32021-01-07 19:09:01 -07001085#if TRIANGULATOR_LOGGING
Chris Dalton24472af2021-01-11 20:05:00 -07001086void VertexList::dump() {
1087 for (Vertex* v = fHead; v; v = v->fNext) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001088 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 -05001089 if (Vertex* p = v->fPartner) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001090 TESS_LOG(", partner %g (%g, %g) alpha %d\n",
1091 p->fID, p->fPoint.fX, p->fPoint.fY, p->fAlpha);
Stephen White95152e12017-12-18 10:52:44 -05001092 } else {
Brian Salomon120e7d62019-09-11 10:29:22 -04001093 TESS_LOG(", null partner\n");
Stephen White95152e12017-12-18 10:52:44 -05001094 }
1095 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001096 TESS_LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
Stephen White95152e12017-12-18 10:52:44 -05001097 }
1098 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001099 TESS_LOG(" edge %g -> %g, winding %d\n", e->fTop->fID, e->fBottom->fID, e->fWinding);
Stephen White95152e12017-12-18 10:52:44 -05001100 }
1101 }
Chris Daltond60c9192021-01-07 18:30:08 +00001102}
Chris Dalton7cf3add2021-01-11 18:33:28 -07001103#endif
Stephen White95152e12017-12-18 10:52:44 -05001104
Stephen White89042d52018-06-08 12:18:22 -04001105#ifdef SK_DEBUG
Chris Dalton811dc6a2021-01-07 16:40:32 -07001106static void validate_edge_pair(Edge* left, Edge* right, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -04001107 if (!left || !right) {
1108 return;
1109 }
1110 if (left->fTop == right->fTop) {
1111 SkASSERT(left->isLeftOf(right->fBottom));
1112 SkASSERT(right->isRightOf(left->fBottom));
1113 } else if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) {
1114 SkASSERT(left->isLeftOf(right->fTop));
1115 } else {
1116 SkASSERT(right->isRightOf(left->fTop));
1117 }
1118 if (left->fBottom == right->fBottom) {
1119 SkASSERT(left->isLeftOf(right->fTop));
1120 SkASSERT(right->isRightOf(left->fTop));
1121 } else if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) {
1122 SkASSERT(left->isLeftOf(right->fBottom));
1123 } else {
1124 SkASSERT(right->isRightOf(left->fBottom));
1125 }
1126}
1127
Chris Dalton811dc6a2021-01-07 16:40:32 -07001128static void validate_edge_list(EdgeList* edges, const Comparator& c) {
Stephen White89042d52018-06-08 12:18:22 -04001129 Edge* left = edges->fHead;
1130 if (!left) {
1131 return;
1132 }
1133 for (Edge* right = left->fRight; right; right = right->fRight) {
1134 validate_edge_pair(left, right, c);
1135 left = right;
1136 }
1137}
1138#endif
1139
ethannicholase9709e82016-01-07 13:34:16 -08001140// Stage 4: Simplify the mesh by inserting new vertices at intersecting edges.
1141
Chris Dalton811dc6a2021-01-07 16:40:32 -07001142GrTriangulator::SimplifyResult GrTriangulator::simplify(VertexList* mesh, const Comparator& c) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001143 TESS_LOG("simplifying complex polygons\n");
ethannicholase9709e82016-01-07 13:34:16 -08001144 EdgeList activeEdges;
Chris Dalton6ccc0322020-01-29 11:38:16 -07001145 auto result = SimplifyResult::kAlreadySimple;
Stephen White0cb31672017-06-08 14:41:01 -04001146 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
Chris Dalton24472af2021-01-11 20:05:00 -07001147 if (!v->isConnected()) {
ethannicholase9709e82016-01-07 13:34:16 -08001148 continue;
1149 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001150 Edge* leftEnclosingEdge;
1151 Edge* rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001152 bool restartChecks;
1153 do {
Brian Salomon120e7d62019-09-11 10:29:22 -04001154 TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n",
1155 v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha);
ethannicholase9709e82016-01-07 13:34:16 -08001156 restartChecks = false;
Chris Dalton47114db2021-01-06 00:35:20 -07001157 FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White3b5a3fa2017-06-06 14:51:19 -04001158 v->fLeftEnclosingEdge = leftEnclosingEdge;
1159 v->fRightEnclosingEdge = rightEnclosingEdge;
ethannicholase9709e82016-01-07 13:34:16 -08001160 if (v->fFirstEdgeBelow) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001161 for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001162 if (this->checkForIntersection(
1163 leftEnclosingEdge, edge, &activeEdges, &v, mesh, c) ||
1164 this->checkForIntersection(
1165 edge, rightEnclosingEdge, &activeEdges, &v, mesh, c)) {
Chris Dalton854ee852021-01-05 15:12:59 -07001166 if (fSimpleInnerPolygons) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001167 return SimplifyResult::kAbort;
1168 }
1169 result = SimplifyResult::kFoundSelfIntersection;
ethannicholase9709e82016-01-07 13:34:16 -08001170 restartChecks = true;
1171 break;
1172 }
1173 }
1174 } else {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001175 if (this->checkForIntersection(leftEnclosingEdge, rightEnclosingEdge, &activeEdges,
1176 &v, mesh, c)) {
Chris Dalton854ee852021-01-05 15:12:59 -07001177 if (fSimpleInnerPolygons) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001178 return SimplifyResult::kAbort;
1179 }
1180 result = SimplifyResult::kFoundSelfIntersection;
ethannicholase9709e82016-01-07 13:34:16 -08001181 restartChecks = true;
1182 }
1183
1184 }
1185 } while (restartChecks);
Stephen White89042d52018-06-08 12:18:22 -04001186#ifdef SK_DEBUG
1187 validate_edge_list(&activeEdges, c);
1188#endif
ethannicholase9709e82016-01-07 13:34:16 -08001189 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Chris Dalton24472af2021-01-11 20:05:00 -07001190 activeEdges.remove(e);
ethannicholase9709e82016-01-07 13:34:16 -08001191 }
1192 Edge* leftEdge = leftEnclosingEdge;
1193 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -07001194 activeEdges.insert(e, leftEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001195 leftEdge = e;
1196 }
ethannicholase9709e82016-01-07 13:34:16 -08001197 }
Stephen Whitee260c462017-12-19 18:09:54 -05001198 SkASSERT(!activeEdges.fHead && !activeEdges.fTail);
Chris Dalton6ccc0322020-01-29 11:38:16 -07001199 return result;
ethannicholase9709e82016-01-07 13:34:16 -08001200}
1201
1202// Stage 5: Tessellate the simplified mesh into monotone polygons.
1203
Chris Dalton93c2d812021-01-11 19:51:59 -07001204Poly* GrTriangulator::tessellate(const VertexList& vertices, const Comparator&) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001205 TESS_LOG("\ntessellating simple polygons\n");
Chris Dalton6ccc0322020-01-29 11:38:16 -07001206 int maxWindMagnitude = std::numeric_limits<int>::max();
Chris Dalton854ee852021-01-05 15:12:59 -07001207 if (fSimpleInnerPolygons && !SkPathFillType_IsEvenOdd(fPath.getFillType())) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001208 maxWindMagnitude = 1;
1209 }
ethannicholase9709e82016-01-07 13:34:16 -08001210 EdgeList activeEdges;
1211 Poly* polys = nullptr;
Stephen Whitebf6137e2017-01-04 15:43:26 -05001212 for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) {
Chris Dalton24472af2021-01-11 20:05:00 -07001213 if (!v->isConnected()) {
ethannicholase9709e82016-01-07 13:34:16 -08001214 continue;
1215 }
Chris Dalton5045de32021-01-07 19:09:01 -07001216#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001217 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 -08001218#endif
Stephen White8a0bfc52017-02-21 15:24:13 -05001219 Edge* leftEnclosingEdge;
1220 Edge* rightEnclosingEdge;
Chris Dalton47114db2021-01-06 00:35:20 -07001221 FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
Stephen White8a0bfc52017-02-21 15:24:13 -05001222 Poly* leftPoly;
1223 Poly* rightPoly;
ethannicholase9709e82016-01-07 13:34:16 -08001224 if (v->fFirstEdgeAbove) {
1225 leftPoly = v->fFirstEdgeAbove->fLeftPoly;
1226 rightPoly = v->fLastEdgeAbove->fRightPoly;
1227 } else {
1228 leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr;
1229 rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr;
1230 }
Chris Dalton5045de32021-01-07 19:09:01 -07001231#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001232 TESS_LOG("edges above:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001233 for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001234 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1235 e->fTop->fID, e->fBottom->fID,
1236 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1237 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001238 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001239 TESS_LOG("edges below:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001240 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001241 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1242 e->fTop->fID, e->fBottom->fID,
1243 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1244 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001245 }
1246#endif
1247 if (v->fFirstEdgeAbove) {
1248 if (leftPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001249 leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, kRight_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001250 }
1251 if (rightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001252 rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001253 }
1254 for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) {
ethannicholase9709e82016-01-07 13:34:16 -08001255 Edge* rightEdge = e->fNextEdgeAbove;
Chris Dalton24472af2021-01-11 20:05:00 -07001256 activeEdges.remove(e);
Stephen White8a0bfc52017-02-21 15:24:13 -05001257 if (e->fRightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001258 e->fRightPoly->addEdge(e, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001259 }
Stephen White8a0bfc52017-02-21 15:24:13 -05001260 if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001261 rightEdge->fLeftPoly->addEdge(e, kRight_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001262 }
1263 }
Chris Dalton24472af2021-01-11 20:05:00 -07001264 activeEdges.remove(v->fLastEdgeAbove);
ethannicholase9709e82016-01-07 13:34:16 -08001265 if (!v->fFirstEdgeBelow) {
1266 if (leftPoly && rightPoly && leftPoly != rightPoly) {
1267 SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr);
1268 rightPoly->fPartner = leftPoly;
1269 leftPoly->fPartner = rightPoly;
1270 }
1271 }
1272 }
1273 if (v->fFirstEdgeBelow) {
1274 if (!v->fFirstEdgeAbove) {
senorblanco93e3fff2016-06-07 12:36:00 -07001275 if (leftPoly && rightPoly) {
senorblanco531237e2016-06-02 11:36:48 -07001276 if (leftPoly == rightPoly) {
Chris Dalton17ce8c52021-01-07 18:08:46 -07001277 if (leftPoly->fTail && leftPoly->fTail->fSide == kLeft_Side) {
Chris Dalton7cf3add2021-01-11 18:33:28 -07001278 leftPoly = this->makePoly(&polys, leftPoly->lastVertex(),
1279 leftPoly->fWinding);
senorblanco531237e2016-06-02 11:36:48 -07001280 leftEnclosingEdge->fRightPoly = leftPoly;
1281 } else {
Chris Dalton7cf3add2021-01-11 18:33:28 -07001282 rightPoly = this->makePoly(&polys, rightPoly->lastVertex(),
1283 rightPoly->fWinding);
senorblanco531237e2016-06-02 11:36:48 -07001284 rightEnclosingEdge->fLeftPoly = rightPoly;
1285 }
ethannicholase9709e82016-01-07 13:34:16 -08001286 }
Chris Daltond60c9192021-01-07 18:30:08 +00001287 Edge* join = fAlloc.make<Edge>(leftPoly->lastVertex(), v, 1,
Chris Dalton17ce8c52021-01-07 18:08:46 -07001288 EdgeType::kInner);
1289 leftPoly = leftPoly->addEdge(join, kRight_Side, fAlloc);
1290 rightPoly = rightPoly->addEdge(join, kLeft_Side, fAlloc);
ethannicholase9709e82016-01-07 13:34:16 -08001291 }
1292 }
1293 Edge* leftEdge = v->fFirstEdgeBelow;
1294 leftEdge->fLeftPoly = leftPoly;
Chris Dalton24472af2021-01-11 20:05:00 -07001295 activeEdges.insert(leftEdge, leftEnclosingEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001296 for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge;
1297 rightEdge = rightEdge->fNextEdgeBelow) {
Chris Dalton24472af2021-01-11 20:05:00 -07001298 activeEdges.insert(rightEdge, leftEdge);
ethannicholase9709e82016-01-07 13:34:16 -08001299 int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0;
1300 winding += leftEdge->fWinding;
1301 if (winding != 0) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001302 if (abs(winding) > maxWindMagnitude) {
1303 return nullptr; // We can't have weighted wind in kSimpleInnerPolygons mode
1304 }
Chris Dalton7cf3add2021-01-11 18:33:28 -07001305 Poly* poly = this->makePoly(&polys, v, winding);
ethannicholase9709e82016-01-07 13:34:16 -08001306 leftEdge->fRightPoly = rightEdge->fLeftPoly = poly;
1307 }
1308 leftEdge = rightEdge;
1309 }
1310 v->fLastEdgeBelow->fRightPoly = rightPoly;
1311 }
Chris Dalton5045de32021-01-07 19:09:01 -07001312#if TRIANGULATOR_LOGGING
Brian Salomon120e7d62019-09-11 10:29:22 -04001313 TESS_LOG("\nactive edges:\n");
ethannicholase9709e82016-01-07 13:34:16 -08001314 for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001315 TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n",
1316 e->fTop->fID, e->fBottom->fID,
1317 e->fLeftPoly ? e->fLeftPoly->fID : -1,
1318 e->fRightPoly ? e->fRightPoly->fID : -1);
ethannicholase9709e82016-01-07 13:34:16 -08001319 }
1320#endif
1321 }
1322 return polys;
1323}
1324
Stephen Whitebda29c02017-03-13 15:10:13 -04001325// This is a driver function that calls stages 2-5 in turn.
ethannicholase9709e82016-01-07 13:34:16 -08001326
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001327void GrTriangulator::contoursToMesh(VertexList* contours, int contourCnt, VertexList* mesh,
Chris Dalton811dc6a2021-01-07 16:40:32 -07001328 const Comparator& c) {
Chris Dalton5045de32021-01-07 19:09:01 -07001329#if TRIANGULATOR_LOGGING
ethannicholase9709e82016-01-07 13:34:16 -08001330 for (int i = 0; i < contourCnt; ++i) {
Stephen White3a9aab92017-03-07 14:07:18 -05001331 Vertex* v = contours[i].fHead;
ethannicholase9709e82016-01-07 13:34:16 -08001332 SkASSERT(v);
Brian Salomon120e7d62019-09-11 10:29:22 -04001333 TESS_LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
Stephen White3a9aab92017-03-07 14:07:18 -05001334 for (v = v->fNext; v; v = v->fNext) {
Brian Salomon120e7d62019-09-11 10:29:22 -04001335 TESS_LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY);
ethannicholase9709e82016-01-07 13:34:16 -08001336 }
1337 }
1338#endif
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001339 this->sanitizeContours(contours, contourCnt);
1340 this->buildEdges(contours, contourCnt, mesh, c);
senorblancof57372d2016-08-31 10:36:19 -07001341}
1342
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001343void GrTriangulator::SortMesh(VertexList* vertices, const Comparator& c) {
Stephen Whitebf6137e2017-01-04 15:43:26 -05001344 if (!vertices || !vertices->fHead) {
Stephen White2f4686f2017-01-03 16:20:01 -05001345 return;
ethannicholase9709e82016-01-07 13:34:16 -08001346 }
1347
1348 // Sort vertices in Y (secondarily in X).
Stephen White16a40cb2017-02-23 11:10:01 -05001349 if (c.fDirection == Comparator::Direction::kHorizontal) {
1350 merge_sort<sweep_lt_horiz>(vertices);
1351 } else {
1352 merge_sort<sweep_lt_vert>(vertices);
1353 }
Chris Dalton5045de32021-01-07 19:09:01 -07001354#if TRIANGULATOR_LOGGING
Stephen White2e2cb9b2017-01-09 13:11:18 -05001355 for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) {
ethannicholase9709e82016-01-07 13:34:16 -08001356 static float gID = 0.0f;
1357 v->fID = gID++;
1358 }
1359#endif
Stephen White2f4686f2017-01-03 16:20:01 -05001360}
1361
Chris Dalton93c2d812021-01-11 19:51:59 -07001362Poly* GrTriangulator::contoursToPolys(VertexList* contours, int contourCnt) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001363 const SkRect& pathBounds = fPath.getBounds();
Stephen White16a40cb2017-02-23 11:10:01 -05001364 Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal
1365 : Comparator::Direction::kVertical);
Stephen Whitebf6137e2017-01-04 15:43:26 -05001366 VertexList mesh;
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001367 this->contoursToMesh(contours, contourCnt, &mesh, c);
1368 SortMesh(&mesh, c);
1369 this->mergeCoincidentVertices(&mesh, c);
1370 if (SimplifyResult::kAbort == this->simplify(&mesh, c)) {
Chris Dalton6ccc0322020-01-29 11:38:16 -07001371 return nullptr;
1372 }
Brian Salomon120e7d62019-09-11 10:29:22 -04001373 TESS_LOG("\nsimplified mesh:\n");
Chris Dalton7cf3add2021-01-11 18:33:28 -07001374 DUMP_MESH(mesh);
Chris Dalton93c2d812021-01-11 19:51:59 -07001375 return this->tessellate(mesh, c);
Chris Dalton7cf3add2021-01-11 18:33:28 -07001376}
1377
senorblancof57372d2016-08-31 10:36:19 -07001378// Stage 6: Triangulate the monotone polygons into a vertex buffer.
Chris Dalton93c2d812021-01-11 19:51:59 -07001379void* GrTriangulator::polysToTrianglesImpl(Poly* polys, void* data,
1380 SkPathFillType overrideFillType) {
senorblancof57372d2016-08-31 10:36:19 -07001381 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001382 if (apply_fill_type(overrideFillType, poly)) {
Chris Dalton9a4904f2021-01-07 19:10:14 -07001383 data = this->emitPoly(poly, data);
senorblancof57372d2016-08-31 10:36:19 -07001384 }
1385 }
1386 return data;
ethannicholase9709e82016-01-07 13:34:16 -08001387}
1388
Chris Dalton93c2d812021-01-11 19:51:59 -07001389Poly* GrTriangulator::pathToPolys(float tolerance, const SkRect& clipBounds, int contourCnt) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001390 if (SkPathFillType_IsInverse(fPath.getFillType())) {
ethannicholase9709e82016-01-07 13:34:16 -08001391 contourCnt++;
1392 }
Stephen White3a9aab92017-03-07 14:07:18 -05001393 std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]);
ethannicholase9709e82016-01-07 13:34:16 -08001394
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001395 this->pathToContours(tolerance, clipBounds, contours.get());
Chris Dalton93c2d812021-01-11 19:51:59 -07001396 return this->contoursToPolys(contours.get(), contourCnt);
ethannicholase9709e82016-01-07 13:34:16 -08001397}
1398
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001399static int get_contour_count(const SkPath& path, SkScalar tolerance) {
Chris Daltonc71b3d42020-01-08 21:29:59 -07001400 // We could theoretically be more aggressive about not counting empty contours, but we need to
1401 // actually match the exact number of contour linked lists the tessellator will create later on.
1402 int contourCnt = 1;
1403 bool hasPoints = false;
1404
Chris Dalton7156db22020-05-07 22:06:28 +00001405 SkPath::Iter iter(path, false);
1406 SkPath::Verb verb;
1407 SkPoint pts[4];
Chris Daltonc71b3d42020-01-08 21:29:59 -07001408 bool first = true;
Chris Dalton7156db22020-05-07 22:06:28 +00001409 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
Chris Daltonc71b3d42020-01-08 21:29:59 -07001410 switch (verb) {
Chris Dalton7156db22020-05-07 22:06:28 +00001411 case SkPath::kMove_Verb:
Chris Daltonc71b3d42020-01-08 21:29:59 -07001412 if (!first) {
1413 ++contourCnt;
1414 }
John Stiles30212b72020-06-11 17:55:07 -04001415 [[fallthrough]];
Chris Dalton7156db22020-05-07 22:06:28 +00001416 case SkPath::kLine_Verb:
1417 case SkPath::kConic_Verb:
1418 case SkPath::kQuad_Verb:
1419 case SkPath::kCubic_Verb:
Chris Daltonc71b3d42020-01-08 21:29:59 -07001420 hasPoints = true;
John Stiles30212b72020-06-11 17:55:07 -04001421 break;
Chris Daltonc71b3d42020-01-08 21:29:59 -07001422 default:
1423 break;
1424 }
1425 first = false;
1426 }
1427 if (!hasPoints) {
Stephen White11f65e02017-02-16 19:00:39 -05001428 return 0;
ethannicholase9709e82016-01-07 13:34:16 -08001429 }
Stephen White11f65e02017-02-16 19:00:39 -05001430 return contourCnt;
ethannicholase9709e82016-01-07 13:34:16 -08001431}
1432
Chris Dalton93c2d812021-01-11 19:51:59 -07001433int64_t GrTriangulator::countPointsImpl(Poly* polys, SkPathFillType overrideFillType) const {
Greg Danield5b45932018-06-07 13:15:10 -04001434 int64_t count = 0;
ethannicholase9709e82016-01-07 13:34:16 -08001435 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton93c2d812021-01-11 19:51:59 -07001436 if (apply_fill_type(overrideFillType, poly) && poly->fCount >= 3) {
Chris Dalton17dc4182020-03-25 16:18:16 -06001437 count += (poly->fCount - 2) * (TRIANGULATOR_WIREFRAME ? 6 : 3);
ethannicholase9709e82016-01-07 13:34:16 -08001438 }
1439 }
1440 return count;
1441}
1442
ethannicholase9709e82016-01-07 13:34:16 -08001443// Stage 6: Triangulate the monotone polygons into a vertex buffer.
1444
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001445int GrTriangulator::pathToTriangles(float tolerance, const SkRect& clipBounds,
Chris Dalton93c2d812021-01-11 19:51:59 -07001446 GrEagerVertexAllocator* vertexAllocator) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001447 int contourCnt = get_contour_count(fPath, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001448 if (contourCnt <= 0) {
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001449 fIsLinear = true;
ethannicholase9709e82016-01-07 13:34:16 -08001450 return 0;
1451 }
Chris Dalton93c2d812021-01-11 19:51:59 -07001452 Poly* polys = this->pathToPolys(tolerance, clipBounds, contourCnt);
1453 int64_t count64 = this->countPoints(polys);
Greg Danield5b45932018-06-07 13:15:10 -04001454 if (0 == count64 || count64 > SK_MaxS32) {
Stephen Whiteff60b172017-05-05 15:54:52 -04001455 return 0;
1456 }
Greg Danield5b45932018-06-07 13:15:10 -04001457 int count = count64;
ethannicholase9709e82016-01-07 13:34:16 -08001458
Chris Dalton854ee852021-01-05 15:12:59 -07001459 size_t vertexStride = sizeof(SkPoint);
1460 if (fEmitCoverage) {
1461 vertexStride += sizeof(float);
1462 }
Chris Daltond081dce2020-01-23 12:09:04 -07001463 void* verts = vertexAllocator->lock(vertexStride, count);
senorblanco6599eff2016-03-10 08:38:45 -08001464 if (!verts) {
ethannicholase9709e82016-01-07 13:34:16 -08001465 SkDebugf("Could not allocate vertices\n");
1466 return 0;
1467 }
senorblancof57372d2016-08-31 10:36:19 -07001468
Brian Salomon120e7d62019-09-11 10:29:22 -04001469 TESS_LOG("emitting %d verts\n", count);
Chris Dalton93c2d812021-01-11 19:51:59 -07001470 void* end = this->polysToTriangles(polys, verts);
Brian Osman80879d42019-01-07 16:15:27 -05001471
senorblancof57372d2016-08-31 10:36:19 -07001472 int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts))
Chris Daltond081dce2020-01-23 12:09:04 -07001473 / vertexStride);
ethannicholase9709e82016-01-07 13:34:16 -08001474 SkASSERT(actualCount <= count);
senorblanco6599eff2016-03-10 08:38:45 -08001475 vertexAllocator->unlock(actualCount);
ethannicholase9709e82016-01-07 13:34:16 -08001476 return actualCount;
1477}
1478
Chris Dalton57ea1fc2021-01-05 13:37:44 -07001479int GrTriangulator::PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
1480 WindingVertex** verts) {
Stephen White11f65e02017-02-16 19:00:39 -05001481 int contourCnt = get_contour_count(path, tolerance);
ethannicholase9709e82016-01-07 13:34:16 -08001482 if (contourCnt <= 0) {
Chris Dalton84403d72018-02-13 21:46:17 -05001483 *verts = nullptr;
ethannicholase9709e82016-01-07 13:34:16 -08001484 return 0;
1485 }
Chris Dalton854ee852021-01-05 15:12:59 -07001486 GrTriangulator triangulator(path);
Chris Dalton93c2d812021-01-11 19:51:59 -07001487 Poly* polys = triangulator.pathToPolys(tolerance, clipBounds, contourCnt);
1488 int64_t count64 = triangulator.countPoints(polys);
Greg Danield5b45932018-06-07 13:15:10 -04001489 if (0 == count64 || count64 > SK_MaxS32) {
ethannicholase9709e82016-01-07 13:34:16 -08001490 *verts = nullptr;
1491 return 0;
1492 }
Greg Danield5b45932018-06-07 13:15:10 -04001493 int count = count64;
ethannicholase9709e82016-01-07 13:34:16 -08001494
Chris Dalton17dc4182020-03-25 16:18:16 -06001495 *verts = new WindingVertex[count];
1496 WindingVertex* vertsEnd = *verts;
ethannicholase9709e82016-01-07 13:34:16 -08001497 SkPoint* points = new SkPoint[count];
1498 SkPoint* pointsEnd = points;
1499 for (Poly* poly = polys; poly; poly = poly->fNext) {
Chris Dalton93c2d812021-01-11 19:51:59 -07001500 if (apply_fill_type(path.getFillType(), poly)) {
ethannicholase9709e82016-01-07 13:34:16 -08001501 SkPoint* start = pointsEnd;
Chris Dalton9a4904f2021-01-07 19:10:14 -07001502 pointsEnd = static_cast<SkPoint*>(triangulator.emitPoly(poly, pointsEnd));
ethannicholase9709e82016-01-07 13:34:16 -08001503 while (start != pointsEnd) {
1504 vertsEnd->fPos = *start;
1505 vertsEnd->fWinding = poly->fWinding;
1506 ++start;
1507 ++vertsEnd;
1508 }
1509 }
1510 }
1511 int actualCount = static_cast<int>(vertsEnd - *verts);
1512 SkASSERT(actualCount <= count);
1513 SkASSERT(pointsEnd - points == actualCount);
1514 delete[] points;
1515 return actualCount;
1516}