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