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