blob: 402f58bc1ae3b18c4bfa224d91488a7cbc7b377f [file] [log] [blame]
Chris Dalton47114db2021-01-06 00:35:20 -07001/*
2 * Copyright 2020 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
8#include "src/gpu/GrAATriangulator.h"
9
10#include <queue>
11#include <vector>
12#include <unordered_map>
13
14#if TRIANGULATOR_LOGGING
15#define TESS_LOG SkDebugf
16#define DUMP_MESH(MESH) (MESH).dump()
17#else
18#define TESS_LOG(...)
19#define DUMP_MESH(MESH)
20#endif
21
22constexpr static float kCosMiterAngle = 0.97f; // Corresponds to an angle of ~14 degrees.
23
24using EdgeType = GrTriangulator::EdgeType;
25using Vertex = GrTriangulator::Vertex;
26using VertexList = GrTriangulator::VertexList;
27using Line = GrTriangulator::Line;
28using Edge = GrTriangulator::Edge;
29using EdgeList = GrTriangulator::EdgeList;
30using Poly = GrTriangulator::Poly;
31using Comparator = GrTriangulator::Comparator;
32using SSEdge = GrAATriangulator::SSEdge;
33using EventList = GrAATriangulator::EventList;
34using Event = GrAATriangulator::Event;
35using EventComparator = GrAATriangulator::EventComparator;
36
37struct SSVertex {
38 SSVertex(Vertex* v) : fVertex(v), fPrev(nullptr), fNext(nullptr) {}
39 Vertex* fVertex;
40 SSEdge* fPrev;
41 SSEdge* fNext;
42};
43
44struct GrAATriangulator::SSEdge {
45 SSEdge(Edge* edge, SSVertex* prev, SSVertex* next)
46 : fEdge(edge), fEvent(nullptr), fPrev(prev), fNext(next) {
47 }
48 Edge* fEdge;
49 Event* fEvent;
50 SSVertex* fPrev;
51 SSVertex* fNext;
52};
53
54typedef std::unordered_map<Vertex*, SSVertex*> SSVertexMap;
55typedef std::vector<SSEdge*> SSEdgeList;
56typedef std::priority_queue<Event*, std::vector<Event*>, EventComparator> EventPQ;
57
58struct GrAATriangulator::EventList : EventPQ {
59 EventList(EventComparator comparison) : EventPQ(comparison) {
60 }
61};
62
63void GrAATriangulator::makeEvent(SSEdge* e, EventList* events) {
64 Vertex* prev = e->fPrev->fVertex;
65 Vertex* next = e->fNext->fVertex;
66 if (prev == next || !prev->fPartner || !next->fPartner) {
67 return;
68 }
69 Edge bisector1(prev, prev->fPartner, 1, EdgeType::kConnector);
70 Edge bisector2(next, next->fPartner, 1, EdgeType::kConnector);
71 SkPoint p;
72 uint8_t alpha;
73 if (bisector1.intersect(bisector2, &p, &alpha)) {
74 TESS_LOG("found edge event for %g, %g (original %g -> %g), "
75 "will collapse to %g,%g alpha %d\n",
76 prev->fID, next->fID, e->fEdge->fTop->fID, e->fEdge->fBottom->fID, p.fX, p.fY,
77 alpha);
78 e->fEvent = fAlloc.make<Event>(e, p, alpha);
79 events->push(e->fEvent);
80 }
81}
82
83void GrAATriangulator::makeEvent(SSEdge* edge, Vertex* v, SSEdge* other, Vertex* dest,
84 EventList* events, const Comparator& c) {
85 if (!v->fPartner) {
86 return;
87 }
88 Vertex* top = edge->fEdge->fTop;
89 Vertex* bottom = edge->fEdge->fBottom;
90 if (!top || !bottom ) {
91 return;
92 }
93 Line line = edge->fEdge->fLine;
94 line.fC = -(dest->fPoint.fX * line.fA + dest->fPoint.fY * line.fB);
95 Edge bisector(v, v->fPartner, 1, EdgeType::kConnector);
96 SkPoint p;
97 uint8_t alpha = dest->fAlpha;
98 if (line.intersect(bisector.fLine, &p) && !c.sweep_lt(p, top->fPoint) &&
99 c.sweep_lt(p, bottom->fPoint)) {
100 TESS_LOG("found p edge event for %g, %g (original %g -> %g), "
101 "will collapse to %g,%g alpha %d\n",
102 dest->fID, v->fID, top->fID, bottom->fID, p.fX, p.fY, alpha);
103 edge->fEvent = fAlloc.make<Event>(edge, p, alpha);
104 events->push(edge->fEvent);
105 }
106}
107
108void GrAATriangulator::connectPartners(VertexList* mesh, const Comparator& c) {
109 for (Vertex* outer = mesh->fHead; outer; outer = outer->fNext) {
110 if (Vertex* inner = outer->fPartner) {
111 if ((inner->fPrev || inner->fNext) && (outer->fPrev || outer->fNext)) {
112 // Connector edges get zero winding, since they're only structural (i.e., to ensure
113 // no 0-0-0 alpha triangles are produced), and shouldn't affect the poly winding
114 // number.
115 this->makeConnectingEdge(outer, inner, EdgeType::kConnector, c, 0);
116 inner->fPartner = outer->fPartner = nullptr;
117 }
118 }
119 }
120}
121
122static void dump_skel(const SSEdgeList& ssEdges) {
123#if TRIANGULATOR_LOGGING
124 for (SSEdge* edge : ssEdges) {
125 if (edge->fEdge) {
126 TESS_LOG("skel edge %g -> %g",
127 edge->fPrev->fVertex->fID,
128 edge->fNext->fVertex->fID);
129 if (edge->fEdge->fTop && edge->fEdge->fBottom) {
130 TESS_LOG(" (original %g -> %g)\n",
131 edge->fEdge->fTop->fID,
132 edge->fEdge->fBottom->fID);
133 } else {
134 TESS_LOG("\n");
135 }
136 }
137 }
138#endif
139}
140
141void GrAATriangulator::removeNonBoundaryEdges(const VertexList& mesh) {
142 TESS_LOG("removing non-boundary edges\n");
143 EdgeList activeEdges;
144 for (Vertex* v = mesh.fHead; v != nullptr; v = v->fNext) {
145 if (!v->isConnected()) {
146 continue;
147 }
148 Edge* leftEnclosingEdge;
149 Edge* rightEnclosingEdge;
150 FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
151 bool prevFilled = leftEnclosingEdge && this->applyFillType(leftEnclosingEdge->fWinding);
152 for (Edge* e = v->fFirstEdgeAbove; e;) {
153 Edge* next = e->fNextEdgeAbove;
154 activeEdges.remove(e);
155 bool filled = this->applyFillType(e->fWinding);
156 if (filled == prevFilled) {
157 e->disconnect();
158 }
159 prevFilled = filled;
160 e = next;
161 }
162 Edge* prev = leftEnclosingEdge;
163 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
164 if (prev) {
165 e->fWinding += prev->fWinding;
166 }
167 activeEdges.insert(e, prev);
168 prev = e;
169 }
170 }
171}
172
173// Note: this is the normal to the edge, but not necessarily unit length.
174static void get_edge_normal(const Edge* e, SkVector* normal) {
175 normal->set(SkDoubleToScalar(e->fLine.fA),
176 SkDoubleToScalar(e->fLine.fB));
177}
178
179// Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions
180// and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to
181// invert on stroking.
182
183void GrAATriangulator::simplifyBoundary(EdgeList* boundary, const Comparator& c) {
184 Edge* prevEdge = boundary->fTail;
185 SkVector prevNormal;
186 get_edge_normal(prevEdge, &prevNormal);
187 for (Edge* e = boundary->fHead; e != nullptr;) {
188 Vertex* prev = prevEdge->fWinding == 1 ? prevEdge->fTop : prevEdge->fBottom;
189 Vertex* next = e->fWinding == 1 ? e->fBottom : e->fTop;
190 double distPrev = e->dist(prev->fPoint);
191 double distNext = prevEdge->dist(next->fPoint);
192 SkVector normal;
193 get_edge_normal(e, &normal);
194 constexpr double kQuarterPixelSq = 0.25f * 0.25f;
195 if (prev == next) {
196 boundary->remove(prevEdge);
197 boundary->remove(e);
198 prevEdge = boundary->fTail;
199 e = boundary->fHead;
200 if (prevEdge) {
201 get_edge_normal(prevEdge, &prevNormal);
202 }
203 } else if (prevNormal.dot(normal) < 0.0 &&
204 (distPrev * distPrev <= kQuarterPixelSq || distNext * distNext <= kQuarterPixelSq)) {
205 Edge* join = this->makeEdge(prev, next, EdgeType::kInner, c);
206 if (prev->fPoint != next->fPoint) {
207 join->fLine.normalize();
208 join->fLine = join->fLine * join->fWinding;
209 }
210 boundary->insert(join, e);
211 boundary->remove(prevEdge);
212 boundary->remove(e);
213 if (join->fLeft && join->fRight) {
214 prevEdge = join->fLeft;
215 e = join;
216 } else {
217 prevEdge = boundary->fTail;
218 e = boundary->fHead; // join->fLeft ? join->fLeft : join;
219 }
220 get_edge_normal(prevEdge, &prevNormal);
221 } else {
222 prevEdge = e;
223 prevNormal = normal;
224 e = e->fRight;
225 }
226 }
227}
228
229void GrAATriangulator::connectSSEdge(Vertex* v, Vertex* dest, const Comparator& c) {
230 if (v == dest) {
231 return;
232 }
233 TESS_LOG("ss_connecting vertex %g to vertex %g\n", v->fID, dest->fID);
234 if (v->fSynthetic) {
235 this->makeConnectingEdge(v, dest, EdgeType::kConnector, c, 0);
236 } else if (v->fPartner) {
237 TESS_LOG("setting %g's partner to %g ", v->fPartner->fID, dest->fID);
238 TESS_LOG("and %g's partner to null\n", v->fID);
239 v->fPartner->fPartner = dest;
240 v->fPartner = nullptr;
241 }
242}
243
244void GrAATriangulator::Event::apply(VertexList* mesh, const Comparator& c, EventList* events,
245 GrAATriangulator* triangulator) {
246 if (!fEdge) {
247 return;
248 }
249 Vertex* prev = fEdge->fPrev->fVertex;
250 Vertex* next = fEdge->fNext->fVertex;
251 SSEdge* prevEdge = fEdge->fPrev->fPrev;
252 SSEdge* nextEdge = fEdge->fNext->fNext;
253 if (!prevEdge || !nextEdge || !prevEdge->fEdge || !nextEdge->fEdge) {
254 return;
255 }
256 Vertex* dest = triangulator->makeSortedVertex(fPoint, fAlpha, mesh, prev, c);
257 dest->fSynthetic = true;
258 SSVertex* ssv = triangulator->fAlloc.make<SSVertex>(dest);
259 TESS_LOG("collapsing %g, %g (original edge %g -> %g) to %g (%g, %g) alpha %d\n",
260 prev->fID, next->fID, fEdge->fEdge->fTop->fID, fEdge->fEdge->fBottom->fID, dest->fID,
261 fPoint.fX, fPoint.fY, fAlpha);
262 fEdge->fEdge = nullptr;
263
264 triangulator->connectSSEdge(prev, dest, c);
265 triangulator->connectSSEdge(next, dest, c);
266
267 prevEdge->fNext = nextEdge->fPrev = ssv;
268 ssv->fPrev = prevEdge;
269 ssv->fNext = nextEdge;
270 if (!prevEdge->fEdge || !nextEdge->fEdge) {
271 return;
272 }
273 if (prevEdge->fEvent) {
274 prevEdge->fEvent->fEdge = nullptr;
275 }
276 if (nextEdge->fEvent) {
277 nextEdge->fEvent->fEdge = nullptr;
278 }
279 if (prevEdge->fPrev == nextEdge->fNext) {
280 triangulator->connectSSEdge(prevEdge->fPrev->fVertex, dest, c);
281 prevEdge->fEdge = nextEdge->fEdge = nullptr;
282 } else {
283 triangulator->computeBisector(prevEdge->fEdge, nextEdge->fEdge, dest);
284 SkASSERT(prevEdge != fEdge && nextEdge != fEdge);
285 if (dest->fPartner) {
286 triangulator->makeEvent(prevEdge, events);
287 triangulator->makeEvent(nextEdge, events);
288 } else {
289 triangulator->makeEvent(prevEdge, prevEdge->fPrev->fVertex, nextEdge, dest, events, c);
290 triangulator->makeEvent(nextEdge, nextEdge->fNext->fVertex, prevEdge, dest, events, c);
291 }
292 }
293}
294
295static bool is_overlap_edge(Edge* e) {
296 if (e->fType == EdgeType::kOuter) {
297 return e->fWinding != 0 && e->fWinding != 1;
298 } else if (e->fType == EdgeType::kInner) {
299 return e->fWinding != 0 && e->fWinding != -2;
300 } else {
301 return false;
302 }
303}
304
305// This is a stripped-down version of tessellate() which computes edges which
306// join two filled regions, which represent overlap regions, and collapses them.
307bool GrAATriangulator::collapseOverlapRegions(VertexList* mesh, const Comparator& c,
308 EventComparator comp) {
309 TESS_LOG("\nfinding overlap regions\n");
310 EdgeList activeEdges;
311 EventList events(comp);
312 SSVertexMap ssVertices;
313 SSEdgeList ssEdges;
314 for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) {
315 if (!v->isConnected()) {
316 continue;
317 }
318 Edge* leftEnclosingEdge;
319 Edge* rightEnclosingEdge;
320 FindEnclosingEdges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge);
321 for (Edge* e = v->fLastEdgeAbove; e && e != leftEnclosingEdge;) {
322 Edge* prev = e->fPrevEdgeAbove ? e->fPrevEdgeAbove : leftEnclosingEdge;
323 activeEdges.remove(e);
324 bool leftOverlap = prev && is_overlap_edge(prev);
325 bool rightOverlap = is_overlap_edge(e);
326 bool isOuterBoundary = e->fType == EdgeType::kOuter &&
327 (!prev || prev->fWinding == 0 || e->fWinding == 0);
328 if (prev) {
329 e->fWinding -= prev->fWinding;
330 }
331 if (leftOverlap && rightOverlap) {
332 TESS_LOG("found interior overlap edge %g -> %g, disconnecting\n",
333 e->fTop->fID, e->fBottom->fID);
334 e->disconnect();
335 } else if (leftOverlap || rightOverlap) {
336 TESS_LOG("found overlap edge %g -> %g%s\n",
337 e->fTop->fID, e->fBottom->fID,
338 isOuterBoundary ? ", is outer boundary" : "");
339 Vertex* prevVertex = e->fWinding < 0 ? e->fBottom : e->fTop;
340 Vertex* nextVertex = e->fWinding < 0 ? e->fTop : e->fBottom;
341 SSVertex* ssPrev = ssVertices[prevVertex];
342 if (!ssPrev) {
343 ssPrev = ssVertices[prevVertex] = fAlloc.make<SSVertex>(prevVertex);
344 }
345 SSVertex* ssNext = ssVertices[nextVertex];
346 if (!ssNext) {
347 ssNext = ssVertices[nextVertex] = fAlloc.make<SSVertex>(nextVertex);
348 }
349 SSEdge* ssEdge = fAlloc.make<SSEdge>(e, ssPrev, ssNext);
350 ssEdges.push_back(ssEdge);
351// SkASSERT(!ssPrev->fNext && !ssNext->fPrev);
352 ssPrev->fNext = ssNext->fPrev = ssEdge;
353 this->makeEvent(ssEdge, &events);
354 if (!isOuterBoundary) {
355 e->disconnect();
356 }
357 }
358 e = prev;
359 }
360 Edge* prev = leftEnclosingEdge;
361 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
362 if (prev) {
363 e->fWinding += prev->fWinding;
364 }
365 activeEdges.insert(e, prev);
366 prev = e;
367 }
368 }
369 bool complex = events.size() > 0;
370
371 TESS_LOG("\ncollapsing overlap regions\n");
372 TESS_LOG("skeleton before:\n");
373 dump_skel(ssEdges);
374 while (events.size() > 0) {
375 Event* event = events.top();
376 events.pop();
377 event->apply(mesh, c, &events, this);
378 }
379 TESS_LOG("skeleton after:\n");
380 dump_skel(ssEdges);
381 for (SSEdge* edge : ssEdges) {
382 if (Edge* e = edge->fEdge) {
383 this->makeConnectingEdge(edge->fPrev->fVertex, edge->fNext->fVertex, e->fType, c, 0);
384 }
385 }
386 return complex;
387}
388
389static bool inversion(Vertex* prev, Vertex* next, Edge* origEdge, const Comparator& c) {
390 if (!prev || !next) {
391 return true;
392 }
393 int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1;
394 return winding != origEdge->fWinding;
395}
396
397// Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to
398// find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a
399// new antialiased mesh from those vertices.
400
401void GrAATriangulator::strokeBoundary(EdgeList* boundary, VertexList* innerMesh,
402 const Comparator& c) {
403 TESS_LOG("\nstroking boundary\n");
404 // A boundary with fewer than 3 edges is degenerate.
405 if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) {
406 return;
407 }
408 Edge* prevEdge = boundary->fTail;
409 Vertex* prevV = prevEdge->fWinding > 0 ? prevEdge->fTop : prevEdge->fBottom;
410 SkVector prevNormal;
411 get_edge_normal(prevEdge, &prevNormal);
412 double radius = 0.5;
413 Line prevInner(prevEdge->fLine);
414 prevInner.fC -= radius;
415 Line prevOuter(prevEdge->fLine);
416 prevOuter.fC += radius;
417 VertexList innerVertices;
418 VertexList outerVertices;
419 bool innerInversion = true;
420 bool outerInversion = true;
421 for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) {
422 Vertex* v = e->fWinding > 0 ? e->fTop : e->fBottom;
423 SkVector normal;
424 get_edge_normal(e, &normal);
425 Line inner(e->fLine);
426 inner.fC -= radius;
427 Line outer(e->fLine);
428 outer.fC += radius;
429 SkPoint innerPoint, outerPoint;
430 TESS_LOG("stroking vertex %g (%g, %g)\n", v->fID, v->fPoint.fX, v->fPoint.fY);
431 if (!prevEdge->fLine.nearParallel(e->fLine) && prevInner.intersect(inner, &innerPoint) &&
432 prevOuter.intersect(outer, &outerPoint)) {
433 float cosAngle = normal.dot(prevNormal);
434 if (cosAngle < -kCosMiterAngle) {
435 Vertex* nextV = e->fWinding > 0 ? e->fBottom : e->fTop;
436
437 // This is a pointy vertex whose angle is smaller than the threshold; miter it.
438 Line bisector(innerPoint, outerPoint);
439 Line tangent(v->fPoint, v->fPoint + SkPoint::Make(bisector.fA, bisector.fB));
440 if (tangent.fA == 0 && tangent.fB == 0) {
441 continue;
442 }
443 tangent.normalize();
444 Line innerTangent(tangent);
445 Line outerTangent(tangent);
446 innerTangent.fC -= 0.5;
447 outerTangent.fC += 0.5;
448 SkPoint innerPoint1, innerPoint2, outerPoint1, outerPoint2;
449 if (prevNormal.cross(normal) > 0) {
450 // Miter inner points
451 if (!innerTangent.intersect(prevInner, &innerPoint1) ||
452 !innerTangent.intersect(inner, &innerPoint2) ||
453 !outerTangent.intersect(bisector, &outerPoint)) {
454 continue;
455 }
456 Line prevTangent(prevV->fPoint,
457 prevV->fPoint + SkVector::Make(prevOuter.fA, prevOuter.fB));
458 Line nextTangent(nextV->fPoint,
459 nextV->fPoint + SkVector::Make(outer.fA, outer.fB));
460 if (prevTangent.dist(outerPoint) > 0) {
461 bisector.intersect(prevTangent, &outerPoint);
462 }
463 if (nextTangent.dist(outerPoint) < 0) {
464 bisector.intersect(nextTangent, &outerPoint);
465 }
466 outerPoint1 = outerPoint2 = outerPoint;
467 } else {
468 // Miter outer points
469 if (!outerTangent.intersect(prevOuter, &outerPoint1) ||
470 !outerTangent.intersect(outer, &outerPoint2)) {
471 continue;
472 }
473 Line prevTangent(prevV->fPoint,
474 prevV->fPoint + SkVector::Make(prevInner.fA, prevInner.fB));
475 Line nextTangent(nextV->fPoint,
476 nextV->fPoint + SkVector::Make(inner.fA, inner.fB));
477 if (prevTangent.dist(innerPoint) > 0) {
478 bisector.intersect(prevTangent, &innerPoint);
479 }
480 if (nextTangent.dist(innerPoint) < 0) {
481 bisector.intersect(nextTangent, &innerPoint);
482 }
483 innerPoint1 = innerPoint2 = innerPoint;
484 }
485 if (!innerPoint1.isFinite() || !innerPoint2.isFinite() ||
486 !outerPoint1.isFinite() || !outerPoint2.isFinite()) {
487 continue;
488 }
489 TESS_LOG("inner (%g, %g), (%g, %g), ",
490 innerPoint1.fX, innerPoint1.fY, innerPoint2.fX, innerPoint2.fY);
491 TESS_LOG("outer (%g, %g), (%g, %g)\n",
492 outerPoint1.fX, outerPoint1.fY, outerPoint2.fX, outerPoint2.fY);
493 Vertex* innerVertex1 = fAlloc.make<Vertex>(innerPoint1, 255);
494 Vertex* innerVertex2 = fAlloc.make<Vertex>(innerPoint2, 255);
495 Vertex* outerVertex1 = fAlloc.make<Vertex>(outerPoint1, 0);
496 Vertex* outerVertex2 = fAlloc.make<Vertex>(outerPoint2, 0);
497 innerVertex1->fPartner = outerVertex1;
498 innerVertex2->fPartner = outerVertex2;
499 outerVertex1->fPartner = innerVertex1;
500 outerVertex2->fPartner = innerVertex2;
501 if (!inversion(innerVertices.fTail, innerVertex1, prevEdge, c)) {
502 innerInversion = false;
503 }
504 if (!inversion(outerVertices.fTail, outerVertex1, prevEdge, c)) {
505 outerInversion = false;
506 }
507 innerVertices.append(innerVertex1);
508 innerVertices.append(innerVertex2);
509 outerVertices.append(outerVertex1);
510 outerVertices.append(outerVertex2);
511 } else {
512 TESS_LOG("inner (%g, %g), ", innerPoint.fX, innerPoint.fY);
513 TESS_LOG("outer (%g, %g)\n", outerPoint.fX, outerPoint.fY);
514 Vertex* innerVertex = fAlloc.make<Vertex>(innerPoint, 255);
515 Vertex* outerVertex = fAlloc.make<Vertex>(outerPoint, 0);
516 innerVertex->fPartner = outerVertex;
517 outerVertex->fPartner = innerVertex;
518 if (!inversion(innerVertices.fTail, innerVertex, prevEdge, c)) {
519 innerInversion = false;
520 }
521 if (!inversion(outerVertices.fTail, outerVertex, prevEdge, c)) {
522 outerInversion = false;
523 }
524 innerVertices.append(innerVertex);
525 outerVertices.append(outerVertex);
526 }
527 }
528 prevInner = inner;
529 prevOuter = outer;
530 prevV = v;
531 prevEdge = e;
532 prevNormal = normal;
533 }
534 if (!inversion(innerVertices.fTail, innerVertices.fHead, prevEdge, c)) {
535 innerInversion = false;
536 }
537 if (!inversion(outerVertices.fTail, outerVertices.fHead, prevEdge, c)) {
538 outerInversion = false;
539 }
540 // Outer edges get 1 winding, and inner edges get -2 winding. This ensures that the interior
541 // is always filled (1 + -2 = -1 for normal cases, 1 + 2 = 3 for thin features where the
542 // interior inverts).
543 // For total inversion cases, the shape has now reversed handedness, so invert the winding
544 // so it will be detected during collapseOverlapRegions().
545 int innerWinding = innerInversion ? 2 : -2;
546 int outerWinding = outerInversion ? -1 : 1;
547 for (Vertex* v = innerVertices.fHead; v && v->fNext; v = v->fNext) {
548 this->makeConnectingEdge(v, v->fNext, EdgeType::kInner, c, innerWinding);
549 }
550 this->makeConnectingEdge(innerVertices.fTail, innerVertices.fHead, EdgeType::kInner, c,
551 innerWinding);
552 for (Vertex* v = outerVertices.fHead; v && v->fNext; v = v->fNext) {
553 this->makeConnectingEdge(v, v->fNext, EdgeType::kOuter, c, outerWinding);
554 }
555 this->makeConnectingEdge(outerVertices.fTail, outerVertices.fHead, EdgeType::kOuter, c,
556 outerWinding);
557 innerMesh->append(innerVertices);
558 fOuterMesh.append(outerVertices);
559}
560
561void GrAATriangulator::extractBoundary(EdgeList* boundary, Edge* e) {
562 TESS_LOG("\nextracting boundary\n");
563 bool down = this->applyFillType(e->fWinding);
564 Vertex* start = down ? e->fTop : e->fBottom;
565 do {
566 e->fWinding = down ? 1 : -1;
567 Edge* next;
568 e->fLine.normalize();
569 e->fLine = e->fLine * e->fWinding;
570 boundary->append(e);
571 if (down) {
572 // Find outgoing edge, in clockwise order.
573 if ((next = e->fNextEdgeAbove)) {
574 down = false;
575 } else if ((next = e->fBottom->fLastEdgeBelow)) {
576 down = true;
577 } else if ((next = e->fPrevEdgeAbove)) {
578 down = false;
579 }
580 } else {
581 // Find outgoing edge, in counter-clockwise order.
582 if ((next = e->fPrevEdgeBelow)) {
583 down = true;
584 } else if ((next = e->fTop->fFirstEdgeAbove)) {
585 down = false;
586 } else if ((next = e->fNextEdgeBelow)) {
587 down = true;
588 }
589 }
590 e->disconnect();
591 e = next;
592 } while (e && (down ? e->fTop : e->fBottom) != start);
593}
594
595// Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh.
596
597void GrAATriangulator::extractBoundaries(const VertexList& inMesh, VertexList* innerVertices,
598 const Comparator& c) {
599 this->removeNonBoundaryEdges(inMesh);
600 for (Vertex* v = inMesh.fHead; v; v = v->fNext) {
601 while (v->fFirstEdgeBelow) {
602 EdgeList boundary;
603 this->extractBoundary(&boundary, v->fFirstEdgeBelow);
604 this->simplifyBoundary(&boundary, c);
605 this->strokeBoundary(&boundary, innerVertices, c);
606 }
607 }
608}
609
610Poly* GrAATriangulator::tessellate(const VertexList& mesh, const Comparator& c) {
611 VertexList innerMesh;
612 this->extractBoundaries(mesh, &innerMesh, c);
613 SortMesh(&innerMesh, c);
614 SortMesh(&fOuterMesh, c);
615 this->mergeCoincidentVertices(&innerMesh, c);
616 bool was_complex = this->mergeCoincidentVertices(&fOuterMesh, c);
617 auto result = this->simplify(&innerMesh, c);
618 SkASSERT(SimplifyResult::kAbort != result);
619 was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex;
620 result = this->simplify(&fOuterMesh, c);
621 SkASSERT(SimplifyResult::kAbort != result);
622 was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex;
623 TESS_LOG("\ninner mesh before:\n");
624 DUMP_MESH(innerMesh);
625 TESS_LOG("\nouter mesh before:\n");
626 DUMP_MESH(fOuterMesh);
627 EventComparator eventLT(EventComparator::Op::kLessThan);
628 EventComparator eventGT(EventComparator::Op::kGreaterThan);
629 was_complex = this->collapseOverlapRegions(&innerMesh, c, eventLT) || was_complex;
630 was_complex = this->collapseOverlapRegions(&fOuterMesh, c, eventGT) || was_complex;
631 if (was_complex) {
632 TESS_LOG("found complex mesh; taking slow path\n");
633 VertexList aaMesh;
634 TESS_LOG("\ninner mesh after:\n");
635 DUMP_MESH(innerMesh);
636 TESS_LOG("\nouter mesh after:\n");
637 DUMP_MESH(fOuterMesh);
638 this->connectPartners(&fOuterMesh, c);
639 this->connectPartners(&innerMesh, c);
640 SortedMerge(&innerMesh, &fOuterMesh, &aaMesh, c);
641 this->mergeCoincidentVertices(&aaMesh, c);
642 result = this->simplify(&aaMesh, c);
643 SkASSERT(SimplifyResult::kAbort != result);
644 TESS_LOG("combined and simplified mesh:\n");
645 DUMP_MESH(aaMesh);
646 fOuterMesh.fHead = fOuterMesh.fTail = nullptr;
647 return this->GrTriangulator::tessellate(aaMesh, c);
648 } else {
649 TESS_LOG("no complex polygons; taking fast path\n");
650 return this->GrTriangulator::tessellate(innerMesh, c);
651 }
652}
653
654int64_t GrAATriangulator::countPoints(Poly* polys) const {
655 int64_t count = this->countPointsImpl(polys, SkPathFillType::kWinding);
656 // Count the points from the outer mesh.
657 for (Vertex* v = fOuterMesh.fHead; v; v = v->fNext) {
658 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
659 count += TRIANGULATOR_WIREFRAME ? 12 : 6;
660 }
661 }
662 return count;
663}
664
665void* GrAATriangulator::polysToTriangles(Poly* polys, void* data) {
666 data = this->polysToTrianglesImpl(polys, data, SkPathFillType::kWinding);
667 // Emit the triangles from the outer mesh.
668 for (Vertex* v = fOuterMesh.fHead; v; v = v->fNext) {
669 for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) {
670 Vertex* v0 = e->fTop;
671 Vertex* v1 = e->fBottom;
672 Vertex* v2 = e->fBottom->fPartner;
673 Vertex* v3 = e->fTop->fPartner;
674 data = this->emitTriangle(v0, v1, v2, 0/*winding*/, data);
675 data = this->emitTriangle(v0, v2, v3, 0/*winding*/, data);
676 }
677 }
678 return data;
679}