blob: d4f4a9fea64f3eed3234858ea160dc9e31c05645 [file] [log] [blame]
ethannicholase9709e82016-01-07 13:34:16 -08001/*
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
Chris Dalton17dc4182020-03-25 16:18:16 -06008#ifndef GrTriangulator_DEFINED
9#define GrTriangulator_DEFINED
ethannicholase9709e82016-01-07 13:34:16 -080010
Chris Dalton57ea1fc2021-01-05 13:37:44 -070011#include "include/core/SkPath.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050012#include "include/core/SkPoint.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/private/SkColorData.h"
Chris Dalton57ea1fc2021-01-05 13:37:44 -070014#include "src/core/SkArenaAlloc.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040015#include "src/gpu/GrColor.h"
senorblanco6599eff2016-03-10 08:38:45 -080016
Chris Daltond081dce2020-01-23 12:09:04 -070017class GrEagerVertexAllocator;
senorblanco6599eff2016-03-10 08:38:45 -080018struct SkRect;
ethannicholase9709e82016-01-07 13:34:16 -080019
Chris Dalton5045de32021-01-07 19:09:01 -070020#define TRIANGULATOR_LOGGING 0
Chris Dalton57ea1fc2021-01-05 13:37:44 -070021#define TRIANGULATOR_WIREFRAME 0
22
ethannicholase9709e82016-01-07 13:34:16 -080023/**
24 * Provides utility functions for converting paths to a collection of triangles.
25 */
Chris Dalton57ea1fc2021-01-05 13:37:44 -070026class GrTriangulator {
27public:
Chris Dalton854ee852021-01-05 15:12:59 -070028 static int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
29 GrEagerVertexAllocator* vertexAllocator, bool* isLinear) {
30 GrTriangulator triangulator(path);
Chris Dalton93c2d812021-01-11 19:51:59 -070031 int count = triangulator.pathToTriangles(tolerance, clipBounds, vertexAllocator);
Chris Dalton854ee852021-01-05 15:12:59 -070032 *isLinear = triangulator.fIsLinear;
33 return count;
Chris Dalton57ea1fc2021-01-05 13:37:44 -070034 }
ethannicholase9709e82016-01-07 13:34:16 -080035
Chris Dalton68b8bd52021-01-14 10:48:02 -070036 // The breadcrumb triangles serve as a glue that erases T-junctions between a path's outer
37 // curves and its inner polygon triangulation. Drawing a path's outer curves, breadcrumb
38 // triangles, and inner polygon triangulation all together into the stencil buffer has the same
39 // identical rasterized effect as stenciling a classic Redbook fan.
40 //
41 // The breadcrumb triangles track all the edge splits that led from the original inner polygon
42 // edges to the final triangulation. Every time an edge splits, we emit a razor-thin breadcrumb
43 // triangle consisting of the edge's original endpoints and the split point. (We also add
44 // supplemental breadcrumb triangles to areas where abs(winding) > 1.)
45 //
46 // a
47 // /
48 // /
49 // /
50 // x <- Edge splits at x. New breadcrumb triangle is: [a, b, x].
51 // /
52 // /
53 // b
54 //
55 // The opposite-direction shared edges between the triangulation and breadcrumb triangles should
56 // all cancel out, leaving just the set of edges from the original polygon.
57 class BreadcrumbTriangleCollector { public:
58 void push(SkPoint a, SkPoint b, SkPoint c, int winding) {
59 if (a != b && a != c && b != c) {
60 if (winding > 0) {
61 this->onPush(a, b, c, winding);
62 } else if (winding < 0) {
63 this->onPush(b, a, c, -winding);
64 }
65 }
66 }
67 virtual ~BreadcrumbTriangleCollector() {}
68 private:
69 virtual void onPush(SkPoint a, SkPoint b, SkPoint c, int winding) = 0;
70 };
71
72 static int TriangulateInnerPolygons(const SkPath& path, GrEagerVertexAllocator* vertexAllocator,
73 BreadcrumbTriangleCollector* breadcrumbTriangles, bool
74 *isLinear) {
75 GrTriangulator triangulator(path);
76 triangulator.fCullCollinearVertices = false;
77 triangulator.fBreadcrumbTriangles = breadcrumbTriangles;
78 int count = triangulator.pathToTriangles(0, SkRect::MakeEmpty(), vertexAllocator);
79 *isLinear = triangulator.fIsLinear;
80 return count;
81 }
82
Chris Dalton854ee852021-01-05 15:12:59 -070083 static int TriangulateSimpleInnerPolygons(const SkPath& path,
84 GrEagerVertexAllocator* vertexAllocator,
85 bool *isLinear) {
86 GrTriangulator triangulator(path);
87 triangulator.fCullCollinearVertices = false;
Chris Dalton57115c02021-01-12 18:12:18 -070088 triangulator.fDisallowSelfIntersection = true;
Chris Dalton93c2d812021-01-11 19:51:59 -070089 int count = triangulator.pathToTriangles(0, SkRect::MakeEmpty(), vertexAllocator);
Chris Dalton854ee852021-01-05 15:12:59 -070090 *isLinear = triangulator.fIsLinear;
91 return count;
92 }
ethannicholase9709e82016-01-07 13:34:16 -080093
Chris Dalton57ea1fc2021-01-05 13:37:44 -070094 struct WindingVertex {
95 SkPoint fPos;
96 int fWinding;
97 };
Chris Dalton6ccc0322020-01-29 11:38:16 -070098
Chris Dalton57ea1fc2021-01-05 13:37:44 -070099 // *DEPRECATED*: Once CCPR is removed this method will go away.
Chris Dalton6ccc0322020-01-29 11:38:16 -0700100 //
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700101 // Triangulates a path to an array of vertices. Each triangle is represented as a set of three
102 // WindingVertex entries, each of which contains the position and winding count (which is the
103 // same for all three vertices of a triangle). The 'verts' out parameter is set to point to the
104 // resultant vertex array. CALLER IS RESPONSIBLE for deleting this buffer to avoid a memory
105 // leak!
106 static int PathToVertices(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds,
107 WindingVertex** verts);
108
Chris Dalton17ce8c52021-01-07 18:08:46 -0700109 // Enums used by GrTriangulator internals.
110 typedef enum { kLeft_Side, kRight_Side } Side;
111 enum class EdgeType { kInner, kOuter, kConnector };
112
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700113 // Structs used by GrTriangulator internals.
114 struct Vertex;
115 struct VertexList;
Chris Dalton17ce8c52021-01-07 18:08:46 -0700116 struct Line;
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700117 struct Edge;
118 struct EdgeList;
Chris Dalton17ce8c52021-01-07 18:08:46 -0700119 struct MonotonePoly;
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700120 struct Poly;
121 struct Comparator;
122
Chris Dalton7cf3add2021-01-11 18:33:28 -0700123protected:
Chris Dalton854ee852021-01-05 15:12:59 -0700124 GrTriangulator(const SkPath& path) : fPath(path) {}
Chris Dalton7cf3add2021-01-11 18:33:28 -0700125 virtual ~GrTriangulator() {}
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700126
127 // There are six stages to the basic algorithm:
128 //
129 // 1) Linearize the path contours into piecewise linear segments:
130 void pathToContours(float tolerance, const SkRect& clipBounds, VertexList* contours);
131
132 // 2) Build a mesh of edges connecting the vertices:
Chris Dalton811dc6a2021-01-07 16:40:32 -0700133 void contoursToMesh(VertexList* contours, int contourCnt, VertexList* mesh, const Comparator&);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700134
Chris Dalton68b8bd52021-01-14 10:48:02 -0700135 // 3) Sort the vertices in Y (and secondarily in X):
Chris Dalton47114db2021-01-06 00:35:20 -0700136 static void SortedMerge(VertexList* front, VertexList* back, VertexList* result,
137 const Comparator&);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700138 static void SortMesh(VertexList* vertices, const Comparator&);
139
140 // 4) Simplify the mesh by inserting new vertices at intersecting edges:
141 enum class SimplifyResult {
142 kAlreadySimple,
143 kFoundSelfIntersection,
144 kAbort
145 };
146
Chris Dalton811dc6a2021-01-07 16:40:32 -0700147 SimplifyResult simplify(VertexList* mesh, const Comparator&);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700148
149 // 5) Tessellate the simplified mesh into monotone polygons:
Chris Dalton93c2d812021-01-11 19:51:59 -0700150 virtual Poly* tessellate(const VertexList& vertices, const Comparator&);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700151
152 // 6) Triangulate the monotone polygons directly into a vertex buffer:
Chris Dalton93c2d812021-01-11 19:51:59 -0700153 virtual int64_t countPoints(Poly* polys) const {
154 return this->countPointsImpl(polys, fPath.getFillType());
155 }
156 virtual void* polysToTriangles(Poly* polys, void* data) {
157 return this->polysToTrianglesImpl(polys, data, fPath.getFillType());
158 }
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700159
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700160 // The vertex sorting in step (3) is a merge sort, since it plays well with the linked list
161 // of vertices (and the necessity of inserting new vertices on intersection).
162 //
163 // Stages (4) and (5) use an active edge list -- a list of all edges for which the
164 // sweep line has crossed the top vertex, but not the bottom vertex. It's sorted
165 // left-to-right based on the point where both edges are active (when both top vertices
166 // have been seen, so the "lower" top vertex of the two). If the top vertices are equal
167 // (shared), it's sorted based on the last point where both edges are active, so the
168 // "upper" bottom vertex.
169 //
170 // The most complex step is the simplification (4). It's based on the Bentley-Ottman
171 // line-sweep algorithm, but due to floating point inaccuracy, the intersection points are
172 // not exact and may violate the mesh topology or active edge list ordering. We
173 // accommodate this by adjusting the topology of the mesh and AEL to match the intersection
174 // points. This occurs in two ways:
175 //
176 // A) Intersections may cause a shortened edge to no longer be ordered with respect to its
177 // neighbouring edges at the top or bottom vertex. This is handled by merging the
Chris Dalton68b8bd52021-01-14 10:48:02 -0700178 // edges (mergeCollinearVertices()).
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700179 // B) Intersections may cause an edge to violate the left-to-right ordering of the
180 // active edge list. This is handled by detecting potential violations and rewinding
181 // the active edge list to the vertex before they occur (rewind() during merging,
182 // rewind_if_necessary() during splitting).
183 //
184 // The tessellation steps (5) and (6) are based on "Triangulating Simple Polygons and
185 // Equivalent Problems" (Fournier and Montuno); also a line-sweep algorithm. Note that it
186 // currently uses a linked list for the active edge list, rather than a 2-3 tree as the
187 // paper describes. The 2-3 tree gives O(lg N) lookups, but insertion and removal also
188 // become O(lg N). In all the test cases, it was found that the cost of frequent O(lg N)
189 // insertions and removals was greater than the cost of infrequent O(N) lookups with the
190 // linked list implementation. With the latter, all removals are O(1), and most insertions
191 // are O(1), since we know the adjacent edge in the active edge list based on the topology.
192 // Only type 2 vertices (see paper) require the O(N) lookups, and these are much less
193 // frequent. There may be other data structures worth investigating, however.
194 //
195 // Note that the orientation of the line sweep algorithms is determined by the aspect ratio of
196 // the path bounds. When the path is taller than it is wide, we sort vertices based on
197 // increasing Y coordinate, and secondarily by increasing X coordinate. When the path is wider
198 // than it is tall, we sort by increasing X coordinate, but secondarily by *decreasing* Y
199 // coordinate. This is so that the "left" and "right" orientation in the code remains correct
200 // (edges to the left are increasing in Y; edges to the right are decreasing in Y). That is, the
201 // setting rotates 90 degrees counterclockwise, rather that transposing.
202
203 // Additional helpers and driver functions.
Chris Dalton9a4904f2021-01-07 19:10:14 -0700204 void* emitMonotonePoly(const MonotonePoly*, void* data);
205 void* emitTriangle(Vertex* prev, Vertex* curr, Vertex* next, int winding, void* data) const;
206 void* emitPoly(const Poly*, void *data);
Chris Dalton7cf3add2021-01-11 18:33:28 -0700207 Poly* makePoly(Poly** head, Vertex* v, int winding);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700208 void appendPointToContour(const SkPoint& p, VertexList* contour);
209 void appendQuadraticToContour(const SkPoint[3], SkScalar toleranceSqd, VertexList* contour);
210 void generateCubicPoints(const SkPoint&, const SkPoint&, const SkPoint&, const SkPoint&,
211 SkScalar tolSqd, VertexList* contour, int pointsLeft);
Chris Dalton47114db2021-01-06 00:35:20 -0700212 bool applyFillType(int winding);
Chris Dalton7cf3add2021-01-11 18:33:28 -0700213 Edge* makeEdge(Vertex* prev, Vertex* next, EdgeType type, const Comparator&);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700214 void setTop(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current, const Comparator&);
215 void setBottom(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
216 const Comparator&);
217 void mergeEdgesAbove(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
218 const Comparator&);
219 void mergeEdgesBelow(Edge* edge, Edge* other, EdgeList* activeEdges, Vertex** current,
220 const Comparator&);
Chris Dalton7cf3add2021-01-11 18:33:28 -0700221 Edge* makeConnectingEdge(Vertex* prev, Vertex* next, EdgeType, const Comparator&,
222 int windingScale = 1);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700223 void mergeVertices(Vertex* src, Vertex* dst, VertexList* mesh, const Comparator&);
Chris Dalton47114db2021-01-06 00:35:20 -0700224 static void FindEnclosingEdges(Vertex* v, EdgeList* edges, Edge** left, Edge** right);
Chris Dalton68b8bd52021-01-14 10:48:02 -0700225 void mergeCollinearEdges(Edge* edge, EdgeList* activeEdges, Vertex** current,
226 const Comparator&);
Chris Dalton811dc6a2021-01-07 16:40:32 -0700227 bool splitEdge(Edge* edge, Vertex* v, EdgeList* activeEdges, Vertex** current,
228 const Comparator&);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700229 bool intersectEdgePair(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700230 const Comparator&);
Chris Dalton7cf3add2021-01-11 18:33:28 -0700231 Vertex* makeSortedVertex(const SkPoint&, uint8_t alpha, VertexList* mesh, Vertex* reference,
232 const Comparator&);
233 void computeBisector(Edge* edge1, Edge* edge2, Vertex*);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700234 bool checkForIntersection(Edge* left, Edge* right, EdgeList* activeEdges, Vertex** current,
Chris Dalton811dc6a2021-01-07 16:40:32 -0700235 VertexList* mesh, const Comparator&);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700236 void sanitizeContours(VertexList* contours, int contourCnt);
Chris Dalton811dc6a2021-01-07 16:40:32 -0700237 bool mergeCoincidentVertices(VertexList* mesh, const Comparator&);
238 void buildEdges(VertexList* contours, int contourCnt, VertexList* mesh, const Comparator&);
Chris Dalton93c2d812021-01-11 19:51:59 -0700239 Poly* contoursToPolys(VertexList* contours, int contourCnt);
240 Poly* pathToPolys(float tolerance, const SkRect& clipBounds, int contourCnt);
241 int64_t countPointsImpl(Poly* polys, SkPathFillType overrideFillType) const;
242 void* polysToTrianglesImpl(Poly* polys, void* data, SkPathFillType overrideFillType);
243 int pathToTriangles(float tolerance, const SkRect& clipBounds, GrEagerVertexAllocator*);
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700244
245 constexpr static int kArenaChunkSize = 16 * 1024;
246 SkArenaAlloc fAlloc{kArenaChunkSize};
247 const SkPath fPath;
Chris Dalton57ea1fc2021-01-05 13:37:44 -0700248 bool fIsLinear = false;
Chris Dalton854ee852021-01-05 15:12:59 -0700249
Chris Dalton68b8bd52021-01-14 10:48:02 -0700250 // Internal control knobs.
Chris Dalton854ee852021-01-05 15:12:59 -0700251 bool fRoundVerticesToQuarterPixel = false;
252 bool fEmitCoverage = false;
253 bool fCullCollinearVertices = true;
Chris Dalton57115c02021-01-12 18:12:18 -0700254 bool fDisallowSelfIntersection = false;
Chris Dalton68b8bd52021-01-14 10:48:02 -0700255 BreadcrumbTriangleCollector* fBreadcrumbTriangles = nullptr;
Chris Daltondcc8c542020-01-28 17:55:56 -0700256};
257
Chris Dalton5045de32021-01-07 19:09:01 -0700258/**
259 * Vertices are used in three ways: first, the path contours are converted into a
260 * circularly-linked list of Vertices for each contour. After edge construction, the same Vertices
261 * are re-ordered by the merge sort according to the sweep_lt comparator (usually, increasing
262 * in Y) using the same fPrev/fNext pointers that were used for the contours, to avoid
263 * reallocation. Finally, MonotonePolys are built containing a circularly-linked list of
264 * Vertices. (Currently, those Vertices are newly-allocated for the MonotonePolys, since
265 * an individual Vertex from the path mesh may belong to multiple
266 * MonotonePolys, so the original Vertices cannot be re-used.
267 */
268
269struct GrTriangulator::Vertex {
270 Vertex(const SkPoint& point, uint8_t alpha)
271 : fPoint(point), fPrev(nullptr), fNext(nullptr)
272 , fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr)
273 , fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr)
274 , fLeftEnclosingEdge(nullptr), fRightEnclosingEdge(nullptr)
275 , fPartner(nullptr)
276 , fAlpha(alpha)
277 , fSynthetic(false)
278#if TRIANGULATOR_LOGGING
279 , fID (-1.0f)
280#endif
281 {}
282 SkPoint fPoint; // Vertex position
283 Vertex* fPrev; // Linked list of contours, then Y-sorted vertices.
284 Vertex* fNext; // "
285 Edge* fFirstEdgeAbove; // Linked list of edges above this vertex.
286 Edge* fLastEdgeAbove; // "
287 Edge* fFirstEdgeBelow; // Linked list of edges below this vertex.
288 Edge* fLastEdgeBelow; // "
289 Edge* fLeftEnclosingEdge; // Nearest edge in the AEL left of this vertex.
290 Edge* fRightEnclosingEdge; // Nearest edge in the AEL right of this vertex.
291 Vertex* fPartner; // Corresponding inner or outer vertex (for AA).
292 uint8_t fAlpha;
293 bool fSynthetic; // Is this a synthetic vertex?
294#if TRIANGULATOR_LOGGING
295 float fID; // Identifier used for logging.
296#endif
Chris Dalton24472af2021-01-11 20:05:00 -0700297 bool isConnected() const { return this->fFirstEdgeAbove || this->fFirstEdgeBelow; }
Chris Dalton5045de32021-01-07 19:09:01 -0700298};
299
300struct GrTriangulator::VertexList {
301 VertexList() : fHead(nullptr), fTail(nullptr) {}
302 VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {}
303 Vertex* fHead;
304 Vertex* fTail;
305 void insert(Vertex* v, Vertex* prev, Vertex* next);
306 void append(Vertex* v) { insert(v, fTail, nullptr); }
307 void append(const VertexList& list) {
308 if (!list.fHead) {
309 return;
310 }
311 if (fTail) {
312 fTail->fNext = list.fHead;
313 list.fHead->fPrev = fTail;
314 } else {
315 fHead = list.fHead;
316 }
317 fTail = list.fTail;
318 }
319 void prepend(Vertex* v) { insert(v, nullptr, fHead); }
320 void remove(Vertex* v);
321 void close() {
322 if (fHead && fTail) {
323 fTail->fNext = fHead;
324 fHead->fPrev = fTail;
325 }
326 }
Chris Dalton24472af2021-01-11 20:05:00 -0700327#if TRIANGULATOR_LOGGING
328 void dump();
329#endif
Chris Dalton5045de32021-01-07 19:09:01 -0700330};
331
332// A line equation in implicit form. fA * x + fB * y + fC = 0, for all points (x, y) on the line.
333struct GrTriangulator::Line {
334 Line(double a, double b, double c) : fA(a), fB(b), fC(c) {}
335 Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {}
336 Line(const SkPoint& p, const SkPoint& q)
337 : fA(static_cast<double>(q.fY) - p.fY) // a = dY
338 , fB(static_cast<double>(p.fX) - q.fX) // b = -dX
339 , fC(static_cast<double>(p.fY) * q.fX - // c = cross(q, p)
340 static_cast<double>(p.fX) * q.fY) {}
341 double dist(const SkPoint& p) const { return fA * p.fX + fB * p.fY + fC; }
342 Line operator*(double v) const { return Line(fA * v, fB * v, fC * v); }
343 double magSq() const { return fA * fA + fB * fB; }
344 void normalize() {
345 double len = sqrt(this->magSq());
346 if (len == 0.0) {
347 return;
348 }
349 double scale = 1.0f / len;
350 fA *= scale;
351 fB *= scale;
352 fC *= scale;
353 }
354 bool nearParallel(const Line& o) const {
355 return fabs(o.fA - fA) < 0.00001 && fabs(o.fB - fB) < 0.00001;
356 }
357
358 // Compute the intersection of two (infinite) Lines.
359 bool intersect(const Line& other, SkPoint* point) const;
360 double fA, fB, fC;
361};
362
363/**
364 * An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and
365 * "edge below" a vertex as well as for the active edge list is handled by isLeftOf()/isRightOf().
366 * Note that an Edge will give occasionally dist() != 0 for its own endpoints (because floating
367 * point). For speed, that case is only tested by the callers that require it (e.g.,
368 * rewind_if_necessary()). Edges also handle checking for intersection with other edges.
369 * Currently, this converts the edges to the parametric form, in order to avoid doing a division
370 * until an intersection has been confirmed. This is slightly slower in the "found" case, but
371 * a lot faster in the "not found" case.
372 *
373 * The coefficients of the line equation stored in double precision to avoid catastrophic
374 * cancellation in the isLeftOf() and isRightOf() checks. Using doubles ensures that the result is
375 * correct in float, since it's a polynomial of degree 2. The intersect() function, being
376 * degree 5, is still subject to catastrophic cancellation. We deal with that by assuming its
377 * output may be incorrect, and adjusting the mesh topology to match (see comment at the top of
378 * this file).
379 */
380
381struct GrTriangulator::Edge {
382 Edge(Vertex* top, Vertex* bottom, int winding, EdgeType type)
383 : fWinding(winding)
384 , fTop(top)
385 , fBottom(bottom)
386 , fType(type)
387 , fLeft(nullptr)
388 , fRight(nullptr)
389 , fPrevEdgeAbove(nullptr)
390 , fNextEdgeAbove(nullptr)
391 , fPrevEdgeBelow(nullptr)
392 , fNextEdgeBelow(nullptr)
393 , fLeftPoly(nullptr)
394 , fRightPoly(nullptr)
395 , fLeftPolyPrev(nullptr)
396 , fLeftPolyNext(nullptr)
397 , fRightPolyPrev(nullptr)
398 , fRightPolyNext(nullptr)
399 , fUsedInLeftPoly(false)
400 , fUsedInRightPoly(false)
401 , fLine(top, bottom) {
402 }
403 int fWinding; // 1 == edge goes downward; -1 = edge goes upward.
404 Vertex* fTop; // The top vertex in vertex-sort-order (sweep_lt).
405 Vertex* fBottom; // The bottom vertex in vertex-sort-order.
406 EdgeType fType;
407 Edge* fLeft; // The linked list of edges in the active edge list.
408 Edge* fRight; // "
409 Edge* fPrevEdgeAbove; // The linked list of edges in the bottom Vertex's "edges above".
410 Edge* fNextEdgeAbove; // "
411 Edge* fPrevEdgeBelow; // The linked list of edges in the top Vertex's "edges below".
412 Edge* fNextEdgeBelow; // "
413 Poly* fLeftPoly; // The Poly to the left of this edge, if any.
414 Poly* fRightPoly; // The Poly to the right of this edge, if any.
415 Edge* fLeftPolyPrev;
416 Edge* fLeftPolyNext;
417 Edge* fRightPolyPrev;
418 Edge* fRightPolyNext;
419 bool fUsedInLeftPoly;
420 bool fUsedInRightPoly;
421 Line fLine;
422 double dist(const SkPoint& p) const { return fLine.dist(p); }
423 bool isRightOf(Vertex* v) const { return fLine.dist(v->fPoint) < 0.0; }
424 bool isLeftOf(Vertex* v) const { return fLine.dist(v->fPoint) > 0.0; }
425 void recompute() { fLine = Line(fTop, fBottom); }
Chris Dalton24472af2021-01-11 20:05:00 -0700426 void insertAbove(Vertex*, const Comparator&);
427 void insertBelow(Vertex*, const Comparator&);
428 void disconnect();
Chris Dalton5045de32021-01-07 19:09:01 -0700429 bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) const;
430};
431
432struct GrTriangulator::EdgeList {
433 EdgeList() : fHead(nullptr), fTail(nullptr) {}
434 Edge* fHead;
435 Edge* fTail;
436 void insert(Edge* edge, Edge* prev, Edge* next);
Chris Dalton24472af2021-01-11 20:05:00 -0700437 void insert(Edge* edge, Edge* prev);
Chris Dalton5045de32021-01-07 19:09:01 -0700438 void append(Edge* e) { insert(e, fTail, nullptr); }
439 void remove(Edge* edge);
440 void removeAll() {
441 while (fHead) {
442 this->remove(fHead);
443 }
444 }
445 void close() {
446 if (fHead && fTail) {
447 fTail->fRight = fHead;
448 fHead->fLeft = fTail;
449 }
450 }
451 bool contains(Edge* edge) const { return edge->fLeft || edge->fRight || fHead == edge; }
452};
453
454struct 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 , fWinding(winding) {
462 this->addEdge(edge);
463 }
464 Side fSide;
465 Edge* fFirstEdge;
466 Edge* fLastEdge;
467 MonotonePoly* fPrev;
468 MonotonePoly* fNext;
469 int fWinding;
470 void addEdge(Edge*);
471 void* emit(bool emitCoverage, void* data);
472 void* emitTriangle(Vertex* prev, Vertex* curr, Vertex* next, bool emitCoverage,
473 void* data) const;
474};
475
476struct GrTriangulator::Poly {
477 Poly(Vertex* v, int winding)
478 : fFirstVertex(v)
479 , fWinding(winding)
480 , fHead(nullptr)
481 , fTail(nullptr)
482 , fNext(nullptr)
483 , fPartner(nullptr)
484 , fCount(0)
485 {
486#if TRIANGULATOR_LOGGING
487 static int gID = 0;
488 fID = gID++;
489 TESS_LOG("*** created Poly %d\n", fID);
490#endif
491 }
492 Poly* addEdge(Edge* e, Side side, SkArenaAlloc& alloc);
493 void* emit(bool emitCoverage, void *data);
494 Vertex* lastVertex() const { return fTail ? fTail->fLastEdge->fBottom : fFirstVertex; }
495 Vertex* fFirstVertex;
496 int fWinding;
497 MonotonePoly* fHead;
498 MonotonePoly* fTail;
499 Poly* fNext;
500 Poly* fPartner;
501 int fCount;
502#if TRIANGULATOR_LOGGING
503 int fID;
504#endif
505};
506
507struct GrTriangulator::Comparator {
508 enum class Direction { kVertical, kHorizontal };
509 Comparator(Direction direction) : fDirection(direction) {}
510 bool sweep_lt(const SkPoint& a, const SkPoint& b) const;
511 Direction fDirection;
512};
513
ethannicholase9709e82016-01-07 13:34:16 -0800514#endif