Index: src/gpu/GrTessellator.cpp |
diff --git a/src/gpu/GrTessellator.cpp b/src/gpu/GrTessellator.cpp |
index 9ce1a739df8dff27b24d3364da825fa35928ca24..ccffa9ffbeed21b29156e96c8d8e4cffe82e06c7 100644 |
--- a/src/gpu/GrTessellator.cpp |
+++ b/src/gpu/GrTessellator.cpp |
@@ -7,7 +7,6 @@ |
#include "GrTessellator.h" |
-#include "GrDefaultGeoProcFactory.h" |
#include "GrPathUtils.h" |
#include "SkChunkAlloc.h" |
@@ -17,7 +16,7 @@ |
#include <stdio.h> |
/* |
- * There are six stages to the basic algorithm: |
+ * There are six stages to the algorithm: |
* |
* 1) Linearize the path contours into piecewise linear segments (path_to_contours()). |
* 2) Build a mesh of edges connecting the vertices (build_edges()). |
@@ -25,16 +24,6 @@ |
* 4) Simplify the mesh by inserting new vertices at intersecting edges (simplify()). |
* 5) Tessellate the simplified mesh into monotone polygons (tessellate()). |
* 6) Triangulate the monotone polygons directly into a vertex buffer (polys_to_triangles()). |
- * |
- * For screenspace antialiasing, the algorithm is modified as follows: |
- * |
- * Run steps 1-5 above to produce polygons. |
- * 5b) Apply fill rules to extract boundary contours from the polygons (extract_boundaries()). |
- * 5c) Simplify boundaries to remove "pointy" vertices which cause inversions (simplify_boundary()). |
- * 5d) Displace edges by half a pixel inward and outward along their normals. Intersect to find |
- * new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a new |
- * antialiased mesh from those vertices (boundary_to_aa_mesh()). |
- * Run steps 3-6 above on the new mesh, and produce antialiased triangles. |
* |
* The vertex sorting in step (3) is a merge sort, since it plays well with the linked list |
* of vertices (and the necessity of inserting new vertices on intersection). |
@@ -141,12 +130,11 @@ |
*/ |
struct Vertex { |
- Vertex(const SkPoint& point, uint8_t alpha) |
+ Vertex(const SkPoint& point) |
: fPoint(point), fPrev(nullptr), fNext(nullptr) |
, fFirstEdgeAbove(nullptr), fLastEdgeAbove(nullptr) |
, fFirstEdgeBelow(nullptr), fLastEdgeBelow(nullptr) |
, fProcessed(false) |
- , fAlpha(alpha) |
#if LOGGING_ENABLED |
, fID (-1.0f) |
#endif |
@@ -159,7 +147,6 @@ |
Edge* fFirstEdgeBelow; // Linked list of edges below this vertex. |
Edge* fLastEdgeBelow; // " |
bool fProcessed; // Has this vertex been seen in simplify()? |
- uint8_t fAlpha; |
#if LOGGING_ENABLED |
float fID; // Identifier used for logging. |
#endif |
@@ -167,11 +154,6 @@ |
/***************************************************************************************/ |
-struct AAParams { |
- bool fTweakAlpha; |
- GrColor fColor; |
-}; |
- |
typedef bool (*CompareFunc)(const SkPoint& a, const SkPoint& b); |
struct Comparator { |
@@ -195,42 +177,32 @@ |
return a.fY == b.fY ? a.fX > b.fX : a.fY > b.fY; |
} |
-inline void* emit_vertex(Vertex* v, const AAParams* aaParams, void* data) { |
- if (!aaParams) { |
- SkPoint* d = static_cast<SkPoint*>(data); |
- *d++ = v->fPoint; |
- return d; |
- } |
- if (aaParams->fTweakAlpha) { |
- auto d = static_cast<GrDefaultGeoProcFactory::PositionColorAttr*>(data); |
- d->fPosition = v->fPoint; |
- d->fColor = SkAlphaMulQ(aaParams->fColor, v->fAlpha); |
- d++; |
- return d; |
- } |
- auto d = static_cast<GrDefaultGeoProcFactory::PositionColorCoverageAttr*>(data); |
- d->fPosition = v->fPoint; |
- d->fColor = aaParams->fColor; |
- d->fCoverage = GrNormalizeByteToFloat(v->fAlpha); |
- d++; |
- return d; |
-} |
- |
-void* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, const AAParams* aaParams, void* data) { |
-#if TESSELLATOR_WIREFRAME |
- data = emit_vertex(v0, aaParams, data); |
- data = emit_vertex(v1, aaParams, data); |
- data = emit_vertex(v1, aaParams, data); |
- data = emit_vertex(v2, aaParams, data); |
- data = emit_vertex(v2, aaParams, data); |
- data = emit_vertex(v0, aaParams, data); |
+inline SkPoint* emit_vertex(Vertex* v, SkPoint* data) { |
+ *data++ = v->fPoint; |
+ return data; |
+} |
+ |
+SkPoint* emit_triangle(Vertex* v0, Vertex* v1, Vertex* v2, SkPoint* data) { |
+#if WIREFRAME |
+ data = emit_vertex(v0, data); |
+ data = emit_vertex(v1, data); |
+ data = emit_vertex(v1, data); |
+ data = emit_vertex(v2, data); |
+ data = emit_vertex(v2, data); |
+ data = emit_vertex(v0, data); |
#else |
- data = emit_vertex(v0, aaParams, data); |
- data = emit_vertex(v1, aaParams, data); |
- data = emit_vertex(v2, aaParams, data); |
+ data = emit_vertex(v0, data); |
+ data = emit_vertex(v1, data); |
+ data = emit_vertex(v2, data); |
#endif |
return data; |
} |
+ |
+struct EdgeList { |
+ EdgeList() : fHead(nullptr), fTail(nullptr) {} |
+ Edge* fHead; |
+ Edge* fTail; |
+}; |
struct VertexList { |
VertexList() : fHead(nullptr), fTail(nullptr) {} |
@@ -245,20 +217,7 @@ |
void prepend(Vertex* v) { |
insert(v, nullptr, fHead); |
} |
- void close() { |
- if (fHead && fTail) { |
- fTail->fNext = fHead; |
- fHead->fPrev = fTail; |
- } |
- } |
}; |
- |
-// Round to nearest quarter-pixel. This is used for screenspace tessellation. |
- |
-inline void round(SkPoint* p) { |
- p->fX = SkScalarRoundToScalar(p->fX * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f); |
- p->fY = SkScalarRoundToScalar(p->fY * SkFloatToScalar(4.0f)) * SkFloatToScalar(0.25f); |
-} |
/** |
* An Edge joins a top Vertex to a bottom Vertex. Edge ordering for the list of "edges above" and |
@@ -361,33 +320,8 @@ |
p->fY = SkDoubleToScalar(fTop->fPoint.fY + s * fDY); |
return true; |
} |
-}; |
- |
-struct EdgeList { |
- EdgeList() : fHead(nullptr), fTail(nullptr), fNext(nullptr), fCount(0) {} |
- Edge* fHead; |
- Edge* fTail; |
- EdgeList* fNext; |
- int fCount; |
- void insert(Edge* edge, Edge* prev, Edge* next) { |
- list_insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &fHead, &fTail); |
- fCount++; |
- } |
- void append(Edge* e) { |
- insert(e, fTail, nullptr); |
- } |
- void remove(Edge* edge) { |
- list_remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &fHead, &fTail); |
- fCount--; |
- } |
- void close() { |
- if (fHead && fTail) { |
- fTail->fRight = fHead; |
- fHead->fLeft = fTail; |
- } |
- } |
- bool contains(Edge* edge) const { |
- return edge->fLeft || edge->fRight || fHead == edge; |
+ bool isActive(EdgeList* activeEdges) const { |
+ return activeEdges && (fLeft || fRight || activeEdges->fHead == this); |
} |
}; |
@@ -438,7 +372,7 @@ |
} |
} |
- void* emit(const AAParams* aaParams, void* data) { |
+ SkPoint* emit(SkPoint* data) { |
Edge* e = fFirstEdge; |
e->fTop->fPrev = e->fTop->fNext = nullptr; |
VertexList vertices; |
@@ -465,7 +399,7 @@ |
double bx = static_cast<double>(next->fPoint.fX) - curr->fPoint.fX; |
double by = static_cast<double>(next->fPoint.fY) - curr->fPoint.fY; |
if (ax * by - ay * bx >= 0.0) { |
- data = emit_triangle(prev, curr, next, aaParams, data); |
+ data = emit_triangle(prev, curr, next, data); |
v->fPrev->fNext = v->fNext; |
v->fNext->fPrev = v->fPrev; |
if (v->fPrev == first) { |
@@ -521,13 +455,13 @@ |
} |
return poly; |
} |
- void* emit(const AAParams* aaParams, void *data) { |
+ SkPoint* emit(SkPoint *data) { |
if (fCount < 3) { |
return data; |
} |
LOG("emit() %d, size %d\n", fID, fCount); |
for (MonotonePoly* m = fHead; m != nullptr; m = m->fNext) { |
- data = m->emit(aaParams, data); |
+ data = m->emit(data); |
} |
return data; |
} |
@@ -557,16 +491,9 @@ |
return poly; |
} |
-EdgeList* new_contour(EdgeList** head, SkChunkAlloc& alloc) { |
- EdgeList* contour = ALLOC_NEW(EdgeList, (), alloc); |
- contour->fNext = *head; |
- *head = contour; |
- return contour; |
-} |
- |
Vertex* append_point_to_contour(const SkPoint& p, Vertex* prev, Vertex** head, |
SkChunkAlloc& alloc) { |
- Vertex* v = ALLOC_NEW(Vertex, (p, 255), alloc); |
+ Vertex* v = ALLOC_NEW(Vertex, (p), alloc); |
#if LOGGING_ENABLED |
static float gID = 0.0f; |
v->fID = gID++; |
@@ -651,7 +578,7 @@ |
if (path.isInverseFillType()) { |
SkPoint quad[4]; |
clipBounds.toQuad(quad); |
- for (int i = 0; i < 4; i++) { |
+ for (int i = 3; i >= 0; i--) { |
prev = append_point_to_contour(quad[i], prev, &head, alloc); |
} |
head->fPrev = prev; |
@@ -722,18 +649,14 @@ |
} |
} |
-inline bool apply_fill_type(SkPath::FillType fillType, Poly* poly) { |
- if (!poly) { |
- return false; |
- } |
- int winding = poly->fWinding; |
+inline bool apply_fill_type(SkPath::FillType fillType, int winding) { |
switch (fillType) { |
case SkPath::kWinding_FillType: |
return winding != 0; |
case SkPath::kEvenOdd_FillType: |
return (winding & 1) != 0; |
case SkPath::kInverseWinding_FillType: |
- return winding == -1; |
+ return winding == 1; |
case SkPath::kInverseEvenOdd_FillType: |
return (winding & 1) == 1; |
default: |
@@ -742,9 +665,8 @@ |
} |
} |
-Edge* new_edge(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator& c, |
- int winding_scale = 1) { |
- int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? winding_scale : -winding_scale; |
+Edge* new_edge(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator& c) { |
+ int winding = c.sweep_lt(prev->fPoint, next->fPoint) ? 1 : -1; |
Vertex* top = winding < 0 ? next : prev; |
Vertex* bottom = winding < 0 ? prev : next; |
return ALLOC_NEW(Edge, (top, bottom, winding), alloc); |
@@ -752,15 +674,15 @@ |
void remove_edge(Edge* edge, EdgeList* edges) { |
LOG("removing edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID); |
- SkASSERT(edges->contains(edge)); |
- edges->remove(edge); |
+ SkASSERT(edge->isActive(edges)); |
+ list_remove<Edge, &Edge::fLeft, &Edge::fRight>(edge, &edges->fHead, &edges->fTail); |
} |
void insert_edge(Edge* edge, Edge* prev, EdgeList* edges) { |
LOG("inserting edge %g -> %g\n", edge->fTop->fID, edge->fBottom->fID); |
- SkASSERT(!edges->contains(edge)); |
+ SkASSERT(!edge->isActive(edges)); |
Edge* next = prev ? prev->fRight : edges->fHead; |
- edges->insert(edge, prev, next); |
+ list_insert<Edge, &Edge::fLeft, &Edge::fRight>(edge, prev, next, &edges->fHead, &edges->fTail); |
} |
void find_enclosing_edges(Vertex* v, EdgeList* edges, Edge** left, Edge** right) { |
@@ -800,7 +722,7 @@ |
} |
void fix_active_state(Edge* edge, EdgeList* activeEdges, Comparator& c) { |
- if (activeEdges && activeEdges->contains(edge)) { |
+ if (edge->isActive(activeEdges)) { |
if (edge->fBottom->fProcessed || !edge->fTop->fProcessed) { |
remove_edge(edge, activeEdges); |
} |
@@ -869,7 +791,7 @@ |
LOG("erasing edge (%g -> %g)\n", edge->fTop->fID, edge->fBottom->fID); |
remove_edge_above(edge); |
remove_edge_below(edge); |
- if (edges && edges->contains(edge)) { |
+ if (edge->isActive(edges)) { |
remove_edge(edge, edges); |
} |
} |
@@ -1006,24 +928,9 @@ |
} |
} |
-Edge* connect(Vertex* prev, Vertex* next, SkChunkAlloc& alloc, Comparator c, |
- int winding_scale = 1) { |
- Edge* edge = new_edge(prev, next, alloc, c, winding_scale); |
- if (edge->fWinding > 0) { |
- insert_edge_below(edge, prev, c); |
- insert_edge_above(edge, next, c); |
- } else { |
- insert_edge_below(edge, next, c); |
- insert_edge_above(edge, prev, c); |
- } |
- merge_collinear_edges(edge, nullptr, c); |
- return edge; |
-} |
- |
void merge_vertices(Vertex* src, Vertex* dst, Vertex** head, Comparator& c, SkChunkAlloc& alloc) { |
LOG("found coincident verts at %g, %g; merging %g into %g\n", src->fPoint.fX, src->fPoint.fY, |
src->fID, dst->fID); |
- dst->fAlpha = SkTMax(src->fAlpha, dst->fAlpha); |
for (Edge* edge = src->fFirstEdgeAbove; edge;) { |
Edge* next = edge->fNextEdgeAbove; |
set_bottom(edge, dst, nullptr, c); |
@@ -1035,11 +942,6 @@ |
edge = next; |
} |
list_remove<Vertex, &Vertex::fPrev, &Vertex::fNext>(src, head, nullptr); |
-} |
- |
-uint8_t max_edge_alpha(Edge* a, Edge* b) { |
- return SkTMax(SkTMax(a->fTop->fAlpha, a->fBottom->fAlpha), |
- SkTMax(b->fTop->fAlpha, b->fBottom->fAlpha)); |
} |
Vertex* check_for_intersection(Edge* edge, Edge* other, EdgeList* activeEdges, Comparator& c, |
@@ -1077,8 +979,7 @@ |
} else if (coincident(nextV->fPoint, p)) { |
v = nextV; |
} else { |
- uint8_t alpha = max_edge_alpha(edge, other); |
- v = ALLOC_NEW(Vertex, (p, alpha), alloc); |
+ v = ALLOC_NEW(Vertex, (p), alloc); |
LOG("inserting between %g (%g, %g) and %g (%g, %g)\n", |
prevV->fID, prevV->fPoint.fX, prevV->fPoint.fY, |
nextV->fID, nextV->fPoint.fX, nextV->fPoint.fY); |
@@ -1098,13 +999,10 @@ |
return nullptr; |
} |
-void sanitize_contours(Vertex** contours, int contourCnt, bool approximate) { |
+void sanitize_contours(Vertex** contours, int contourCnt) { |
for (int i = 0; i < contourCnt; ++i) { |
SkASSERT(contours[i]); |
for (Vertex* v = contours[i];;) { |
- if (approximate) { |
- round(&v->fPoint); |
- } |
if (coincident(v->fPrev->fPoint, v->fPoint)) { |
LOG("vertex %g,%g coincident; removing\n", v->fPoint.fX, v->fPoint.fY); |
if (v->fPrev == v) { |
@@ -1144,7 +1042,15 @@ |
for (int i = 0; i < contourCnt; ++i) { |
for (Vertex* v = contours[i]; v != nullptr;) { |
Vertex* vNext = v->fNext; |
- connect(v->fPrev, v, alloc, c); |
+ Edge* edge = new_edge(v->fPrev, v, alloc, c); |
+ if (edge->fWinding > 0) { |
+ insert_edge_below(edge, v->fPrev, c); |
+ insert_edge_above(edge, v, c); |
+ } else { |
+ insert_edge_below(edge, v, c); |
+ insert_edge_above(edge, v->fPrev, c); |
+ } |
+ merge_collinear_edges(edge, nullptr, c); |
if (prev) { |
prev->fNext = v; |
v->fPrev = prev; |
@@ -1239,7 +1145,7 @@ |
continue; |
} |
#if LOGGING_ENABLED |
- LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha); |
+ LOG("\nvertex %g: (%g,%g)\n", v->fID, v->fPoint.fX, v->fPoint.fY); |
#endif |
Edge* leftEnclosingEdge = nullptr; |
Edge* rightEnclosingEdge = nullptr; |
@@ -1269,12 +1175,6 @@ |
} |
} while (restartChecks); |
- if (v->fAlpha == 0) { |
- if ((leftEnclosingEdge && leftEnclosingEdge->fWinding < 0) && |
- (rightEnclosingEdge && rightEnclosingEdge->fWinding > 0)) { |
- v->fAlpha = max_edge_alpha(leftEnclosingEdge, rightEnclosingEdge); |
- } |
- } |
for (Edge* e = v->fFirstEdgeAbove; e; e = e->fNextEdgeAbove) { |
remove_edge(e, &activeEdges); |
} |
@@ -1298,7 +1198,7 @@ |
continue; |
} |
#if LOGGING_ENABLED |
- LOG("\nvertex %g: (%g,%g), alpha %d\n", v->fID, v->fPoint.fX, v->fPoint.fY, v->fAlpha); |
+ LOG("\nvertex %g: (%g,%g)\n", v->fID, v->fPoint.fX, v->fPoint.fY); |
#endif |
Edge* leftEnclosingEdge = nullptr; |
Edge* rightEnclosingEdge = nullptr; |
@@ -1398,255 +1298,9 @@ |
return polys; |
} |
-bool is_boundary_edge(Edge* edge, SkPath::FillType fillType) { |
- return apply_fill_type(fillType, edge->fLeftPoly) != |
- apply_fill_type(fillType, edge->fRightPoly); |
-} |
- |
-bool is_boundary_start(Edge* edge, SkPath::FillType fillType) { |
- return !apply_fill_type(fillType, edge->fLeftPoly) && |
- apply_fill_type(fillType, edge->fRightPoly); |
-} |
- |
-Vertex* remove_non_boundary_edges(Vertex* vertices, SkPath::FillType fillType, |
- SkChunkAlloc& alloc) { |
- for (Vertex* v = vertices; v != nullptr; v = v->fNext) { |
- for (Edge* e = v->fFirstEdgeBelow; e != nullptr;) { |
- Edge* next = e->fNextEdgeBelow; |
- if (!is_boundary_edge(e, fillType)) { |
- remove_edge_above(e); |
- remove_edge_below(e); |
- } |
- e = next; |
- } |
- } |
- return vertices; |
-} |
- |
-// This is different from Edge::intersect, in that it intersects lines, not line segments. |
-bool intersect(const Edge& a, const Edge& b, SkPoint* point) { |
- double denom = a.fDX * b.fDY - a.fDY * b.fDX; |
- if (denom == 0.0) { |
- return false; |
- } |
- double scale = 1.0f / denom; |
- point->fX = SkDoubleToScalar((b.fDX * a.fC - a.fDX * b.fC) * scale); |
- point->fY = SkDoubleToScalar((b.fDY * a.fC - a.fDY * b.fC) * scale); |
- round(point); |
- return true; |
-} |
- |
-void get_edge_normal(const Edge* e, SkVector* normal) { |
- normal->setNormalize(SkDoubleToScalar(e->fDX) * e->fWinding, |
- SkDoubleToScalar(e->fDY) * e->fWinding); |
-} |
- |
-// Stage 5c: detect and remove "pointy" vertices whose edge normals point in opposite directions |
-// and whose adjacent vertices are less than a quarter pixel from an edge. These are guaranteed to |
-// invert on stroking. |
- |
-void simplify_boundary(EdgeList* boundary, Comparator& c, SkChunkAlloc& alloc) { |
- Edge* prevEdge = boundary->fTail; |
- SkVector prevNormal; |
- get_edge_normal(prevEdge, &prevNormal); |
- for (Edge* e = boundary->fHead; e != nullptr;) { |
- Vertex* prev = prevEdge->fWinding == 1 ? prevEdge->fTop : prevEdge->fBottom; |
- Vertex* next = e->fWinding == 1 ? e->fBottom : e->fTop; |
- double dist = e->dist(prev->fPoint); |
- SkVector normal; |
- get_edge_normal(e, &normal); |
- float denom = 0.25f * static_cast<float>(e->fDX * e->fDX + e->fDY * e->fDY); |
- if (prevNormal.dot(normal) < 0.0 && (dist * dist) <= denom) { |
- Edge* join = new_edge(prev, next, alloc, c); |
- insert_edge(join, e, boundary); |
- remove_edge(prevEdge, boundary); |
- remove_edge(e, boundary); |
- if (join->fLeft && join->fRight) { |
- prevEdge = join->fLeft; |
- e = join; |
- } else { |
- prevEdge = boundary->fTail; |
- e = boundary->fHead; // join->fLeft ? join->fLeft : join; |
- } |
- get_edge_normal(prevEdge, &prevNormal); |
- } else { |
- prevEdge = e; |
- prevNormal = normal; |
- e = e->fRight; |
- } |
- } |
-} |
- |
-// Stage 5d: Displace edges by half a pixel inward and outward along their normals. Intersect to |
-// find new vertices, and set zero alpha on the exterior and one alpha on the interior. Build a |
-// new antialiased mesh from those vertices. |
- |
-void boundary_to_aa_mesh(EdgeList* boundary, VertexList* mesh, Comparator& c, SkChunkAlloc& alloc) { |
- EdgeList outerContour; |
- Edge* prevEdge = boundary->fTail; |
- float radius = 0.5f; |
- double offset = radius * sqrt(prevEdge->fDX * prevEdge->fDX + prevEdge->fDY * prevEdge->fDY) |
- * prevEdge->fWinding; |
- Edge prevInner(prevEdge->fTop, prevEdge->fBottom, prevEdge->fWinding); |
- prevInner.fC -= offset; |
- Edge prevOuter(prevEdge->fTop, prevEdge->fBottom, prevEdge->fWinding); |
- prevOuter.fC += offset; |
- VertexList innerVertices; |
- VertexList outerVertices; |
- SkScalar innerCount = SK_Scalar1, outerCount = SK_Scalar1; |
- for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) { |
- double offset = radius * sqrt(e->fDX * e->fDX + e->fDY * e->fDY) * e->fWinding; |
- Edge inner(e->fTop, e->fBottom, e->fWinding); |
- inner.fC -= offset; |
- Edge outer(e->fTop, e->fBottom, e->fWinding); |
- outer.fC += offset; |
- SkPoint innerPoint, outerPoint; |
- if (intersect(prevInner, inner, &innerPoint) && |
- intersect(prevOuter, outer, &outerPoint)) { |
- Vertex* innerVertex = ALLOC_NEW(Vertex, (innerPoint, 255), alloc); |
- Vertex* outerVertex = ALLOC_NEW(Vertex, (outerPoint, 0), alloc); |
- if (innerVertices.fTail && outerVertices.fTail) { |
- Edge innerEdge(innerVertices.fTail, innerVertex, 1); |
- Edge outerEdge(outerVertices.fTail, outerVertex, 1); |
- SkVector innerNormal; |
- get_edge_normal(&innerEdge, &innerNormal); |
- SkVector outerNormal; |
- get_edge_normal(&outerEdge, &outerNormal); |
- SkVector normal; |
- get_edge_normal(prevEdge, &normal); |
- if (normal.dot(innerNormal) < 0) { |
- innerPoint += innerVertices.fTail->fPoint * innerCount; |
- innerCount++; |
- innerPoint *= SkScalarInvert(innerCount); |
- innerVertices.fTail->fPoint = innerVertex->fPoint = innerPoint; |
- } else { |
- innerCount = SK_Scalar1; |
- } |
- if (normal.dot(outerNormal) < 0) { |
- outerPoint += outerVertices.fTail->fPoint * outerCount; |
- outerCount++; |
- outerPoint *= SkScalarInvert(outerCount); |
- outerVertices.fTail->fPoint = outerVertex->fPoint = outerPoint; |
- } else { |
- outerCount = SK_Scalar1; |
- } |
- } |
- innerVertices.append(innerVertex); |
- outerVertices.append(outerVertex); |
- prevEdge = e; |
- } |
- prevInner = inner; |
- prevOuter = outer; |
- } |
- innerVertices.close(); |
- outerVertices.close(); |
- |
- Vertex* innerVertex = innerVertices.fHead; |
- Vertex* outerVertex = outerVertices.fHead; |
- // Alternate clockwise and counterclockwise polys, so the tesselator |
- // doesn't cancel out the interior edges. |
- if (!innerVertex || !outerVertex) { |
- return; |
- } |
- do { |
- connect(outerVertex->fNext, outerVertex, alloc, c); |
- connect(innerVertex->fNext, innerVertex, alloc, c, 2); |
- connect(innerVertex, outerVertex->fNext, alloc, c, 2); |
- connect(outerVertex, innerVertex, alloc, c, 2); |
- Vertex* innerNext = innerVertex->fNext; |
- Vertex* outerNext = outerVertex->fNext; |
- mesh->append(innerVertex); |
- mesh->append(outerVertex); |
- innerVertex = innerNext; |
- outerVertex = outerNext; |
- } while (innerVertex != innerVertices.fHead && outerVertex != outerVertices.fHead); |
-} |
- |
-void extract_boundary(EdgeList* boundary, Edge* e, SkPath::FillType fillType, SkChunkAlloc& alloc) { |
- bool down = is_boundary_start(e, fillType); |
- while (e) { |
- e->fWinding = down ? 1 : -1; |
- Edge* next; |
- boundary->append(e); |
- if (down) { |
- // Find outgoing edge, in clockwise order. |
- if ((next = e->fNextEdgeAbove)) { |
- down = false; |
- } else if ((next = e->fBottom->fLastEdgeBelow)) { |
- down = true; |
- } else if ((next = e->fPrevEdgeAbove)) { |
- down = false; |
- } |
- } else { |
- // Find outgoing edge, in counter-clockwise order. |
- if ((next = e->fPrevEdgeBelow)) { |
- down = true; |
- } else if ((next = e->fTop->fFirstEdgeAbove)) { |
- down = false; |
- } else if ((next = e->fNextEdgeBelow)) { |
- down = true; |
- } |
- } |
- remove_edge_above(e); |
- remove_edge_below(e); |
- e = next; |
- } |
-} |
- |
-// Stage 5b: Extract boundary edges. |
- |
-EdgeList* extract_boundaries(Vertex* vertices, SkPath::FillType fillType, SkChunkAlloc& alloc) { |
- LOG("extracting boundaries\n"); |
- vertices = remove_non_boundary_edges(vertices, fillType, alloc); |
- EdgeList* boundaries = nullptr; |
- for (Vertex* v = vertices; v != nullptr; v = v->fNext) { |
- while (v->fFirstEdgeBelow) { |
- EdgeList* boundary = new_contour(&boundaries, alloc); |
- extract_boundary(boundary, v->fFirstEdgeBelow, fillType, alloc); |
- } |
- } |
- return boundaries; |
-} |
- |
// This is a driver function which calls stages 2-5 in turn. |
-Vertex* contours_to_mesh(Vertex** contours, int contourCnt, bool antialias, |
- Comparator& c, SkChunkAlloc& alloc) { |
-#if LOGGING_ENABLED |
- for (int i = 0; i < contourCnt; ++i) { |
- Vertex* v = contours[i]; |
- SkASSERT(v); |
- LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); |
- for (v = v->fNext; v != contours[i]; v = v->fNext) { |
- LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); |
- } |
- } |
-#endif |
- sanitize_contours(contours, contourCnt, antialias); |
- return build_edges(contours, contourCnt, c, alloc); |
-} |
- |
-Poly* mesh_to_polys(Vertex** vertices, SkPath::FillType fillType, Comparator& c, |
- SkChunkAlloc& alloc) { |
- if (!vertices || !*vertices) { |
- return nullptr; |
- } |
- |
- // Sort vertices in Y (secondarily in X). |
- merge_sort(vertices, c); |
- merge_coincident_vertices(vertices, c, alloc); |
-#if LOGGING_ENABLED |
- for (Vertex* v = *vertices; v != nullptr; v = v->fNext) { |
- static float gID = 0.0f; |
- v->fID = gID++; |
- } |
-#endif |
- simplify(*vertices, c, alloc); |
- return tessellate(*vertices, alloc); |
-} |
- |
-Poly* contours_to_polys(Vertex** contours, int contourCnt, SkPath::FillType fillType, |
- const SkRect& pathBounds, bool antialias, |
+Poly* contours_to_polys(Vertex** contours, int contourCnt, const SkRect& pathBounds, |
SkChunkAlloc& alloc) { |
Comparator c; |
if (pathBounds.width() > pathBounds.height()) { |
@@ -1656,35 +1310,37 @@ |
c.sweep_lt = sweep_lt_vert; |
c.sweep_gt = sweep_gt_vert; |
} |
- Vertex* mesh = contours_to_mesh(contours, contourCnt, antialias, c, alloc); |
- Poly* polys = mesh_to_polys(&mesh, fillType, c, alloc); |
- if (antialias) { |
- EdgeList* boundaries = extract_boundaries(mesh, fillType, alloc); |
- VertexList aaMesh; |
- for (EdgeList* boundary = boundaries; boundary != nullptr; boundary = boundary->fNext) { |
- simplify_boundary(boundary, c, alloc); |
- if (boundary->fCount > 2) { |
- boundary_to_aa_mesh(boundary, &aaMesh, c, alloc); |
- } |
- } |
- return mesh_to_polys(&aaMesh.fHead, SkPath::kWinding_FillType, c, alloc); |
- } |
- return polys; |
-} |
- |
-// Stage 6: Triangulate the monotone polygons into a vertex buffer. |
-void* polys_to_triangles(Poly* polys, SkPath::FillType fillType, const AAParams* aaParams, |
- void* data) { |
- for (Poly* poly = polys; poly; poly = poly->fNext) { |
- if (apply_fill_type(fillType, poly)) { |
- data = poly->emit(aaParams, data); |
- } |
- } |
- return data; |
+#if LOGGING_ENABLED |
+ for (int i = 0; i < contourCnt; ++i) { |
+ Vertex* v = contours[i]; |
+ SkASSERT(v); |
+ LOG("path.moveTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); |
+ for (v = v->fNext; v != contours[i]; v = v->fNext) { |
+ LOG("path.lineTo(%20.20g, %20.20g);\n", v->fPoint.fX, v->fPoint.fY); |
+ } |
+ } |
+#endif |
+ sanitize_contours(contours, contourCnt); |
+ Vertex* vertices = build_edges(contours, contourCnt, c, alloc); |
+ if (!vertices) { |
+ return nullptr; |
+ } |
+ |
+ // Sort vertices in Y (secondarily in X). |
+ merge_sort(&vertices, c); |
+ merge_coincident_vertices(&vertices, c, alloc); |
+#if LOGGING_ENABLED |
+ for (Vertex* v = vertices; v != nullptr; v = v->fNext) { |
+ static float gID = 0.0f; |
+ v->fID = gID++; |
+ } |
+#endif |
+ simplify(vertices, c, alloc); |
+ return tessellate(vertices, alloc); |
} |
Poly* path_to_polys(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, |
- int contourCnt, SkChunkAlloc& alloc, bool antialias, bool* isLinear) { |
+ int contourCnt, SkChunkAlloc& alloc, bool* isLinear) { |
SkPath::FillType fillType = path.getFillType(); |
if (SkPath::IsInverseFillType(fillType)) { |
contourCnt++; |
@@ -1692,8 +1348,7 @@ |
SkAutoTDeleteArray<Vertex*> contours(new Vertex* [contourCnt]); |
path_to_contours(path, tolerance, clipBounds, contours.get(), alloc, isLinear); |
- return contours_to_polys(contours.get(), contourCnt, path.getFillType(), path.getBounds(), |
- antialias, alloc); |
+ return contours_to_polys(contours.get(), contourCnt, path.getBounds(), alloc); |
} |
void get_contour_count_and_size_estimate(const SkPath& path, SkScalar tolerance, int* contourCnt, |
@@ -1718,7 +1373,7 @@ |
int count_points(Poly* polys, SkPath::FillType fillType) { |
int count = 0; |
for (Poly* poly = polys; poly; poly = poly->fNext) { |
- if (apply_fill_type(fillType, poly) && poly->fCount >= 3) { |
+ if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3) { |
count += (poly->fCount - 2) * (TESSELLATOR_WIREFRAME ? 6 : 3); |
} |
} |
@@ -1732,8 +1387,7 @@ |
// Stage 6: Triangulate the monotone polygons into a vertex buffer. |
int PathToTriangles(const SkPath& path, SkScalar tolerance, const SkRect& clipBounds, |
- VertexAllocator* vertexAllocator, bool antialias, const GrColor& color, |
- bool canTweakAlphaForCoverage, bool* isLinear) { |
+ VertexAllocator* vertexAllocator, bool* isLinear) { |
int contourCnt; |
int sizeEstimate; |
get_contour_count_and_size_estimate(path, tolerance, &contourCnt, &sizeEstimate); |
@@ -1742,28 +1396,26 @@ |
return 0; |
} |
SkChunkAlloc alloc(sizeEstimate); |
- Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, antialias, |
- isLinear); |
+ Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, isLinear); |
SkPath::FillType fillType = path.getFillType(); |
int count = count_points(polys, fillType); |
if (0 == count) { |
return 0; |
} |
- void* verts = vertexAllocator->lock(count); |
+ SkPoint* verts = vertexAllocator->lock(count); |
if (!verts) { |
SkDebugf("Could not allocate vertices\n"); |
return 0; |
} |
- |
- LOG("emitting %d verts\n", count); |
- AAParams aaParams; |
- aaParams.fTweakAlpha = canTweakAlphaForCoverage; |
- aaParams.fColor = color; |
- |
- void* end = polys_to_triangles(polys, fillType, antialias ? &aaParams : nullptr, verts); |
- int actualCount = static_cast<int>((static_cast<uint8_t*>(end) - static_cast<uint8_t*>(verts)) |
- / vertexAllocator->stride()); |
+ SkPoint* end = verts; |
+ for (Poly* poly = polys; poly; poly = poly->fNext) { |
+ if (apply_fill_type(fillType, poly->fWinding)) { |
+ end = poly->emit(end); |
+ } |
+ } |
+ int actualCount = static_cast<int>(end - verts); |
+ LOG("actual count: %d\n", actualCount); |
SkASSERT(actualCount <= count); |
vertexAllocator->unlock(actualCount); |
return actualCount; |
@@ -1779,7 +1431,7 @@ |
} |
SkChunkAlloc alloc(sizeEstimate); |
bool isLinear; |
- Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, false, &isLinear); |
+ Poly* polys = path_to_polys(path, tolerance, clipBounds, contourCnt, alloc, &isLinear); |
SkPath::FillType fillType = path.getFillType(); |
int count = count_points(polys, fillType); |
if (0 == count) { |
@@ -1792,9 +1444,9 @@ |
SkPoint* points = new SkPoint[count]; |
SkPoint* pointsEnd = points; |
for (Poly* poly = polys; poly; poly = poly->fNext) { |
- if (apply_fill_type(fillType, poly)) { |
+ if (apply_fill_type(fillType, poly->fWinding)) { |
SkPoint* start = pointsEnd; |
- pointsEnd = static_cast<SkPoint*>(poly->emit(nullptr, pointsEnd)); |
+ pointsEnd = poly->emit(pointsEnd); |
while (start != pointsEnd) { |
vertsEnd->fPos = *start; |
vertsEnd->fWinding = poly->fWinding; |