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