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