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 #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 PathToTriangles(const SkPath & path,SkScalar tolerance,const SkRect & clipBounds,GrEagerVertexAllocator * vertexAllocator,bool * isLinear)30 static int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, 31 GrEagerVertexAllocator* vertexAllocator, bool* isLinear) { 32 SkArenaAlloc alloc(kArenaDefaultChunkSize); 33 GrTriangulator triangulator(path, &alloc); 34 Poly* polys = triangulator.pathToPolys(tolerance, clipBounds, isLinear); 35 int count = triangulator.polysToTriangles(polys, vertexAllocator); 36 return count; 37 } 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: GrTriangulator(const SkPath & path,SkArenaAlloc * alloc)54 GrTriangulator(const SkPath& path, SkArenaAlloc* alloc) : fPath(path), fAlloc(alloc) {} ~GrTriangulator()55 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 { NodeNode208 Node(SkPoint a, SkPoint b, SkPoint c) : fPts{a, b, c} {} 209 SkPoint fPts[3]; 210 Node* fNext = nullptr; 211 }; head()212 const Node* head() const { return fHead; } count()213 int count() const { return fCount; } 214 append(SkArenaAlloc * alloc,SkPoint a,SkPoint b,SkPoint c,int winding)215 void append(SkArenaAlloc* alloc, SkPoint a, SkPoint b, SkPoint c, int winding) { 216 if (a == b || a == c || b == c || winding == 0) { 217 return; 218 } 219 if (winding < 0) { 220 std::swap(a, b); 221 winding = -winding; 222 } 223 for (int i = 0; i < winding; ++i) { 224 SkASSERT(fTail && !(*fTail)); 225 *fTail = alloc->make<Node>(a, b, c); 226 fTail = &(*fTail)->fNext; 227 } 228 fCount += winding; 229 } 230 concat(BreadcrumbTriangleList && list)231 void concat(BreadcrumbTriangleList&& list) { 232 SkASSERT(fTail && !(*fTail)); 233 if (list.fHead) { 234 *fTail = list.fHead; 235 fTail = list.fTail; 236 fCount += list.fCount; 237 list.fHead = nullptr; 238 list.fTail = &list.fHead; 239 list.fCount = 0; 240 } 241 } 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 { VertexVertex264 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 {} 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 isConnectedVertex291 bool isConnected() const { return this->fFirstEdgeAbove || this->fFirstEdgeBelow; } 292 }; 293 294 struct GrTriangulator::VertexList { VertexListVertexList295 VertexList() : fHead(nullptr), fTail(nullptr) {} VertexListVertexList296 VertexList(Vertex* head, Vertex* tail) : fHead(head), fTail(tail) {} 297 Vertex* fHead; 298 Vertex* fTail; 299 void insert(Vertex* v, Vertex* prev, Vertex* next); appendVertexList300 void append(Vertex* v) { insert(v, fTail, nullptr); } appendVertexList301 void append(const VertexList& list) { 302 if (!list.fHead) { 303 return; 304 } 305 if (fTail) { 306 fTail->fNext = list.fHead; 307 list.fHead->fPrev = fTail; 308 } else { 309 fHead = list.fHead; 310 } 311 fTail = list.fTail; 312 } prependVertexList313 void prepend(Vertex* v) { insert(v, nullptr, fHead); } 314 void remove(Vertex* v); closeVertexList315 void close() { 316 if (fHead && fTail) { 317 fTail->fNext = fHead; 318 fHead->fPrev = fTail; 319 } 320 } 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 { LineLine328 Line(double a, double b, double c) : fA(a), fB(b), fC(c) {} LineLine329 Line(Vertex* p, Vertex* q) : Line(p->fPoint, q->fPoint) {} LineLine330 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 static_cast<double>(p.fX) * q.fY) {} distLine335 double dist(const SkPoint& p) const { return fA * p.fX + fB * p.fY + fC; } 336 Line operator*(double v) const { return Line(fA * v, fB * v, fC * v); } magSqLine337 double magSq() const { return fA * fA + fB * fB; } normalizeLine338 void normalize() { 339 double len = sqrt(this->magSq()); 340 if (len == 0.0) { 341 return; 342 } 343 double scale = 1.0f / len; 344 fA *= scale; 345 fB *= scale; 346 fC *= scale; 347 } nearParallelLine348 bool nearParallel(const Line& o) const { 349 return fabs(o.fA - fA) < 0.00001 && fabs(o.fB - fB) < 0.00001; 350 } 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 { EdgeEdge376 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 , fLine(top, bottom) { 396 } 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; distEdge416 double dist(const SkPoint& p) const { return fLine.dist(p); } isRightOfEdge417 bool isRightOf(Vertex* v) const { return fLine.dist(v->fPoint) < 0.0; } isLeftOfEdge418 bool isLeftOf(Vertex* v) const { return fLine.dist(v->fPoint) > 0.0; } recomputeEdge419 void recompute() { fLine = Line(fTop, fBottom); } 420 void insertAbove(Vertex*, const Comparator&); 421 void insertBelow(Vertex*, const Comparator&); 422 void disconnect(); 423 bool intersect(const Edge& other, SkPoint* p, uint8_t* alpha = nullptr) const; 424 }; 425 426 struct GrTriangulator::EdgeList { EdgeListEdgeList427 EdgeList() : fHead(nullptr), fTail(nullptr) {} 428 Edge* fHead; 429 Edge* fTail; 430 void insert(Edge* edge, Edge* prev, Edge* next); 431 void insert(Edge* edge, Edge* prev); appendEdgeList432 void append(Edge* e) { insert(e, fTail, nullptr); } 433 void remove(Edge* edge); removeAllEdgeList434 void removeAll() { 435 while (fHead) { 436 this->remove(fHead); 437 } 438 } closeEdgeList439 void close() { 440 if (fHead && fTail) { 441 fTail->fRight = fHead; 442 fHead->fLeft = fTail; 443 } 444 } containsEdgeList445 bool contains(Edge* edge) const { return edge->fLeft || edge->fRight || fHead == edge; } 446 }; 447 448 struct GrTriangulator::MonotonePoly { MonotonePolyMonotonePoly449 MonotonePoly(Edge* edge, Side side, int winding) 450 : fSide(side) 451 , fFirstEdge(nullptr) 452 , fLastEdge(nullptr) 453 , fPrev(nullptr) 454 , fNext(nullptr) 455 , fWinding(winding) { 456 this->addEdge(edge); 457 } 458 Side fSide; 459 Edge* fFirstEdge; 460 Edge* fLastEdge; 461 MonotonePoly* fPrev; 462 MonotonePoly* fNext; 463 int fWinding; 464 void addEdge(Edge*); 465 }; 466 467 struct GrTriangulator::Poly { 468 Poly(Vertex* v, int winding); 469 470 Poly* addEdge(Edge* e, Side side, SkArenaAlloc* alloc); lastVertexPoly471 Vertex* lastVertex() const { return fTail ? fTail->fLastEdge->fBottom : fFirstVertex; } 472 Vertex* fFirstVertex; 473 int fWinding; 474 MonotonePoly* fHead; 475 MonotonePoly* fTail; 476 Poly* fNext; 477 Poly* fPartner; 478 int fCount; 479 #if TRIANGULATOR_LOGGING 480 int fID; 481 #endif 482 }; 483 484 struct GrTriangulator::Comparator { 485 enum class Direction { kVertical, kHorizontal }; ComparatorComparator486 Comparator(Direction direction) : fDirection(direction) {} 487 bool sweep_lt(const SkPoint& a, const SkPoint& b) const; 488 Direction fDirection; 489 }; 490 491 #endif 492