AA GrTessellator: fix bevelling of acute angles.
The code to handle acute outer angles in generated geometry was pretty broken: it did a simple runnning average of consecutive acute vertices, and didn't handle acute angles between the last and first edges. Replaced it with something simpler that does proper bevelling for angles less than 2.5 degrees. This revealed a bug with thin path segments, exposed by the thinconcavepaths test. This will be fixed by upcoming changes, but I've also dded a few more test cases to make it clearer. Change-Id: I23a628ab2e16acaab798c746a5fd87842cacbfab Reviewed-on: https://skia-review.googlesource.com/7660 Reviewed-by: Brian Salomon <bsalomon@google.com> Commit-Queue: Stephan White <senorblanco@chromium.org>
This commit is contained in:
parent
2d0c238fcb
commit
86cc841e23
@ -44,7 +44,7 @@ DEF_SIMPLE_GM(thinconcavepaths, canvas, 400, 400) {
|
||||
paint.setStyle(SkPaint::kFill_Style);
|
||||
|
||||
canvas->save();
|
||||
for (SkScalar width = 1.0; width < 2.05; width += 0.25) {
|
||||
for (SkScalar width = 0.5; width < 2.05; width += 0.25) {
|
||||
draw_thin_stroked_rect(canvas, paint, width);
|
||||
canvas->translate(0, 25);
|
||||
}
|
||||
|
@ -1502,7 +1502,6 @@ void simplify_boundary(EdgeList* boundary, Comparator& c, SkChunkAlloc& alloc) {
|
||||
// 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->fLine.magSq()) * prevEdge->fWinding;
|
||||
@ -1512,7 +1511,8 @@ void boundary_to_aa_mesh(EdgeList* boundary, VertexList* mesh, Comparator& c, Sk
|
||||
prevOuter.fC += offset;
|
||||
VertexList innerVertices;
|
||||
VertexList outerVertices;
|
||||
SkScalar innerCount = SK_Scalar1, outerCount = SK_Scalar1;
|
||||
SkVector prevNormal;
|
||||
get_edge_normal(prevEdge, &prevNormal);
|
||||
for (Edge* e = boundary->fHead; e != nullptr; e = e->fRight) {
|
||||
double offset = radius * sqrt(e->fLine.magSq()) * e->fWinding;
|
||||
Line inner(e->fTop, e->fBottom);
|
||||
@ -1520,50 +1520,35 @@ void boundary_to_aa_mesh(EdgeList* boundary, VertexList* mesh, Comparator& c, Sk
|
||||
Line outer(e->fTop, e->fBottom);
|
||||
outer.fC += offset;
|
||||
SkPoint innerPoint, outerPoint;
|
||||
SkVector normal;
|
||||
get_edge_normal(e, &normal);
|
||||
if (prevInner.intersect(inner, &innerPoint) &&
|
||||
prevOuter.intersect(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::Type::kInner);
|
||||
Edge outerEdge(outerVertices.fTail, outerVertex, 1, Edge::Type::kInner);
|
||||
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;
|
||||
}
|
||||
// cos(theta) < -0.999 implies a miter angle of ~2.5 degrees,
|
||||
// below which we'll bevel the outer edges.
|
||||
if (prevNormal.dot(normal) < -0.999) {
|
||||
SkPoint p = e->fWinding > 0 ? e->fTop->fPoint : e->fBottom->fPoint;
|
||||
SkPoint outerPoint1 = p - prevNormal * radius;
|
||||
SkPoint outerPoint2 = p - normal * radius;
|
||||
innerVertices.append(ALLOC_NEW(Vertex, (innerPoint, 255), alloc));
|
||||
innerVertices.append(ALLOC_NEW(Vertex, (innerPoint, 255), alloc));
|
||||
outerVertices.append(ALLOC_NEW(Vertex, (outerPoint1, 0), alloc));
|
||||
outerVertices.append(ALLOC_NEW(Vertex, (outerPoint2, 0), alloc));
|
||||
} else {
|
||||
innerVertices.append(ALLOC_NEW(Vertex, (innerPoint, 255), alloc));
|
||||
outerVertices.append(ALLOC_NEW(Vertex, (outerPoint, 0), alloc));
|
||||
}
|
||||
innerVertices.append(innerVertex);
|
||||
outerVertices.append(outerVertex);
|
||||
prevEdge = e;
|
||||
}
|
||||
prevInner = inner;
|
||||
prevOuter = outer;
|
||||
prevEdge = e;
|
||||
prevNormal = normal;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user