1 | /* |
2 | * Copyright 2015 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/GrTriangulator.h" |
9 | |
10 | #include "src/gpu/GrEagerVertexAllocator.h" |
11 | #include "src/gpu/GrVertexWriter.h" |
12 | #include "src/gpu/geometry/GrPathUtils.h" |
13 | |
14 | #include "include/core/SkPath.h" |
15 | #include "src/core/SkArenaAlloc.h" |
16 | #include "src/core/SkGeometry.h" |
17 | #include "src/core/SkPointPriv.h" |
18 | |
19 | #include <algorithm> |
20 | #include <cstdio> |
21 | #include <queue> |
22 | #include <unordered_map> |
23 | #include <utility> |
24 | |
25 | /* |
26 | * There are six stages to the basic algorithm: |
27 | * |
28 | * 1) Linearize the path contours into piecewise linear segments (path_to_contours()). |
29 | * 2) Build a mesh of edges connecting the vertices (build_edges()). |
30 | * 3) Sort the vertices in Y (and secondarily in X) (merge_sort()). |
31 | * 4) Simplify the mesh by inserting new vertices at intersecting edges (simplify()). |
32 | * 5) Tessellate the simplified mesh into monotone polygons (tessellate()). |
33 | * 6) Triangulate the monotone polygons directly into a vertex buffer (polys_to_triangles()). |
34 | * |
35 | * For screenspace antialiasing, the algorithm is modified as follows: |
36 | * |
37 | * Run steps 1-5 above to produce polygons. |
38 | * 5b) Apply fill rules to extract boundary contours from the polygons (extract_boundaries()). |
39 | * 5c) Simplify boundaries to remove "pointy" vertices that cause inversions (simplify_boundary()). |
40 | * 5d) Displace edges by half a pixel inward and outward along their normals. Intersect to find |
41 | * new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a new |
42 | * antialiased mesh from those vertices (stroke_boundary()). |
43 | * Run steps 3-6 above on the new mesh, and produce antialiased triangles. |
44 | * |
45 | * The vertex sorting in step (3) is a merge sort, since it plays well with the linked list |
46 | * of vertices (and the necessity of inserting new vertices on intersection). |
47 | * |
48 | * Stages (4) and (5) use an active edge list -- a list of all edges for which the |
49 | * sweep line has crossed the top vertex, but not the bottom vertex. It's sorted |
50 | * left-to-right based on the point where both edges are active (when both top vertices |
51 | * have been seen, so the "lower" top vertex of the two). If the top vertices are equal |
52 | * (shared), it's sorted based on the last point where both edges are active, so the |
53 | * "upper" bottom vertex. |
54 | * |
55 | * The most complex step is the simplification (4). It's based on the Bentley-Ottman |
56 | * line-sweep algorithm, but due to floating point inaccuracy, the intersection points are |
57 | * not exact and may violate the mesh topology or active edge list ordering. We |
58 | * accommodate this by adjusting the topology of the mesh and AEL to match the intersection |
59 | * points. This occurs in two ways: |
60 | * |
61 | * A) Intersections may cause a shortened edge to no longer be ordered with respect to its |
62 | * neighbouring edges at the top or bottom vertex. This is handled by merging the |
63 | * edges (merge_collinear_edges()). |
64 | * B) Intersections may cause an edge to violate the left-to-right ordering of the |
65 | * active edge list. This is handled by detecting potential violations and rewinding |
66 | * the active edge list to the vertex before they occur (rewind() during merging, |
67 | * rewind_if_necessary() during splitting). |
68 | * |
69 | * The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and |
70 | * Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it |
71 | * currently uses a linked list for the active edge list, rather than a 2-3 tree as the |
72 | * paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also |
73 | * become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N) |
74 | * insertions and removals was greater than the cost of infrequent O(N) lookups with the |
75 | * linked list implementation. With the latter, all removals are O(1), and most insertions |
76 | * are O(1), since we know the adjacent edge in the active edge list based on the topology. |
77 | * Only type 2 vertices (see paper) require the O(N) lookups, and these are much less |
78 | * frequent. There may be other data structures worth investigating, however. |
79 | * |
80 | * Note that the orientation of the line sweep algorithms is determined by the aspect ratio of the |
81 | * path bounds. When the path is taller than it is wide, we sort vertices based on increasing Y |
82 | * coordinate, and secondarily by increasing X coordinate. When the path is wider than it is tall, |
83 | * we sort by increasing X coordinate, but secondarily by *decreasing* Y coordinate. This is so |
84 | * that the "left" and "right" orientation in the code remains correct (edges to the left are |
85 | * increasing in Y; edges to the right are decreasing in Y). That is, the setting rotates 90 |
86 | * degrees counterclockwise, rather that transposing. |
87 | */ |
88 | |
89 | #define LOGGING_ENABLED 0 |
90 | |
91 | #if LOGGING_ENABLED |
92 | #define TESS_LOG printf |
93 | #else |
94 | #define TESS_LOG(...) |
95 | #endif |
96 | |
97 | namespace { |
98 | |
99 | using GrTriangulator::Mode; |
100 | |
101 | const int kArenaChunkSize = 16 * 1024; |
102 | const float kCosMiterAngle = 0.97f; // Corresponds to an angle of ~14 degrees. |
103 | |
104 | struct Vertex; |
105 | struct Edge; |
106 | struct Event; |
107 | struct Poly; |
108 | |
109 | template <class T, T* T::*Prev, T* T::*Next> |
110 | void list_insert(T* t, T* prev, T* next, T** head, T** tail) { |
111 | t->*Prev = prev; |
112 | t->*Next = next; |
113 | if (prev) { |
114 | prev->*Next = t; |
115 | } else if (head) { |
116 | *head = t; |
117 | } |
118 | if (next) { |
119 | next->*Prev = t; |
120 | } else if (tail) { |
121 | *tail = t; |
122 | } |
123 | } |
124 | |
125 | template <class T, T* T::*Prev, T* T::*Next> |
126 | void list_remove(T* t, T** head, T** tail) { |
127 | if (t->*Prev) { |
128 | t->*Prev->*Next = t->*Next; |
129 | } else if (head) { |
130 | *head = t->*Next; |
131 | } |
132 | if (t->*Next) { |
133 | t->*Next->*Prev = t->*Prev; |
134 | } else if (tail) { |
135 | *tail = t->*Prev; |
136 | } |
137 | t->*Prev = t->*Next = nullptr; |
138 | } |
139 | |
140 | /** |
141 | * Vertices are used in three ways: first, the path contours are converted into a |
142 | * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices |
143 | * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing |
144 | * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid |
145 | * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of |
146 | * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since |
147 | * an individual Vertex from the path mesh may belong to multiple |
148 | * MonotonePolys, so the original Vertices cannot be re-used. |
149 | */ |
150 | |
151 | struct Vertex { |
152 | Vertex(const SkPoint& point, uint8_t alpha) |
153 | : fPoint(point), fPrev(nullptr), fNext(nullptr) |
154 | , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr) |
155 | , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr) |
156 | , fLeftEnclosingEdge(nullptr), fRightEnclosingEdge(nullptr) |
157 | , fPartner(nullptr) |
158 | , fAlpha(alpha) |
159 | , fSynthetic(false) |
160 | #if LOGGING_ENABLED |
161 | , fID (-1.0f) |
162 | #endif |
163 | {} |
164 | SkPoint fPoint; // Vertex position |
165 | Vertex* fPrev; // Linked list of contours, then Y-sorted vertices. |
166 | Vertex* fNext; // " |
167 | Edge* fFirstEdgeAbove; // Linked list of edges above this vertex. |
168 | Edge* fLastEdgeAbove; // " |
169 | Edge* fFirstEdgeBelow; // Linked list of edges below this vertex. |
170 | Edge* fLastEdgeBelow; // " |
171 | Edge* fLeftEnclosingEdge; // Nearest edge in the AEL left of this vertex. |
172 | Edge* fRightEnclosingEdge; // Nearest edge in the AEL right of this vertex. |
173 | Vertex* fPartner; // Corresponding inner or outer vertex (for AA). |
174 | uint8_t fAlpha; |
175 | bool fSynthetic; // Is this a synthetic vertex? |
176 | #if LOGGING_ENABLED |
177 | float fID; // Identifier used for logging. |
178 | #endif |
179 | }; |
180 | |
181 | /***************************************************************************************/ |
182 | |
183 | typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b); |
184 | |
185 | bool sweep_lt_horiz(const SkPoint& a, const SkPoint& b) { |
186 | return a.fX < b.fX || (a.fX == b.fX && a.fY > b.fY); |
187 | } |
188 | |
189 | bool sweep_lt_vert(const SkPoint& a, const SkPoint& b) { |
190 | return a.fY < b.fY || (a.fY == b.fY && a.fX < b.fX); |
191 | } |
192 | |
193 | struct Comparator { |
194 | enum class Direction { kVertical, kHorizontal }; |
195 | Comparator(Direction direction) : fDirection(direction) {} |
196 | bool sweep_lt(const SkPoint& a, const SkPoint& b) const { |
197 | return fDirection == Direction::kHorizontal ? sweep_lt_horiz(a, b) : sweep_lt_vert(a, b); |
198 | } |
199 | Direction fDirection; |
200 | }; |
201 | |
202 | inline void* emit_vertex(Vertex* v, bool emitCoverage, void* data) { |
203 | GrVertexWriter verts{data}; |
204 | verts.write(v->fPoint); |
205 | |
206 | if (emitCoverage) { |
207 | verts.write(GrNormalizeByteToFloat(v->fAlpha)); |
208 | } |
209 | |
210 | return verts.fPtr; |
211 | } |
212 | |
213 | void* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, bool emitCoverage, void* data) { |
214 | TESS_LOG("emit_triangle %g (%g, %g) %d\n" , v0->fID, v0->fPoint.fX, v0->fPoint.fY, v0->fAlpha); |
215 | TESS_LOG(" %g (%g, %g) %d\n" , v1->fID, v1->fPoint.fX, v1->fPoint.fY, v1->fAlpha); |
216 | TESS_LOG(" %g (%g, %g) %d\n" , v2->fID, v2->fPoint.fX, v2->fPoint.fY, v2->fAlpha); |
217 | #if TESSELLATOR_WIREFRAME |
218 | data = emit_vertex(v0, emitCoverage, data); |
219 | data = emit_vertex(v1, emitCoverage, data); |
220 | data = emit_vertex(v1, emitCoverage, data); |
221 | data = emit_vertex(v2, emitCoverage, data); |
222 | data = emit_vertex(v2, emitCoverage, data); |
223 | data = emit_vertex(v0, emitCoverage, data); |
224 | #else |
225 | data = emit_vertex(v0, emitCoverage, data); |
226 | data = emit_vertex(v1, emitCoverage, data); |
227 | data = emit_vertex(v2, emitCoverage, data); |
228 | #endif |
229 | return data; |
230 | } |
231 | |
232 | struct VertexList { |
233 | VertexList() : fHead(nullptr), fTail(nullptr) {} |
234 | VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {} |
235 | Vertex* fHead; |
236 | Vertex* fTail; |
237 | void insert(Vertex* v, Vertex* prev, Vertex* next) { |
238 | list_insert<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, prev, next, &fHead, &fTail); |
239 | } |
240 | void append(Vertex* v) { |
241 | insert(v, fTail, nullptr); |
242 | } |
243 | void append(const VertexList& list) { |
244 | if (!list.fHead) { |
245 | return; |
246 | } |
247 | if (fTail) { |
248 | fTail->fNext = list.fHead; |
249 | list.fHead->fPrev = fTail; |
250 | } else { |
251 | fHead = list.fHead; |
252 | } |
253 | fTail = list.fTail; |
254 | } |
255 | void prepend(Vertex* v) { |
256 | insert(v, nullptr, fHead); |
257 | } |
258 | void remove(Vertex* v) { |
259 | list_remove<Vertex, &Vertex::fPrev, &Vertex::fNext>(v, &fHead, &fTail); |
260 | } |
261 | void close() { |
262 | if (fHead && fTail) { |
263 | fTail->fNext = fHead; |
264 | fHead->fPrev = fTail; |
265 | } |
266 | } |
267 | }; |
268 | |
269 | // Round to nearest quarter-pixel. This is used for screenspace tessellation. |
270 | |
271 | inline void round(SkPoint* p) { |
272 | p->fX = SkScalarRoundToScalar(p->fX * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f); |
273 | p->fY = SkScalarRoundToScalar(p->fY * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f); |
274 | } |
275 | |
276 | inline SkScalar double_to_clamped_scalar(double d) { |
277 | return SkDoubleToScalar(std::min((double) SK_ScalarMax, std::max(d, (double) -SK_ScalarMax))); |
278 | } |
279 | |
280 | // A line equation in implicit form. fA * x + fB * y + fC = 0, for all points (x, y) on the line. |
281 | struct Line { |
282 | Line(double a, double b, double c) : fA(a), fB(b), fC(c) {} |
283 | Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {} |
284 | Line(const SkPoint& p, const SkPoint& q) |
285 | : fA(static_cast<double>(q.fY) - p.fY) // a = dY |
286 | , fB(static_cast<double>(p.fX) - q.fX) // b = -dX |
287 | , fC(static_cast<double>(p.fY) * q.fX - // c = cross(q, p) |
288 | static_cast<double>(p.fX) * q.fY) {} |
289 | double dist(const SkPoint& p) const { |
290 | return fA * p.fX + fB * p.fY + fC; |
291 | } |
292 | Line operator*(double v) const { |
293 | return Line(fA * v, fB * v, fC * v); |
294 | } |
295 | double magSq() const { |
296 | return fA * fA + fB * fB; |
297 | } |
298 | void normalize() { |
299 | double len = sqrt(this->magSq()); |
300 | if (len == 0.0) { |
301 | return; |
302 | } |
303 | double scale = 1.0f / len; |
304 | fA *= scale; |
305 | fB *= scale; |
306 | fC *= scale; |
307 | } |
308 | bool nearParallel(const Line& o) const { |
309 | return fabs(o.fA - fA) < 0.00001 && fabs(o.fB - fB) < 0.00001; |
310 | } |
311 | |
312 | // Compute the intersection of two (infinite) Lines. |
313 | bool intersect(const Line& other, SkPoint* point) const { |
314 | double denom = fA * other.fB - fB * other.fA; |
315 | if (denom == 0.0) { |
316 | return false; |
317 | } |
318 | double scale = 1.0 / denom; |
319 | point->fX = double_to_clamped_scalar((fB * other.fC - other.fB * fC) * scale); |
320 | point->fY = double_to_clamped_scalar((other.fA * fC - fA * other.fC) * scale); |
321 | round(point); |
322 | return point->isFinite(); |
323 | } |
324 | double fA, fB, fC; |
325 | }; |
326 | |
327 | /** |
328 | * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and |
329 | * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf(). |
330 | * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating |
331 | * point). For speed, that case is only tested by the callers that require it (e.g., |
332 | * rewind_if_necessary()). Edges also handle checking for intersection with other edges. |
333 | * Currently, this converts the edges to the parametric form, in order to avoid doing a division |
334 | * until an intersection has been confirmed. This is slightly slower in the "found" case, but |
335 | * a lot faster in the "not found" case. |
336 | * |
337 | * The coefficients of the line equation stored in double precision to avoid catastrphic |
338 | * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is |
339 | * correct in float, since it's a polynomial of degree 2. The intersect() function, being |
340 | * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its |
341 | * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of |
342 | * this file). |
343 | */ |
344 | |
345 | struct Edge { |
346 | enum class Type { kInner, kOuter, kConnector }; |
347 | Edge(Vertex* top, Vertex* bottom, int winding, Type type) |
348 | : fWinding(winding) |
349 | , fTop(top) |
350 | , fBottom(bottom) |
351 | , fType(type) |
352 | , fLeft(nullptr) |
353 | , fRight(nullptr) |
354 | , fPrevEdgeAbove(nullptr) |
355 | , fNextEdgeAbove(nullptr) |
356 | , fPrevEdgeBelow(nullptr) |
357 | , fNextEdgeBelow(nullptr) |
358 | , fLeftPoly(nullptr) |
359 | , fRightPoly(nullptr) |
360 | , fLeftPolyPrev(nullptr) |
361 | , fLeftPolyNext(nullptr) |
362 | , fRightPolyPrev(nullptr) |
363 | , fRightPolyNext(nullptr) |
364 | , fUsedInLeftPoly(false) |
365 | , fUsedInRightPoly(false) |
366 | , fLine(top, bottom) { |
367 | } |
368 | int fWinding; // 1 == edge goes downward; -1 = edge goes upward. |
369 | Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt). |
370 | Vertex* fBottom; // The bottom vertex in vertex-sort-order. |
371 | Type fType; |
372 | Edge* fLeft; // The linked list of edges in the active edge list. |
373 | Edge* fRight; // " |
374 | Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above". |
375 | Edge* fNextEdgeAbove; // " |
376 | Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below". |
377 | Edge* fNextEdgeBelow; // " |
378 | Poly* fLeftPoly; // The Poly to the left of this edge, if any. |
379 | Poly* fRightPoly; // The Poly to the right of this edge, if any. |
380 | Edge* fLeftPolyPrev; |
381 | Edge* fLeftPolyNext; |
382 | Edge* fRightPolyPrev; |
383 | Edge* fRightPolyNext; |
384 | bool fUsedInLeftPoly; |
385 | bool fUsedInRightPoly; |
386 | Line fLine; |
387 | double dist(const SkPoint& p) const { |
388 | return fLine.dist(p); |
389 | } |
390 | bool isRightOf(Vertex* v) const { |
391 | return fLine.dist(v->fPoint) < 0.0; |
392 | } |
393 | bool isLeftOf(Vertex* v) const { |
394 | return fLine.dist(v->fPoint) > 0.0; |
395 | } |
396 | void recompute() { |
397 | fLine = Line(fTop, fBottom); |
398 | } |
399 | bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) const { |
400 | TESS_LOG("intersecting %g -> %g with %g -> %g\n" , |
401 | fTop->fID, fBottom->fID, other.fTop->fID, other.fBottom->fID); |
402 | if (fTop == other.fTop || fBottom == other.fBottom) { |
403 | return false; |
404 | } |
405 | double denom = fLine.fA * other.fLine.fB - fLine.fB * other.fLine.fA; |
406 | if (denom == 0.0) { |
407 | return false; |
408 | } |
409 | double dx = static_cast<double>(other.fTop->fPoint.fX) - fTop->fPoint.fX; |
410 | double dy = static_cast<double>(other.fTop->fPoint.fY) - fTop->fPoint.fY; |
411 | double sNumer = dy * other.fLine.fB + dx * other.fLine.fA; |
412 | double tNumer = dy * fLine.fB + dx * fLine.fA; |
413 | // If (sNumer / denom) or (tNumer / denom) is not in [0..1], exit early. |
414 | // This saves us doing the divide below unless absolutely necessary. |
415 | if (denom > 0.0 ? (sNumer < 0.0 || sNumer > denom || tNumer < 0.0 || tNumer > denom) |
416 | : (sNumer > 0.0 || sNumer < denom || tNumer > 0.0 || tNumer < denom)) { |
417 | return false; |
418 | } |
419 | double s = sNumer / denom; |
420 | SkASSERT(s >= 0.0 && s <= 1.0); |
421 | p->fX = SkDoubleToScalar(fTop->fPoint.fX - s * fLine.fB); |
422 | p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fLine.fA); |
423 | if (alpha) { |
424 | if (fType == Type::kConnector) { |
425 | *alpha = (1.0 - s) * fTop->fAlpha + s * fBottom->fAlpha; |
426 | } else if (other.fType == Type::kConnector) { |
427 | double t = tNumer / denom; |
428 | *alpha = (1.0 - t) * other.fTop->fAlpha + t * other.fBottom->fAlpha; |
429 | } else if (fType == Type::kOuter && other.fType == Type::kOuter) { |
430 | *alpha = 0; |
431 | } else { |
432 | *alpha = 255; |
433 | } |
434 | } |
435 | return true; |
436 | } |
437 | }; |
438 | |
439 | struct SSEdge; |
440 | |
441 | struct SSVertex { |
442 | SSVertex(Vertex* v) : fVertex(v), fPrev(nullptr), fNext(nullptr) {} |
443 | Vertex* fVertex; |
444 | SSEdge* fPrev; |
445 | SSEdge* fNext; |
446 | }; |
447 | |
448 | struct SSEdge { |
449 | SSEdge(Edge* edge, SSVertex* prev, SSVertex* next) |
450 | : fEdge(edge), fEvent(nullptr), fPrev(prev), fNext(next) { |
451 | } |
452 | Edge* fEdge; |
453 | Event* fEvent; |
454 | SSVertex* fPrev; |
455 | SSVertex* fNext; |
456 | }; |
457 | |
458 | typedef std::unordered_map<Vertex*, SSVertex*> SSVertexMap; |
459 | typedef std::vector<SSEdge*> SSEdgeList; |
460 | |
461 | struct EdgeList { |
462 | EdgeList() : fHead(nullptr), fTail(nullptr) {} |
463 | Edge* fHead; |
464 | Edge* fTail; |
465 | void insert(Edge* edge, Edge* prev, Edge* next) { |
466 | list_insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &fHead, &fTail); |
467 | } |
468 | void append(Edge* e) { |
469 | insert(e, fTail, nullptr); |
470 | } |
471 | void remove(Edge* edge) { |
472 | list_remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &fHead, &fTail); |
473 | } |
474 | void removeAll() { |
475 | while (fHead) { |
476 | this->remove(fHead); |
477 | } |
478 | } |
479 | void close() { |
480 | if (fHead && fTail) { |
481 | fTail->fRight = fHead; |
482 | fHead->fLeft = fTail; |
483 | } |
484 | } |
485 | bool contains(Edge* edge) const { |
486 | return edge->fLeft || edge->fRight || fHead == edge; |
487 | } |
488 | }; |
489 | |
490 | struct EventList; |
491 | |
492 | struct Event { |
493 | Event(SSEdge* edge, const SkPoint& point, uint8_t alpha) |
494 | : fEdge(edge), fPoint(point), fAlpha(alpha) { |
495 | } |
496 | SSEdge* fEdge; |
497 | SkPoint fPoint; |
498 | uint8_t fAlpha; |
499 | void apply(VertexList* mesh, Comparator& c, EventList* events, SkArenaAlloc& alloc); |
500 | }; |
501 | |
502 | struct EventComparator { |
503 | enum class Op { kLessThan, kGreaterThan }; |
504 | EventComparator(Op op) : fOp(op) {} |
505 | bool operator() (Event* const &e1, Event* const &e2) { |
506 | return fOp == Op::kLessThan ? e1->fAlpha < e2->fAlpha |
507 | : e1->fAlpha > e2->fAlpha; |
508 | } |
509 | Op fOp; |
510 | }; |
511 | |
512 | typedef std::priority_queue<Event*, std::vector<Event*>, EventComparator> EventPQ; |
513 | |
514 | struct EventList : EventPQ { |
515 | EventList(EventComparator comparison) : EventPQ(comparison) { |
516 | } |
517 | }; |
518 | |
519 | void create_event(SSEdge* e, EventList* events, SkArenaAlloc& alloc) { |
520 | Vertex* prev = e->fPrev->fVertex; |
521 | Vertex* next = e->fNext->fVertex; |
522 | if (prev == next || !prev->fPartner || !next->fPartner) { |
523 | return; |
524 | } |
525 | Edge bisector1(prev, prev->fPartner, 1, Edge::Type::kConnector); |
526 | Edge bisector2(next, next->fPartner, 1, Edge::Type::kConnector); |
527 | SkPoint p; |
528 | uint8_t alpha; |
529 | if (bisector1.intersect(bisector2, &p, &alpha)) { |
530 | TESS_LOG("found edge event for %g, %g (original %g -> %g), " |
531 | "will collapse to %g,%g alpha %d\n" , |
532 | prev->fID, next->fID, e->fEdge->fTop->fID, e->fEdge->fBottom->fID, p.fX, p.fY, |
533 | alpha); |
534 | e->fEvent = alloc.make<Event>(e, p, alpha); |
535 | events->push(e->fEvent); |
536 | } |
537 | } |
538 | |
539 | void create_event(SSEdge* edge, Vertex* v, SSEdge* other, Vertex* dest, EventList* events, |
540 | Comparator& c, SkArenaAlloc& alloc) { |
541 | if (!v->fPartner) { |
542 | return; |
543 | } |
544 | Vertex* top = edge->fEdge->fTop; |
545 | Vertex* bottom = edge->fEdge->fBottom; |
546 | if (!top || !bottom ) { |
547 | return; |
548 | } |
549 | Line line = edge->fEdge->fLine; |
550 | line.fC = -(dest->fPoint.fX * line.fA + dest->fPoint.fY * line.fB); |
551 | Edge bisector(v, v->fPartner, 1, Edge::Type::kConnector); |
552 | SkPoint p; |
553 | uint8_t alpha = dest->fAlpha; |
554 | if (line.intersect(bisector.fLine, &p) && !c.sweep_lt(p, top->fPoint) && |
555 | c.sweep_lt(p, bottom->fPoint)) { |
556 | TESS_LOG("found p edge event for %g, %g (original %g -> %g), " |
557 | "will collapse to %g,%g alpha %d\n" , |
558 | dest->fID, v->fID, top->fID, bottom->fID, p.fX, p.fY, alpha); |
559 | edge->fEvent = alloc.make<Event>(edge, p, alpha); |
560 | events->push(edge->fEvent); |
561 | } |
562 | } |
563 | |
564 | /***************************************************************************************/ |
565 | |
566 | struct Poly { |
567 | Poly(Vertex* v, int winding) |
568 | : fFirstVertex(v) |
569 | , fWinding(winding) |
570 | , fHead(nullptr) |
571 | , fTail(nullptr) |
572 | , fNext(nullptr) |
573 | , fPartner(nullptr) |
574 | , fCount(0) |
575 | { |
576 | #if LOGGING_ENABLED |
577 | static int gID = 0; |
578 | fID = gID++; |
579 | TESS_LOG("*** created Poly %d\n" , fID); |
580 | #endif |
581 | } |
582 | typedef enum { kLeft_Side, kRight_Side } Side; |
583 | struct MonotonePoly { |
584 | MonotonePoly(Edge* edge, Side side, int winding) |
585 | : fSide(side) |
586 | , fFirstEdge(nullptr) |
587 | , fLastEdge(nullptr) |
588 | , fPrev(nullptr) |
589 | , fNext(nullptr) |
590 | , fWinding(winding) { |
591 | this->addEdge(edge); |
592 | } |
593 | Side fSide; |
594 | Edge* fFirstEdge; |
595 | Edge* fLastEdge; |
596 | MonotonePoly* fPrev; |
597 | MonotonePoly* fNext; |
598 | int fWinding; |
599 | void addEdge(Edge* edge) { |
600 | if (fSide == kRight_Side) { |
601 | SkASSERT(!edge->fUsedInRightPoly); |
602 | list_insert<Edge, &Edge::fRightPolyPrev, &Edge::fRightPolyNext>( |
603 | edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge); |
604 | edge->fUsedInRightPoly = true; |
605 | } else { |
606 | SkASSERT(!edge->fUsedInLeftPoly); |
607 | list_insert<Edge, &Edge::fLeftPolyPrev, &Edge::fLeftPolyNext>( |
608 | edge, fLastEdge, nullptr, &fFirstEdge, &fLastEdge); |
609 | edge->fUsedInLeftPoly = true; |
610 | } |
611 | } |
612 | |
613 | void* emit(bool emitCoverage, void* data) { |
614 | Edge* e = fFirstEdge; |
615 | VertexList vertices; |
616 | vertices.append(e->fTop); |
617 | int count = 1; |
618 | while (e != nullptr) { |
619 | if (kRight_Side == fSide) { |
620 | vertices.append(e->fBottom); |
621 | e = e->fRightPolyNext; |
622 | } else { |
623 | vertices.prepend(e->fBottom); |
624 | e = e->fLeftPolyNext; |
625 | } |
626 | count++; |
627 | } |
628 | Vertex* first = vertices.fHead; |
629 | Vertex* v = first->fNext; |
630 | while (v != vertices.fTail) { |
631 | SkASSERT(v && v->fPrev && v->fNext); |
632 | Vertex* prev = v->fPrev; |
633 | Vertex* curr = v; |
634 | Vertex* next = v->fNext; |
635 | if (count == 3) { |
636 | return this->emitTriangle(prev, curr, next, emitCoverage, data); |
637 | } |
638 | double ax = static_cast<double>(curr->fPoint.fX) - prev->fPoint.fX; |
639 | double ay = static_cast<double>(curr->fPoint.fY) - prev->fPoint.fY; |
640 | double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX; |
641 | double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY; |
642 | if (ax * by - ay * bx >= 0.0) { |
643 | data = this->emitTriangle(prev, curr, next, emitCoverage, data); |
644 | v->fPrev->fNext = v->fNext; |
645 | v->fNext->fPrev = v->fPrev; |
646 | count--; |
647 | if (v->fPrev == first) { |
648 | v = v->fNext; |
649 | } else { |
650 | v = v->fPrev; |
651 | } |
652 | } else { |
653 | v = v->fNext; |
654 | } |
655 | } |
656 | return data; |
657 | } |
658 | void* emitTriangle(Vertex* prev, Vertex* curr, Vertex* next, bool emitCoverage, |
659 | void* data) const { |
660 | if (fWinding < 0) { |
661 | // Ensure our triangles always wind in the same direction as if the path had been |
662 | // triangulated as a simple fan (a la red book). |
663 | std::swap(prev, next); |
664 | } |
665 | return emit_triangle(next, curr, prev, emitCoverage, data); |
666 | } |
667 | }; |
668 | Poly* addEdge(Edge* e, Side side, SkArenaAlloc& alloc) { |
669 | TESS_LOG("addEdge (%g -> %g) to poly %d, %s side\n" , |
670 | e->fTop->fID, e->fBottom->fID, fID, side == kLeft_Side ? "left" : "right" ); |
671 | Poly* partner = fPartner; |
672 | Poly* poly = this; |
673 | if (side == kRight_Side) { |
674 | if (e->fUsedInRightPoly) { |
675 | return this; |
676 | } |
677 | } else { |
678 | if (e->fUsedInLeftPoly) { |
679 | return this; |
680 | } |
681 | } |
682 | if (partner) { |
683 | fPartner = partner->fPartner = nullptr; |
684 | } |
685 | if (!fTail) { |
686 | fHead = fTail = alloc.make<MonotonePoly>(e, side, fWinding); |
687 | fCount += 2; |
688 | } else if (e->fBottom == fTail->fLastEdge->fBottom) { |
689 | return poly; |
690 | } else if (side == fTail->fSide) { |
691 | fTail->addEdge(e); |
692 | fCount++; |
693 | } else { |
694 | e = alloc.make<Edge>(fTail->fLastEdge->fBottom, e->fBottom, 1, Edge::Type::kInner); |
695 | fTail->addEdge(e); |
696 | fCount++; |
697 | if (partner) { |
698 | partner->addEdge(e, side, alloc); |
699 | poly = partner; |
700 | } else { |
701 | MonotonePoly* m = alloc.make<MonotonePoly>(e, side, fWinding); |
702 | m->fPrev = fTail; |
703 | fTail->fNext = m; |
704 | fTail = m; |
705 | } |
706 | } |
707 | return poly; |
708 | } |
709 | void* emit(bool emitCoverage, void *data) { |
710 | if (fCount < 3) { |
711 | return data; |
712 | } |
713 | TESS_LOG("emit() %d, size %d\n" , fID, fCount); |
714 | for (MonotonePoly* m = fHead; m != nullptr; m = m->fNext) { |
715 | data = m->emit(emitCoverage, data); |
716 | } |
717 | return data; |
718 | } |
719 | Vertex* lastVertex() const { return fTail ? fTail->fLastEdge->fBottom : fFirstVertex; } |
720 | Vertex* fFirstVertex; |
721 | int fWinding; |
722 | MonotonePoly* fHead; |
723 | MonotonePoly* fTail; |
724 | Poly* fNext; |
725 | Poly* fPartner; |
726 | int fCount; |
727 | #if LOGGING_ENABLED |
728 | int fID; |
729 | #endif |
730 | }; |
731 | |
732 | /***************************************************************************************/ |
733 | |
734 | bool coincident(const SkPoint& a, const SkPoint& b) { |
735 | return a == b; |
736 | } |
737 | |
738 | Poly* new_poly(Poly** head, Vertex* v, int winding, SkArenaAlloc& alloc) { |
739 | Poly* poly = alloc.make<Poly>(v, winding); |
740 | poly->fNext = *head; |
741 | *head = poly; |
742 | return poly; |
743 | } |
744 | |
745 | void append_point_to_contour(const SkPoint& p, VertexList* contour, SkArenaAlloc& alloc) { |
746 | Vertex* v = alloc.make<Vertex>(p, 255); |
747 | #if LOGGING_ENABLED |
748 | static float gID = 0.0f; |
749 | v->fID = gID++; |
750 | #endif |
751 | contour->append(v); |
752 | } |
753 | |
754 | SkScalar quad_error_at(const SkPoint pts[3], SkScalar t, SkScalar u) { |
755 | SkQuadCoeff quad(pts); |
756 | SkPoint p0 = to_point(quad.eval(t - 0.5f * u)); |
757 | SkPoint mid = to_point(quad.eval(t)); |
758 | SkPoint p1 = to_point(quad.eval(t + 0.5f * u)); |
759 | if (!p0.isFinite() || !mid.isFinite() || !p1.isFinite()) { |
760 | return 0; |
761 | } |
762 | return SkPointPriv::DistanceToLineSegmentBetweenSqd(mid, p0, p1); |
763 | } |
764 | |
765 | void append_quadratic_to_contour(const SkPoint pts[3], SkScalar toleranceSqd, VertexList* contour, |
766 | SkArenaAlloc& alloc) { |
767 | SkQuadCoeff quad(pts); |
768 | Sk2s aa = quad.fA * quad.fA; |
769 | SkScalar denom = 2.0f * (aa[0] + aa[1]); |
770 | Sk2s ab = quad.fA * quad.fB; |
771 | SkScalar t = denom ? (-ab[0] - ab[1]) / denom : 0.0f; |
772 | int nPoints = 1; |
773 | SkScalar u = 1.0f; |
774 | // Test possible subdivision values only at the point of maximum curvature. |
775 | // If it passes the flatness metric there, it'll pass everywhere. |
776 | while (nPoints < GrPathUtils::kMaxPointsPerCurve) { |
777 | u = 1.0f / nPoints; |
778 | if (quad_error_at(pts, t, u) < toleranceSqd) { |
779 | break; |
780 | } |
781 | nPoints++; |
782 | } |
783 | for (int j = 1; j <= nPoints; j++) { |
784 | append_point_to_contour(to_point(quad.eval(j * u)), contour, alloc); |
785 | } |
786 | } |
787 | |
788 | void generate_cubic_points(const SkPoint& p0, |
789 | const SkPoint& p1, |
790 | const SkPoint& p2, |
791 | const SkPoint& p3, |
792 | SkScalar tolSqd, |
793 | VertexList* contour, |
794 | int pointsLeft, |
795 | SkArenaAlloc& alloc) { |
796 | SkScalar d1 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p1, p0, p3); |
797 | SkScalar d2 = SkPointPriv::DistanceToLineSegmentBetweenSqd(p2, p0, p3); |
798 | if (pointsLeft < 2 || (d1 < tolSqd && d2 < tolSqd) || |
799 | !SkScalarIsFinite(d1) || !SkScalarIsFinite(d2)) { |
800 | append_point_to_contour(p3, contour, alloc); |
801 | return; |
802 | } |
803 | const SkPoint q[] = { |
804 | { SkScalarAve(p0.fX, p1.fX), SkScalarAve(p0.fY, p1.fY) }, |
805 | { SkScalarAve(p1.fX, p2.fX), SkScalarAve(p1.fY, p2.fY) }, |
806 | { SkScalarAve(p2.fX, p3.fX), SkScalarAve(p2.fY, p3.fY) } |
807 | }; |
808 | const SkPoint r[] = { |
809 | { SkScalarAve(q[0].fX, q[1].fX), SkScalarAve(q[0].fY, q[1].fY) }, |
810 | { SkScalarAve(q[1].fX, q[2].fX), SkScalarAve(q[1].fY, q[2].fY) } |
811 | }; |
812 | const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1].fY) }; |
813 | pointsLeft >>= 1; |
814 | generate_cubic_points(p0, q[0], r[0], s, tolSqd, contour, pointsLeft, alloc); |
815 | generate_cubic_points(s, r[1], q[2], p3, tolSqd, contour, pointsLeft, alloc); |
816 | } |
817 | |
818 | // Stage 1: convert the input path to a set of linear contours (linked list of Vertices). |
819 | |
820 | void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, |
821 | VertexList* contours, SkArenaAlloc& alloc, Mode mode, int* numCountedCurves) { |
822 | SkScalar toleranceSqd = tolerance * tolerance; |
823 | bool innerPolygons = (Mode::kSimpleInnerPolygons == mode); |
824 | |
825 | SkPoint pts[4]; |
826 | int localCurveCount = 0; |
827 | VertexList* contour = contours; |
828 | SkPath::Iter iter(path, false); |
829 | if (path.isInverseFillType()) { |
830 | SkPoint quad[4]; |
831 | clipBounds.toQuad(quad); |
832 | for (int i = 3; i >= 0; i--) { |
833 | append_point_to_contour(quad[i], contours, alloc); |
834 | } |
835 | contour++; |
836 | } |
837 | SkAutoConicToQuads converter; |
838 | SkPath::Verb verb; |
839 | while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
840 | switch (verb) { |
841 | case SkPath::kConic_Verb: { |
842 | ++localCurveCount; |
843 | if (innerPolygons) { |
844 | append_point_to_contour(pts[2], contour, alloc); |
845 | break; |
846 | } |
847 | SkScalar weight = iter.conicWeight(); |
848 | const SkPoint* quadPts = converter.computeQuads(pts, weight, toleranceSqd); |
849 | for (int i = 0; i < converter.countQuads(); ++i) { |
850 | append_quadratic_to_contour(quadPts, toleranceSqd, contour, alloc); |
851 | quadPts += 2; |
852 | } |
853 | break; |
854 | } |
855 | case SkPath::kMove_Verb: |
856 | if (contour->fHead) { |
857 | contour++; |
858 | } |
859 | append_point_to_contour(pts[0], contour, alloc); |
860 | break; |
861 | case SkPath::kLine_Verb: { |
862 | append_point_to_contour(pts[1], contour, alloc); |
863 | break; |
864 | } |
865 | case SkPath::kQuad_Verb: { |
866 | ++localCurveCount; |
867 | if (innerPolygons) { |
868 | append_point_to_contour(pts[2], contour, alloc); |
869 | break; |
870 | } |
871 | append_quadratic_to_contour(pts, toleranceSqd, contour, alloc); |
872 | break; |
873 | } |
874 | case SkPath::kCubic_Verb: { |
875 | ++localCurveCount; |
876 | if (innerPolygons) { |
877 | append_point_to_contour(pts[3], contour, alloc); |
878 | break; |
879 | } |
880 | int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance); |
881 | generate_cubic_points(pts[0], pts[1], pts[2], pts[3], toleranceSqd, contour, |
882 | pointsLeft, alloc); |
883 | break; |
884 | } |
885 | case SkPath::kClose_Verb: |
886 | case SkPath::kDone_Verb: |
887 | break; |
888 | } |
889 | } |
890 | *numCountedCurves = localCurveCount; |
891 | } |
892 | |
893 | inline bool apply_fill_type(SkPathFillType fillType, int winding) { |
894 | switch (fillType) { |
895 | case SkPathFillType::kWinding: |
896 | return winding != 0; |
897 | case SkPathFillType::kEvenOdd: |
898 | return (winding & 1) != 0; |
899 | case SkPathFillType::kInverseWinding: |
900 | return winding == 1; |
901 | case SkPathFillType::kInverseEvenOdd: |
902 | return (winding & 1) == 1; |
903 | default: |
904 | SkASSERT(false); |
905 | return false; |
906 | } |
907 | } |
908 | |
909 | inline bool apply_fill_type(SkPathFillType fillType, Poly* poly) { |
910 | return poly && apply_fill_type(fillType, poly->fWinding); |
911 | } |
912 | |
913 | Edge* new_edge(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc) { |
914 | int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; |
915 | Vertex* top = winding < 0 ? next : prev; |
916 | Vertex* bottom = winding < 0 ? prev : next; |
917 | return alloc.make<Edge>(top, bottom, winding, type); |
918 | } |
919 | |
920 | void remove_edge(Edge* edge, EdgeList* edges) { |
921 | TESS_LOG("removing edge %g -> %g\n" , edge->fTop->fID, edge->fBottom->fID); |
922 | SkASSERT(edges->contains(edge)); |
923 | edges->remove(edge); |
924 | } |
925 | |
926 | void insert_edge(Edge* edge, Edge* prev, EdgeList* edges) { |
927 | TESS_LOG("inserting edge %g -> %g\n" , edge->fTop->fID, edge->fBottom->fID); |
928 | SkASSERT(!edges->contains(edge)); |
929 | Edge* next = prev ? prev->fRight : edges->fHead; |
930 | edges->insert(edge, prev, next); |
931 | } |
932 | |
933 | void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) { |
934 | if (v->fFirstEdgeAbove && v->fLastEdgeAbove) { |
935 | *left = v->fFirstEdgeAbove->fLeft; |
936 | *right = v->fLastEdgeAbove->fRight; |
937 | return; |
938 | } |
939 | Edge* next = nullptr; |
940 | Edge* prev; |
941 | for (prev = edges->fTail; prev != nullptr; prev = prev->fLeft) { |
942 | if (prev->isLeftOf(v)) { |
943 | break; |
944 | } |
945 | next = prev; |
946 | } |
947 | *left = prev; |
948 | *right = next; |
949 | } |
950 | |
951 | void insert_edge_above(Edge* edge, Vertex* v, Comparator& c) { |
952 | if (edge->fTop->fPoint == edge->fBottom->fPoint || |
953 | c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) { |
954 | return; |
955 | } |
956 | TESS_LOG("insert edge (%g -> %g) above vertex %g\n" , |
957 | edge->fTop->fID, edge->fBottom->fID, v->fID); |
958 | Edge* prev = nullptr; |
959 | Edge* next; |
960 | for (next = v->fFirstEdgeAbove; next; next = next->fNextEdgeAbove) { |
961 | if (next->isRightOf(edge->fTop)) { |
962 | break; |
963 | } |
964 | prev = next; |
965 | } |
966 | list_insert<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>( |
967 | edge, prev, next, &v->fFirstEdgeAbove, &v->fLastEdgeAbove); |
968 | } |
969 | |
970 | void insert_edge_below(Edge* edge, Vertex* v, Comparator& c) { |
971 | if (edge->fTop->fPoint == edge->fBottom->fPoint || |
972 | c.sweep_lt(edge->fBottom->fPoint, edge->fTop->fPoint)) { |
973 | return; |
974 | } |
975 | TESS_LOG("insert edge (%g -> %g) below vertex %g\n" , |
976 | edge->fTop->fID, edge->fBottom->fID, v->fID); |
977 | Edge* prev = nullptr; |
978 | Edge* next; |
979 | for (next = v->fFirstEdgeBelow; next; next = next->fNextEdgeBelow) { |
980 | if (next->isRightOf(edge->fBottom)) { |
981 | break; |
982 | } |
983 | prev = next; |
984 | } |
985 | list_insert<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>( |
986 | edge, prev, next, &v->fFirstEdgeBelow, &v->fLastEdgeBelow); |
987 | } |
988 | |
989 | void remove_edge_above(Edge* edge) { |
990 | SkASSERT(edge->fTop && edge->fBottom); |
991 | TESS_LOG("removing edge (%g -> %g) above vertex %g\n" , edge->fTop->fID, edge->fBottom->fID, |
992 | edge->fBottom->fID); |
993 | list_remove<Edge, &Edge::fPrevEdgeAbove, &Edge::fNextEdgeAbove>( |
994 | edge, &edge->fBottom->fFirstEdgeAbove, &edge->fBottom->fLastEdgeAbove); |
995 | } |
996 | |
997 | void remove_edge_below(Edge* edge) { |
998 | SkASSERT(edge->fTop && edge->fBottom); |
999 | TESS_LOG("removing edge (%g -> %g) below vertex %g\n" , |
1000 | edge->fTop->fID, edge->fBottom->fID, edge->fTop->fID); |
1001 | list_remove<Edge, &Edge::fPrevEdgeBelow, &Edge::fNextEdgeBelow>( |
1002 | edge, &edge->fTop->fFirstEdgeBelow, &edge->fTop->fLastEdgeBelow); |
1003 | } |
1004 | |
1005 | void disconnect(Edge* edge) |
1006 | { |
1007 | remove_edge_above(edge); |
1008 | remove_edge_below(edge); |
1009 | } |
1010 | |
1011 | void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c); |
1012 | |
1013 | void rewind(EdgeList* activeEdges, Vertex** current, Vertex* dst, Comparator& c) { |
1014 | if (!current || *current == dst || c.sweep_lt((*current)->fPoint, dst->fPoint)) { |
1015 | return; |
1016 | } |
1017 | Vertex* v = *current; |
1018 | TESS_LOG("rewinding active edges from vertex %g to vertex %g\n" , v->fID, dst->fID); |
1019 | while (v != dst) { |
1020 | v = v->fPrev; |
1021 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
1022 | remove_edge(e, activeEdges); |
1023 | } |
1024 | Edge* leftEdge = v->fLeftEnclosingEdge; |
1025 | for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { |
1026 | insert_edge(e, leftEdge, activeEdges); |
1027 | leftEdge = e; |
1028 | Vertex* top = e->fTop; |
1029 | if (c.sweep_lt(top->fPoint, dst->fPoint) && |
1030 | ((top->fLeftEnclosingEdge && !top->fLeftEnclosingEdge->isLeftOf(e->fTop)) || |
1031 | (top->fRightEnclosingEdge && !top->fRightEnclosingEdge->isRightOf(e->fTop)))) { |
1032 | dst = top; |
1033 | } |
1034 | } |
1035 | } |
1036 | *current = v; |
1037 | } |
1038 | |
1039 | void rewind_if_necessary(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) { |
1040 | if (!activeEdges || !current) { |
1041 | return; |
1042 | } |
1043 | Vertex* top = edge->fTop; |
1044 | Vertex* bottom = edge->fBottom; |
1045 | if (edge->fLeft) { |
1046 | Vertex* leftTop = edge->fLeft->fTop; |
1047 | Vertex* leftBottom = edge->fLeft->fBottom; |
1048 | if (c.sweep_lt(leftTop->fPoint, top->fPoint) && !edge->fLeft->isLeftOf(top)) { |
1049 | rewind(activeEdges, current, leftTop, c); |
1050 | } else if (c.sweep_lt(top->fPoint, leftTop->fPoint) && !edge->isRightOf(leftTop)) { |
1051 | rewind(activeEdges, current, top, c); |
1052 | } else if (c.sweep_lt(bottom->fPoint, leftBottom->fPoint) && |
1053 | !edge->fLeft->isLeftOf(bottom)) { |
1054 | rewind(activeEdges, current, leftTop, c); |
1055 | } else if (c.sweep_lt(leftBottom->fPoint, bottom->fPoint) && !edge->isRightOf(leftBottom)) { |
1056 | rewind(activeEdges, current, top, c); |
1057 | } |
1058 | } |
1059 | if (edge->fRight) { |
1060 | Vertex* rightTop = edge->fRight->fTop; |
1061 | Vertex* rightBottom = edge->fRight->fBottom; |
1062 | if (c.sweep_lt(rightTop->fPoint, top->fPoint) && !edge->fRight->isRightOf(top)) { |
1063 | rewind(activeEdges, current, rightTop, c); |
1064 | } else if (c.sweep_lt(top->fPoint, rightTop->fPoint) && !edge->isLeftOf(rightTop)) { |
1065 | rewind(activeEdges, current, top, c); |
1066 | } else if (c.sweep_lt(bottom->fPoint, rightBottom->fPoint) && |
1067 | !edge->fRight->isRightOf(bottom)) { |
1068 | rewind(activeEdges, current, rightTop, c); |
1069 | } else if (c.sweep_lt(rightBottom->fPoint, bottom->fPoint) && |
1070 | !edge->isLeftOf(rightBottom)) { |
1071 | rewind(activeEdges, current, top, c); |
1072 | } |
1073 | } |
1074 | } |
1075 | |
1076 | void set_top(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) { |
1077 | remove_edge_below(edge); |
1078 | edge->fTop = v; |
1079 | edge->recompute(); |
1080 | insert_edge_below(edge, v, c); |
1081 | rewind_if_necessary(edge, activeEdges, current, c); |
1082 | merge_collinear_edges(edge, activeEdges, current, c); |
1083 | } |
1084 | |
1085 | void set_bottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c) { |
1086 | remove_edge_above(edge); |
1087 | edge->fBottom = v; |
1088 | edge->recompute(); |
1089 | insert_edge_above(edge, v, c); |
1090 | rewind_if_necessary(edge, activeEdges, current, c); |
1091 | merge_collinear_edges(edge, activeEdges, current, c); |
1092 | } |
1093 | |
1094 | void merge_edges_above(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current, |
1095 | Comparator& c) { |
1096 | if (coincident(edge->fTop->fPoint, other->fTop->fPoint)) { |
1097 | TESS_LOG("merging coincident above edges (%g, %g) -> (%g, %g)\n" , |
1098 | edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, |
1099 | edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); |
1100 | rewind(activeEdges, current, edge->fTop, c); |
1101 | other->fWinding += edge->fWinding; |
1102 | disconnect(edge); |
1103 | edge->fTop = edge->fBottom = nullptr; |
1104 | } else if (c.sweep_lt(edge->fTop->fPoint, other->fTop->fPoint)) { |
1105 | rewind(activeEdges, current, edge->fTop, c); |
1106 | other->fWinding += edge->fWinding; |
1107 | set_bottom(edge, other->fTop, activeEdges, current, c); |
1108 | } else { |
1109 | rewind(activeEdges, current, other->fTop, c); |
1110 | edge->fWinding += other->fWinding; |
1111 | set_bottom(other, edge->fTop, activeEdges, current, c); |
1112 | } |
1113 | } |
1114 | |
1115 | void merge_edges_below(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current, |
1116 | Comparator& c) { |
1117 | if (coincident(edge->fBottom->fPoint, other->fBottom->fPoint)) { |
1118 | TESS_LOG("merging coincident below edges (%g, %g) -> (%g, %g)\n" , |
1119 | edge->fTop->fPoint.fX, edge->fTop->fPoint.fY, |
1120 | edge->fBottom->fPoint.fX, edge->fBottom->fPoint.fY); |
1121 | rewind(activeEdges, current, edge->fTop, c); |
1122 | other->fWinding += edge->fWinding; |
1123 | disconnect(edge); |
1124 | edge->fTop = edge->fBottom = nullptr; |
1125 | } else if (c.sweep_lt(edge->fBottom->fPoint, other->fBottom->fPoint)) { |
1126 | rewind(activeEdges, current, other->fTop, c); |
1127 | edge->fWinding += other->fWinding; |
1128 | set_top(other, edge->fBottom, activeEdges, current, c); |
1129 | } else { |
1130 | rewind(activeEdges, current, edge->fTop, c); |
1131 | other->fWinding += edge->fWinding; |
1132 | set_top(edge, other->fBottom, activeEdges, current, c); |
1133 | } |
1134 | } |
1135 | |
1136 | bool top_collinear(Edge* left, Edge* right) { |
1137 | if (!left || !right) { |
1138 | return false; |
1139 | } |
1140 | return left->fTop->fPoint == right->fTop->fPoint || |
1141 | !left->isLeftOf(right->fTop) || !right->isRightOf(left->fTop); |
1142 | } |
1143 | |
1144 | bool bottom_collinear(Edge* left, Edge* right) { |
1145 | if (!left || !right) { |
1146 | return false; |
1147 | } |
1148 | return left->fBottom->fPoint == right->fBottom->fPoint || |
1149 | !left->isLeftOf(right->fBottom) || !right->isRightOf(left->fBottom); |
1150 | } |
1151 | |
1152 | void merge_collinear_edges(Edge* edge, EdgeList* activeEdges, Vertex** current, Comparator& c) { |
1153 | for (;;) { |
1154 | if (top_collinear(edge->fPrevEdgeAbove, edge)) { |
1155 | merge_edges_above(edge->fPrevEdgeAbove, edge, activeEdges, current, c); |
1156 | } else if (top_collinear(edge, edge->fNextEdgeAbove)) { |
1157 | merge_edges_above(edge->fNextEdgeAbove, edge, activeEdges, current, c); |
1158 | } else if (bottom_collinear(edge->fPrevEdgeBelow, edge)) { |
1159 | merge_edges_below(edge->fPrevEdgeBelow, edge, activeEdges, current, c); |
1160 | } else if (bottom_collinear(edge, edge->fNextEdgeBelow)) { |
1161 | merge_edges_below(edge->fNextEdgeBelow, edge, activeEdges, current, c); |
1162 | } else { |
1163 | break; |
1164 | } |
1165 | } |
1166 | SkASSERT(!top_collinear(edge->fPrevEdgeAbove, edge)); |
1167 | SkASSERT(!top_collinear(edge, edge->fNextEdgeAbove)); |
1168 | SkASSERT(!bottom_collinear(edge->fPrevEdgeBelow, edge)); |
1169 | SkASSERT(!bottom_collinear(edge, edge->fNextEdgeBelow)); |
1170 | } |
1171 | |
1172 | bool split_edge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, Comparator& c, |
1173 | SkArenaAlloc& alloc) { |
1174 | if (!edge->fTop || !edge->fBottom || v == edge->fTop || v == edge->fBottom) { |
1175 | return false; |
1176 | } |
1177 | TESS_LOG("splitting edge (%g -> %g) at vertex %g (%g, %g)\n" , |
1178 | edge->fTop->fID, edge->fBottom->fID, v->fID, v->fPoint.fX, v->fPoint.fY); |
1179 | Vertex* top; |
1180 | Vertex* bottom; |
1181 | int winding = edge->fWinding; |
1182 | if (c.sweep_lt(v->fPoint, edge->fTop->fPoint)) { |
1183 | top = v; |
1184 | bottom = edge->fTop; |
1185 | set_top(edge, v, activeEdges, current, c); |
1186 | } else if (c.sweep_lt(edge->fBottom->fPoint, v->fPoint)) { |
1187 | top = edge->fBottom; |
1188 | bottom = v; |
1189 | set_bottom(edge, v, activeEdges, current, c); |
1190 | } else { |
1191 | top = v; |
1192 | bottom = edge->fBottom; |
1193 | set_bottom(edge, v, activeEdges, current, c); |
1194 | } |
1195 | Edge* newEdge = alloc.make<Edge>(top, bottom, winding, edge->fType); |
1196 | insert_edge_below(newEdge, top, c); |
1197 | insert_edge_above(newEdge, bottom, c); |
1198 | merge_collinear_edges(newEdge, activeEdges, current, c); |
1199 | return true; |
1200 | } |
1201 | |
1202 | bool intersect_edge_pair(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current, Comparator& c, SkArenaAlloc& alloc) { |
1203 | if (!left->fTop || !left->fBottom || !right->fTop || !right->fBottom) { |
1204 | return false; |
1205 | } |
1206 | if (left->fTop == right->fTop || left->fBottom == right->fBottom) { |
1207 | return false; |
1208 | } |
1209 | if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) { |
1210 | if (!left->isLeftOf(right->fTop)) { |
1211 | rewind(activeEdges, current, right->fTop, c); |
1212 | return split_edge(left, right->fTop, activeEdges, current, c, alloc); |
1213 | } |
1214 | } else { |
1215 | if (!right->isRightOf(left->fTop)) { |
1216 | rewind(activeEdges, current, left->fTop, c); |
1217 | return split_edge(right, left->fTop, activeEdges, current, c, alloc); |
1218 | } |
1219 | } |
1220 | if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) { |
1221 | if (!left->isLeftOf(right->fBottom)) { |
1222 | rewind(activeEdges, current, right->fBottom, c); |
1223 | return split_edge(left, right->fBottom, activeEdges, current, c, alloc); |
1224 | } |
1225 | } else { |
1226 | if (!right->isRightOf(left->fBottom)) { |
1227 | rewind(activeEdges, current, left->fBottom, c); |
1228 | return split_edge(right, left->fBottom, activeEdges, current, c, alloc); |
1229 | } |
1230 | } |
1231 | return false; |
1232 | } |
1233 | |
1234 | Edge* connect(Vertex* prev, Vertex* next, Edge::Type type, Comparator& c, SkArenaAlloc& alloc, |
1235 | int winding_scale = 1) { |
1236 | if (!prev || !next || prev->fPoint == next->fPoint) { |
1237 | return nullptr; |
1238 | } |
1239 | Edge* edge = new_edge(prev, next, type, c, alloc); |
1240 | insert_edge_below(edge, edge->fTop, c); |
1241 | insert_edge_above(edge, edge->fBottom, c); |
1242 | edge->fWinding *= winding_scale; |
1243 | merge_collinear_edges(edge, nullptr, nullptr, c); |
1244 | return edge; |
1245 | } |
1246 | |
1247 | void merge_vertices(Vertex* src, Vertex* dst, VertexList* mesh, Comparator& c, |
1248 | SkArenaAlloc& alloc) { |
1249 | TESS_LOG("found coincident verts at %g, %g; merging %g into %g\n" , |
1250 | src->fPoint.fX, src->fPoint.fY, src->fID, dst->fID); |
1251 | dst->fAlpha = std::max(src->fAlpha, dst->fAlpha); |
1252 | if (src->fPartner) { |
1253 | src->fPartner->fPartner = dst; |
1254 | } |
1255 | while (Edge* edge = src->fFirstEdgeAbove) { |
1256 | set_bottom(edge, dst, nullptr, nullptr, c); |
1257 | } |
1258 | while (Edge* edge = src->fFirstEdgeBelow) { |
1259 | set_top(edge, dst, nullptr, nullptr, c); |
1260 | } |
1261 | mesh->remove(src); |
1262 | dst->fSynthetic = true; |
1263 | } |
1264 | |
1265 | Vertex* create_sorted_vertex(const SkPoint& p, uint8_t alpha, VertexList* mesh, |
1266 | Vertex* reference, Comparator& c, SkArenaAlloc& alloc) { |
1267 | Vertex* prevV = reference; |
1268 | while (prevV && c.sweep_lt(p, prevV->fPoint)) { |
1269 | prevV = prevV->fPrev; |
1270 | } |
1271 | Vertex* nextV = prevV ? prevV->fNext : mesh->fHead; |
1272 | while (nextV && c.sweep_lt(nextV->fPoint, p)) { |
1273 | prevV = nextV; |
1274 | nextV = nextV->fNext; |
1275 | } |
1276 | Vertex* v; |
1277 | if (prevV && coincident(prevV->fPoint, p)) { |
1278 | v = prevV; |
1279 | } else if (nextV && coincident(nextV->fPoint, p)) { |
1280 | v = nextV; |
1281 | } else { |
1282 | v = alloc.make<Vertex>(p, alpha); |
1283 | #if LOGGING_ENABLED |
1284 | if (!prevV) { |
1285 | v->fID = mesh->fHead->fID - 1.0f; |
1286 | } else if (!nextV) { |
1287 | v->fID = mesh->fTail->fID + 1.0f; |
1288 | } else { |
1289 | v->fID = (prevV->fID + nextV->fID) * 0.5f; |
1290 | } |
1291 | #endif |
1292 | mesh->insert(v, prevV, nextV); |
1293 | } |
1294 | return v; |
1295 | } |
1296 | |
1297 | // If an edge's top and bottom points differ only by 1/2 machine epsilon in the primary |
1298 | // sort criterion, it may not be possible to split correctly, since there is no point which is |
1299 | // below the top and above the bottom. This function detects that case. |
1300 | bool nearly_flat(Comparator& c, Edge* edge) { |
1301 | SkPoint diff = edge->fBottom->fPoint - edge->fTop->fPoint; |
1302 | float primaryDiff = c.fDirection == Comparator::Direction::kHorizontal ? diff.fX : diff.fY; |
1303 | return fabs(primaryDiff) < std::numeric_limits<float>::epsilon() && primaryDiff != 0.0f; |
1304 | } |
1305 | |
1306 | SkPoint clamp(SkPoint p, SkPoint min, SkPoint max, Comparator& c) { |
1307 | if (c.sweep_lt(p, min)) { |
1308 | return min; |
1309 | } else if (c.sweep_lt(max, p)) { |
1310 | return max; |
1311 | } else { |
1312 | return p; |
1313 | } |
1314 | } |
1315 | |
1316 | void compute_bisector(Edge* edge1, Edge* edge2, Vertex* v, SkArenaAlloc& alloc) { |
1317 | Line line1 = edge1->fLine; |
1318 | Line line2 = edge2->fLine; |
1319 | line1.normalize(); |
1320 | line2.normalize(); |
1321 | double cosAngle = line1.fA * line2.fA + line1.fB * line2.fB; |
1322 | if (cosAngle > 0.999) { |
1323 | return; |
1324 | } |
1325 | line1.fC += edge1->fWinding > 0 ? -1 : 1; |
1326 | line2.fC += edge2->fWinding > 0 ? -1 : 1; |
1327 | SkPoint p; |
1328 | if (line1.intersect(line2, &p)) { |
1329 | uint8_t alpha = edge1->fType == Edge::Type::kOuter ? 255 : 0; |
1330 | v->fPartner = alloc.make<Vertex>(p, alpha); |
1331 | TESS_LOG("computed bisector (%g,%g) alpha %d for vertex %g\n" , p.fX, p.fY, alpha, v->fID); |
1332 | } |
1333 | } |
1334 | |
1335 | bool check_for_intersection(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current, |
1336 | VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { |
1337 | if (!left || !right) { |
1338 | return false; |
1339 | } |
1340 | SkPoint p; |
1341 | uint8_t alpha; |
1342 | if (left->intersect(*right, &p, &alpha) && p.isFinite()) { |
1343 | Vertex* v; |
1344 | TESS_LOG("found intersection, pt is %g, %g\n" , p.fX, p.fY); |
1345 | Vertex* top = *current; |
1346 | // If the intersection point is above the current vertex, rewind to the vertex above the |
1347 | // intersection. |
1348 | while (top && c.sweep_lt(p, top->fPoint)) { |
1349 | top = top->fPrev; |
1350 | } |
1351 | if (!nearly_flat(c, left)) { |
1352 | p = clamp(p, left->fTop->fPoint, left->fBottom->fPoint, c); |
1353 | } |
1354 | if (!nearly_flat(c, right)) { |
1355 | p = clamp(p, right->fTop->fPoint, right->fBottom->fPoint, c); |
1356 | } |
1357 | if (p == left->fTop->fPoint) { |
1358 | v = left->fTop; |
1359 | } else if (p == left->fBottom->fPoint) { |
1360 | v = left->fBottom; |
1361 | } else if (p == right->fTop->fPoint) { |
1362 | v = right->fTop; |
1363 | } else if (p == right->fBottom->fPoint) { |
1364 | v = right->fBottom; |
1365 | } else { |
1366 | v = create_sorted_vertex(p, alpha, mesh, top, c, alloc); |
1367 | if (left->fTop->fPartner) { |
1368 | v->fSynthetic = true; |
1369 | compute_bisector(left, right, v, alloc); |
1370 | } |
1371 | } |
1372 | rewind(activeEdges, current, top ? top : v, c); |
1373 | split_edge(left, v, activeEdges, current, c, alloc); |
1374 | split_edge(right, v, activeEdges, current, c, alloc); |
1375 | v->fAlpha = std::max(v->fAlpha, alpha); |
1376 | return true; |
1377 | } |
1378 | return intersect_edge_pair(left, right, activeEdges, current, c, alloc); |
1379 | } |
1380 | |
1381 | void sanitize_contours(VertexList* contours, int contourCnt, Mode mode) { |
1382 | bool approximate = (Mode::kEdgeAntialias == mode); |
1383 | bool removeCollinearVertices = (Mode::kSimpleInnerPolygons != mode); |
1384 | for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) { |
1385 | SkASSERT(contour->fHead); |
1386 | Vertex* prev = contour->fTail; |
1387 | if (approximate) { |
1388 | round(&prev->fPoint); |
1389 | } |
1390 | for (Vertex* v = contour->fHead; v;) { |
1391 | if (approximate) { |
1392 | round(&v->fPoint); |
1393 | } |
1394 | Vertex* next = v->fNext; |
1395 | Vertex* nextWrap = next ? next : contour->fHead; |
1396 | if (coincident(prev->fPoint, v->fPoint)) { |
1397 | TESS_LOG("vertex %g,%g coincident; removing\n" , v->fPoint.fX, v->fPoint.fY); |
1398 | contour->remove(v); |
1399 | } else if (!v->fPoint.isFinite()) { |
1400 | TESS_LOG("vertex %g,%g non-finite; removing\n" , v->fPoint.fX, v->fPoint.fY); |
1401 | contour->remove(v); |
1402 | } else if (removeCollinearVertices && |
1403 | Line(prev->fPoint, nextWrap->fPoint).dist(v->fPoint) == 0.0) { |
1404 | TESS_LOG("vertex %g,%g collinear; removing\n" , v->fPoint.fX, v->fPoint.fY); |
1405 | contour->remove(v); |
1406 | } else { |
1407 | prev = v; |
1408 | } |
1409 | v = next; |
1410 | } |
1411 | } |
1412 | } |
1413 | |
1414 | bool merge_coincident_vertices(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { |
1415 | if (!mesh->fHead) { |
1416 | return false; |
1417 | } |
1418 | bool merged = false; |
1419 | for (Vertex* v = mesh->fHead->fNext; v;) { |
1420 | Vertex* next = v->fNext; |
1421 | if (c.sweep_lt(v->fPoint, v->fPrev->fPoint)) { |
1422 | v->fPoint = v->fPrev->fPoint; |
1423 | } |
1424 | if (coincident(v->fPrev->fPoint, v->fPoint)) { |
1425 | merge_vertices(v, v->fPrev, mesh, c, alloc); |
1426 | merged = true; |
1427 | } |
1428 | v = next; |
1429 | } |
1430 | return merged; |
1431 | } |
1432 | |
1433 | // Stage 2: convert the contours to a mesh of edges connecting the vertices. |
1434 | |
1435 | void build_edges(VertexList* contours, int contourCnt, VertexList* mesh, Comparator& c, |
1436 | SkArenaAlloc& alloc) { |
1437 | for (VertexList* contour = contours; contourCnt > 0; --contourCnt, ++contour) { |
1438 | Vertex* prev = contour->fTail; |
1439 | for (Vertex* v = contour->fHead; v;) { |
1440 | Vertex* next = v->fNext; |
1441 | connect(prev, v, Edge::Type::kInner, c, alloc); |
1442 | mesh->append(v); |
1443 | prev = v; |
1444 | v = next; |
1445 | } |
1446 | } |
1447 | } |
1448 | |
1449 | void connect_partners(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { |
1450 | for (Vertex* outer = mesh->fHead; outer; outer = outer->fNext) { |
1451 | if (Vertex* inner = outer->fPartner) { |
1452 | if ((inner->fPrev || inner->fNext) && (outer->fPrev || outer->fNext)) { |
1453 | // Connector edges get zero winding, since they're only structural (i.e., to ensure |
1454 | // no 0-0-0 alpha triangles are produced), and shouldn't affect the poly winding |
1455 | // number. |
1456 | connect(outer, inner, Edge::Type::kConnector, c, alloc, 0); |
1457 | inner->fPartner = outer->fPartner = nullptr; |
1458 | } |
1459 | } |
1460 | } |
1461 | } |
1462 | |
1463 | template <CompareFunc sweep_lt> |
1464 | void sorted_merge(VertexList* front, VertexList* back, VertexList* result) { |
1465 | Vertex* a = front->fHead; |
1466 | Vertex* b = back->fHead; |
1467 | while (a && b) { |
1468 | if (sweep_lt(a->fPoint, b->fPoint)) { |
1469 | front->remove(a); |
1470 | result->append(a); |
1471 | a = front->fHead; |
1472 | } else { |
1473 | back->remove(b); |
1474 | result->append(b); |
1475 | b = back->fHead; |
1476 | } |
1477 | } |
1478 | result->append(*front); |
1479 | result->append(*back); |
1480 | } |
1481 | |
1482 | void sorted_merge(VertexList* front, VertexList* back, VertexList* result, Comparator& c) { |
1483 | if (c.fDirection == Comparator::Direction::kHorizontal) { |
1484 | sorted_merge<sweep_lt_horiz>(front, back, result); |
1485 | } else { |
1486 | sorted_merge<sweep_lt_vert>(front, back, result); |
1487 | } |
1488 | #if LOGGING_ENABLED |
1489 | float id = 0.0f; |
1490 | for (Vertex* v = result->fHead; v; v = v->fNext) { |
1491 | v->fID = id++; |
1492 | } |
1493 | #endif |
1494 | } |
1495 | |
1496 | // Stage 3: sort the vertices by increasing sweep direction. |
1497 | |
1498 | template <CompareFunc sweep_lt> |
1499 | void merge_sort(VertexList* vertices) { |
1500 | Vertex* slow = vertices->fHead; |
1501 | if (!slow) { |
1502 | return; |
1503 | } |
1504 | Vertex* fast = slow->fNext; |
1505 | if (!fast) { |
1506 | return; |
1507 | } |
1508 | do { |
1509 | fast = fast->fNext; |
1510 | if (fast) { |
1511 | fast = fast->fNext; |
1512 | slow = slow->fNext; |
1513 | } |
1514 | } while (fast); |
1515 | VertexList front(vertices->fHead, slow); |
1516 | VertexList back(slow->fNext, vertices->fTail); |
1517 | front.fTail->fNext = back.fHead->fPrev = nullptr; |
1518 | |
1519 | merge_sort<sweep_lt>(&front); |
1520 | merge_sort<sweep_lt>(&back); |
1521 | |
1522 | vertices->fHead = vertices->fTail = nullptr; |
1523 | sorted_merge<sweep_lt>(&front, &back, vertices); |
1524 | } |
1525 | |
1526 | void dump_mesh(const VertexList& mesh) { |
1527 | #if LOGGING_ENABLED |
1528 | for (Vertex* v = mesh.fHead; v; v = v->fNext) { |
1529 | TESS_LOG("vertex %g (%g, %g) alpha %d" , v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha); |
1530 | if (Vertex* p = v->fPartner) { |
1531 | TESS_LOG(", partner %g (%g, %g) alpha %d\n" , |
1532 | p->fID, p->fPoint.fX, p->fPoint.fY, p->fAlpha); |
1533 | } else { |
1534 | TESS_LOG(", null partner\n" ); |
1535 | } |
1536 | for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { |
1537 | TESS_LOG(" edge %g -> %g, winding %d\n" , e->fTop->fID, e->fBottom->fID, e->fWinding); |
1538 | } |
1539 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
1540 | TESS_LOG(" edge %g -> %g, winding %d\n" , e->fTop->fID, e->fBottom->fID, e->fWinding); |
1541 | } |
1542 | } |
1543 | #endif |
1544 | } |
1545 | |
1546 | void dump_skel(const SSEdgeList& ssEdges) { |
1547 | #if LOGGING_ENABLED |
1548 | for (SSEdge* edge : ssEdges) { |
1549 | if (edge->fEdge) { |
1550 | TESS_LOG("skel edge %g -> %g" , |
1551 | edge->fPrev->fVertex->fID, |
1552 | edge->fNext->fVertex->fID); |
1553 | if (edge->fEdge->fTop && edge->fEdge->fBottom) { |
1554 | TESS_LOG(" (original %g -> %g)\n" , |
1555 | edge->fEdge->fTop->fID, |
1556 | edge->fEdge->fBottom->fID); |
1557 | } else { |
1558 | TESS_LOG("\n" ); |
1559 | } |
1560 | } |
1561 | } |
1562 | #endif |
1563 | } |
1564 | |
1565 | #ifdef SK_DEBUG |
1566 | void validate_edge_pair(Edge* left, Edge* right, Comparator& c) { |
1567 | if (!left || !right) { |
1568 | return; |
1569 | } |
1570 | if (left->fTop == right->fTop) { |
1571 | SkASSERT(left->isLeftOf(right->fBottom)); |
1572 | SkASSERT(right->isRightOf(left->fBottom)); |
1573 | } else if (c.sweep_lt(left->fTop->fPoint, right->fTop->fPoint)) { |
1574 | SkASSERT(left->isLeftOf(right->fTop)); |
1575 | } else { |
1576 | SkASSERT(right->isRightOf(left->fTop)); |
1577 | } |
1578 | if (left->fBottom == right->fBottom) { |
1579 | SkASSERT(left->isLeftOf(right->fTop)); |
1580 | SkASSERT(right->isRightOf(left->fTop)); |
1581 | } else if (c.sweep_lt(right->fBottom->fPoint, left->fBottom->fPoint)) { |
1582 | SkASSERT(left->isLeftOf(right->fBottom)); |
1583 | } else { |
1584 | SkASSERT(right->isRightOf(left->fBottom)); |
1585 | } |
1586 | } |
1587 | |
1588 | void validate_edge_list(EdgeList* edges, Comparator& c) { |
1589 | Edge* left = edges->fHead; |
1590 | if (!left) { |
1591 | return; |
1592 | } |
1593 | for (Edge* right = left->fRight; right; right = right->fRight) { |
1594 | validate_edge_pair(left, right, c); |
1595 | left = right; |
1596 | } |
1597 | } |
1598 | #endif |
1599 | |
1600 | // Stage 4: Simplify the mesh by inserting new vertices at intersecting edges. |
1601 | |
1602 | bool connected(Vertex* v) { |
1603 | return v->fFirstEdgeAbove || v->fFirstEdgeBelow; |
1604 | } |
1605 | |
1606 | enum class SimplifyResult { |
1607 | kAlreadySimple, |
1608 | kFoundSelfIntersection, |
1609 | kAbort |
1610 | }; |
1611 | |
1612 | SimplifyResult simplify(Mode mode, VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { |
1613 | TESS_LOG("simplifying complex polygons\n" ); |
1614 | EdgeList activeEdges; |
1615 | auto result = SimplifyResult::kAlreadySimple; |
1616 | for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) { |
1617 | if (!connected(v)) { |
1618 | continue; |
1619 | } |
1620 | Edge* leftEnclosingEdge; |
1621 | Edge* rightEnclosingEdge; |
1622 | bool restartChecks; |
1623 | do { |
1624 | TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n" , |
1625 | v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha); |
1626 | restartChecks = false; |
1627 | find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); |
1628 | v->fLeftEnclosingEdge = leftEnclosingEdge; |
1629 | v->fRightEnclosingEdge = rightEnclosingEdge; |
1630 | if (v->fFirstEdgeBelow) { |
1631 | for (Edge* edge = v->fFirstEdgeBelow; edge; edge = edge->fNextEdgeBelow) { |
1632 | if (check_for_intersection( |
1633 | leftEnclosingEdge, edge, &activeEdges, &v, mesh, c, alloc) || |
1634 | check_for_intersection( |
1635 | edge, rightEnclosingEdge, &activeEdges, &v, mesh, c, alloc)) { |
1636 | if (Mode::kSimpleInnerPolygons == mode) { |
1637 | return SimplifyResult::kAbort; |
1638 | } |
1639 | result = SimplifyResult::kFoundSelfIntersection; |
1640 | restartChecks = true; |
1641 | break; |
1642 | } |
1643 | } |
1644 | } else { |
1645 | if (check_for_intersection(leftEnclosingEdge, rightEnclosingEdge, |
1646 | &activeEdges, &v, mesh, c, alloc)) { |
1647 | if (Mode::kSimpleInnerPolygons == mode) { |
1648 | return SimplifyResult::kAbort; |
1649 | } |
1650 | result = SimplifyResult::kFoundSelfIntersection; |
1651 | restartChecks = true; |
1652 | } |
1653 | |
1654 | } |
1655 | } while (restartChecks); |
1656 | #ifdef SK_DEBUG |
1657 | validate_edge_list(&activeEdges, c); |
1658 | #endif |
1659 | for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { |
1660 | remove_edge(e, &activeEdges); |
1661 | } |
1662 | Edge* leftEdge = leftEnclosingEdge; |
1663 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
1664 | insert_edge(e, leftEdge, &activeEdges); |
1665 | leftEdge = e; |
1666 | } |
1667 | } |
1668 | SkASSERT(!activeEdges.fHead && !activeEdges.fTail); |
1669 | return result; |
1670 | } |
1671 | |
1672 | // Stage 5: Tessellate the simplified mesh into monotone polygons. |
1673 | |
1674 | Poly* tessellate(SkPathFillType fillType, Mode mode, const VertexList& vertices, |
1675 | SkArenaAlloc& alloc) { |
1676 | TESS_LOG("\ntessellating simple polygons\n" ); |
1677 | int maxWindMagnitude = std::numeric_limits<int>::max(); |
1678 | if (Mode::kSimpleInnerPolygons == mode && !SkPathFillType_IsEvenOdd(fillType)) { |
1679 | maxWindMagnitude = 1; |
1680 | } |
1681 | EdgeList activeEdges; |
1682 | Poly* polys = nullptr; |
1683 | for (Vertex* v = vertices.fHead; v != nullptr; v = v->fNext) { |
1684 | if (!connected(v)) { |
1685 | continue; |
1686 | } |
1687 | #if LOGGING_ENABLED |
1688 | TESS_LOG("\nvertex %g: (%g,%g), alpha %d\n" , v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha); |
1689 | #endif |
1690 | Edge* leftEnclosingEdge; |
1691 | Edge* rightEnclosingEdge; |
1692 | find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); |
1693 | Poly* leftPoly; |
1694 | Poly* rightPoly; |
1695 | if (v->fFirstEdgeAbove) { |
1696 | leftPoly = v->fFirstEdgeAbove->fLeftPoly; |
1697 | rightPoly = v->fLastEdgeAbove->fRightPoly; |
1698 | } else { |
1699 | leftPoly = leftEnclosingEdge ? leftEnclosingEdge->fRightPoly : nullptr; |
1700 | rightPoly = rightEnclosingEdge ? rightEnclosingEdge->fLeftPoly : nullptr; |
1701 | } |
1702 | #if LOGGING_ENABLED |
1703 | TESS_LOG("edges above:\n" ); |
1704 | for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { |
1705 | TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n" , |
1706 | e->fTop->fID, e->fBottom->fID, |
1707 | e->fLeftPoly ? e->fLeftPoly->fID : -1, |
1708 | e->fRightPoly ? e->fRightPoly->fID : -1); |
1709 | } |
1710 | TESS_LOG("edges below:\n" ); |
1711 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
1712 | TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n" , |
1713 | e->fTop->fID, e->fBottom->fID, |
1714 | e->fLeftPoly ? e->fLeftPoly->fID : -1, |
1715 | e->fRightPoly ? e->fRightPoly->fID : -1); |
1716 | } |
1717 | #endif |
1718 | if (v->fFirstEdgeAbove) { |
1719 | if (leftPoly) { |
1720 | leftPoly = leftPoly->addEdge(v->fFirstEdgeAbove, Poly::kRight_Side, alloc); |
1721 | } |
1722 | if (rightPoly) { |
1723 | rightPoly = rightPoly->addEdge(v->fLastEdgeAbove, Poly::kLeft_Side, alloc); |
1724 | } |
1725 | for (Edge* e = v->fFirstEdgeAbove; e != v->fLastEdgeAbove; e = e->fNextEdgeAbove) { |
1726 | Edge* rightEdge = e->fNextEdgeAbove; |
1727 | remove_edge(e, &activeEdges); |
1728 | if (e->fRightPoly) { |
1729 | e->fRightPoly->addEdge(e, Poly::kLeft_Side, alloc); |
1730 | } |
1731 | if (rightEdge->fLeftPoly && rightEdge->fLeftPoly != e->fRightPoly) { |
1732 | rightEdge->fLeftPoly->addEdge(e, Poly::kRight_Side, alloc); |
1733 | } |
1734 | } |
1735 | remove_edge(v->fLastEdgeAbove, &activeEdges); |
1736 | if (!v->fFirstEdgeBelow) { |
1737 | if (leftPoly && rightPoly && leftPoly != rightPoly) { |
1738 | SkASSERT(leftPoly->fPartner == nullptr && rightPoly->fPartner == nullptr); |
1739 | rightPoly->fPartner = leftPoly; |
1740 | leftPoly->fPartner = rightPoly; |
1741 | } |
1742 | } |
1743 | } |
1744 | if (v->fFirstEdgeBelow) { |
1745 | if (!v->fFirstEdgeAbove) { |
1746 | if (leftPoly && rightPoly) { |
1747 | if (leftPoly == rightPoly) { |
1748 | if (leftPoly->fTail && leftPoly->fTail->fSide == Poly::kLeft_Side) { |
1749 | leftPoly = new_poly(&polys, leftPoly->lastVertex(), |
1750 | leftPoly->fWinding, alloc); |
1751 | leftEnclosingEdge->fRightPoly = leftPoly; |
1752 | } else { |
1753 | rightPoly = new_poly(&polys, rightPoly->lastVertex(), |
1754 | rightPoly->fWinding, alloc); |
1755 | rightEnclosingEdge->fLeftPoly = rightPoly; |
1756 | } |
1757 | } |
1758 | Edge* join = alloc.make<Edge>(leftPoly->lastVertex(), v, 1, Edge::Type::kInner); |
1759 | leftPoly = leftPoly->addEdge(join, Poly::kRight_Side, alloc); |
1760 | rightPoly = rightPoly->addEdge(join, Poly::kLeft_Side, alloc); |
1761 | } |
1762 | } |
1763 | Edge* leftEdge = v->fFirstEdgeBelow; |
1764 | leftEdge->fLeftPoly = leftPoly; |
1765 | insert_edge(leftEdge, leftEnclosingEdge, &activeEdges); |
1766 | for (Edge* rightEdge = leftEdge->fNextEdgeBelow; rightEdge; |
1767 | rightEdge = rightEdge->fNextEdgeBelow) { |
1768 | insert_edge(rightEdge, leftEdge, &activeEdges); |
1769 | int winding = leftEdge->fLeftPoly ? leftEdge->fLeftPoly->fWinding : 0; |
1770 | winding += leftEdge->fWinding; |
1771 | if (winding != 0) { |
1772 | if (abs(winding) > maxWindMagnitude) { |
1773 | return nullptr; // We can't have weighted wind in kSimpleInnerPolygons mode |
1774 | } |
1775 | Poly* poly = new_poly(&polys, v, winding, alloc); |
1776 | leftEdge->fRightPoly = rightEdge->fLeftPoly = poly; |
1777 | } |
1778 | leftEdge = rightEdge; |
1779 | } |
1780 | v->fLastEdgeBelow->fRightPoly = rightPoly; |
1781 | } |
1782 | #if LOGGING_ENABLED |
1783 | TESS_LOG("\nactive edges:\n" ); |
1784 | for (Edge* e = activeEdges.fHead; e != nullptr; e = e->fRight) { |
1785 | TESS_LOG("%g -> %g, lpoly %d, rpoly %d\n" , |
1786 | e->fTop->fID, e->fBottom->fID, |
1787 | e->fLeftPoly ? e->fLeftPoly->fID : -1, |
1788 | e->fRightPoly ? e->fRightPoly->fID : -1); |
1789 | } |
1790 | #endif |
1791 | } |
1792 | return polys; |
1793 | } |
1794 | |
1795 | void remove_non_boundary_edges(const VertexList& mesh, SkPathFillType fillType, |
1796 | SkArenaAlloc& alloc) { |
1797 | TESS_LOG("removing non-boundary edges\n" ); |
1798 | EdgeList activeEdges; |
1799 | for (Vertex* v = mesh.fHead; v != nullptr; v = v->fNext) { |
1800 | if (!connected(v)) { |
1801 | continue; |
1802 | } |
1803 | Edge* leftEnclosingEdge; |
1804 | Edge* rightEnclosingEdge; |
1805 | find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); |
1806 | bool prevFilled = leftEnclosingEdge && |
1807 | apply_fill_type(fillType, leftEnclosingEdge->fWinding); |
1808 | for (Edge* e = v->fFirstEdgeAbove; e;) { |
1809 | Edge* next = e->fNextEdgeAbove; |
1810 | remove_edge(e, &activeEdges); |
1811 | bool filled = apply_fill_type(fillType, e->fWinding); |
1812 | if (filled == prevFilled) { |
1813 | disconnect(e); |
1814 | } |
1815 | prevFilled = filled; |
1816 | e = next; |
1817 | } |
1818 | Edge* prev = leftEnclosingEdge; |
1819 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
1820 | if (prev) { |
1821 | e->fWinding += prev->fWinding; |
1822 | } |
1823 | insert_edge(e, prev, &activeEdges); |
1824 | prev = e; |
1825 | } |
1826 | } |
1827 | } |
1828 | |
1829 | // Note: this is the normal to the edge, but not necessarily unit length. |
1830 | void get_edge_normal(const Edge* e, SkVector* normal) { |
1831 | normal->set(SkDoubleToScalar(e->fLine.fA), |
1832 | SkDoubleToScalar(e->fLine.fB)); |
1833 | } |
1834 | |
1835 | // Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions |
1836 | // and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to |
1837 | // invert on stroking. |
1838 | |
1839 | void simplify_boundary(EdgeList* boundary, Comparator& c, SkArenaAlloc& alloc) { |
1840 | Edge* prevEdge = boundary->fTail; |
1841 | SkVector prevNormal; |
1842 | get_edge_normal(prevEdge, &prevNormal); |
1843 | for (Edge* e = boundary->fHead; e != nullptr;) { |
1844 | Vertex* prev = prevEdge->fWinding == 1 ? prevEdge->fTop : prevEdge->fBottom; |
1845 | Vertex* next = e->fWinding == 1 ? e->fBottom : e->fTop; |
1846 | double distPrev = e->dist(prev->fPoint); |
1847 | double distNext = prevEdge->dist(next->fPoint); |
1848 | SkVector normal; |
1849 | get_edge_normal(e, &normal); |
1850 | constexpr double kQuarterPixelSq = 0.25f * 0.25f; |
1851 | if (prev == next) { |
1852 | remove_edge(prevEdge, boundary); |
1853 | remove_edge(e, boundary); |
1854 | prevEdge = boundary->fTail; |
1855 | e = boundary->fHead; |
1856 | if (prevEdge) { |
1857 | get_edge_normal(prevEdge, &prevNormal); |
1858 | } |
1859 | } else if (prevNormal.dot(normal) < 0.0 && |
1860 | (distPrev * distPrev <= kQuarterPixelSq || distNext * distNext <= kQuarterPixelSq)) { |
1861 | Edge* join = new_edge(prev, next, Edge::Type::kInner, c, alloc); |
1862 | if (prev->fPoint != next->fPoint) { |
1863 | join->fLine.normalize(); |
1864 | join->fLine = join->fLine * join->fWinding; |
1865 | } |
1866 | insert_edge(join, e, boundary); |
1867 | remove_edge(prevEdge, boundary); |
1868 | remove_edge(e, boundary); |
1869 | if (join->fLeft && join->fRight) { |
1870 | prevEdge = join->fLeft; |
1871 | e = join; |
1872 | } else { |
1873 | prevEdge = boundary->fTail; |
1874 | e = boundary->fHead; // join->fLeft ? join->fLeft : join; |
1875 | } |
1876 | get_edge_normal(prevEdge, &prevNormal); |
1877 | } else { |
1878 | prevEdge = e; |
1879 | prevNormal = normal; |
1880 | e = e->fRight; |
1881 | } |
1882 | } |
1883 | } |
1884 | |
1885 | void ss_connect(Vertex* v, Vertex* dest, Comparator& c, SkArenaAlloc& alloc) { |
1886 | if (v == dest) { |
1887 | return; |
1888 | } |
1889 | TESS_LOG("ss_connecting vertex %g to vertex %g\n" , v->fID, dest->fID); |
1890 | if (v->fSynthetic) { |
1891 | connect(v, dest, Edge::Type::kConnector, c, alloc, 0); |
1892 | } else if (v->fPartner) { |
1893 | TESS_LOG("setting %g's partner to %g " , v->fPartner->fID, dest->fID); |
1894 | TESS_LOG("and %g's partner to null\n" , v->fID); |
1895 | v->fPartner->fPartner = dest; |
1896 | v->fPartner = nullptr; |
1897 | } |
1898 | } |
1899 | |
1900 | void Event::apply(VertexList* mesh, Comparator& c, EventList* events, SkArenaAlloc& alloc) { |
1901 | if (!fEdge) { |
1902 | return; |
1903 | } |
1904 | Vertex* prev = fEdge->fPrev->fVertex; |
1905 | Vertex* next = fEdge->fNext->fVertex; |
1906 | SSEdge* prevEdge = fEdge->fPrev->fPrev; |
1907 | SSEdge* nextEdge = fEdge->fNext->fNext; |
1908 | if (!prevEdge || !nextEdge || !prevEdge->fEdge || !nextEdge->fEdge) { |
1909 | return; |
1910 | } |
1911 | Vertex* dest = create_sorted_vertex(fPoint, fAlpha, mesh, prev, c, alloc); |
1912 | dest->fSynthetic = true; |
1913 | SSVertex* ssv = alloc.make<SSVertex>(dest); |
1914 | TESS_LOG("collapsing %g, %g (original edge %g -> %g) to %g (%g, %g) alpha %d\n" , |
1915 | prev->fID, next->fID, fEdge->fEdge->fTop->fID, fEdge->fEdge->fBottom->fID, dest->fID, |
1916 | fPoint.fX, fPoint.fY, fAlpha); |
1917 | fEdge->fEdge = nullptr; |
1918 | |
1919 | ss_connect(prev, dest, c, alloc); |
1920 | ss_connect(next, dest, c, alloc); |
1921 | |
1922 | prevEdge->fNext = nextEdge->fPrev = ssv; |
1923 | ssv->fPrev = prevEdge; |
1924 | ssv->fNext = nextEdge; |
1925 | if (!prevEdge->fEdge || !nextEdge->fEdge) { |
1926 | return; |
1927 | } |
1928 | if (prevEdge->fEvent) { |
1929 | prevEdge->fEvent->fEdge = nullptr; |
1930 | } |
1931 | if (nextEdge->fEvent) { |
1932 | nextEdge->fEvent->fEdge = nullptr; |
1933 | } |
1934 | if (prevEdge->fPrev == nextEdge->fNext) { |
1935 | ss_connect(prevEdge->fPrev->fVertex, dest, c, alloc); |
1936 | prevEdge->fEdge = nextEdge->fEdge = nullptr; |
1937 | } else { |
1938 | compute_bisector(prevEdge->fEdge, nextEdge->fEdge, dest, alloc); |
1939 | SkASSERT(prevEdge != fEdge && nextEdge != fEdge); |
1940 | if (dest->fPartner) { |
1941 | create_event(prevEdge, events, alloc); |
1942 | create_event(nextEdge, events, alloc); |
1943 | } else { |
1944 | create_event(prevEdge, prevEdge->fPrev->fVertex, nextEdge, dest, events, c, alloc); |
1945 | create_event(nextEdge, nextEdge->fNext->fVertex, prevEdge, dest, events, c, alloc); |
1946 | } |
1947 | } |
1948 | } |
1949 | |
1950 | bool is_overlap_edge(Edge* e) { |
1951 | if (e->fType == Edge::Type::kOuter) { |
1952 | return e->fWinding != 0 && e->fWinding != 1; |
1953 | } else if (e->fType == Edge::Type::kInner) { |
1954 | return e->fWinding != 0 && e->fWinding != -2; |
1955 | } else { |
1956 | return false; |
1957 | } |
1958 | } |
1959 | |
1960 | // This is a stripped-down version of tessellate() which computes edges which |
1961 | // join two filled regions, which represent overlap regions, and collapses them. |
1962 | bool collapse_overlap_regions(VertexList* mesh, Comparator& c, SkArenaAlloc& alloc, |
1963 | EventComparator comp) { |
1964 | TESS_LOG("\nfinding overlap regions\n" ); |
1965 | EdgeList activeEdges; |
1966 | EventList events(comp); |
1967 | SSVertexMap ssVertices; |
1968 | SSEdgeList ssEdges; |
1969 | for (Vertex* v = mesh->fHead; v != nullptr; v = v->fNext) { |
1970 | if (!connected(v)) { |
1971 | continue; |
1972 | } |
1973 | Edge* leftEnclosingEdge; |
1974 | Edge* rightEnclosingEdge; |
1975 | find_enclosing_edges(v, &activeEdges, &leftEnclosingEdge, &rightEnclosingEdge); |
1976 | for (Edge* e = v->fLastEdgeAbove; e && e != leftEnclosingEdge;) { |
1977 | Edge* prev = e->fPrevEdgeAbove ? e->fPrevEdgeAbove : leftEnclosingEdge; |
1978 | remove_edge(e, &activeEdges); |
1979 | bool leftOverlap = prev && is_overlap_edge(prev); |
1980 | bool rightOverlap = is_overlap_edge(e); |
1981 | bool isOuterBoundary = e->fType == Edge::Type::kOuter && |
1982 | (!prev || prev->fWinding == 0 || e->fWinding == 0); |
1983 | if (prev) { |
1984 | e->fWinding -= prev->fWinding; |
1985 | } |
1986 | if (leftOverlap && rightOverlap) { |
1987 | TESS_LOG("found interior overlap edge %g -> %g, disconnecting\n" , |
1988 | e->fTop->fID, e->fBottom->fID); |
1989 | disconnect(e); |
1990 | } else if (leftOverlap || rightOverlap) { |
1991 | TESS_LOG("found overlap edge %g -> %g%s\n" , |
1992 | e->fTop->fID, e->fBottom->fID, |
1993 | isOuterBoundary ? ", is outer boundary" : "" ); |
1994 | Vertex* prevVertex = e->fWinding < 0 ? e->fBottom : e->fTop; |
1995 | Vertex* nextVertex = e->fWinding < 0 ? e->fTop : e->fBottom; |
1996 | SSVertex* ssPrev = ssVertices[prevVertex]; |
1997 | if (!ssPrev) { |
1998 | ssPrev = ssVertices[prevVertex] = alloc.make<SSVertex>(prevVertex); |
1999 | } |
2000 | SSVertex* ssNext = ssVertices[nextVertex]; |
2001 | if (!ssNext) { |
2002 | ssNext = ssVertices[nextVertex] = alloc.make<SSVertex>(nextVertex); |
2003 | } |
2004 | SSEdge* ssEdge = alloc.make<SSEdge>(e, ssPrev, ssNext); |
2005 | ssEdges.push_back(ssEdge); |
2006 | // SkASSERT(!ssPrev->fNext && !ssNext->fPrev); |
2007 | ssPrev->fNext = ssNext->fPrev = ssEdge; |
2008 | create_event(ssEdge, &events, alloc); |
2009 | if (!isOuterBoundary) { |
2010 | disconnect(e); |
2011 | } |
2012 | } |
2013 | e = prev; |
2014 | } |
2015 | Edge* prev = leftEnclosingEdge; |
2016 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
2017 | if (prev) { |
2018 | e->fWinding += prev->fWinding; |
2019 | } |
2020 | insert_edge(e, prev, &activeEdges); |
2021 | prev = e; |
2022 | } |
2023 | } |
2024 | bool complex = events.size() > 0; |
2025 | |
2026 | TESS_LOG("\ncollapsing overlap regions\n" ); |
2027 | TESS_LOG("skeleton before:\n" ); |
2028 | dump_skel(ssEdges); |
2029 | while (events.size() > 0) { |
2030 | Event* event = events.top(); |
2031 | events.pop(); |
2032 | event->apply(mesh, c, &events, alloc); |
2033 | } |
2034 | TESS_LOG("skeleton after:\n" ); |
2035 | dump_skel(ssEdges); |
2036 | for (SSEdge* edge : ssEdges) { |
2037 | if (Edge* e = edge->fEdge) { |
2038 | connect(edge->fPrev->fVertex, edge->fNext->fVertex, e->fType, c, alloc, 0); |
2039 | } |
2040 | } |
2041 | return complex; |
2042 | } |
2043 | |
2044 | bool inversion(Vertex* prev, Vertex* next, Edge* origEdge, Comparator& c) { |
2045 | if (!prev || !next) { |
2046 | return true; |
2047 | } |
2048 | int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; |
2049 | return winding != origEdge->fWinding; |
2050 | } |
2051 | |
2052 | // Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to |
2053 | // find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a |
2054 | // new antialiased mesh from those vertices. |
2055 | |
2056 | void stroke_boundary(EdgeList* boundary, VertexList* innerMesh, VertexList* outerMesh, |
2057 | Comparator& c, SkArenaAlloc& alloc) { |
2058 | TESS_LOG("\nstroking boundary\n" ); |
2059 | // A boundary with fewer than 3 edges is degenerate. |
2060 | if (!boundary->fHead || !boundary->fHead->fRight || !boundary->fHead->fRight->fRight) { |
2061 | return; |
2062 | } |
2063 | Edge* prevEdge = boundary->fTail; |
2064 | Vertex* prevV = prevEdge->fWinding > 0 ? prevEdge->fTop : prevEdge->fBottom; |
2065 | SkVector prevNormal; |
2066 | get_edge_normal(prevEdge, &prevNormal); |
2067 | double radius = 0.5; |
2068 | Line prevInner(prevEdge->fLine); |
2069 | prevInner.fC -= radius; |
2070 | Line prevOuter(prevEdge->fLine); |
2071 | prevOuter.fC += radius; |
2072 | VertexList innerVertices; |
2073 | VertexList outerVertices; |
2074 | bool innerInversion = true; |
2075 | bool outerInversion = true; |
2076 | for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) { |
2077 | Vertex* v = e->fWinding > 0 ? e->fTop : e->fBottom; |
2078 | SkVector normal; |
2079 | get_edge_normal(e, &normal); |
2080 | Line inner(e->fLine); |
2081 | inner.fC -= radius; |
2082 | Line outer(e->fLine); |
2083 | outer.fC += radius; |
2084 | SkPoint innerPoint, outerPoint; |
2085 | TESS_LOG("stroking vertex %g (%g, %g)\n" , v->fID, v->fPoint.fX, v->fPoint.fY); |
2086 | if (!prevEdge->fLine.nearParallel(e->fLine) && prevInner.intersect(inner, &innerPoint) && |
2087 | prevOuter.intersect(outer, &outerPoint)) { |
2088 | float cosAngle = normal.dot(prevNormal); |
2089 | if (cosAngle < -kCosMiterAngle) { |
2090 | Vertex* nextV = e->fWinding > 0 ? e->fBottom : e->fTop; |
2091 | |
2092 | // This is a pointy vertex whose angle is smaller than the threshold; miter it. |
2093 | Line bisector(innerPoint, outerPoint); |
2094 | Line tangent(v->fPoint, v->fPoint + SkPoint::Make(bisector.fA, bisector.fB)); |
2095 | if (tangent.fA == 0 && tangent.fB == 0) { |
2096 | continue; |
2097 | } |
2098 | tangent.normalize(); |
2099 | Line innerTangent(tangent); |
2100 | Line outerTangent(tangent); |
2101 | innerTangent.fC -= 0.5; |
2102 | outerTangent.fC += 0.5; |
2103 | SkPoint innerPoint1, innerPoint2, outerPoint1, outerPoint2; |
2104 | if (prevNormal.cross(normal) > 0) { |
2105 | // Miter inner points |
2106 | if (!innerTangent.intersect(prevInner, &innerPoint1) || |
2107 | !innerTangent.intersect(inner, &innerPoint2) || |
2108 | !outerTangent.intersect(bisector, &outerPoint)) { |
2109 | continue; |
2110 | } |
2111 | Line prevTangent(prevV->fPoint, |
2112 | prevV->fPoint + SkVector::Make(prevOuter.fA, prevOuter.fB)); |
2113 | Line nextTangent(nextV->fPoint, |
2114 | nextV->fPoint + SkVector::Make(outer.fA, outer.fB)); |
2115 | if (prevTangent.dist(outerPoint) > 0) { |
2116 | bisector.intersect(prevTangent, &outerPoint); |
2117 | } |
2118 | if (nextTangent.dist(outerPoint) < 0) { |
2119 | bisector.intersect(nextTangent, &outerPoint); |
2120 | } |
2121 | outerPoint1 = outerPoint2 = outerPoint; |
2122 | } else { |
2123 | // Miter outer points |
2124 | if (!outerTangent.intersect(prevOuter, &outerPoint1) || |
2125 | !outerTangent.intersect(outer, &outerPoint2)) { |
2126 | continue; |
2127 | } |
2128 | Line prevTangent(prevV->fPoint, |
2129 | prevV->fPoint + SkVector::Make(prevInner.fA, prevInner.fB)); |
2130 | Line nextTangent(nextV->fPoint, |
2131 | nextV->fPoint + SkVector::Make(inner.fA, inner.fB)); |
2132 | if (prevTangent.dist(innerPoint) > 0) { |
2133 | bisector.intersect(prevTangent, &innerPoint); |
2134 | } |
2135 | if (nextTangent.dist(innerPoint) < 0) { |
2136 | bisector.intersect(nextTangent, &innerPoint); |
2137 | } |
2138 | innerPoint1 = innerPoint2 = innerPoint; |
2139 | } |
2140 | if (!innerPoint1.isFinite() || !innerPoint2.isFinite() || |
2141 | !outerPoint1.isFinite() || !outerPoint2.isFinite()) { |
2142 | continue; |
2143 | } |
2144 | TESS_LOG("inner (%g, %g), (%g, %g), " , |
2145 | innerPoint1.fX, innerPoint1.fY, innerPoint2.fX, innerPoint2.fY); |
2146 | TESS_LOG("outer (%g, %g), (%g, %g)\n" , |
2147 | outerPoint1.fX, outerPoint1.fY, outerPoint2.fX, outerPoint2.fY); |
2148 | Vertex* innerVertex1 = alloc.make<Vertex>(innerPoint1, 255); |
2149 | Vertex* innerVertex2 = alloc.make<Vertex>(innerPoint2, 255); |
2150 | Vertex* outerVertex1 = alloc.make<Vertex>(outerPoint1, 0); |
2151 | Vertex* outerVertex2 = alloc.make<Vertex>(outerPoint2, 0); |
2152 | innerVertex1->fPartner = outerVertex1; |
2153 | innerVertex2->fPartner = outerVertex2; |
2154 | outerVertex1->fPartner = innerVertex1; |
2155 | outerVertex2->fPartner = innerVertex2; |
2156 | if (!inversion(innerVertices.fTail, innerVertex1, prevEdge, c)) { |
2157 | innerInversion = false; |
2158 | } |
2159 | if (!inversion(outerVertices.fTail, outerVertex1, prevEdge, c)) { |
2160 | outerInversion = false; |
2161 | } |
2162 | innerVertices.append(innerVertex1); |
2163 | innerVertices.append(innerVertex2); |
2164 | outerVertices.append(outerVertex1); |
2165 | outerVertices.append(outerVertex2); |
2166 | } else { |
2167 | TESS_LOG("inner (%g, %g), " , innerPoint.fX, innerPoint.fY); |
2168 | TESS_LOG("outer (%g, %g)\n" , outerPoint.fX, outerPoint.fY); |
2169 | Vertex* innerVertex = alloc.make<Vertex>(innerPoint, 255); |
2170 | Vertex* outerVertex = alloc.make<Vertex>(outerPoint, 0); |
2171 | innerVertex->fPartner = outerVertex; |
2172 | outerVertex->fPartner = innerVertex; |
2173 | if (!inversion(innerVertices.fTail, innerVertex, prevEdge, c)) { |
2174 | innerInversion = false; |
2175 | } |
2176 | if (!inversion(outerVertices.fTail, outerVertex, prevEdge, c)) { |
2177 | outerInversion = false; |
2178 | } |
2179 | innerVertices.append(innerVertex); |
2180 | outerVertices.append(outerVertex); |
2181 | } |
2182 | } |
2183 | prevInner = inner; |
2184 | prevOuter = outer; |
2185 | prevV = v; |
2186 | prevEdge = e; |
2187 | prevNormal = normal; |
2188 | } |
2189 | if (!inversion(innerVertices.fTail, innerVertices.fHead, prevEdge, c)) { |
2190 | innerInversion = false; |
2191 | } |
2192 | if (!inversion(outerVertices.fTail, outerVertices.fHead, prevEdge, c)) { |
2193 | outerInversion = false; |
2194 | } |
2195 | // Outer edges get 1 winding, and inner edges get -2 winding. This ensures that the interior |
2196 | // is always filled (1 + -2 = -1 for normal cases, 1 + 2 = 3 for thin features where the |
2197 | // interior inverts). |
2198 | // For total inversion cases, the shape has now reversed handedness, so invert the winding |
2199 | // so it will be detected during collapse_overlap_regions(). |
2200 | int innerWinding = innerInversion ? 2 : -2; |
2201 | int outerWinding = outerInversion ? -1 : 1; |
2202 | for (Vertex* v = innerVertices.fHead; v && v->fNext; v = v->fNext) { |
2203 | connect(v, v->fNext, Edge::Type::kInner, c, alloc, innerWinding); |
2204 | } |
2205 | connect(innerVertices.fTail, innerVertices.fHead, Edge::Type::kInner, c, alloc, innerWinding); |
2206 | for (Vertex* v = outerVertices.fHead; v && v->fNext; v = v->fNext) { |
2207 | connect(v, v->fNext, Edge::Type::kOuter, c, alloc, outerWinding); |
2208 | } |
2209 | connect(outerVertices.fTail, outerVertices.fHead, Edge::Type::kOuter, c, alloc, outerWinding); |
2210 | innerMesh->append(innerVertices); |
2211 | outerMesh->append(outerVertices); |
2212 | } |
2213 | |
2214 | void (EdgeList* boundary, Edge* e, SkPathFillType fillType, SkArenaAlloc& alloc) { |
2215 | TESS_LOG("\nextracting boundary\n" ); |
2216 | bool down = apply_fill_type(fillType, e->fWinding); |
2217 | Vertex* start = down ? e->fTop : e->fBottom; |
2218 | do { |
2219 | e->fWinding = down ? 1 : -1; |
2220 | Edge* next; |
2221 | e->fLine.normalize(); |
2222 | e->fLine = e->fLine * e->fWinding; |
2223 | boundary->append(e); |
2224 | if (down) { |
2225 | // Find outgoing edge, in clockwise order. |
2226 | if ((next = e->fNextEdgeAbove)) { |
2227 | down = false; |
2228 | } else if ((next = e->fBottom->fLastEdgeBelow)) { |
2229 | down = true; |
2230 | } else if ((next = e->fPrevEdgeAbove)) { |
2231 | down = false; |
2232 | } |
2233 | } else { |
2234 | // Find outgoing edge, in counter-clockwise order. |
2235 | if ((next = e->fPrevEdgeBelow)) { |
2236 | down = true; |
2237 | } else if ((next = e->fTop->fFirstEdgeAbove)) { |
2238 | down = false; |
2239 | } else if ((next = e->fNextEdgeBelow)) { |
2240 | down = true; |
2241 | } |
2242 | } |
2243 | disconnect(e); |
2244 | e = next; |
2245 | } while (e && (down ? e->fTop : e->fBottom) != start); |
2246 | } |
2247 | |
2248 | // Stage 5b: Extract boundaries from mesh, simplify and stroke them into a new mesh. |
2249 | |
2250 | void (const VertexList& inMesh, VertexList* innerVertices, |
2251 | VertexList* outerVertices, SkPathFillType fillType, |
2252 | Comparator& c, SkArenaAlloc& alloc) { |
2253 | remove_non_boundary_edges(inMesh, fillType, alloc); |
2254 | for (Vertex* v = inMesh.fHead; v; v = v->fNext) { |
2255 | while (v->fFirstEdgeBelow) { |
2256 | EdgeList boundary; |
2257 | extract_boundary(&boundary, v->fFirstEdgeBelow, fillType, alloc); |
2258 | simplify_boundary(&boundary, c, alloc); |
2259 | stroke_boundary(&boundary, innerVertices, outerVertices, c, alloc); |
2260 | } |
2261 | } |
2262 | } |
2263 | |
2264 | // This is a driver function that calls stages 2-5 in turn. |
2265 | |
2266 | void contours_to_mesh(VertexList* contours, int contourCnt, Mode mode, |
2267 | VertexList* mesh, Comparator& c, SkArenaAlloc& alloc) { |
2268 | #if LOGGING_ENABLED |
2269 | for (int i = 0; i < contourCnt; ++i) { |
2270 | Vertex* v = contours[i].fHead; |
2271 | SkASSERT(v); |
2272 | TESS_LOG("path.moveTo(%20.20g, %20.20g);\n" , v->fPoint.fX, v->fPoint.fY); |
2273 | for (v = v->fNext; v; v = v->fNext) { |
2274 | TESS_LOG("path.lineTo(%20.20g, %20.20g);\n" , v->fPoint.fX, v->fPoint.fY); |
2275 | } |
2276 | } |
2277 | #endif |
2278 | sanitize_contours(contours, contourCnt, mode); |
2279 | build_edges(contours, contourCnt, mesh, c, alloc); |
2280 | } |
2281 | |
2282 | void sort_mesh(VertexList* vertices, Comparator& c, SkArenaAlloc& alloc) { |
2283 | if (!vertices || !vertices->fHead) { |
2284 | return; |
2285 | } |
2286 | |
2287 | // Sort vertices in Y (secondarily in X). |
2288 | if (c.fDirection == Comparator::Direction::kHorizontal) { |
2289 | merge_sort<sweep_lt_horiz>(vertices); |
2290 | } else { |
2291 | merge_sort<sweep_lt_vert>(vertices); |
2292 | } |
2293 | #if LOGGING_ENABLED |
2294 | for (Vertex* v = vertices->fHead; v != nullptr; v = v->fNext) { |
2295 | static float gID = 0.0f; |
2296 | v->fID = gID++; |
2297 | } |
2298 | #endif |
2299 | } |
2300 | |
2301 | Poly* contours_to_polys(VertexList* contours, int contourCnt, SkPathFillType fillType, |
2302 | const SkRect& pathBounds, Mode mode, VertexList* outerMesh, |
2303 | SkArenaAlloc& alloc) { |
2304 | Comparator c(pathBounds.width() > pathBounds.height() ? Comparator::Direction::kHorizontal |
2305 | : Comparator::Direction::kVertical); |
2306 | VertexList mesh; |
2307 | contours_to_mesh(contours, contourCnt, mode, &mesh, c, alloc); |
2308 | sort_mesh(&mesh, c, alloc); |
2309 | merge_coincident_vertices(&mesh, c, alloc); |
2310 | if (SimplifyResult::kAbort == simplify(mode, &mesh, c, alloc)) { |
2311 | return nullptr; |
2312 | } |
2313 | TESS_LOG("\nsimplified mesh:\n" ); |
2314 | dump_mesh(mesh); |
2315 | if (Mode::kEdgeAntialias == mode) { |
2316 | VertexList innerMesh; |
2317 | extract_boundaries(mesh, &innerMesh, outerMesh, fillType, c, alloc); |
2318 | sort_mesh(&innerMesh, c, alloc); |
2319 | sort_mesh(outerMesh, c, alloc); |
2320 | merge_coincident_vertices(&innerMesh, c, alloc); |
2321 | bool was_complex = merge_coincident_vertices(outerMesh, c, alloc); |
2322 | auto result = simplify(mode, &innerMesh, c, alloc); |
2323 | SkASSERT(SimplifyResult::kAbort != result); |
2324 | was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex; |
2325 | result = simplify(mode, outerMesh, c, alloc); |
2326 | SkASSERT(SimplifyResult::kAbort != result); |
2327 | was_complex = (SimplifyResult::kFoundSelfIntersection == result) || was_complex; |
2328 | TESS_LOG("\ninner mesh before:\n" ); |
2329 | dump_mesh(innerMesh); |
2330 | TESS_LOG("\nouter mesh before:\n" ); |
2331 | dump_mesh(*outerMesh); |
2332 | EventComparator eventLT(EventComparator::Op::kLessThan); |
2333 | EventComparator eventGT(EventComparator::Op::kGreaterThan); |
2334 | was_complex = collapse_overlap_regions(&innerMesh, c, alloc, eventLT) || was_complex; |
2335 | was_complex = collapse_overlap_regions(outerMesh, c, alloc, eventGT) || was_complex; |
2336 | if (was_complex) { |
2337 | TESS_LOG("found complex mesh; taking slow path\n" ); |
2338 | VertexList aaMesh; |
2339 | TESS_LOG("\ninner mesh after:\n" ); |
2340 | dump_mesh(innerMesh); |
2341 | TESS_LOG("\nouter mesh after:\n" ); |
2342 | dump_mesh(*outerMesh); |
2343 | connect_partners(outerMesh, c, alloc); |
2344 | connect_partners(&innerMesh, c, alloc); |
2345 | sorted_merge(&innerMesh, outerMesh, &aaMesh, c); |
2346 | merge_coincident_vertices(&aaMesh, c, alloc); |
2347 | result = simplify(mode, &aaMesh, c, alloc); |
2348 | SkASSERT(SimplifyResult::kAbort != result); |
2349 | TESS_LOG("combined and simplified mesh:\n" ); |
2350 | dump_mesh(aaMesh); |
2351 | outerMesh->fHead = outerMesh->fTail = nullptr; |
2352 | return tessellate(fillType, mode, aaMesh, alloc); |
2353 | } else { |
2354 | TESS_LOG("no complex polygons; taking fast path\n" ); |
2355 | return tessellate(fillType, mode, innerMesh, alloc); |
2356 | } |
2357 | } else { |
2358 | return tessellate(fillType, mode, mesh, alloc); |
2359 | } |
2360 | } |
2361 | |
2362 | // Stage 6: Triangulate the monotone polygons into a vertex buffer. |
2363 | void* polys_to_triangles(Poly* polys, SkPathFillType fillType, Mode mode, void* data) { |
2364 | bool emitCoverage = (Mode::kEdgeAntialias == mode); |
2365 | for (Poly* poly = polys; poly; poly = poly->fNext) { |
2366 | if (apply_fill_type(fillType, poly)) { |
2367 | data = poly->emit(emitCoverage, data); |
2368 | } |
2369 | } |
2370 | return data; |
2371 | } |
2372 | |
2373 | Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, |
2374 | int contourCnt, SkArenaAlloc& alloc, Mode mode, int* numCountedCurves, |
2375 | VertexList* outerMesh) { |
2376 | SkPathFillType fillType = path.getFillType(); |
2377 | if (SkPathFillType_IsInverse(fillType)) { |
2378 | contourCnt++; |
2379 | } |
2380 | std::unique_ptr<VertexList[]> contours(new VertexList[contourCnt]); |
2381 | |
2382 | path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, mode, numCountedCurves); |
2383 | return contours_to_polys(contours.get(), contourCnt, path.getFillType(), path.getBounds(), |
2384 | mode, outerMesh, alloc); |
2385 | } |
2386 | |
2387 | int get_contour_count(const SkPath& path, SkScalar tolerance) { |
2388 | // We could theoretically be more aggressive about not counting empty contours, but we need to |
2389 | // actually match the exact number of contour linked lists the tessellator will create later on. |
2390 | int contourCnt = 1; |
2391 | bool hasPoints = false; |
2392 | |
2393 | SkPath::Iter iter(path, false); |
2394 | SkPath::Verb verb; |
2395 | SkPoint pts[4]; |
2396 | bool first = true; |
2397 | while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
2398 | switch (verb) { |
2399 | case SkPath::kMove_Verb: |
2400 | if (!first) { |
2401 | ++contourCnt; |
2402 | } |
2403 | [[fallthrough]]; |
2404 | case SkPath::kLine_Verb: |
2405 | case SkPath::kConic_Verb: |
2406 | case SkPath::kQuad_Verb: |
2407 | case SkPath::kCubic_Verb: |
2408 | hasPoints = true; |
2409 | break; |
2410 | default: |
2411 | break; |
2412 | } |
2413 | first = false; |
2414 | } |
2415 | if (!hasPoints) { |
2416 | return 0; |
2417 | } |
2418 | return contourCnt; |
2419 | } |
2420 | |
2421 | int64_t count_points(Poly* polys, SkPathFillType fillType) { |
2422 | int64_t count = 0; |
2423 | for (Poly* poly = polys; poly; poly = poly->fNext) { |
2424 | if (apply_fill_type(fillType, poly) && poly->fCount >= 3) { |
2425 | count += (poly->fCount - 2) * (TRIANGULATOR_WIREFRAME ? 6 : 3); |
2426 | } |
2427 | } |
2428 | return count; |
2429 | } |
2430 | |
2431 | int64_t count_outer_mesh_points(const VertexList& outerMesh) { |
2432 | int64_t count = 0; |
2433 | for (Vertex* v = outerMesh.fHead; v; v = v->fNext) { |
2434 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
2435 | count += TRIANGULATOR_WIREFRAME ? 12 : 6; |
2436 | } |
2437 | } |
2438 | return count; |
2439 | } |
2440 | |
2441 | void* outer_mesh_to_triangles(const VertexList& outerMesh, bool emitCoverage, void* data) { |
2442 | for (Vertex* v = outerMesh.fHead; v; v = v->fNext) { |
2443 | for (Edge* e = v->fFirstEdgeBelow; e; e = e->fNextEdgeBelow) { |
2444 | Vertex* v0 = e->fTop; |
2445 | Vertex* v1 = e->fBottom; |
2446 | Vertex* v2 = e->fBottom->fPartner; |
2447 | Vertex* v3 = e->fTop->fPartner; |
2448 | data = emit_triangle(v0, v1, v2, emitCoverage, data); |
2449 | data = emit_triangle(v0, v2, v3, emitCoverage, data); |
2450 | } |
2451 | } |
2452 | return data; |
2453 | } |
2454 | |
2455 | } // namespace |
2456 | |
2457 | namespace GrTriangulator { |
2458 | |
2459 | // Stage 6: Triangulate the monotone polygons into a vertex buffer. |
2460 | |
2461 | int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, |
2462 | GrEagerVertexAllocator* vertexAllocator, Mode mode, int* numCountedCurves) { |
2463 | int contourCnt = get_contour_count(path, tolerance); |
2464 | if (contourCnt <= 0) { |
2465 | *numCountedCurves = 0; |
2466 | return 0; |
2467 | } |
2468 | SkArenaAlloc alloc(kArenaChunkSize); |
2469 | VertexList outerMesh; |
2470 | Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, mode, |
2471 | numCountedCurves, &outerMesh); |
2472 | SkPathFillType fillType = (Mode::kEdgeAntialias == mode) ? |
2473 | SkPathFillType::kWinding : path.getFillType(); |
2474 | int64_t count64 = count_points(polys, fillType); |
2475 | if (Mode::kEdgeAntialias == mode) { |
2476 | count64 += count_outer_mesh_points(outerMesh); |
2477 | } |
2478 | if (0 == count64 || count64 > SK_MaxS32) { |
2479 | return 0; |
2480 | } |
2481 | int count = count64; |
2482 | |
2483 | size_t vertexStride = GetVertexStride(mode); |
2484 | void* verts = vertexAllocator->lock(vertexStride, count); |
2485 | if (!verts) { |
2486 | SkDebugf("Could not allocate vertices\n" ); |
2487 | return 0; |
2488 | } |
2489 | |
2490 | TESS_LOG("emitting %d verts\n" , count); |
2491 | void* end = polys_to_triangles(polys, fillType, mode, verts); |
2492 | end = outer_mesh_to_triangles(outerMesh, true, end); |
2493 | |
2494 | int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts)) |
2495 | / vertexStride); |
2496 | SkASSERT(actualCount <= count); |
2497 | vertexAllocator->unlock(actualCount); |
2498 | return actualCount; |
2499 | } |
2500 | |
2501 | int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, |
2502 | WindingVertex** verts) { |
2503 | int contourCnt = get_contour_count(path, tolerance); |
2504 | if (contourCnt <= 0) { |
2505 | *verts = nullptr; |
2506 | return 0; |
2507 | } |
2508 | SkArenaAlloc alloc(kArenaChunkSize); |
2509 | int numCountedCurves; |
2510 | Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, Mode::kNormal, |
2511 | &numCountedCurves, nullptr); |
2512 | SkPathFillType fillType = path.getFillType(); |
2513 | int64_t count64 = count_points(polys, fillType); |
2514 | if (0 == count64 || count64 > SK_MaxS32) { |
2515 | *verts = nullptr; |
2516 | return 0; |
2517 | } |
2518 | int count = count64; |
2519 | |
2520 | *verts = new WindingVertex[count]; |
2521 | WindingVertex* vertsEnd = *verts; |
2522 | SkPoint* points = new SkPoint[count]; |
2523 | SkPoint* pointsEnd = points; |
2524 | for (Poly* poly = polys; poly; poly = poly->fNext) { |
2525 | if (apply_fill_type(fillType, poly)) { |
2526 | SkPoint* start = pointsEnd; |
2527 | pointsEnd = static_cast<SkPoint*>(poly->emit(false, pointsEnd)); |
2528 | while (start != pointsEnd) { |
2529 | vertsEnd->fPos = *start; |
2530 | vertsEnd->fWinding = poly->fWinding; |
2531 | ++start; |
2532 | ++vertsEnd; |
2533 | } |
2534 | } |
2535 | } |
2536 | int actualCount = static_cast<int>(vertsEnd - *verts); |
2537 | SkASSERT(actualCount <= count); |
2538 | SkASSERT(pointsEnd - points == actualCount); |
2539 | delete[] points; |
2540 | return actualCount; |
2541 | } |
2542 | |
2543 | } // namespace GrTriangulator |
2544 | |