Index: src/gpu/batches/GrAAConvexTessellator.cpp |
diff --git a/src/gpu/batches/GrAAConvexTessellator.cpp b/src/gpu/batches/GrAAConvexTessellator.cpp |
index 7e28d24e9339f35d92263b66bd27f025c5793f9f..2c069f634205a385b991ac9f091105aac14d1b7f 100644 |
--- a/src/gpu/batches/GrAAConvexTessellator.cpp |
+++ b/src/gpu/batches/GrAAConvexTessellator.cpp |
@@ -29,6 +29,9 @@ static const SkScalar kConicTolerance = 0.5f; |
// dot product below which we use a round cap between curve segments |
static const SkScalar kRoundCapThreshold = 0.8f; |
+// dot product above which we consider two adjacent curves to be part of the "same" curve |
+static const SkScalar kCurveConnectionThreshold = 0.95f; |
+ |
static SkScalar intersect(const SkPoint& p0, const SkPoint& n0, |
const SkPoint& p1, const SkPoint& n1) { |
const SkPoint v = p1 - p0; |
@@ -60,14 +63,14 @@ int GrAAConvexTessellator::addPt(const SkPoint& pt, |
SkScalar depth, |
SkScalar coverage, |
bool movable, |
- bool isCurve) { |
+ CurveState curve) { |
this->validate(); |
int index = fPts.count(); |
*fPts.push() = pt; |
*fCoverages.push() = coverage; |
*fMovable.push() = movable; |
- *fIsCurve.push() = isCurve; |
+ *fCurveState.push() = curve; |
this->validate(); |
return index; |
@@ -146,6 +149,19 @@ void GrAAConvexTessellator::computeBisectors() { |
} else { |
fBisectors[cur].negate(); // make the bisector face in |
} |
+ if (fCurveState[prev] == kIndeterminate_CurveState) { |
+ if (fCurveState[cur] == kSharp_CurveState) { |
+ fCurveState[prev] = kSharp_CurveState; |
+ } else { |
+ if (SkScalarAbs(fNorms[cur].dot(fNorms[prev])) > kCurveConnectionThreshold) { |
+ fCurveState[prev] = kCurve_CurveState; |
+ fCurveState[cur] = kCurve_CurveState; |
+ } else { |
+ fCurveState[prev] = kSharp_CurveState; |
+ fCurveState[cur] = kSharp_CurveState; |
+ } |
+ } |
+ } |
SkASSERT(SkScalarNearlyEqual(1.0f, fBisectors[cur].length())); |
} |
@@ -304,7 +320,7 @@ bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat |
while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
switch (verb) { |
case SkPath::kLine_Verb: |
- this->lineTo(m, pts[1], false); |
+ this->lineTo(m, pts[1], kSharp_CurveState); |
break; |
case SkPath::kQuad_Verb: |
this->quadTo(m, pts); |
@@ -461,11 +477,11 @@ void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o |
perp2.scale(outset); |
perp2 += fPts[originalIdx]; |
- bool isCurve = fIsCurve[originalIdx]; |
+ CurveState curve = fCurveState[originalIdx]; |
// We know it isn't a duplicate of the prior point (since it and this |
// one are just perpendicular offsets from the non-merged polygon points) |
- int perp1Idx = this->addPt(perp1, -outset, coverage, false, isCurve); |
+ int perp1Idx = this->addPt(perp1, -outset, coverage, false, curve); |
nextRing->addIdx(perp1Idx, originalIdx); |
int perp2Idx; |
@@ -473,11 +489,11 @@ void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o |
if (duplicate_pt(perp2, this->point(perp1Idx))) { |
perp2Idx = perp1Idx; |
} else { |
- perp2Idx = this->addPt(perp2, -outset, coverage, false, isCurve); |
+ perp2Idx = this->addPt(perp2, -outset, coverage, false, curve); |
} |
if (perp2Idx != perp1Idx) { |
- if (isCurve) { |
+ if (curve == kCurve_CurveState) { |
// bevel or round depending upon curvature |
SkScalar dotProd = normal1.dot(normal2); |
if (dotProd < kRoundCapThreshold) { |
@@ -492,7 +508,7 @@ void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o |
// For very shallow angles all the corner points could fuse |
if (!duplicate_pt(miter, this->point(perp1Idx))) { |
int miterIdx; |
- miterIdx = this->addPt(miter, -outset, coverage, false, false); |
+ miterIdx = this->addPt(miter, -outset, coverage, false, kSharp_CurveState); |
nextRing->addIdx(miterIdx, originalIdx); |
// The two triangles for the corner |
this->addTri(originalIdx, perp1Idx, miterIdx); |
@@ -520,7 +536,8 @@ void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o |
// For very shallow angles all the corner points could fuse |
if (!duplicate_pt(miter, this->point(perp1Idx))) { |
int miterIdx; |
- miterIdx = this->addPt(miter, -outset, coverage, false, false); |
+ miterIdx = this->addPt(miter, -outset, coverage, false, |
+ kSharp_CurveState); |
nextRing->addIdx(miterIdx, originalIdx); |
// The two triangles for the corner |
this->addTri(originalIdx, perp1Idx, miterIdx); |
@@ -704,7 +721,7 @@ bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing |
SkScalar coverage = compute_coverage(depth, initialDepth, initialCoverage, |
targetDepth, targetCoverage); |
newIdx = this->addPt(fCandidateVerts.point(i), depth, coverage, |
- fCandidateVerts.originatingIdx(i) != -1, false); |
+ fCandidateVerts.originatingIdx(i) != -1, kSharp_CurveState); |
} else { |
SkASSERT(fCandidateVerts.originatingIdx(i) != -1); |
this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.point(i), depth, |
@@ -823,7 +840,7 @@ bool GrAAConvexTessellator::Ring::isConvex(const GrAAConvexTessellator& tess) co |
#endif |
-void GrAAConvexTessellator::lineTo(SkPoint p, bool isCurve) { |
+void GrAAConvexTessellator::lineTo(SkPoint p, CurveState curve) { |
if (this->numPts() > 0 && duplicate_pt(p, this->lastPoint())) { |
return; |
} |
@@ -834,7 +851,7 @@ void GrAAConvexTessellator::lineTo(SkPoint p, bool isCurve) { |
// The old last point is on the line from the second to last to the new point |
this->popLastPt(); |
fNorms.pop(); |
- fIsCurve.pop(); |
+ fCurveState.pop(); |
// double-check that the new last point is not a duplicate of the new point. In an ideal |
// world this wouldn't be necessary (since it's only possible for non-convex paths), but |
// floating point precision issues mean it can actually happen on paths that were determined |
@@ -844,7 +861,7 @@ void GrAAConvexTessellator::lineTo(SkPoint p, bool isCurve) { |
} |
} |
SkScalar initialRingCoverage = fStrokeWidth < 0.0f ? 0.5f : 1.0f; |
- this->addPt(p, 0.0f, initialRingCoverage, false, isCurve); |
+ this->addPt(p, 0.0f, initialRingCoverage, false, curve); |
if (this->numPts() > 1) { |
*fNorms.push() = fPts.top() - fPts[fPts.count()-2]; |
SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top()); |
@@ -853,9 +870,9 @@ void GrAAConvexTessellator::lineTo(SkPoint p, bool isCurve) { |
} |
} |
-void GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, bool isCurve) { |
+void GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, CurveState curve) { |
m.mapPoints(&p, 1); |
- this->lineTo(p, isCurve); |
+ this->lineTo(p, curve); |
} |
void GrAAConvexTessellator::quadTo(SkPoint pts[3]) { |
@@ -865,9 +882,10 @@ void GrAAConvexTessellator::quadTo(SkPoint pts[3]) { |
int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], |
kQuadTolerance, &target, maxCount); |
fPointBuffer.setCount(count); |
- for (int i = 0; i < count; i++) { |
- lineTo(fPointBuffer[i], true); |
+ for (int i = 0; i < count - 1; i++) { |
+ lineTo(fPointBuffer[i], kCurve_CurveState); |
} |
+ lineTo(fPointBuffer[count - 1], kIndeterminate_CurveState); |
} |
void GrAAConvexTessellator::quadTo(const SkMatrix& m, SkPoint pts[3]) { |
@@ -887,9 +905,10 @@ void GrAAConvexTessellator::cubicTo(const SkMatrix& m, SkPoint pts[4]) { |
int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], |
kCubicTolerance, &target, maxCount); |
fPointBuffer.setCount(count); |
- for (int i = 0; i < count; i++) { |
- lineTo(fPointBuffer[i], true); |
+ for (int i = 0; i < count - 1; i++) { |
+ lineTo(fPointBuffer[i], kCurve_CurveState); |
} |
+ lineTo(fPointBuffer[count - 1], kIndeterminate_CurveState); |
} |
// include down here to avoid compilation errors caused by "-" overload in SkGeometry.h |