Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrAAConvexTessellator.h" | 8 #include "GrAAConvexTessellator.h" |
| 9 #include "SkCanvas.h" | 9 #include "SkCanvas.h" |
| 10 #include "SkPath.h" | 10 #include "SkPath.h" |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 25 static const SkScalar kQuadTolerance = 0.2f; | 25 static const SkScalar kQuadTolerance = 0.2f; |
| 26 static const SkScalar kCubicTolerance = 0.2f; | 26 static const SkScalar kCubicTolerance = 0.2f; |
| 27 static const SkScalar kConicTolerance = 0.5f; | 27 static const SkScalar kConicTolerance = 0.5f; |
| 28 | 28 |
| 29 // dot product below which we use a round cap between curve segments | 29 // dot product below which we use a round cap between curve segments |
| 30 static const SkScalar kRoundCapThreshold = 0.8f; | 30 static const SkScalar kRoundCapThreshold = 0.8f; |
| 31 | 31 |
| 32 // dot product above which we consider two adjacent curves to be part of the "sa me" curve | 32 // dot product above which we consider two adjacent curves to be part of the "sa me" curve |
| 33 static const SkScalar kCurveConnectionThreshold = 0.8f; | 33 static const SkScalar kCurveConnectionThreshold = 0.8f; |
| 34 | 34 |
| 35 static SkScalar intersect(const SkPoint& p0, const SkPoint& n0, | 35 static bool intersect(const SkPoint& p0, const SkPoint& n0, |
| 36 const SkPoint& p1, const SkPoint& n1) { | 36 const SkPoint& p1, const SkPoint& n1, |
| 37 SkScalar* t) { | |
| 37 const SkPoint v = p1 - p0; | 38 const SkPoint v = p1 - p0; |
| 38 SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX; | 39 SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX; |
| 39 return (v.fX * n1.fY - v.fY * n1.fX) / perpDot; | 40 if (SkScalarNearlyZero(perpDot)) { |
| 41 return true; | |
|
ethannicholas
2016/09/06 20:34:05
The return value of this function seems backward t
robertphillips
2016/09/06 20:47:06
Haha - good point. Fixed.
| |
| 42 } | |
| 43 *t = (v.fX * n1.fY - v.fY * n1.fX) / perpDot; | |
| 44 SkASSERT(SkScalarIsFinite(*t)); | |
| 45 return false; | |
| 40 } | 46 } |
| 41 | 47 |
| 42 // This is a special case version of intersect where we have the vector | 48 // This is a special case version of intersect where we have the vector |
| 43 // perpendicular to the second line rather than the vector parallel to it. | 49 // perpendicular to the second line rather than the vector parallel to it. |
| 44 static SkScalar perp_intersect(const SkPoint& p0, const SkPoint& n0, | 50 static SkScalar perp_intersect(const SkPoint& p0, const SkPoint& n0, |
| 45 const SkPoint& p1, const SkPoint& perp) { | 51 const SkPoint& p1, const SkPoint& perp) { |
| 46 const SkPoint v = p1 - p0; | 52 const SkPoint v = p1 - p0; |
| 47 SkScalar perpDot = n0.dot(perp); | 53 SkScalar perpDot = n0.dot(perp); |
| 48 return v.dot(perp) / perpDot; | 54 return v.dot(perp) / perpDot; |
| 49 } | 55 } |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 211 // The polygon state is captured in the Ring class while the GrAAConvexTessellat or | 217 // The polygon state is captured in the Ring class while the GrAAConvexTessellat or |
| 212 // controls the iteration. The CandidateVerts holds the formative points for the | 218 // controls the iteration. The CandidateVerts holds the formative points for the |
| 213 // next ring. | 219 // next ring. |
| 214 bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { | 220 bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { |
| 215 if (!this->extractFromPath(m, path)) { | 221 if (!this->extractFromPath(m, path)) { |
| 216 return false; | 222 return false; |
| 217 } | 223 } |
| 218 | 224 |
| 219 SkScalar coverage = 1.0f; | 225 SkScalar coverage = 1.0f; |
| 220 SkScalar scaleFactor = 0.0f; | 226 SkScalar scaleFactor = 0.0f; |
| 221 if (fStrokeWidth >= 0.0f) { | 227 |
| 228 if (SkStrokeRec::kStrokeAndFill_Style == fStyle) { | |
| 222 SkASSERT(m.isSimilarity()); | 229 SkASSERT(m.isSimilarity()); |
| 223 scaleFactor = m.getMaxScale(); // x and y scale are the same | 230 scaleFactor = m.getMaxScale(); // x and y scale are the same |
| 224 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; | 231 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; |
| 232 Ring outerStrokeAndAARing; | |
| 233 this->createOuterRing(fInitialRing, | |
| 234 effectiveStrokeWidth / 2 + kAntialiasingRadius, 0. 0, | |
| 235 &outerStrokeAndAARing); | |
| 236 | |
| 237 // discard all the triangles added between the originating ring and the new outer ring | |
| 238 fIndices.rewind(); | |
| 239 | |
| 240 outerStrokeAndAARing.init(*this); | |
| 241 | |
| 242 outerStrokeAndAARing.makeOriginalRing(); | |
| 243 | |
| 244 // Add the outer stroke ring's normals to the originating ring's normals | |
| 245 // so it can also act as an originating ring | |
| 246 fNorms.setReserve(fNorms.count() + outerStrokeAndAARing.numPts()); | |
| 247 for (int i = 0; i < outerStrokeAndAARing.numPts(); ++i) { | |
| 248 fNorms.push(outerStrokeAndAARing.norm(i)); | |
| 249 } | |
| 250 | |
| 251 // the bisectors are only needed for the computation of the outer ring | |
| 252 fBisectors.rewind(); | |
| 253 | |
| 254 Ring* insetAARing; | |
| 255 this->createInsetRings(outerStrokeAndAARing, | |
| 256 0.0f, 0.0f, 2*kAntialiasingRadius, 1.0f, | |
| 257 &insetAARing); | |
| 258 | |
| 259 SkDEBUGCODE(this->validate();) | |
| 260 return true; | |
| 261 } | |
| 262 | |
| 263 if (SkStrokeRec::kStroke_Style == fStyle) { | |
| 264 SkASSERT(fStrokeWidth >= 0.0f); | |
| 265 SkASSERT(m.isSimilarity()); | |
| 266 scaleFactor = m.getMaxScale(); // x and y scale are the same | |
| 267 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; | |
| 225 Ring outerStrokeRing; | 268 Ring outerStrokeRing; |
| 226 this->createOuterRing(fInitialRing, effectiveStrokeWidth / 2 - kAntialia singRadius, | 269 this->createOuterRing(fInitialRing, effectiveStrokeWidth / 2 - kAntialia singRadius, |
| 227 coverage, &outerStrokeRing); | 270 coverage, &outerStrokeRing); |
| 228 outerStrokeRing.init(*this); | 271 outerStrokeRing.init(*this); |
| 229 Ring outerAARing; | 272 Ring outerAARing; |
| 230 this->createOuterRing(outerStrokeRing, kAntialiasingRadius * 2, 0.0f, &o uterAARing); | 273 this->createOuterRing(outerStrokeRing, kAntialiasingRadius * 2, 0.0f, &o uterAARing); |
| 231 } else { | 274 } else { |
| 232 Ring outerAARing; | 275 Ring outerAARing; |
| 233 this->createOuterRing(fInitialRing, kAntialiasingRadius, 0.0f, &outerAAR ing); | 276 this->createOuterRing(fInitialRing, kAntialiasingRadius, 0.0f, &outerAAR ing); |
| 234 } | 277 } |
| 235 | 278 |
| 236 // the bisectors are only needed for the computation of the outer ring | 279 // the bisectors are only needed for the computation of the outer ring |
| 237 fBisectors.rewind(); | 280 fBisectors.rewind(); |
| 238 if (fStrokeWidth >= 0.0f && fInitialRing.numPts() > 2) { | 281 if (SkStrokeRec::kStroke_Style == fStyle && fInitialRing.numPts() > 2) { |
| 282 SkASSERT(fStrokeWidth >= 0.0f); | |
| 239 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; | 283 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; |
| 240 Ring* insetStrokeRing; | 284 Ring* insetStrokeRing; |
| 241 SkScalar strokeDepth = effectiveStrokeWidth / 2 - kAntialiasingRadius; | 285 SkScalar strokeDepth = effectiveStrokeWidth / 2 - kAntialiasingRadius; |
| 242 if (this->createInsetRings(fInitialRing, 0.0f, coverage, strokeDepth, co verage, | 286 if (this->createInsetRings(fInitialRing, 0.0f, coverage, strokeDepth, co verage, |
| 243 &insetStrokeRing)) { | 287 &insetStrokeRing)) { |
| 244 Ring* insetAARing; | 288 Ring* insetAARing; |
| 245 this->createInsetRings(*insetStrokeRing, strokeDepth, coverage, stro keDepth + | 289 this->createInsetRings(*insetStrokeRing, strokeDepth, coverage, stro keDepth + |
| 246 kAntialiasingRadius * 2, 0.0f, &insetAARing); | 290 kAntialiasingRadius * 2, 0.0f, &insetAARing); |
| 247 } | 291 } |
| 248 } else { | 292 } else { |
| 249 Ring* insetAARing; | 293 Ring* insetAARing; |
| 250 this->createInsetRings(fInitialRing, 0.0f, 0.5f, kAntialiasingRadius, 1. 0f, &insetAARing); | 294 this->createInsetRings(fInitialRing, 0.0f, 0.5f, kAntialiasingRadius, 1. 0f, &insetAARing); |
| 251 } | 295 } |
| 252 | 296 |
| 253 SkDEBUGCODE(this->validate();) | 297 SkDEBUGCODE(this->validate();) |
| 254 return true; | 298 return true; |
| 255 } | 299 } |
| 256 | 300 |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 383 | 427 |
| 384 // Make all the normals face outwards rather than along the edge | 428 // Make all the normals face outwards rather than along the edge |
| 385 for (int cur = 0; cur < fNorms.count(); ++cur) { | 429 for (int cur = 0; cur < fNorms.count(); ++cur) { |
| 386 fNorms[cur].setOrthog(fNorms[cur], fSide); | 430 fNorms[cur].setOrthog(fNorms[cur], fSide); |
| 387 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); | 431 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); |
| 388 } | 432 } |
| 389 | 433 |
| 390 this->computeBisectors(); | 434 this->computeBisectors(); |
| 391 } else if (this->numPts() == 2) { | 435 } else if (this->numPts() == 2) { |
| 392 // We've got two points, so we're degenerate. | 436 // We've got two points, so we're degenerate. |
| 393 if (fStrokeWidth < 0.0f) { | 437 if (fStyle == SkStrokeRec::kFill_Style) { |
| 394 // it's a fill, so we don't need to worry about degenerate paths | 438 // it's a fill, so we don't need to worry about degenerate paths |
| 395 return false; | 439 return false; |
| 396 } | 440 } |
| 397 // For stroking, we still need to process the degenerate path, so fix it up | 441 // For stroking, we still need to process the degenerate path, so fix it up |
| 398 fSide = SkPoint::kLeft_Side; | 442 fSide = SkPoint::kLeft_Side; |
| 399 | 443 |
| 400 // Make all the normals face outwards rather than along the edge | 444 // Make all the normals face outwards rather than along the edge |
| 401 for (int cur = 0; cur < fNorms.count(); ++cur) { | 445 for (int cur = 0; cur < fNorms.count(); ++cur) { |
| 402 fNorms[cur].setOrthog(fNorms[cur], fSide); | 446 fNorms[cur].setOrthog(fNorms[cur], fSide); |
| 403 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); | 447 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 579 int lastIdx = previousRing.index(numPts - 1); | 623 int lastIdx = previousRing.index(numPts - 1); |
| 580 this->addTri(lastIdx, firstPerpIdx, previousRing.index(0)); | 624 this->addTri(lastIdx, firstPerpIdx, previousRing.index(0)); |
| 581 this->addTri(lastIdx, lastPerpIdx, firstPerpIdx); | 625 this->addTri(lastIdx, lastPerpIdx, firstPerpIdx); |
| 582 | 626 |
| 583 this->validate(); | 627 this->validate(); |
| 584 } | 628 } |
| 585 | 629 |
| 586 // Something went wrong in the creation of the next ring. If we're filling the s hape, just go ahead | 630 // Something went wrong in the creation of the next ring. If we're filling the s hape, just go ahead |
| 587 // and fan it. | 631 // and fan it. |
| 588 void GrAAConvexTessellator::terminate(const Ring& ring) { | 632 void GrAAConvexTessellator::terminate(const Ring& ring) { |
| 589 if (fStrokeWidth < 0.0f) { | 633 if (fStyle != SkStrokeRec::kStroke_Style) { |
| 590 this->fanRing(ring); | 634 this->fanRing(ring); |
| 591 } | 635 } |
| 592 } | 636 } |
| 593 | 637 |
| 594 static SkScalar compute_coverage(SkScalar depth, SkScalar initialDepth, SkScalar initialCoverage, | 638 static SkScalar compute_coverage(SkScalar depth, SkScalar initialDepth, SkScalar initialCoverage, |
| 595 SkScalar targetDepth, SkScalar targetCoverage) { | 639 SkScalar targetDepth, SkScalar targetCoverage) { |
| 596 if (SkScalarNearlyEqual(initialDepth, targetDepth)) { | 640 if (SkScalarNearlyEqual(initialDepth, targetDepth)) { |
| 597 return targetCoverage; | 641 return targetCoverage; |
| 598 } | 642 } |
| 599 SkScalar result = (depth - initialDepth) / (targetDepth - initialDepth) * | 643 SkScalar result = (depth - initialDepth) / (targetDepth - initialDepth) * |
| 600 (targetCoverage - initialCoverage) + initialCoverage; | 644 (targetCoverage - initialCoverage) + initialCoverage; |
| 601 return SkScalarClampMax(result, 1.0f); | 645 return SkScalarClampMax(result, 1.0f); |
| 602 } | 646 } |
| 603 | 647 |
| 604 // return true when processing is complete | 648 // return true when processing is complete |
| 605 bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing , | 649 bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing , |
| 606 SkScalar initialDepth, SkScalar init ialCoverage, | 650 SkScalar initialDepth, SkScalar init ialCoverage, |
| 607 SkScalar targetDepth, SkScalar targe tCoverage, | 651 SkScalar targetDepth, SkScalar targe tCoverage, |
| 608 bool forceNew) { | 652 bool forceNew) { |
| 609 bool done = false; | 653 bool done = false; |
| 610 | 654 |
| 611 fCandidateVerts.rewind(); | 655 fCandidateVerts.rewind(); |
| 612 | 656 |
| 613 // Loop through all the points in the ring and find the intersection with th e smallest depth | 657 // Loop through all the points in the ring and find the intersection with th e smallest depth |
| 614 SkScalar minDist = SK_ScalarMax, minT = 0.0f; | 658 SkScalar minDist = SK_ScalarMax, minT = 0.0f; |
| 615 int minEdgeIdx = -1; | 659 int minEdgeIdx = -1; |
| 616 | 660 |
| 617 for (int cur = 0; cur < lastRing.numPts(); ++cur) { | 661 for (int cur = 0; cur < lastRing.numPts(); ++cur) { |
| 618 int next = (cur + 1) % lastRing.numPts(); | 662 int next = (cur + 1) % lastRing.numPts(); |
| 619 SkScalar t = intersect(this->point(lastRing.index(cur)), lastRing.bisec tor(cur), | 663 |
| 620 this->point(lastRing.index(next)), lastRing.bisec tor(next)); | 664 SkScalar t; |
| 665 bool parallel = intersect(this->point(lastRing.index(cur)), lastRing.bi sector(cur), | |
| 666 this->point(lastRing.index(next)), lastRing.bi sector(next), | |
| 667 &t); | |
| 668 if (parallel) { | |
| 669 continue; | |
| 670 } | |
| 621 SkScalar dist = -t * lastRing.norm(cur).dot(lastRing.bisector(cur)); | 671 SkScalar dist = -t * lastRing.norm(cur).dot(lastRing.bisector(cur)); |
| 622 | 672 |
| 623 if (minDist > dist) { | 673 if (minDist > dist) { |
| 624 minDist = dist; | 674 minDist = dist; |
| 625 minT = t; | 675 minT = t; |
| 626 minEdgeIdx = cur; | 676 minEdgeIdx = cur; |
| 627 } | 677 } |
| 628 } | 678 } |
| 629 | 679 |
| 630 if (minEdgeIdx == -1) { | 680 if (minEdgeIdx == -1) { |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 738 dst[i] = nextRing->index(dst[i]); | 788 dst[i] = nextRing->index(dst[i]); |
| 739 } | 789 } |
| 740 | 790 |
| 741 for (int i = 0; i < lastRing.numPts(); ++i) { | 791 for (int i = 0; i < lastRing.numPts(); ++i) { |
| 742 int next = (i + 1) % lastRing.numPts(); | 792 int next = (i + 1) % lastRing.numPts(); |
| 743 | 793 |
| 744 this->addTri(lastRing.index(i), lastRing.index(next), dst[next]); | 794 this->addTri(lastRing.index(i), lastRing.index(next), dst[next]); |
| 745 this->addTri(lastRing.index(i), dst[next], dst[i]); | 795 this->addTri(lastRing.index(i), dst[next], dst[i]); |
| 746 } | 796 } |
| 747 | 797 |
| 748 if (done && fStrokeWidth < 0.0f) { | 798 if (done && fStyle != SkStrokeRec::kStroke_Style) { |
| 749 // fill | 799 // fill or stroke-and-fill |
| 750 this->fanRing(*nextRing); | 800 this->fanRing(*nextRing); |
| 751 } | 801 } |
| 752 | 802 |
| 753 if (nextRing->numPts() < 3) { | 803 if (nextRing->numPts() < 3) { |
| 754 done = true; | 804 done = true; |
| 755 } | 805 } |
| 756 return done; | 806 return done; |
| 757 } | 807 } |
| 758 | 808 |
| 759 void GrAAConvexTessellator::validate() const { | 809 void GrAAConvexTessellator::validate() const { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 853 fNorms.pop(); | 903 fNorms.pop(); |
| 854 fCurveState.pop(); | 904 fCurveState.pop(); |
| 855 // double-check that the new last point is not a duplicate of the new po int. In an ideal | 905 // double-check that the new last point is not a duplicate of the new po int. In an ideal |
| 856 // world this wouldn't be necessary (since it's only possible for non-co nvex paths), but | 906 // world this wouldn't be necessary (since it's only possible for non-co nvex paths), but |
| 857 // floating point precision issues mean it can actually happen on paths that were determined | 907 // floating point precision issues mean it can actually happen on paths that were determined |
| 858 // to be convex. | 908 // to be convex. |
| 859 if (duplicate_pt(p, this->lastPoint())) { | 909 if (duplicate_pt(p, this->lastPoint())) { |
| 860 return; | 910 return; |
| 861 } | 911 } |
| 862 } | 912 } |
| 863 SkScalar initialRingCoverage = fStrokeWidth < 0.0f ? 0.5f : 1.0f; | 913 SkScalar initialRingCoverage = (SkStrokeRec::kFill_Style == fStyle) ? 0.5f : 1.0f; |
| 864 this->addPt(p, 0.0f, initialRingCoverage, false, curve); | 914 this->addPt(p, 0.0f, initialRingCoverage, false, curve); |
| 865 if (this->numPts() > 1) { | 915 if (this->numPts() > 1) { |
| 866 *fNorms.push() = fPts.top() - fPts[fPts.count()-2]; | 916 *fNorms.push() = fPts.top() - fPts[fPts.count()-2]; |
| 867 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top()); | 917 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top()); |
| 868 SkASSERT(len > 0.0f); | 918 SkASSERT(len > 0.0f); |
| 869 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms.top().length())); | 919 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms.top().length())); |
| 870 } | 920 } |
| 871 } | 921 } |
| 872 | 922 |
| 873 void GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, CurveState curv e) { | 923 void GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, CurveState curv e) { |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1043 | 1093 |
| 1044 SkString num; | 1094 SkString num; |
| 1045 num.printf("%d", i); | 1095 num.printf("%d", i); |
| 1046 canvas->drawText(num.c_str(), num.size(), | 1096 canvas->drawText(num.c_str(), num.size(), |
| 1047 this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f ), | 1097 this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f ), |
| 1048 paint); | 1098 paint); |
| 1049 } | 1099 } |
| 1050 } | 1100 } |
| 1051 | 1101 |
| 1052 #endif | 1102 #endif |
| OLD | NEW |