| 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 18 matching lines...) Expand all Loading... |
| 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 static SkScalar intersect(const SkPoint& p0, const SkPoint& n0, | 32 static SkScalar intersect(const SkPoint& p0, const SkPoint& n0, |
| 33 const SkPoint& p1, const SkPoint& n1) { | 33 const SkPoint& p1, const SkPoint& n1) { |
| 34 const SkPoint v = p1 - p0; | 34 const SkPoint v = p1 - p0; |
| 35 SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX; | 35 SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX; |
| 36 return (v.fX * n1.fY - v.fY * n1.fX) / perpDot; | 36 return (v.fX * n1.fY - v.fY * n1.fX) / perpDot; |
| 37 } | 37 } |
| 38 | 38 |
| 39 // This is a special case version of intersect where we have the vector | 39 // This is a special case version of intersect where we have the vector |
| 40 // perpendicular to the second line rather than the vector parallel to it. | 40 // perpendicular to the second line rather than the vector parallel to it. |
| 41 static SkScalar perp_intersect(const SkPoint& p0, const SkPoint& n0, | 41 static SkScalar perp_intersect(const SkPoint& p0, const SkPoint& n0, |
| 42 const SkPoint& p1, const SkPoint& perp) { | 42 const SkPoint& p1, const SkPoint& perp) { |
| 43 const SkPoint v = p1 - p0; | 43 const SkPoint v = p1 - p0; |
| 44 SkScalar perpDot = n0.dot(perp); | 44 SkScalar perpDot = n0.dot(perp); |
| 45 return v.dot(perp) / perpDot; | 45 return v.dot(perp) / perpDot; |
| 46 } | 46 } |
| 47 | 47 |
| 48 static bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) { | 48 static bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) { |
| 49 SkScalar distSq = p0.distanceToSqd(p1); | 49 SkScalar distSq = p0.distanceToSqd(p1); |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 | 135 |
| 136 int prev = fBisectors.count() - 1; | 136 int prev = fBisectors.count() - 1; |
| 137 for (int cur = 0; cur < fBisectors.count(); prev = cur, ++cur) { | 137 for (int cur = 0; cur < fBisectors.count(); prev = cur, ++cur) { |
| 138 fBisectors[cur] = fNorms[cur] + fNorms[prev]; | 138 fBisectors[cur] = fNorms[cur] + fNorms[prev]; |
| 139 if (!fBisectors[cur].normalize()) { | 139 if (!fBisectors[cur].normalize()) { |
| 140 SkASSERT(SkPoint::kLeft_Side == fSide || SkPoint::kRight_Side == fSi
de); | 140 SkASSERT(SkPoint::kLeft_Side == fSide || SkPoint::kRight_Side == fSi
de); |
| 141 fBisectors[cur].setOrthog(fNorms[cur], (SkPoint::Side)-fSide); | 141 fBisectors[cur].setOrthog(fNorms[cur], (SkPoint::Side)-fSide); |
| 142 SkVector other; | 142 SkVector other; |
| 143 other.setOrthog(fNorms[prev], fSide); | 143 other.setOrthog(fNorms[prev], fSide); |
| 144 fBisectors[cur] += other; | 144 fBisectors[cur] += other; |
| 145 SkAssertResult(fBisectors[cur].normalize()); | 145 SkAssertResult(fBisectors[cur].normalize()); |
| 146 } else { | 146 } else { |
| 147 fBisectors[cur].negate(); // make the bisector face in | 147 fBisectors[cur].negate(); // make the bisector face in |
| 148 } | 148 } |
| 149 | 149 |
| 150 SkASSERT(SkScalarNearlyEqual(1.0f, fBisectors[cur].length())); | 150 SkASSERT(SkScalarNearlyEqual(1.0f, fBisectors[cur].length())); |
| 151 } | 151 } |
| 152 } | 152 } |
| 153 | 153 |
| 154 // Create as many rings as we need to (up to a predefined limit) to reach the sp
ecified target | 154 // Create as many rings as we need to (up to a predefined limit) to reach the sp
ecified target |
| 155 // depth. If we are in fill mode, the final ring will automatically be fanned. | 155 // depth. If we are in fill mode, the final ring will automatically be fanned. |
| 156 bool GrAAConvexTessellator::createInsetRings(Ring& previousRing, SkScalar initia
lDepth, | 156 bool GrAAConvexTessellator::createInsetRings(Ring& previousRing, SkScalar initia
lDepth, |
| 157 SkScalar initialCoverage, SkScalar
targetDepth, | 157 SkScalar initialCoverage, SkScalar
targetDepth, |
| 158 SkScalar targetCoverage, Ring** fin
alRing) { | 158 SkScalar targetCoverage, Ring** fin
alRing) { |
| 159 static const int kMaxNumRings = 8; | 159 static const int kMaxNumRings = 8; |
| 160 | 160 |
| 161 if (previousRing.numPts() < 3) { | 161 if (previousRing.numPts() < 3) { |
| 162 return false; | 162 return false; |
| 163 } | 163 } |
| 164 Ring* currentRing = &previousRing; | 164 Ring* currentRing = &previousRing; |
| 165 int i; | 165 int i; |
| 166 for (i = 0; i < kMaxNumRings; ++i) { | 166 for (i = 0; i < kMaxNumRings; ++i) { |
| 167 Ring* nextRing = this->getNextRing(currentRing); | 167 Ring* nextRing = this->getNextRing(currentRing); |
| 168 SkASSERT(nextRing != currentRing); | 168 SkASSERT(nextRing != currentRing); |
| 169 | 169 |
| 170 bool done = this->createInsetRing(*currentRing, nextRing, initialDepth,
initialCoverage, | 170 bool done = this->createInsetRing(*currentRing, nextRing, initialDepth,
initialCoverage, |
| 171 targetDepth, targetCoverage, i == 0); | 171 targetDepth, targetCoverage, i == 0); |
| 172 currentRing = nextRing; | 172 currentRing = nextRing; |
| 173 if (done) { | 173 if (done) { |
| 174 break; | 174 break; |
| 175 } | 175 } |
| 176 currentRing->init(*this); | 176 currentRing->init(*this); |
| 177 } | 177 } |
| 178 | 178 |
| 179 if (kMaxNumRings == i) { | 179 if (kMaxNumRings == i) { |
| 180 // Bail if we've exceeded the amount of time we want to throw at this. | 180 // Bail if we've exceeded the amount of time we want to throw at this. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 196 // controls the iteration. The CandidateVerts holds the formative points for the | 196 // controls the iteration. The CandidateVerts holds the formative points for the |
| 197 // next ring. | 197 // next ring. |
| 198 bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { | 198 bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { |
| 199 if (!this->extractFromPath(m, path)) { | 199 if (!this->extractFromPath(m, path)) { |
| 200 return false; | 200 return false; |
| 201 } | 201 } |
| 202 | 202 |
| 203 SkScalar coverage = 1.0f; | 203 SkScalar coverage = 1.0f; |
| 204 SkScalar scaleFactor = 0.0f; | 204 SkScalar scaleFactor = 0.0f; |
| 205 if (fStrokeWidth >= 0.0f) { | 205 if (fStrokeWidth >= 0.0f) { |
| 206 SkASSERT(m.isSimilarity()); | 206 SkASSERT(m.isSimilarity()); |
| 207 scaleFactor = m.getMaxScale(); // x and y scale are the same | 207 scaleFactor = m.getMaxScale(); // x and y scale are the same |
| 208 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; | 208 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; |
| 209 Ring outerStrokeRing; | 209 Ring outerStrokeRing; |
| 210 this->createOuterRing(fInitialRing, effectiveStrokeWidth / 2 - kAntialia
singRadius, | 210 this->createOuterRing(fInitialRing, effectiveStrokeWidth / 2 - kAntialia
singRadius, |
| 211 coverage, &outerStrokeRing); | 211 coverage, &outerStrokeRing); |
| 212 outerStrokeRing.init(*this); | 212 outerStrokeRing.init(*this); |
| 213 Ring outerAARing; | 213 Ring outerAARing; |
| 214 this->createOuterRing(outerStrokeRing, kAntialiasingRadius * 2, 0.0f, &o
uterAARing); | 214 this->createOuterRing(outerStrokeRing, kAntialiasingRadius * 2, 0.0f, &o
uterAARing); |
| 215 } else { | 215 } else { |
| 216 Ring outerAARing; | 216 Ring outerAARing; |
| 217 this->createOuterRing(fInitialRing, kAntialiasingRadius, 0.0f, &outerAAR
ing); | 217 this->createOuterRing(fInitialRing, kAntialiasingRadius, 0.0f, &outerAAR
ing); |
| 218 } | 218 } |
| 219 | 219 |
| 220 // the bisectors are only needed for the computation of the outer ring | 220 // the bisectors are only needed for the computation of the outer ring |
| 221 fBisectors.rewind(); | 221 fBisectors.rewind(); |
| 222 if (fStrokeWidth >= 0.0f && fInitialRing.numPts() > 2) { | 222 if (fStrokeWidth >= 0.0f && fInitialRing.numPts() > 2) { |
| 223 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; | 223 SkScalar effectiveStrokeWidth = scaleFactor * fStrokeWidth; |
| 224 Ring* insetStrokeRing; | 224 Ring* insetStrokeRing; |
| 225 SkScalar strokeDepth = effectiveStrokeWidth / 2 - kAntialiasingRadius; | 225 SkScalar strokeDepth = effectiveStrokeWidth / 2 - kAntialiasingRadius; |
| 226 if (this->createInsetRings(fInitialRing, 0.0f, coverage, strokeDepth, co
verage, | 226 if (this->createInsetRings(fInitialRing, 0.0f, coverage, strokeDepth, co
verage, |
| 227 &insetStrokeRing)) { | 227 &insetStrokeRing)) { |
| 228 Ring* insetAARing; | 228 Ring* insetAARing; |
| 229 this->createInsetRings(*insetStrokeRing, strokeDepth, coverage, stro
keDepth + | 229 this->createInsetRings(*insetStrokeRing, strokeDepth, coverage, stro
keDepth + |
| 230 kAntialiasingRadius * 2, 0.0f, &insetAARing); | 230 kAntialiasingRadius * 2, 0.0f, &insetAARing); |
| 231 } | 231 } |
| 232 } else { | 232 } else { |
| 233 Ring* insetAARing; | 233 Ring* insetAARing; |
| 234 this->createInsetRings(fInitialRing, 0.0f, 0.5f, kAntialiasingRadius, 1.
0f, &insetAARing); | 234 this->createInsetRings(fInitialRing, 0.0f, 0.5f, kAntialiasingRadius, 1.
0f, &insetAARing); |
| 235 } | 235 } |
| 236 | 236 |
| 237 SkDEBUGCODE(this->validate();) | 237 SkDEBUGCODE(this->validate();) |
| 238 return true; | 238 return true; |
| 239 } | 239 } |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 } | 366 } |
| 367 | 367 |
| 368 // Make all the normals face outwards rather than along the edge | 368 // Make all the normals face outwards rather than along the edge |
| 369 for (int cur = 0; cur < fNorms.count(); ++cur) { | 369 for (int cur = 0; cur < fNorms.count(); ++cur) { |
| 370 fNorms[cur].setOrthog(fNorms[cur], fSide); | 370 fNorms[cur].setOrthog(fNorms[cur], fSide); |
| 371 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); | 371 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); |
| 372 } | 372 } |
| 373 | 373 |
| 374 this->computeBisectors(); | 374 this->computeBisectors(); |
| 375 } else if (this->numPts() == 2) { | 375 } else if (this->numPts() == 2) { |
| 376 // We've got two points, so we're degenerate. | 376 // We've got two points, so we're degenerate. |
| 377 if (fStrokeWidth < 0.0f) { | 377 if (fStrokeWidth < 0.0f) { |
| 378 // it's a fill, so we don't need to worry about degenerate paths | 378 // it's a fill, so we don't need to worry about degenerate paths |
| 379 return false; | 379 return false; |
| 380 } | 380 } |
| 381 // For stroking, we still need to process the degenerate path, so fix it
up | 381 // For stroking, we still need to process the degenerate path, so fix it
up |
| 382 fSide = SkPoint::kLeft_Side; | 382 fSide = SkPoint::kLeft_Side; |
| 383 | 383 |
| 384 // Make all the normals face outwards rather than along the edge | 384 // Make all the normals face outwards rather than along the edge |
| 385 for (int cur = 0; cur < fNorms.count(); ++cur) { | 385 for (int cur = 0; cur < fNorms.count(); ++cur) { |
| 386 fNorms[cur].setOrthog(fNorms[cur], fSide); | 386 fNorms[cur].setOrthog(fNorms[cur], fSide); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 422 } | 422 } |
| 423 | 423 |
| 424 void GrAAConvexTessellator::fanRing(const Ring& ring) { | 424 void GrAAConvexTessellator::fanRing(const Ring& ring) { |
| 425 // fan out from point 0 | 425 // fan out from point 0 |
| 426 int startIdx = ring.index(0); | 426 int startIdx = ring.index(0); |
| 427 for (int cur = ring.numPts() - 2; cur >= 0; --cur) { | 427 for (int cur = ring.numPts() - 2; cur >= 0; --cur) { |
| 428 this->addTri(startIdx, ring.index(cur), ring.index(cur + 1)); | 428 this->addTri(startIdx, ring.index(cur), ring.index(cur + 1)); |
| 429 } | 429 } |
| 430 } | 430 } |
| 431 | 431 |
| 432 void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o
utset, | 432 void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o
utset, |
| 433 SkScalar coverage, Ring* nextRing) { | 433 SkScalar coverage, Ring* nextRing) { |
| 434 const int numPts = previousRing.numPts(); | 434 const int numPts = previousRing.numPts(); |
| 435 if (numPts == 0) { | 435 if (numPts == 0) { |
| 436 return; | 436 return; |
| 437 } | 437 } |
| 438 | 438 |
| 439 int prev = numPts - 1; | 439 int prev = numPts - 1; |
| 440 int lastPerpIdx = -1, firstPerpIdx = -1; | 440 int lastPerpIdx = -1, firstPerpIdx = -1; |
| 441 | 441 |
| 442 const SkScalar outsetSq = SkScalarMul(outset, outset); | 442 const SkScalar outsetSq = SkScalarMul(outset, outset); |
| 443 SkScalar miterLimitSq = SkScalarMul(outset, fMiterLimit); | 443 SkScalar miterLimitSq = SkScalarMul(outset, fMiterLimit); |
| 444 miterLimitSq = SkScalarMul(miterLimitSq, miterLimitSq); | 444 miterLimitSq = SkScalarMul(miterLimitSq, miterLimitSq); |
| 445 for (int cur = 0; cur < numPts; ++cur) { | 445 for (int cur = 0; cur < numPts; ++cur) { |
| 446 int originalIdx = previousRing.index(cur); | 446 int originalIdx = previousRing.index(cur); |
| 447 // For each vertex of the original polygon we add at least two points to
the | 447 // For each vertex of the original polygon we add at least two points to
the |
| 448 // outset polygon - one extending perpendicular to each impinging edge.
Connecting these | 448 // outset polygon - one extending perpendicular to each impinging edge.
Connecting these |
| 449 // two points yields a bevel join. We need one additional point for a mi
tered join, and | 449 // two points yields a bevel join. We need one additional point for a mi
tered join, and |
| 450 // a round join requires one or more points depending upon curvature. | 450 // a round join requires one or more points depending upon curvature. |
| 451 | 451 |
| 452 // The perpendicular point for the last edge | 452 // The perpendicular point for the last edge |
| 453 SkPoint normal1 = previousRing.norm(prev); | 453 SkPoint normal1 = previousRing.norm(prev); |
| 454 SkPoint perp1 = normal1; | 454 SkPoint perp1 = normal1; |
| 455 perp1.scale(outset); | 455 perp1.scale(outset); |
| 456 perp1 += this->point(originalIdx); | 456 perp1 += this->point(originalIdx); |
| 457 | 457 |
| 458 // The perpendicular point for the next edge. | 458 // The perpendicular point for the next edge. |
| 459 SkPoint normal2 = previousRing.norm(cur); | 459 SkPoint normal2 = previousRing.norm(cur); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 525 // The two triangles for the corner | 525 // The two triangles for the corner |
| 526 this->addTri(originalIdx, perp1Idx, miterIdx); | 526 this->addTri(originalIdx, perp1Idx, miterIdx); |
| 527 this->addTri(originalIdx, miterIdx, perp2Idx); | 527 this->addTri(originalIdx, miterIdx, perp2Idx); |
| 528 } | 528 } |
| 529 break; | 529 break; |
| 530 } | 530 } |
| 531 case SkPaint::Join::kBevel_Join: | 531 case SkPaint::Join::kBevel_Join: |
| 532 this->addTri(originalIdx, perp1Idx, perp2Idx); | 532 this->addTri(originalIdx, perp1Idx, perp2Idx); |
| 533 break; | 533 break; |
| 534 default: | 534 default: |
| 535 // kRound_Join is unsupported for now. GrAALinearizingCo
nvexPathRenderer is | 535 // kRound_Join is unsupported for now. GrAALinearizingCo
nvexPathRenderer is |
| 536 // only willing to draw mitered or beveled, so we should
never get here. | 536 // only willing to draw mitered or beveled, so we should
never get here. |
| 537 SkASSERT(false); | 537 SkASSERT(false); |
| 538 } | 538 } |
| 539 } | 539 } |
| 540 | 540 |
| 541 nextRing->addIdx(perp2Idx, originalIdx); | 541 nextRing->addIdx(perp2Idx, originalIdx); |
| 542 } | 542 } |
| 543 | 543 |
| 544 if (0 == cur) { | 544 if (0 == cur) { |
| 545 // Store the index of the first perpendicular point to finish up | 545 // Store the index of the first perpendicular point to finish up |
| (...skipping 21 matching lines...) Expand all Loading... |
| 567 } | 567 } |
| 568 | 568 |
| 569 // Something went wrong in the creation of the next ring. If we're filling the s
hape, just go ahead | 569 // Something went wrong in the creation of the next ring. If we're filling the s
hape, just go ahead |
| 570 // and fan it. | 570 // and fan it. |
| 571 void GrAAConvexTessellator::terminate(const Ring& ring) { | 571 void GrAAConvexTessellator::terminate(const Ring& ring) { |
| 572 if (fStrokeWidth < 0.0f) { | 572 if (fStrokeWidth < 0.0f) { |
| 573 this->fanRing(ring); | 573 this->fanRing(ring); |
| 574 } | 574 } |
| 575 } | 575 } |
| 576 | 576 |
| 577 static SkScalar compute_coverage(SkScalar depth, SkScalar initialDepth, SkScalar
initialCoverage, | 577 static SkScalar compute_coverage(SkScalar depth, SkScalar initialDepth, SkScalar
initialCoverage, |
| 578 SkScalar targetDepth, SkScalar targetCoverage) { | 578 SkScalar targetDepth, SkScalar targetCoverage) { |
| 579 if (SkScalarNearlyEqual(initialDepth, targetDepth)) { | 579 if (SkScalarNearlyEqual(initialDepth, targetDepth)) { |
| 580 return targetCoverage; | 580 return targetCoverage; |
| 581 } | 581 } |
| 582 SkScalar result = (depth - initialDepth) / (targetDepth - initialDepth) * | 582 SkScalar result = (depth - initialDepth) / (targetDepth - initialDepth) * |
| 583 (targetCoverage - initialCoverage) + initialCoverage; | 583 (targetCoverage - initialCoverage) + initialCoverage; |
| 584 return SkScalarClampMax(result, 1.0f); | 584 return SkScalarClampMax(result, 1.0f); |
| 585 } | 585 } |
| 586 | 586 |
| 587 // return true when processing is complete | 587 // return true when processing is complete |
| 588 bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing
, | 588 bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing
, |
| 589 SkScalar initialDepth, SkScalar init
ialCoverage, | 589 SkScalar initialDepth, SkScalar init
ialCoverage, |
| 590 SkScalar targetDepth, SkScalar targe
tCoverage, | 590 SkScalar targetDepth, SkScalar targe
tCoverage, |
| 591 bool forceNew) { | 591 bool forceNew) { |
| 592 bool done = false; | 592 bool done = false; |
| 593 | 593 |
| 594 fCandidateVerts.rewind(); | 594 fCandidateVerts.rewind(); |
| 595 | 595 |
| 596 // Loop through all the points in the ring and find the intersection with th
e smallest depth | 596 // Loop through all the points in the ring and find the intersection with th
e smallest depth |
| 597 SkScalar minDist = SK_ScalarMax, minT = 0.0f; | 597 SkScalar minDist = SK_ScalarMax, minT = 0.0f; |
| 598 int minEdgeIdx = -1; | 598 int minEdgeIdx = -1; |
| 599 | 599 |
| 600 for (int cur = 0; cur < lastRing.numPts(); ++cur) { | 600 for (int cur = 0; cur < lastRing.numPts(); ++cur) { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 692 for (int i = cur - 1; i >= 0 && dst[i] == targetIdx; i--) { | 692 for (int i = cur - 1; i >= 0 && dst[i] == targetIdx; i--) { |
| 693 dst[i] = fused; | 693 dst[i] = fused; |
| 694 } | 694 } |
| 695 } | 695 } |
| 696 } | 696 } |
| 697 | 697 |
| 698 // Fold the new ring's points into the global pool | 698 // Fold the new ring's points into the global pool |
| 699 for (int i = 0; i < fCandidateVerts.numPts(); ++i) { | 699 for (int i = 0; i < fCandidateVerts.numPts(); ++i) { |
| 700 int newIdx; | 700 int newIdx; |
| 701 if (fCandidateVerts.needsToBeNew(i) || forceNew) { | 701 if (fCandidateVerts.needsToBeNew(i) || forceNew) { |
| 702 // if the originating index is still valid then this point wasn't | 702 // if the originating index is still valid then this point wasn't |
| 703 // fused (and is thus movable) | 703 // fused (and is thus movable) |
| 704 SkScalar coverage = compute_coverage(depth, initialDepth, initialCov
erage, | 704 SkScalar coverage = compute_coverage(depth, initialDepth, initialCov
erage, |
| 705 targetDepth, targetCoverage); | 705 targetDepth, targetCoverage); |
| 706 newIdx = this->addPt(fCandidateVerts.point(i), depth, coverage, | 706 newIdx = this->addPt(fCandidateVerts.point(i), depth, coverage, |
| 707 fCandidateVerts.originatingIdx(i) != -1, false)
; | 707 fCandidateVerts.originatingIdx(i) != -1, false)
; |
| 708 } else { | 708 } else { |
| 709 SkASSERT(fCandidateVerts.originatingIdx(i) != -1); | 709 SkASSERT(fCandidateVerts.originatingIdx(i) != -1); |
| 710 this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.po
int(i), depth, | 710 this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.po
int(i), depth, |
| 711 targetCoverage); | 711 targetCoverage); |
| 712 newIdx = fCandidateVerts.originatingIdx(i); | 712 newIdx = fCandidateVerts.originatingIdx(i); |
| 713 } | 713 } |
| 714 | 714 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 822 } | 822 } |
| 823 | 823 |
| 824 #endif | 824 #endif |
| 825 | 825 |
| 826 void GrAAConvexTessellator::lineTo(SkPoint p, bool isCurve) { | 826 void GrAAConvexTessellator::lineTo(SkPoint p, bool isCurve) { |
| 827 if (this->numPts() > 0 && duplicate_pt(p, this->lastPoint())) { | 827 if (this->numPts() > 0 && duplicate_pt(p, this->lastPoint())) { |
| 828 return; | 828 return; |
| 829 } | 829 } |
| 830 | 830 |
| 831 SkASSERT(fPts.count() <= 1 || fPts.count() == fNorms.count()+1); | 831 SkASSERT(fPts.count() <= 1 || fPts.count() == fNorms.count()+1); |
| 832 if (this->numPts() >= 2 && | 832 if (this->numPts() >= 2 && |
| 833 abs_dist_from_line(fPts.top(), fNorms.top(), p) < kClose) { | 833 abs_dist_from_line(fPts.top(), fNorms.top(), p) < kClose) { |
| 834 // The old last point is on the line from the second to last to the new
point | 834 // The old last point is on the line from the second to last to the new
point |
| 835 this->popLastPt(); | 835 this->popLastPt(); |
| 836 fNorms.pop(); | 836 fNorms.pop(); |
| 837 fIsCurve.pop(); | 837 fIsCurve.pop(); |
| 838 // double-check that the new last point is not a duplicate of the new po
int. In an ideal | 838 // double-check that the new last point is not a duplicate of the new po
int. In an ideal |
| 839 // world this wouldn't be necessary (since it's only possible for non-co
nvex paths), but | 839 // world this wouldn't be necessary (since it's only possible for non-co
nvex paths), but |
| 840 // floating point precision issues mean it can actually happen on paths
that were determined | 840 // floating point precision issues mean it can actually happen on paths
that were determined |
| 841 // to be convex. | 841 // to be convex. |
| 842 if (duplicate_pt(p, this->lastPoint())) { | 842 if (duplicate_pt(p, this->lastPoint())) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 855 | 855 |
| 856 void GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, bool isCurve) { | 856 void GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, bool isCurve) { |
| 857 m.mapPoints(&p, 1); | 857 m.mapPoints(&p, 1); |
| 858 this->lineTo(p, isCurve); | 858 this->lineTo(p, isCurve); |
| 859 } | 859 } |
| 860 | 860 |
| 861 void GrAAConvexTessellator::quadTo(SkPoint pts[3]) { | 861 void GrAAConvexTessellator::quadTo(SkPoint pts[3]) { |
| 862 int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance); | 862 int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance); |
| 863 fPointBuffer.setReserve(maxCount); | 863 fPointBuffer.setReserve(maxCount); |
| 864 SkPoint* target = fPointBuffer.begin(); | 864 SkPoint* target = fPointBuffer.begin(); |
| 865 int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], | 865 int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], |
| 866 kQuadTolerance, &target, maxCount); | 866 kQuadTolerance, &target, maxCount); |
| 867 fPointBuffer.setCount(count); | 867 fPointBuffer.setCount(count); |
| 868 for (int i = 0; i < count; i++) { | 868 for (int i = 0; i < count; i++) { |
| 869 lineTo(fPointBuffer[i], true); | 869 lineTo(fPointBuffer[i], true); |
| 870 } | 870 } |
| 871 } | 871 } |
| 872 | 872 |
| 873 void GrAAConvexTessellator::quadTo(const SkMatrix& m, SkPoint pts[3]) { | 873 void GrAAConvexTessellator::quadTo(const SkMatrix& m, SkPoint pts[3]) { |
| 874 SkPoint transformed[3]; | 874 SkPoint transformed[3]; |
| 875 transformed[0] = pts[0]; | 875 transformed[0] = pts[0]; |
| 876 transformed[1] = pts[1]; | 876 transformed[1] = pts[1]; |
| 877 transformed[2] = pts[2]; | 877 transformed[2] = pts[2]; |
| 878 m.mapPoints(transformed, 3); | 878 m.mapPoints(transformed, 3); |
| 879 quadTo(transformed); | 879 quadTo(transformed); |
| 880 } | 880 } |
| 881 | 881 |
| 882 void GrAAConvexTessellator::cubicTo(const SkMatrix& m, SkPoint pts[4]) { | 882 void GrAAConvexTessellator::cubicTo(const SkMatrix& m, SkPoint pts[4]) { |
| 883 m.mapPoints(pts, 4); | 883 m.mapPoints(pts, 4); |
| 884 int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance); | 884 int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance); |
| 885 fPointBuffer.setReserve(maxCount); | 885 fPointBuffer.setReserve(maxCount); |
| 886 SkPoint* target = fPointBuffer.begin(); | 886 SkPoint* target = fPointBuffer.begin(); |
| 887 int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
| 887 int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], |
| 888 kCubicTolerance, &target, maxCount); | 888 kCubicTolerance, &target, maxCount); |
| 889 fPointBuffer.setCount(count); | 889 fPointBuffer.setCount(count); |
| 890 for (int i = 0; i < count; i++) { | 890 for (int i = 0; i < count; i++) { |
| 891 lineTo(fPointBuffer[i], true); | 891 lineTo(fPointBuffer[i], true); |
| 892 } | 892 } |
| 893 } | 893 } |
| 894 | 894 |
| 895 // include down here to avoid compilation errors caused by "-" overload in SkGeo
metry.h | 895 // include down here to avoid compilation errors caused by "-" overload in SkGeo
metry.h |
| 896 #include "SkGeometry.h" | 896 #include "SkGeometry.h" |
| 897 | 897 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 926 int gs = int(255*paramValue); | 926 int gs = int(255*paramValue); |
| 927 paint.setARGB(255, gs, gs, gs); | 927 paint.setARGB(255, gs, gs, gs); |
| 928 | 928 |
| 929 canvas->drawCircle(p.fX, p.fY, kPointRadius, paint); | 929 canvas->drawCircle(p.fX, p.fY, kPointRadius, paint); |
| 930 | 930 |
| 931 if (stroke) { | 931 if (stroke) { |
| 932 SkPaint stroke; | 932 SkPaint stroke; |
| 933 stroke.setColor(SK_ColorYELLOW); | 933 stroke.setColor(SK_ColorYELLOW); |
| 934 stroke.setStyle(SkPaint::kStroke_Style); | 934 stroke.setStyle(SkPaint::kStroke_Style); |
| 935 stroke.setStrokeWidth(kPointRadius/3.0f); | 935 stroke.setStrokeWidth(kPointRadius/3.0f); |
| 936 canvas->drawCircle(p.fX, p.fY, kPointRadius, stroke); | 936 canvas->drawCircle(p.fX, p.fY, kPointRadius, stroke); |
| 937 } | 937 } |
| 938 } | 938 } |
| 939 | 939 |
| 940 static void draw_line(SkCanvas* canvas, const SkPoint& p0, const SkPoint& p1, Sk
Color color) { | 940 static void draw_line(SkCanvas* canvas, const SkPoint& p0, const SkPoint& p1, Sk
Color color) { |
| 941 SkPaint p; | 941 SkPaint p; |
| 942 p.setColor(color); | 942 p.setColor(color); |
| 943 | 943 |
| 944 canvas->drawLine(p0.fX, p0.fY, p1.fX, p1.fY, p); | 944 canvas->drawLine(p0.fX, p0.fY, p1.fX, p1.fY, p); |
| 945 } | 945 } |
| 946 | 946 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 978 } | 978 } |
| 979 | 979 |
| 980 SkString num; | 980 SkString num; |
| 981 num.printf("%d", this->origEdgeID(cur)); | 981 num.printf("%d", this->origEdgeID(cur)); |
| 982 canvas->drawText(num.c_str(), num.size(), mid.fX, mid.fY, paint); | 982 canvas->drawText(num.c_str(), num.size(), mid.fX, mid.fY, paint); |
| 983 | 983 |
| 984 if (fPts.count()) { | 984 if (fPts.count()) { |
| 985 draw_arrow(canvas, tess.point(fPts[cur].fIndex), fPts[cur].fBisector
, | 985 draw_arrow(canvas, tess.point(fPts[cur].fIndex), fPts[cur].fBisector
, |
| 986 kArrowLength, SK_ColorBLUE); | 986 kArrowLength, SK_ColorBLUE); |
| 987 } | 987 } |
| 988 } | 988 } |
| 989 } | 989 } |
| 990 | 990 |
| 991 void GrAAConvexTessellator::draw(SkCanvas* canvas) const { | 991 void GrAAConvexTessellator::draw(SkCanvas* canvas) const { |
| 992 for (int i = 0; i < fIndices.count(); i += 3) { | 992 for (int i = 0; i < fIndices.count(); i += 3) { |
| 993 SkASSERT(fIndices[i] < this->numPts()) ; | 993 SkASSERT(fIndices[i] < this->numPts()) ; |
| 994 SkASSERT(fIndices[i+1] < this->numPts()) ; | 994 SkASSERT(fIndices[i+1] < this->numPts()) ; |
| 995 SkASSERT(fIndices[i+2] < this->numPts()) ; | 995 SkASSERT(fIndices[i+2] < this->numPts()) ; |
| 996 | 996 |
| 997 draw_line(canvas, | 997 draw_line(canvas, |
| 998 this->point(this->fIndices[i]), this->point(this->fIndices[i+1
]), | 998 this->point(this->fIndices[i]), this->point(this->fIndices[i+1
]), |
| 999 SK_ColorBLACK); | 999 SK_ColorBLACK); |
| 1000 draw_line(canvas, | 1000 draw_line(canvas, |
| 1001 this->point(this->fIndices[i+1]), this->point(this->fIndices[i
+2]), | 1001 this->point(this->fIndices[i+1]), this->point(this->fIndices[i
+2]), |
| 1002 SK_ColorBLACK); | 1002 SK_ColorBLACK); |
| 1003 draw_line(canvas, | 1003 draw_line(canvas, |
| 1004 this->point(this->fIndices[i+2]), this->point(this->fIndices[i
]), | 1004 this->point(this->fIndices[i+2]), this->point(this->fIndices[i
]), |
| 1005 SK_ColorBLACK); | 1005 SK_ColorBLACK); |
| 1006 } | 1006 } |
| 1007 | 1007 |
| 1008 fInitialRing.draw(canvas, *this); | 1008 fInitialRing.draw(canvas, *this); |
| 1009 for (int i = 0; i < fRings.count(); ++i) { | 1009 for (int i = 0; i < fRings.count(); ++i) { |
| 1010 fRings[i]->draw(canvas, *this); | 1010 fRings[i]->draw(canvas, *this); |
| 1011 } | 1011 } |
| 1012 | 1012 |
| 1013 for (int i = 0; i < this->numPts(); ++i) { | 1013 for (int i = 0; i < this->numPts(); ++i) { |
| 1014 draw_point(canvas, | 1014 draw_point(canvas, |
| 1015 this->point(i), 0.5f + (this->depth(i)/(2 * kAntialiasingRadi
us)), | 1015 this->point(i), 0.5f + (this->depth(i)/(2 * kAntialiasingRadi
us)), |
| 1016 !this->movable(i)); | 1016 !this->movable(i)); |
| 1017 | 1017 |
| 1018 SkPaint paint; | 1018 SkPaint paint; |
| 1019 paint.setTextSize(kPointTextSize); | 1019 paint.setTextSize(kPointTextSize); |
| 1020 paint.setTextAlign(SkPaint::kCenter_Align); | 1020 paint.setTextAlign(SkPaint::kCenter_Align); |
| 1021 if (this->depth(i) <= -kAntialiasingRadius) { | 1021 if (this->depth(i) <= -kAntialiasingRadius) { |
| 1022 paint.setColor(SK_ColorWHITE); | 1022 paint.setColor(SK_ColorWHITE); |
| 1023 } | 1023 } |
| 1024 | 1024 |
| 1025 SkString num; | 1025 SkString num; |
| 1026 num.printf("%d", i); | 1026 num.printf("%d", i); |
| 1027 canvas->drawText(num.c_str(), num.size(), | 1027 canvas->drawText(num.c_str(), num.size(), |
| 1028 this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f
), | 1028 this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f
), |
| 1029 paint); | 1029 paint); |
| 1030 } | 1030 } |
| 1031 } | 1031 } |
| 1032 | 1032 |
| 1033 #endif | 1033 #endif |
| 1034 | |
| OLD | NEW |