/src/skia/src/gpu/geometry/GrTriangulator.h
Line | Count | Source (jump to first uncovered line) |
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 | | #ifndef GrTriangulator_DEFINED |
9 | | #define GrTriangulator_DEFINED |
10 | | |
11 | | #include "include/core/SkPath.h" |
12 | | #include "include/core/SkPoint.h" |
13 | | #include "include/private/SkColorData.h" |
14 | | #include "src/core/SkArenaAlloc.h" |
15 | | #include "src/gpu/GrColor.h" |
16 | | |
17 | | class GrEagerVertexAllocator; |
18 | | struct SkRect; |
19 | | |
20 | | #define TRIANGULATOR_LOGGING 0 |
21 | 1.37M | #define TRIANGULATOR_WIREFRAME 0 |
22 | | |
23 | | /** |
24 | | * Provides utility functions for converting paths to a collection of triangles. |
25 | | */ |
26 | | class GrTriangulator { |
27 | | public: |
28 | | constexpr static int kArenaDefaultChunkSize = 16 * 1024; |
29 | | |
30 | | static int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, |
31 | 1.27k | GrEagerVertexAllocator* vertexAllocator, bool* isLinear) { |
32 | 1.27k | SkArenaAlloc alloc(kArenaDefaultChunkSize); |
33 | 1.27k | GrTriangulator triangulator(path, &alloc); |
34 | 1.27k | Poly* polys = triangulator.pathToPolys(tolerance, clipBounds, isLinear); |
35 | 1.27k | int count = triangulator.polysToTriangles(polys, vertexAllocator); |
36 | 1.27k | return count; |
37 | 1.27k | } |
38 | | |
39 | | // Enums used by GrTriangulator internals. |
40 | | typedef enum { kLeft_Side, kRight_Side } Side; |
41 | | enum class EdgeType { kInner, kOuter, kConnector }; |
42 | | |
43 | | // Structs used by GrTriangulator internals. |
44 | | struct Vertex; |
45 | | struct VertexList; |
46 | | struct Line; |
47 | | struct Edge; |
48 | | struct EdgeList; |
49 | | struct MonotonePoly; |
50 | | struct Poly; |
51 | | struct Comparator; |
52 | | |
53 | | protected: |
54 | 10.0k | GrTriangulator(const SkPath& path, SkArenaAlloc* alloc) : fPath(path), fAlloc(alloc) {} |
55 | 10.0k | virtual ~GrTriangulator() {} |
56 | | |
57 | | // There are six stages to the basic algorithm: |
58 | | // |
59 | | // 1) Linearize the path contours into piecewise linear segments: |
60 | | void pathToContours(float tolerance, const SkRect& clipBounds, VertexList* contours, |
61 | | bool* isLinear) const; |
62 | | |
63 | | // 2) Build a mesh of edges connecting the vertices: |
64 | | void contoursToMesh(VertexList* contours, int contourCnt, VertexList* mesh, |
65 | | const Comparator&) const; |
66 | | |
67 | | // 3) Sort the vertices in Y (and secondarily in X): |
68 | | static void SortedMerge(VertexList* front, VertexList* back, VertexList* result, |
69 | | const Comparator&); |
70 | | static void SortMesh(VertexList* vertices, const Comparator&); |
71 | | |
72 | | // 4) Simplify the mesh by inserting new vertices at intersecting edges: |
73 | | enum class SimplifyResult : bool { |
74 | | kAlreadySimple, |
75 | | kFoundSelfIntersection |
76 | | }; |
77 | | |
78 | | SimplifyResult simplify(VertexList* mesh, const Comparator&) const; |
79 | | |
80 | | // 5) Tessellate the simplified mesh into monotone polygons: |
81 | | virtual Poly* tessellate(const VertexList& vertices, const Comparator&) const; |
82 | | |
83 | | // 6) Triangulate the monotone polygons directly into a vertex buffer: |
84 | | void* polysToTriangles(Poly* polys, void* data, SkPathFillType overrideFillType) const; |
85 | | |
86 | | // The vertex sorting in step (3) is a merge sort, since it plays well with the linked list |
87 | | // of vertices (and the necessity of inserting new vertices on intersection). |
88 | | // |
89 | | // Stages (4) and (5) use an active edge list -- a list of all edges for which the |
90 | | // sweep line has crossed the top vertex, but not the bottom vertex. It's sorted |
91 | | // left-to-right based on the point where both edges are active (when both top vertices |
92 | | // have been seen, so the "lower" top vertex of the two). If the top vertices are equal |
93 | | // (shared), it's sorted based on the last point where both edges are active, so the |
94 | | // "upper" bottom vertex. |
95 | | // |
96 | | // The most complex step is the simplification (4). It's based on the Bentley-Ottman |
97 | | // line-sweep algorithm, but due to floating point inaccuracy, the intersection points are |
98 | | // not exact and may violate the mesh topology or active edge list ordering. We |
99 | | // accommodate this by adjusting the topology of the mesh and AEL to match the intersection |
100 | | // points. This occurs in two ways: |
101 | | // |
102 | | // A) Intersections may cause a shortened edge to no longer be ordered with respect to its |
103 | | // neighbouring edges at the top or bottom vertex. This is handled by merging the |
104 | | // edges (mergeCollinearVertices()). |
105 | | // B) Intersections may cause an edge to violate the left-to-right ordering of the |
106 | | // active edge list. This is handled by detecting potential violations and rewinding |
107 | | // the active edge list to the vertex before they occur (rewind() during merging, |
108 | | // rewind_if_necessary() during splitting). |
109 | | // |
110 | | // The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and |
111 | | // Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it |
112 | | // currently uses a linked list for the active edge list, rather than a 2-3 tree as the |
113 | | // paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also |
114 | | // become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N) |
115 | | // insertions and removals was greater than the cost of infrequent O(N) lookups with the |
116 | | // linked list implementation. With the latter, all removals are O(1), and most insertions |
117 | | // are O(1), since we know the adjacent edge in the active edge list based on the topology. |
118 | | // Only type 2 vertices (see paper) require the O(N) lookups, and these are much less |
119 | | // frequent. There may be other data structures worth investigating, however. |
120 | | // |
121 | | // Note that the orientation of the line sweep algorithms is determined by the aspect ratio of |
122 | | // the path bounds. When the path is taller than it is wide, we sort vertices based on |
123 | | // increasing Y coordinate, and secondarily by increasing X coordinate. When the path is wider |
124 | | // than it is tall, we sort by increasing X coordinate, but secondarily by *decreasing* Y |
125 | | // coordinate. This is so that the "left" and "right" orientation in the code remains correct |
126 | | // (edges to the left are increasing in Y; edges to the right are decreasing in Y). That is, the |
127 | | // setting rotates 90 degrees counterclockwise, rather that transposing. |
128 | | |
129 | | // Additional helpers and driver functions. |
130 | | void* emitMonotonePoly(const MonotonePoly*, void* data) const; |
131 | | void* emitTriangle(Vertex* prev, Vertex* curr, Vertex* next, int winding, void* data) const; |
132 | | void* emitPoly(const Poly*, void *data) const; |
133 | | Poly* makePoly(Poly** head, Vertex* v, int winding) const; |
134 | | void appendPointToContour(const SkPoint& p, VertexList* contour) const; |
135 | | void appendQuadraticToContour(const SkPoint[3], SkScalar toleranceSqd, |
136 | | VertexList* contour) const; |
137 | | void generateCubicPoints(const SkPoint&, const SkPoint&, const SkPoint&, const SkPoint&, |
138 | | SkScalar tolSqd, VertexList* contour, int pointsLeft) const; |
139 | | bool applyFillType(int winding) const; |
140 | | Edge* makeEdge(Vertex* prev, Vertex* next, EdgeType type, const Comparator&) const; |
141 | | void setTop(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, |
142 | | const Comparator&) const; |
143 | | void setBottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, |
144 | | const Comparator&) const; |
145 | | void mergeEdgesAbove(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current, |
146 | | const Comparator&) const; |
147 | | void mergeEdgesBelow(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current, |
148 | | const Comparator&) const; |
149 | | Edge* makeConnectingEdge(Vertex* prev, Vertex* next, EdgeType, const Comparator&, |
150 | | int windingScale = 1) const; |
151 | | void mergeVertices(Vertex* src, Vertex* dst, VertexList* mesh, const Comparator&) const; |
152 | | static void FindEnclosingEdges(Vertex* v, EdgeList* edges, Edge** left, Edge** right); |
153 | | void mergeCollinearEdges(Edge* edge, EdgeList* activeEdges, Vertex** current, |
154 | | const Comparator&) const; |
155 | | bool splitEdge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, |
156 | | const Comparator&) const; |
157 | | bool intersectEdgePair(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current, |
158 | | const Comparator&) const; |
159 | | Vertex* makeSortedVertex(const SkPoint&, uint8_t alpha, VertexList* mesh, Vertex* reference, |
160 | | const Comparator&) const; |
161 | | void computeBisector(Edge* edge1, Edge* edge2, Vertex*) const; |
162 | | bool checkForIntersection(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current, |
163 | | VertexList* mesh, const Comparator&) const; |
164 | | void sanitizeContours(VertexList* contours, int contourCnt) const; |
165 | | bool mergeCoincidentVertices(VertexList* mesh, const Comparator&) const; |
166 | | void buildEdges(VertexList* contours, int contourCnt, VertexList* mesh, |
167 | | const Comparator&) const; |
168 | | Poly* contoursToPolys(VertexList* contours, int contourCnt) const; |
169 | | Poly* pathToPolys(float tolerance, const SkRect& clipBounds, |
170 | | bool* isLinear) const; |
171 | | static int64_t CountPoints(Poly* polys, SkPathFillType overrideFillType); |
172 | | int polysToTriangles(Poly*, GrEagerVertexAllocator*) const; |
173 | | |
174 | | // FIXME: fPath should be plumbed through function parameters instead. |
175 | | const SkPath fPath; |
176 | | SkArenaAlloc* const fAlloc; |
177 | | |
178 | | // Internal control knobs. |
179 | | bool fRoundVerticesToQuarterPixel = false; |
180 | | bool fEmitCoverage = false; |
181 | | bool fPreserveCollinearVertices = false; |
182 | | bool fCollectBreadcrumbTriangles = false; |
183 | | |
184 | | // The breadcrumb triangles serve as a glue that erases T-junctions between a path's outer |
185 | | // curves and its inner polygon triangulation. Drawing a path's outer curves, breadcrumb |
186 | | // triangles, and inner polygon triangulation all together into the stencil buffer has the same |
187 | | // identical rasterized effect as stenciling a classic Redbook fan. |
188 | | // |
189 | | // The breadcrumb triangles track all the edge splits that led from the original inner polygon |
190 | | // edges to the final triangulation. Every time an edge splits, we emit a razor-thin breadcrumb |
191 | | // triangle consisting of the edge's original endpoints and the split point. (We also add |
192 | | // supplemental breadcrumb triangles to areas where abs(winding) > 1.) |
193 | | // |
194 | | // a |
195 | | // / |
196 | | // / |
197 | | // / |
198 | | // x <- Edge splits at x. New breadcrumb triangle is: [a, b, x]. |
199 | | // / |
200 | | // / |
201 | | // b |
202 | | // |
203 | | // The opposite-direction shared edges between the triangulation and breadcrumb triangles should |
204 | | // all cancel out, leaving just the set of edges from the original polygon. |
205 | | class BreadcrumbTriangleList { |
206 | | public: |
207 | | struct Node { |
208 | 0 | Node(SkPoint a, SkPoint b, SkPoint c) : fPts{a, b, c} {} |
209 | | SkPoint fPts[3]; |
210 | | Node* fNext = nullptr; |
211 | | }; |
212 | 0 | const Node* head() const { return fHead; } |
213 | 0 | int count() const { return fCount; } |
214 | | |
215 | 0 | void append(SkArenaAlloc* alloc, SkPoint a, SkPoint b, SkPoint c, int winding) { |
216 | 0 | if (a == b || a == c || b == c || winding == 0) { |
217 | 0 | return; |
218 | 0 | } |
219 | 0 | if (winding < 0) { |
220 | 0 | std::swap(a, b); |
221 | 0 | winding = -winding; |
222 | 0 | } |
223 | 0 | for (int i = 0; i < winding; ++i) { |
224 | 0 | SkASSERT(fTail && !(*fTail)); |
225 | 0 | *fTail = alloc->make<Node>(a, b, c); |
226 | 0 | fTail = &(*fTail)->fNext; |
227 | 0 | } |
228 | 0 | fCount += winding; |
229 | 0 | } Unexecuted instantiation: GrTriangulator::BreadcrumbTriangleList::append(SkArenaAlloc*, SkPoint, SkPoint, SkPoint, int) Unexecuted instantiation: GrTriangulator::BreadcrumbTriangleList::append(SkArenaAlloc*, SkPoint, SkPoint, SkPoint, int) |
230 | | |
231 | 0 | void concat(BreadcrumbTriangleList&& list) { |
232 | 0 | SkASSERT(fTail && !(*fTail)); |
233 | 0 | if (list.fHead) { |
234 | 0 | *fTail = list.fHead; |
235 | 0 | fTail = list.fTail; |
236 | 0 | fCount += list.fCount; |
237 | 0 | list.fHead = nullptr; |
238 | 0 | list.fTail = &list.fHead; |
239 | 0 | list.fCount = 0; |
240 | 0 | } |
241 | 0 | } Unexecuted instantiation: GrTriangulator::BreadcrumbTriangleList::concat(GrTriangulator::BreadcrumbTriangleList&&) Unexecuted instantiation: GrTriangulator::BreadcrumbTriangleList::concat(GrTriangulator::BreadcrumbTriangleList&&) |
242 | | |
243 | | private: |
244 | | Node* fHead = nullptr; |
245 | | Node** fTail = &fHead; |
246 | | int fCount = 0; |
247 | | }; |
248 | | |
249 | | mutable BreadcrumbTriangleList fBreadcrumbList; |
250 | | }; |
251 | | |
252 | | /** |
253 | | * Vertices are used in three ways: first, the path contours are converted into a |
254 | | * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices |
255 | | * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing |
256 | | * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid |
257 | | * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of |
258 | | * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since |
259 | | * an individual Vertex from the path mesh may belong to multiple |
260 | | * MonotonePolys, so the original Vertices cannot be re-used. |
261 | | */ |
262 | | |
263 | | struct GrTriangulator::Vertex { |
264 | | Vertex(const SkPoint& point, uint8_t alpha) |
265 | | : fPoint(point), fPrev(nullptr), fNext(nullptr) |
266 | | , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr) |
267 | | , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr) |
268 | | , fLeftEnclosingEdge(nullptr), fRightEnclosingEdge(nullptr) |
269 | | , fPartner(nullptr) |
270 | | , fAlpha(alpha) |
271 | | , fSynthetic(false) |
272 | | #if TRIANGULATOR_LOGGING |
273 | | , fID (-1.0f) |
274 | | #endif |
275 | 20.0M | {} |
276 | | SkPoint fPoint; // Vertex position |
277 | | Vertex* fPrev; // Linked list of contours, then Y-sorted vertices. |
278 | | Vertex* fNext; // " |
279 | | Edge* fFirstEdgeAbove; // Linked list of edges above this vertex. |
280 | | Edge* fLastEdgeAbove; // " |
281 | | Edge* fFirstEdgeBelow; // Linked list of edges below this vertex. |
282 | | Edge* fLastEdgeBelow; // " |
283 | | Edge* fLeftEnclosingEdge; // Nearest edge in the AEL left of this vertex. |
284 | | Edge* fRightEnclosingEdge; // Nearest edge in the AEL right of this vertex. |
285 | | Vertex* fPartner; // Corresponding inner or outer vertex (for AA). |
286 | | uint8_t fAlpha; |
287 | | bool fSynthetic; // Is this a synthetic vertex? |
288 | | #if TRIANGULATOR_LOGGING |
289 | | float fID; // Identifier used for logging. |
290 | | #endif |
291 | 28.8M | bool isConnected() const { return this->fFirstEdgeAbove || this->fFirstEdgeBelow; } |
292 | | }; |
293 | | |
294 | | struct GrTriangulator::VertexList { |
295 | 4.69M | VertexList() : fHead(nullptr), fTail(nullptr) {} |
296 | 30.4M | VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {} |
297 | | Vertex* fHead; |
298 | | Vertex* fTail; |
299 | | void insert(Vertex* v, Vertex* prev, Vertex* next); |
300 | 216M | void append(Vertex* v) { insert(v, fTail, nullptr); } |
301 | 30.4M | void append(const VertexList& list) { |
302 | 30.4M | if (!list.fHead) { |
303 | 15.2M | return; |
304 | 15.2M | } |
305 | 15.2M | if (fTail) { |
306 | 15.2M | fTail->fNext = list.fHead; |
307 | 15.2M | list.fHead->fPrev = fTail; |
308 | 15.8k | } else { |
309 | 15.8k | fHead = list.fHead; |
310 | 15.8k | } |
311 | 15.2M | fTail = list.fTail; |
312 | 15.2M | } |
313 | 7.79M | void prepend(Vertex* v) { insert(v, nullptr, fHead); } |
314 | | void remove(Vertex* v); |
315 | 0 | void close() { |
316 | 0 | if (fHead && fTail) { |
317 | 0 | fTail->fNext = fHead; |
318 | 0 | fHead->fPrev = fTail; |
319 | 0 | } |
320 | 0 | } |
321 | | #if TRIANGULATOR_LOGGING |
322 | | void dump() const; |
323 | | #endif |
324 | | }; |
325 | | |
326 | | // A line equation in implicit form. fA * x + fB * y + fC = 0, for all points (x, y) on the line. |
327 | | struct GrTriangulator::Line { |
328 | 78.5k | Line(double a, double b, double c) : fA(a), fB(b), fC(c) {} |
329 | 42.5M | Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {} |
330 | | Line(const SkPoint& p, const SkPoint& q) |
331 | | : fA(static_cast<double>(q.fY) - p.fY) // a = dY |
332 | | , fB(static_cast<double>(p.fX) - q.fX) // b = -dX |
333 | | , fC(static_cast<double>(p.fY) * q.fX - // c = cross(q, p) |
334 | 59.6M | static_cast<double>(p.fX) * q.fY) {} |
335 | 163M | double dist(const SkPoint& p) const { return fA * p.fX + fB * p.fY + fC; } |
336 | 78.5k | Line operator*(double v) const { return Line(fA * v, fB * v, fC * v); } |
337 | 169k | double magSq() const { return fA * fA + fB * fB; } |
338 | 169k | void normalize() { |
339 | 169k | double len = sqrt(this->magSq()); |
340 | 169k | if (len == 0.0) { |
341 | 0 | return; |
342 | 0 | } |
343 | 169k | double scale = 1.0f / len; |
344 | 169k | fA *= scale; |
345 | 169k | fB *= scale; |
346 | 169k | fC *= scale; |
347 | 169k | } |
348 | 74.9k | bool nearParallel(const Line& o) const { |
349 | 74.9k | return fabs(o.fA - fA) < 0.00001 && fabs(o.fB - fB) < 0.00001; |
350 | 74.9k | } |
351 | | |
352 | | // Compute the intersection of two (infinite) Lines. |
353 | | bool intersect(const Line& other, SkPoint* point) const; |
354 | | double fA, fB, fC; |
355 | | }; |
356 | | |
357 | | /** |
358 | | * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and |
359 | | * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf(). |
360 | | * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating |
361 | | * point). For speed, that case is only tested by the callers that require it (e.g., |
362 | | * rewind_if_necessary()). Edges also handle checking for intersection with other edges. |
363 | | * Currently, this converts the edges to the parametric form, in order to avoid doing a division |
364 | | * until an intersection has been confirmed. This is slightly slower in the "found" case, but |
365 | | * a lot faster in the "not found" case. |
366 | | * |
367 | | * The coefficients of the line equation stored in double precision to avoid catastrophic |
368 | | * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is |
369 | | * correct in float, since it's a polynomial of degree 2. The intersect() function, being |
370 | | * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its |
371 | | * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of |
372 | | * this file). |
373 | | */ |
374 | | |
375 | | struct GrTriangulator::Edge { |
376 | | Edge(Vertex* top, Vertex* bottom, int winding, EdgeType type) |
377 | | : fWinding(winding) |
378 | | , fTop(top) |
379 | | , fBottom(bottom) |
380 | | , fType(type) |
381 | | , fLeft(nullptr) |
382 | | , fRight(nullptr) |
383 | | , fPrevEdgeAbove(nullptr) |
384 | | , fNextEdgeAbove(nullptr) |
385 | | , fPrevEdgeBelow(nullptr) |
386 | | , fNextEdgeBelow(nullptr) |
387 | | , fLeftPoly(nullptr) |
388 | | , fRightPoly(nullptr) |
389 | | , fLeftPolyPrev(nullptr) |
390 | | , fLeftPolyNext(nullptr) |
391 | | , fRightPolyPrev(nullptr) |
392 | | , fRightPolyNext(nullptr) |
393 | | , fUsedInLeftPoly(false) |
394 | | , fUsedInRightPoly(false) |
395 | 24.4M | , fLine(top, bottom) { |
396 | 24.4M | } |
397 | | int fWinding; // 1 == edge goes downward; -1 = edge goes upward. |
398 | | Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt). |
399 | | Vertex* fBottom; // The bottom vertex in vertex-sort-order. |
400 | | EdgeType fType; |
401 | | Edge* fLeft; // The linked list of edges in the active edge list. |
402 | | Edge* fRight; // " |
403 | | Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above". |
404 | | Edge* fNextEdgeAbove; // " |
405 | | Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below". |
406 | | Edge* fNextEdgeBelow; // " |
407 | | Poly* fLeftPoly; // The Poly to the left of this edge, if any. |
408 | | Poly* fRightPoly; // The Poly to the right of this edge, if any. |
409 | | Edge* fLeftPolyPrev; |
410 | | Edge* fLeftPolyNext; |
411 | | Edge* fRightPolyPrev; |
412 | | Edge* fRightPolyNext; |
413 | | bool fUsedInLeftPoly; |
414 | | bool fUsedInRightPoly; |
415 | | Line fLine; |
416 | | |
417 | 156M | double dist(const SkPoint& p) const { |
418 | | // Coerce points coincident with the vertices to have dist = 0, since converting from |
419 | | // a double intersection point back to float storage might construct a point that's no |
420 | | // longer on the ideal line. |
421 | 156M | return (p == fTop->fPoint || p == fBottom->fPoint) ? 0.0 : fLine.dist(p); |
422 | 156M | } |
423 | 84.4M | bool isRightOf(Vertex* v) const { return this->dist(v->fPoint) < 0.0; } |
424 | 72.1M | bool isLeftOf(Vertex* v) const { return this->dist(v->fPoint) > 0.0; } |
425 | 18.0M | void recompute() { fLine = Line(fTop, fBottom); } |
426 | | void insertAbove(Vertex*, const Comparator&); |
427 | | void insertBelow(Vertex*, const Comparator&); |
428 | | void disconnect(); |
429 | | bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) const; |
430 | | }; |
431 | | |
432 | | struct GrTriangulator::EdgeList { |
433 | 88.6k | EdgeList() : fHead(nullptr), fTail(nullptr) {} |
434 | | Edge* fHead; |
435 | | Edge* fTail; |
436 | | void insert(Edge* edge, Edge* prev, Edge* next); |
437 | | void insert(Edge* edge, Edge* prev); |
438 | 77.3k | void append(Edge* e) { insert(e, fTail, nullptr); } |
439 | | void remove(Edge* edge); |
440 | 0 | void removeAll() { |
441 | 0 | while (fHead) { |
442 | 0 | this->remove(fHead); |
443 | 0 | } |
444 | 0 | } |
445 | 0 | void close() { |
446 | 0 | if (fHead && fTail) { |
447 | 0 | fTail->fRight = fHead; |
448 | 0 | fHead->fLeft = fTail; |
449 | 0 | } |
450 | 0 | } |
451 | 0 | bool contains(Edge* edge) const { return edge->fLeft || edge->fRight || fHead == edge; } |
452 | | }; |
453 | | |
454 | | struct GrTriangulator::MonotonePoly { |
455 | | MonotonePoly(Edge* edge, Side side, int winding) |
456 | | : fSide(side) |
457 | | , fFirstEdge(nullptr) |
458 | | , fLastEdge(nullptr) |
459 | | , fPrev(nullptr) |
460 | | , fNext(nullptr) |
461 | 4.59M | , fWinding(winding) { |
462 | 4.59M | this->addEdge(edge); |
463 | 4.59M | } |
464 | | Side fSide; |
465 | | Edge* fFirstEdge; |
466 | | Edge* fLastEdge; |
467 | | MonotonePoly* fPrev; |
468 | | MonotonePoly* fNext; |
469 | | int fWinding; |
470 | | void addEdge(Edge*); |
471 | | }; |
472 | | |
473 | | struct GrTriangulator::Poly { |
474 | | Poly(Vertex* v, int winding); |
475 | | |
476 | | Poly* addEdge(Edge* e, Side side, SkArenaAlloc* alloc); |
477 | 29.9k | Vertex* lastVertex() const { return fTail ? fTail->fLastEdge->fBottom : fFirstVertex; } |
478 | | Vertex* fFirstVertex; |
479 | | int fWinding; |
480 | | MonotonePoly* fHead; |
481 | | MonotonePoly* fTail; |
482 | | Poly* fNext; |
483 | | Poly* fPartner; |
484 | | int fCount; |
485 | | #if TRIANGULATOR_LOGGING |
486 | | int fID; |
487 | | #endif |
488 | | }; |
489 | | |
490 | | struct GrTriangulator::Comparator { |
491 | | enum class Direction { kVertical, kHorizontal }; |
492 | 10.0k | Comparator(Direction direction) : fDirection(direction) {} |
493 | | bool sweep_lt(const SkPoint& a, const SkPoint& b) const; |
494 | | Direction fDirection; |
495 | | }; |
496 | | |
497 | | #endif |