| OLD | NEW | 
|---|
| (Empty) |  | 
|  | 1 /* | 
|  | 2  * Copyright 2015 Google Inc. | 
|  | 3  * | 
|  | 4  * Use of this source code is governed by a BSD-style license that can be | 
|  | 5  * found in the LICENSE file. | 
|  | 6  */ | 
|  | 7 | 
|  | 8 #include "GrAAConvexTessellator.h" | 
|  | 9 #include "SkCanvas.h" | 
|  | 10 #include "SkPath.h" | 
|  | 11 #include "SkPoint.h" | 
|  | 12 #include "SkString.h" | 
|  | 13 | 
|  | 14 // Next steps: | 
|  | 15 //  use in AAConvexPathRenderer | 
|  | 16 //  add an interactive sample app slide | 
|  | 17 //  add debug check that all points are suitably far apart | 
|  | 18 //  test more degenerate cases | 
|  | 19 | 
|  | 20 // The tolerance for fusing vertices and eliminating colinear lines (It is in de
     vice space). | 
|  | 21 static const SkScalar kClose = (SK_Scalar1 / 16); | 
|  | 22 static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose); | 
|  | 23 | 
|  | 24 static SkScalar intersect(const SkPoint& p0, const SkPoint& n0, | 
|  | 25                           const SkPoint& p1, const SkPoint& n1) { | 
|  | 26     const SkPoint v = p1 - p0; | 
|  | 27 | 
|  | 28     SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX; | 
|  | 29     return (v.fX * n1.fY - v.fY * n1.fX) / perpDot; | 
|  | 30 } | 
|  | 31 | 
|  | 32 // This is a special case version of intersect where we have the vector | 
|  | 33 // perpendicular to the second line rather than the vector parallel to it. | 
|  | 34 static SkScalar perp_intersect(const SkPoint& p0, const SkPoint& n0, | 
|  | 35                                const SkPoint& p1, const SkPoint& perp) { | 
|  | 36     const SkPoint v = p1 - p0; | 
|  | 37     SkScalar perpDot = n0.dot(perp); | 
|  | 38     return v.dot(perp) / perpDot; | 
|  | 39 } | 
|  | 40 | 
|  | 41 static bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) { | 
|  | 42     SkScalar distSq = p0.distanceToSqd(p1); | 
|  | 43     return distSq < kCloseSqd; | 
|  | 44 } | 
|  | 45 | 
|  | 46 static SkScalar abs_dist_from_line(const SkPoint& p0, const SkVector& v, const S
     kPoint& test) { | 
|  | 47     SkPoint testV = test - p0; | 
|  | 48     SkScalar dist = testV.fX * v.fY - testV.fY * v.fX; | 
|  | 49     return SkScalarAbs(dist); | 
|  | 50 } | 
|  | 51 | 
|  | 52 int GrAAConvexTessellator::addPt(const SkPoint& pt, | 
|  | 53                                  SkScalar depth, | 
|  | 54                                  bool movable) { | 
|  | 55     this->validate(); | 
|  | 56 | 
|  | 57     int index = fPts.count(); | 
|  | 58     *fPts.push() = pt; | 
|  | 59     *fDepths.push() = depth; | 
|  | 60     *fMovable.push() = movable; | 
|  | 61 | 
|  | 62     this->validate(); | 
|  | 63     return index; | 
|  | 64 } | 
|  | 65 | 
|  | 66 void GrAAConvexTessellator::popLastPt() { | 
|  | 67     this->validate(); | 
|  | 68 | 
|  | 69     fPts.pop(); | 
|  | 70     fDepths.pop(); | 
|  | 71     fMovable.pop(); | 
|  | 72 | 
|  | 73     this->validate(); | 
|  | 74 } | 
|  | 75 | 
|  | 76 void GrAAConvexTessellator::popFirstPtShuffle() { | 
|  | 77     this->validate(); | 
|  | 78 | 
|  | 79     fPts.removeShuffle(0); | 
|  | 80     fDepths.removeShuffle(0); | 
|  | 81     fMovable.removeShuffle(0); | 
|  | 82 | 
|  | 83     this->validate(); | 
|  | 84 } | 
|  | 85 | 
|  | 86 void GrAAConvexTessellator::updatePt(int index, | 
|  | 87                                      const SkPoint& pt, | 
|  | 88                                      SkScalar depth) { | 
|  | 89     this->validate(); | 
|  | 90     SkASSERT(fMovable[index]); | 
|  | 91 | 
|  | 92     fPts[index] = pt; | 
|  | 93     fDepths[index] = depth; | 
|  | 94 } | 
|  | 95 | 
|  | 96 void GrAAConvexTessellator::addTri(int i0, int i1, int i2) { | 
|  | 97     if (i0 == i1 || i1 == i2 || i2 == i0) { | 
|  | 98         return; | 
|  | 99     } | 
|  | 100 | 
|  | 101     *fIndices.push() = i0; | 
|  | 102     *fIndices.push() = i1; | 
|  | 103     *fIndices.push() = i2; | 
|  | 104 } | 
|  | 105 | 
|  | 106 void GrAAConvexTessellator::rewind() { | 
|  | 107     fPts.rewind(); | 
|  | 108     fDepths.rewind(); | 
|  | 109     fMovable.rewind(); | 
|  | 110     fIndices.rewind(); | 
|  | 111     fNorms.rewind(); | 
|  | 112     fInitialRing.rewind(); | 
|  | 113     fCandidateVerts.rewind(); | 
|  | 114 #if GR_AA_CONVEX_TESSELLATOR_VIZ | 
|  | 115     fRings.rewind();        // TODO: leak in this case! | 
|  | 116 #else | 
|  | 117     fRings[0].rewind(); | 
|  | 118     fRings[1].rewind(); | 
|  | 119 #endif | 
|  | 120 } | 
|  | 121 | 
|  | 122 void GrAAConvexTessellator::computeBisectors() { | 
|  | 123     fBisectors.setCount(fNorms.count()); | 
|  | 124 | 
|  | 125     int prev = fBisectors.count() - 1; | 
|  | 126     for (int cur = 0; cur < fBisectors.count(); prev = cur, ++cur) { | 
|  | 127         fBisectors[cur] = fNorms[cur] + fNorms[prev]; | 
|  | 128         fBisectors[cur].normalize(); | 
|  | 129         fBisectors[cur].negate();      // make the bisector face in | 
|  | 130 | 
|  | 131         SkASSERT(SkScalarNearlyEqual(1.0f, fBisectors[cur].length())); | 
|  | 132     } | 
|  | 133 } | 
|  | 134 | 
|  | 135 // The general idea here is to, conceptually, start with the original polygon an
     d slide | 
|  | 136 // the vertices along the bisectors until the first intersection. At that | 
|  | 137 // point two of the edges collapse and the process repeats on the new polygon. | 
|  | 138 // The polygon state is captured in the Ring class while the GrAAConvexTessellat
     or | 
|  | 139 // controls the iteration. The CandidateVerts holds the formative points for the | 
|  | 140 // next ring. | 
|  | 141 bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { | 
|  | 142     static const int kMaxNumRings = 8; | 
|  | 143 | 
|  | 144     SkDEBUGCODE(fShouldCheckDepths = true;) | 
|  | 145 | 
|  | 146     if (!this->extractFromPath(m, path)) { | 
|  | 147         return false; | 
|  | 148     } | 
|  | 149 | 
|  | 150     this->createOuterRing(); | 
|  | 151 | 
|  | 152     // the bisectors are only needed for the computation of the outer ring | 
|  | 153     fBisectors.rewind(); | 
|  | 154 | 
|  | 155     Ring* lastRing = &fInitialRing; | 
|  | 156     int i; | 
|  | 157     for (i = 0; i < kMaxNumRings; ++i) { | 
|  | 158         Ring* nextRing = this->getNextRing(lastRing); | 
|  | 159 | 
|  | 160         if (this->createInsetRing(*lastRing, nextRing)) { | 
|  | 161             break; | 
|  | 162         } | 
|  | 163 | 
|  | 164         nextRing->init(*this); | 
|  | 165         lastRing = nextRing; | 
|  | 166     } | 
|  | 167 | 
|  | 168     if (kMaxNumRings == i) { | 
|  | 169         // If we've exceeded the amount of time we want to throw at this, set | 
|  | 170         // the depth of all points in the final ring to 'fTargetDepth' and | 
|  | 171         // create a fan. | 
|  | 172         this->terminate(*lastRing); | 
|  | 173         SkDEBUGCODE(fShouldCheckDepths = false;) | 
|  | 174     } | 
|  | 175 | 
|  | 176 #ifdef SK_DEBUG | 
|  | 177     this->validate(); | 
|  | 178     if (fShouldCheckDepths) { | 
|  | 179         SkDEBUGCODE(this->checkAllDepths();) | 
|  | 180     } | 
|  | 181 #endif | 
|  | 182     return true; | 
|  | 183 } | 
|  | 184 | 
|  | 185 SkScalar GrAAConvexTessellator::computeDepthFromEdge(int edgeIdx, const SkPoint&
      p) const { | 
|  | 186     SkASSERT(edgeIdx < fNorms.count()); | 
|  | 187 | 
|  | 188     SkPoint v = p - fPts[edgeIdx]; | 
|  | 189     SkScalar depth = -fNorms[edgeIdx].dot(v); | 
|  | 190     SkASSERT(depth >= 0.0f); | 
|  | 191     return depth; | 
|  | 192 } | 
|  | 193 | 
|  | 194 // Find a point that is 'desiredDepth' away from the 'edgeIdx'-th edge and lies | 
|  | 195 // along the 'bisector' from the 'startIdx'-th point. | 
|  | 196 bool GrAAConvexTessellator::computePtAlongBisector(int startIdx, | 
|  | 197                                                    const SkVector& bisector, | 
|  | 198                                                    int edgeIdx, | 
|  | 199                                                    SkScalar desiredDepth, | 
|  | 200                                                    SkPoint* result) const { | 
|  | 201     const SkPoint& norm = fNorms[edgeIdx]; | 
|  | 202 | 
|  | 203     // First find the point where the edge and the bisector intersect | 
|  | 204     SkPoint newP; | 
|  | 205     SkScalar t = perp_intersect(fPts[startIdx], bisector, fPts[edgeIdx], norm); | 
|  | 206     if (SkScalarNearlyEqual(t, 0.0f)) { | 
|  | 207         // the start point was one of the original ring points | 
|  | 208         SkASSERT(startIdx < fNorms.count()); | 
|  | 209         newP = fPts[startIdx]; | 
|  | 210     } else if (t > 0.0f) { | 
|  | 211         SkASSERT(t < 0.0f); | 
|  | 212         newP = bisector; | 
|  | 213         newP.scale(t); | 
|  | 214         newP += fPts[startIdx]; | 
|  | 215     } else { | 
|  | 216         return false; | 
|  | 217     } | 
|  | 218 | 
|  | 219     // Then offset along the bisector from that point the correct distance | 
|  | 220     t = -desiredDepth / bisector.dot(norm); | 
|  | 221     SkASSERT(t > 0.0f); | 
|  | 222     *result = bisector; | 
|  | 223     result->scale(t); | 
|  | 224     *result += newP; | 
|  | 225 | 
|  | 226 | 
|  | 227     return true; | 
|  | 228 } | 
|  | 229 | 
|  | 230 bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat
     h) { | 
|  | 231     SkASSERT(SkPath::kLine_SegmentMask == path.getSegmentMasks()); | 
|  | 232     SkASSERT(SkPath::kConvex_Convexity == path.getConvexity()); | 
|  | 233 | 
|  | 234     // Outer ring: 3*numPts | 
|  | 235     // Middle ring: numPts | 
|  | 236     // Presumptive inner ring: numPts | 
|  | 237     this->reservePts(5*path.countPoints()); | 
|  | 238     // Outer ring: 12*numPts | 
|  | 239     // Middle ring: 0 | 
|  | 240     // Presumptive inner ring: 6*numPts + 6 | 
|  | 241     fIndices.setReserve(18*path.countPoints() + 6); | 
|  | 242 | 
|  | 243     fNorms.setReserve(path.countPoints()); | 
|  | 244 | 
|  | 245     SkScalar minCross = SK_ScalarMax, maxCross = -SK_ScalarMax; | 
|  | 246 | 
|  | 247     // TODO: is there a faster way to extract the points from the path? Perhaps | 
|  | 248     // get all the points via a new entry point, transform them all in bulk | 
|  | 249     // and then walk them to find duplicates? | 
|  | 250     SkPath::Iter iter(path, true); | 
|  | 251     SkPoint pts[4]; | 
|  | 252     SkPath::Verb verb; | 
|  | 253     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { | 
|  | 254         switch (verb) { | 
|  | 255             case SkPath::kLine_Verb: | 
|  | 256                 m.mapPoints(&pts[1], 1); | 
|  | 257                 if (this->numPts() > 0 && duplicate_pt(pts[1], this->lastPoint()
     )) { | 
|  | 258                     continue; | 
|  | 259                 } | 
|  | 260 | 
|  | 261                 SkASSERT(fPts.count() <= 1 || fPts.count() == fNorms.count()+1); | 
|  | 262                 if (this->numPts() >= 2 && | 
|  | 263                     abs_dist_from_line(fPts.top(), fNorms.top(), pts[1]) < kClos
     e) { | 
|  | 264                     // The old last point is on the line from the second to last
      to the new point | 
|  | 265                     this->popLastPt(); | 
|  | 266                     fNorms.pop(); | 
|  | 267                 } | 
|  | 268 | 
|  | 269                 this->addPt(pts[1], 0.0f, false); | 
|  | 270                 if (this->numPts() > 1) { | 
|  | 271                     *fNorms.push() = fPts.top() - fPts[fPts.count()-2]; | 
|  | 272                     SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top()
     ); | 
|  | 273                     SkASSERT(len > 0.0f); | 
|  | 274                     SkASSERT(SkScalarNearlyEqual(1.0f, fNorms.top().length())); | 
|  | 275                 } | 
|  | 276 | 
|  | 277                 if (this->numPts() >= 3) { | 
|  | 278                     int cur = this->numPts()-1; | 
|  | 279                     SkScalar cross = SkPoint::CrossProduct(fNorms[cur-1], fNorms
     [cur-2]); | 
|  | 280                     maxCross = SkTMax(maxCross, cross); | 
|  | 281                     minCross = SkTMin(minCross, cross); | 
|  | 282                 } | 
|  | 283                 break; | 
|  | 284             case SkPath::kQuad_Verb: | 
|  | 285             case SkPath::kConic_Verb: | 
|  | 286             case SkPath::kCubic_Verb: | 
|  | 287                 SkASSERT(false); | 
|  | 288                 break; | 
|  | 289             case SkPath::kMove_Verb: | 
|  | 290             case SkPath::kClose_Verb: | 
|  | 291             case SkPath::kDone_Verb: | 
|  | 292                 break; | 
|  | 293         } | 
|  | 294     } | 
|  | 295 | 
|  | 296     if (this->numPts() < 3) { | 
|  | 297         return false; | 
|  | 298     } | 
|  | 299 | 
|  | 300     // check if last point is a duplicate of the first point. If so, remove it. | 
|  | 301     if (duplicate_pt(fPts[this->numPts()-1], fPts[0])) { | 
|  | 302         this->popLastPt(); | 
|  | 303         fNorms.pop(); | 
|  | 304     } | 
|  | 305 | 
|  | 306     SkASSERT(fPts.count() == fNorms.count()+1); | 
|  | 307     if (this->numPts() >= 3 && | 
|  | 308         abs_dist_from_line(fPts.top(), fNorms.top(), fPts[0]) < kClose) { | 
|  | 309         // The last point is on the line from the second to last to the first po
     int. | 
|  | 310         this->popLastPt(); | 
|  | 311         fNorms.pop(); | 
|  | 312     } | 
|  | 313 | 
|  | 314     if (this->numPts() < 3) { | 
|  | 315         return false; | 
|  | 316     } | 
|  | 317 | 
|  | 318     *fNorms.push() = fPts[0] - fPts.top(); | 
|  | 319     SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top()); | 
|  | 320     SkASSERT(len > 0.0f); | 
|  | 321     SkASSERT(fPts.count() == fNorms.count()); | 
|  | 322 | 
|  | 323     if (abs_dist_from_line(fPts[0], fNorms.top(), fPts[1]) < kClose) { | 
|  | 324         // The first point is on the line from the last to the second. | 
|  | 325         this->popFirstPtShuffle(); | 
|  | 326         fNorms.removeShuffle(0); | 
|  | 327         fNorms[0] = fPts[1] - fPts[0]; | 
|  | 328         SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms[0]); | 
|  | 329         SkASSERT(len > 0.0f); | 
|  | 330         SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[0].length())); | 
|  | 331     } | 
|  | 332 | 
|  | 333     if (this->numPts() < 3) { | 
|  | 334         return false; | 
|  | 335     } | 
|  | 336 | 
|  | 337     // Check the cross produce of the final trio | 
|  | 338     SkScalar cross = SkPoint::CrossProduct(fNorms[0], fNorms.top()); | 
|  | 339     maxCross = SkTMax(maxCross, cross); | 
|  | 340     minCross = SkTMin(minCross, cross); | 
|  | 341 | 
|  | 342     if (maxCross > 0.0f) { | 
|  | 343         SkASSERT(minCross >= 0.0f); | 
|  | 344         fSide = SkPoint::kRight_Side; | 
|  | 345     } else { | 
|  | 346         SkASSERT(minCross <= 0.0f); | 
|  | 347         fSide = SkPoint::kLeft_Side; | 
|  | 348     } | 
|  | 349 | 
|  | 350     // Make all the normals face outwards rather than along the edge | 
|  | 351     for (int cur = 0; cur < fNorms.count(); ++cur) { | 
|  | 352         fNorms[cur].setOrthog(fNorms[cur], fSide); | 
|  | 353         SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); | 
|  | 354     } | 
|  | 355 | 
|  | 356     this->computeBisectors(); | 
|  | 357 | 
|  | 358     fCandidateVerts.setReserve(this->numPts()); | 
|  | 359     fInitialRing.setReserve(this->numPts()); | 
|  | 360     for (int i = 0; i < this->numPts(); ++i) { | 
|  | 361         fInitialRing.addIdx(i, i); | 
|  | 362     } | 
|  | 363     fInitialRing.init(fNorms, fBisectors); | 
|  | 364 | 
|  | 365     this->validate(); | 
|  | 366     return true; | 
|  | 367 } | 
|  | 368 | 
|  | 369 GrAAConvexTessellator::Ring* GrAAConvexTessellator::getNextRing(Ring* lastRing) 
     { | 
|  | 370 #if GR_AA_CONVEX_TESSELLATOR_VIZ | 
|  | 371     Ring* ring = *fRings.push() = SkNEW(Ring); | 
|  | 372     ring->setReserve(fInitialRing.numPts()); | 
|  | 373     ring->rewind(); | 
|  | 374     return ring; | 
|  | 375 #else | 
|  | 376     // Flip flop back and forth between fRings[0] & fRings[1] | 
|  | 377     int nextRing = (lastRing == &fRings[0]) ? 1 : 0; | 
|  | 378     fRings[nextRing].setReserve(fInitialRing.numPts()); | 
|  | 379     fRings[nextRing].rewind(); | 
|  | 380     return &fRings[nextRing]; | 
|  | 381 #endif | 
|  | 382 } | 
|  | 383 | 
|  | 384 void GrAAConvexTessellator::fanRing(const Ring& ring) { | 
|  | 385     // fan out from point 0 | 
|  | 386     for (int cur = 1; cur < ring.numPts()-1; ++cur) { | 
|  | 387         this->addTri(ring.index(0), ring.index(cur), ring.index(cur+1)); | 
|  | 388     } | 
|  | 389 } | 
|  | 390 | 
|  | 391 void GrAAConvexTessellator::createOuterRing() { | 
|  | 392     // For now, we're only generating one outer ring (at the start). This | 
|  | 393     // could be relaxed for stroking use cases. | 
|  | 394     SkASSERT(0 == fIndices.count()); | 
|  | 395     SkASSERT(fPts.count() == fNorms.count()); | 
|  | 396 | 
|  | 397     const int numPts = fPts.count(); | 
|  | 398 | 
|  | 399     // For each vertex of the original polygon we add three points to the | 
|  | 400     // outset polygon - one extending perpendicular to each impinging edge | 
|  | 401     // and one along the bisector. Two triangles are added for each corner | 
|  | 402     // and two are added along each edge. | 
|  | 403     int prev = numPts - 1; | 
|  | 404     int lastPerpIdx = -1, firstPerpIdx = -1, newIdx0, newIdx1, newIdx2; | 
|  | 405     for (int cur = 0; cur < numPts; ++cur) { | 
|  | 406         // The perpendicular point for the last edge | 
|  | 407         SkPoint temp = fNorms[prev]; | 
|  | 408         temp.scale(fTargetDepth); | 
|  | 409         temp += fPts[cur]; | 
|  | 410 | 
|  | 411         // We know it isn't a duplicate of the prior point (since it and this | 
|  | 412         // one are just perpendicular offsets from the non-merged polygon points
     ) | 
|  | 413         newIdx0 = this->addPt(temp, -fTargetDepth, false); | 
|  | 414 | 
|  | 415         // The bisector outset point | 
|  | 416         temp = fBisectors[cur]; | 
|  | 417         temp.scale(-fTargetDepth);  // the bisectors point in | 
|  | 418         temp += fPts[cur]; | 
|  | 419 | 
|  | 420         // For very shallow angles all the corner points could fuse | 
|  | 421         if (duplicate_pt(temp, this->point(newIdx0))) { | 
|  | 422             newIdx1 = newIdx0; | 
|  | 423         } else { | 
|  | 424             newIdx1 = this->addPt(temp, -fTargetDepth, false); | 
|  | 425         } | 
|  | 426 | 
|  | 427         // The perpendicular point for the next edge. | 
|  | 428         temp = fNorms[cur]; | 
|  | 429         temp.scale(fTargetDepth); | 
|  | 430         temp += fPts[cur]; | 
|  | 431 | 
|  | 432         // For very shallow angles all the corner points could fuse. | 
|  | 433         if (duplicate_pt(temp, this->point(newIdx1))) { | 
|  | 434             newIdx2 = newIdx1; | 
|  | 435         } else { | 
|  | 436             newIdx2 = this->addPt(temp, -fTargetDepth, false); | 
|  | 437         } | 
|  | 438 | 
|  | 439         if (0 == cur) { | 
|  | 440             // Store the index of the first perpendicular point to finish up | 
|  | 441             firstPerpIdx = newIdx0; | 
|  | 442             SkASSERT(-1 == lastPerpIdx); | 
|  | 443         } else { | 
|  | 444             // The triangles for the previous edge | 
|  | 445             this->addTri(prev, newIdx0, cur); | 
|  | 446             this->addTri(prev, lastPerpIdx, newIdx0); | 
|  | 447         } | 
|  | 448 | 
|  | 449         // The two triangles for the corner | 
|  | 450         this->addTri(cur, newIdx0, newIdx1); | 
|  | 451         this->addTri(cur, newIdx1, newIdx2); | 
|  | 452 | 
|  | 453         prev = cur; | 
|  | 454         // Track the last perpendicular outset point so we can construct the | 
|  | 455         // trailing edge triangles. | 
|  | 456         lastPerpIdx = newIdx2; | 
|  | 457     } | 
|  | 458 | 
|  | 459     // pick up the final edge rect | 
|  | 460     this->addTri(numPts-1, firstPerpIdx, 0); | 
|  | 461     this->addTri(numPts-1, lastPerpIdx, firstPerpIdx); | 
|  | 462 | 
|  | 463     this->validate(); | 
|  | 464 } | 
|  | 465 | 
|  | 466 // Something went wrong in the creation of the next ring. Mark the last good | 
|  | 467 // ring as being at the desired depth and fan it. | 
|  | 468 void GrAAConvexTessellator::terminate(const Ring& ring) { | 
|  | 469     for (int i = 0; i < ring.numPts(); ++i) { | 
|  | 470         fDepths[ring.index(i)] = fTargetDepth; | 
|  | 471     } | 
|  | 472 | 
|  | 473     this->fanRing(ring); | 
|  | 474 } | 
|  | 475 | 
|  | 476 // return true when processing is complete | 
|  | 477 bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing
     ) { | 
|  | 478     bool done = false; | 
|  | 479 | 
|  | 480     fCandidateVerts.rewind(); | 
|  | 481 | 
|  | 482     // Loop through all the points in the ring and find the intersection with th
     e smallest depth | 
|  | 483     SkScalar minDist = SK_ScalarMax, minT = 0.0f; | 
|  | 484     int minEdgeIdx = -1; | 
|  | 485 | 
|  | 486     for (int cur = 0; cur < lastRing.numPts(); ++cur) { | 
|  | 487         int next = (cur + 1) % lastRing.numPts(); | 
|  | 488 | 
|  | 489         SkScalar t = intersect(this->point(lastRing.index(cur)),  lastRing.bisec
     tor(cur), | 
|  | 490                                this->point(lastRing.index(next)), lastRing.bisec
     tor(next)); | 
|  | 491         SkScalar dist = -t * lastRing.norm(cur).dot(lastRing.bisector(cur)); | 
|  | 492 | 
|  | 493         if (minDist > dist) { | 
|  | 494             minDist = dist; | 
|  | 495             minT = t; | 
|  | 496             minEdgeIdx = cur; | 
|  | 497         } | 
|  | 498     } | 
|  | 499 | 
|  | 500     SkPoint newPt = lastRing.bisector(minEdgeIdx); | 
|  | 501     newPt.scale(minT); | 
|  | 502     newPt += this->point(lastRing.index(minEdgeIdx)); | 
|  | 503 | 
|  | 504     SkScalar depth = this->computeDepthFromEdge(lastRing.origEdgeID(minEdgeIdx),
      newPt); | 
|  | 505     if (depth >= fTargetDepth) { | 
|  | 506         // None of the bisectors intersect before reaching the desired depth. | 
|  | 507         // Just step them all to the desired depth | 
|  | 508         depth = fTargetDepth; | 
|  | 509         done = true; | 
|  | 510     } | 
|  | 511 | 
|  | 512     // 'dst' stores where each point in the last ring maps to/transforms into | 
|  | 513     // in the next ring. | 
|  | 514     SkTDArray<int> dst; | 
|  | 515     dst.setCount(lastRing.numPts()); | 
|  | 516 | 
|  | 517     // Create the first point (who compares with no one) | 
|  | 518     if (!this->computePtAlongBisector(lastRing.index(0), | 
|  | 519                                       lastRing.bisector(0), | 
|  | 520                                       lastRing.origEdgeID(0), | 
|  | 521                                       depth, &newPt)) { | 
|  | 522         this->terminate(lastRing); | 
|  | 523         SkDEBUGCODE(fShouldCheckDepths = false;) | 
|  | 524         return true; | 
|  | 525     } | 
|  | 526     dst[0] = fCandidateVerts.addNewPt(newPt, | 
|  | 527                                       lastRing.index(0), lastRing.origEdgeID(0), | 
|  | 528                                       !this->movable(lastRing.index(0))); | 
|  | 529 | 
|  | 530     // Handle the middle points (who only compare with the prior point) | 
|  | 531     for (int cur = 1; cur < lastRing.numPts()-1; ++cur) { | 
|  | 532         if (!this->computePtAlongBisector(lastRing.index(cur), | 
|  | 533                                           lastRing.bisector(cur), | 
|  | 534                                           lastRing.origEdgeID(cur), | 
|  | 535                                           depth, &newPt)) { | 
|  | 536             this->terminate(lastRing); | 
|  | 537             SkDEBUGCODE(fShouldCheckDepths = false;) | 
|  | 538             return true; | 
|  | 539         } | 
|  | 540         if (!duplicate_pt(newPt, fCandidateVerts.lastPoint())) { | 
|  | 541             dst[cur] = fCandidateVerts.addNewPt(newPt, | 
|  | 542                                                 lastRing.index(cur), lastRing.or
     igEdgeID(cur), | 
|  | 543                                                 !this->movable(lastRing.index(cu
     r))); | 
|  | 544         } else { | 
|  | 545             dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); | 
|  | 546         } | 
|  | 547     } | 
|  | 548 | 
|  | 549     // Check on the last point (handling the wrap around) | 
|  | 550     int cur = lastRing.numPts()-1; | 
|  | 551     if  (!this->computePtAlongBisector(lastRing.index(cur), | 
|  | 552                                        lastRing.bisector(cur), | 
|  | 553                                        lastRing.origEdgeID(cur), | 
|  | 554                                        depth, &newPt)) { | 
|  | 555         this->terminate(lastRing); | 
|  | 556         SkDEBUGCODE(fShouldCheckDepths = false;) | 
|  | 557         return true; | 
|  | 558     } | 
|  | 559     bool dupPrev = duplicate_pt(newPt, fCandidateVerts.lastPoint()); | 
|  | 560     bool dupNext = duplicate_pt(newPt, fCandidateVerts.firstPoint()); | 
|  | 561 | 
|  | 562     if (!dupPrev && !dupNext) { | 
|  | 563         dst[cur] = fCandidateVerts.addNewPt(newPt, | 
|  | 564                                             lastRing.index(cur), lastRing.origEd
     geID(cur), | 
|  | 565                                             !this->movable(lastRing.index(cur)))
     ; | 
|  | 566     } else if (dupPrev && !dupNext) { | 
|  | 567         dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); | 
|  | 568     } else if (!dupPrev && dupNext) { | 
|  | 569         dst[cur] = fCandidateVerts.fuseWithNext(); | 
|  | 570     } else { | 
|  | 571         bool dupPrevVsNext = duplicate_pt(fCandidateVerts.firstPoint(), fCandida
     teVerts.lastPoint()); | 
|  | 572 | 
|  | 573         if (!dupPrevVsNext) { | 
|  | 574             dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); | 
|  | 575         } else { | 
|  | 576             dst[cur] = dst[cur-1] = fCandidateVerts.fuseWithBoth(); | 
|  | 577         } | 
|  | 578     } | 
|  | 579 | 
|  | 580     // Fold the new ring's points into the global pool | 
|  | 581     for (int i = 0; i < fCandidateVerts.numPts(); ++i) { | 
|  | 582         int newIdx; | 
|  | 583         if (fCandidateVerts.needsToBeNew(i)) { | 
|  | 584             // if the originating index is still valid then this point wasn't | 
|  | 585             // fused (and is thus movable) | 
|  | 586             newIdx = this->addPt(fCandidateVerts.point(i), depth, | 
|  | 587                                  fCandidateVerts.originatingIdx(i) != -1); | 
|  | 588         } else { | 
|  | 589             SkASSERT(fCandidateVerts.originatingIdx(i) != -1); | 
|  | 590             this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.po
     int(i), depth); | 
|  | 591             newIdx = fCandidateVerts.originatingIdx(i); | 
|  | 592         } | 
|  | 593 | 
|  | 594         nextRing->addIdx(newIdx, fCandidateVerts.origEdge(i)); | 
|  | 595     } | 
|  | 596 | 
|  | 597     // 'dst' currently has indices into the ring. Remap these to be indices | 
|  | 598     // into the global pool since the triangulation operates in that space. | 
|  | 599     for (int i = 0; i < dst.count(); ++i) { | 
|  | 600         dst[i] = nextRing->index(dst[i]); | 
|  | 601     } | 
|  | 602 | 
|  | 603     for (int cur = 0; cur < lastRing.numPts(); ++cur) { | 
|  | 604         int next = (cur + 1) % lastRing.numPts(); | 
|  | 605 | 
|  | 606         this->addTri(lastRing.index(cur), lastRing.index(next), dst[next]); | 
|  | 607         this->addTri(lastRing.index(cur), dst[next], dst[cur]); | 
|  | 608     } | 
|  | 609 | 
|  | 610     if (done) { | 
|  | 611         this->fanRing(*nextRing); | 
|  | 612     } | 
|  | 613 | 
|  | 614     if (nextRing->numPts() < 3) { | 
|  | 615         done = true; | 
|  | 616     } | 
|  | 617 | 
|  | 618     return done; | 
|  | 619 } | 
|  | 620 | 
|  | 621 void GrAAConvexTessellator::validate() const { | 
|  | 622     SkASSERT(fPts.count() == fDepths.count()); | 
|  | 623     SkASSERT(fPts.count() == fMovable.count()); | 
|  | 624     SkASSERT(0 == (fIndices.count() % 3)); | 
|  | 625 } | 
|  | 626 | 
|  | 627 ////////////////////////////////////////////////////////////////////////////// | 
|  | 628 void GrAAConvexTessellator::Ring::init(const GrAAConvexTessellator& tess) { | 
|  | 629     this->computeNormals(tess); | 
|  | 630     this->computeBisectors(); | 
|  | 631     SkASSERT(this->isConvex(tess)); | 
|  | 632 } | 
|  | 633 | 
|  | 634 void GrAAConvexTessellator::Ring::init(const SkTDArray<SkVector>& norms, | 
|  | 635                                        const SkTDArray<SkVector>& bisectors) { | 
|  | 636     for (int i = 0; i < fPts.count(); ++i) { | 
|  | 637         fPts[i].fNorm = norms[i]; | 
|  | 638         fPts[i].fBisector = bisectors[i]; | 
|  | 639     } | 
|  | 640 } | 
|  | 641 | 
|  | 642 // Compute the outward facing normal at each vertex. | 
|  | 643 void GrAAConvexTessellator::Ring::computeNormals(const GrAAConvexTessellator& te
     ss) { | 
|  | 644     for (int cur = 0; cur < fPts.count(); ++cur) { | 
|  | 645         int next = (cur + 1) % fPts.count(); | 
|  | 646 | 
|  | 647         fPts[cur].fNorm = tess.point(fPts[next].fIndex) - tess.point(fPts[cur].f
     Index); | 
|  | 648         SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fPts[cur].fNorm); | 
|  | 649         SkASSERT(len > 0.0f); | 
|  | 650         fPts[cur].fNorm.setOrthog(fPts[cur].fNorm, tess.side()); | 
|  | 651 | 
|  | 652         SkASSERT(SkScalarNearlyEqual(1.0f, fPts[cur].fNorm.length())); | 
|  | 653     } | 
|  | 654 } | 
|  | 655 | 
|  | 656 void GrAAConvexTessellator::Ring::computeBisectors() { | 
|  | 657     int prev = fPts.count() - 1; | 
|  | 658     for (int cur = 0; cur < fPts.count(); prev = cur, ++cur) { | 
|  | 659         fPts[cur].fBisector = fPts[cur].fNorm + fPts[prev].fNorm; | 
|  | 660         fPts[cur].fBisector.normalize(); | 
|  | 661         fPts[cur].fBisector.negate();      // make the bisector face in | 
|  | 662 | 
|  | 663         SkASSERT(SkScalarNearlyEqual(1.0f, fPts[cur].fBisector.length())); | 
|  | 664     } | 
|  | 665 } | 
|  | 666 | 
|  | 667 ////////////////////////////////////////////////////////////////////////////// | 
|  | 668 #ifdef SK_DEBUG | 
|  | 669 // Is this ring convex? | 
|  | 670 bool GrAAConvexTessellator::Ring::isConvex(const GrAAConvexTessellator& tess) co
     nst { | 
|  | 671     if (fPts.count() < 3) { | 
|  | 672         return false; | 
|  | 673     } | 
|  | 674 | 
|  | 675     SkPoint prev = tess.point(fPts[0].fIndex) - tess.point(fPts.top().fIndex); | 
|  | 676     SkPoint cur  = tess.point(fPts[1].fIndex) - tess.point(fPts[0].fIndex); | 
|  | 677     SkScalar minDot = prev.fX * cur.fY - prev.fY * cur.fX; | 
|  | 678     SkScalar maxDot = minDot; | 
|  | 679 | 
|  | 680     prev = cur; | 
|  | 681     for (int i = 1; i < fPts.count(); ++i) { | 
|  | 682         int next = (i + 1) % fPts.count(); | 
|  | 683 | 
|  | 684         cur  = tess.point(fPts[next].fIndex) - tess.point(fPts[i].fIndex); | 
|  | 685         SkScalar dot = prev.fX * cur.fY - prev.fY * cur.fX; | 
|  | 686 | 
|  | 687         minDot = SkMinScalar(minDot, dot); | 
|  | 688         maxDot = SkMaxScalar(maxDot, dot); | 
|  | 689 | 
|  | 690         prev = cur; | 
|  | 691     } | 
|  | 692 | 
|  | 693     return (maxDot > 0.0f) == (minDot >= 0.0f); | 
|  | 694 } | 
|  | 695 | 
|  | 696 static SkScalar capsule_depth(const SkPoint& p0, const SkPoint& p1, | 
|  | 697                               const SkPoint& test, SkPoint::Side side, | 
|  | 698                               int* sign) { | 
|  | 699     *sign = -1; | 
|  | 700     SkPoint edge = p1 - p0; | 
|  | 701     SkScalar len = SkPoint::Normalize(&edge); | 
|  | 702 | 
|  | 703     SkPoint testVec = test - p0; | 
|  | 704 | 
|  | 705     SkScalar d0 = edge.dot(testVec); | 
|  | 706     if (d0 < 0.0f) { | 
|  | 707         return SkPoint::Distance(p0, test); | 
|  | 708     } | 
|  | 709     if (d0 > len) { | 
|  | 710         return SkPoint::Distance(p1, test); | 
|  | 711     } | 
|  | 712 | 
|  | 713     SkScalar perpDist = testVec.fY * edge.fX - testVec.fX * edge.fY; | 
|  | 714     if (SkPoint::kRight_Side == side) { | 
|  | 715         perpDist = -perpDist; | 
|  | 716     } | 
|  | 717 | 
|  | 718     if (perpDist < 0.0f) { | 
|  | 719         perpDist = -perpDist; | 
|  | 720     } else { | 
|  | 721         *sign = 1; | 
|  | 722     } | 
|  | 723     return perpDist; | 
|  | 724 } | 
|  | 725 | 
|  | 726 SkScalar GrAAConvexTessellator::computeRealDepth(const SkPoint& p) const { | 
|  | 727     SkScalar minDist = SK_ScalarMax; | 
|  | 728     int closestSign, sign; | 
|  | 729 | 
|  | 730     for (int edge = 0; edge < fNorms.count(); ++edge) { | 
|  | 731         SkScalar dist = capsule_depth(this->point(edge), | 
|  | 732                                       this->point((edge+1) % fNorms.count()), | 
|  | 733                                       p, fSide, &sign); | 
|  | 734         SkASSERT(dist >= 0.0f); | 
|  | 735 | 
|  | 736         if (minDist > dist) { | 
|  | 737             minDist = dist; | 
|  | 738             closestSign = sign; | 
|  | 739         } | 
|  | 740     } | 
|  | 741 | 
|  | 742     return closestSign * minDist; | 
|  | 743 } | 
|  | 744 | 
|  | 745 // Verify that the incrementally computed depths are close to the actual depths. | 
|  | 746 void GrAAConvexTessellator::checkAllDepths() const { | 
|  | 747     for (int cur = 0; cur < this->numPts(); ++cur) { | 
|  | 748         SkScalar realDepth = this->computeRealDepth(this->point(cur)); | 
|  | 749         SkScalar computedDepth = this->depth(cur); | 
|  | 750         SkASSERT(SkScalarNearlyEqual(realDepth, computedDepth, 0.01f)); | 
|  | 751     } | 
|  | 752 } | 
|  | 753 #endif | 
|  | 754 | 
|  | 755 ////////////////////////////////////////////////////////////////////////////// | 
|  | 756 #if GR_AA_CONVEX_TESSELLATOR_VIZ | 
|  | 757 static const SkScalar kPointRadius = 0.02f; | 
|  | 758 static const SkScalar kArrowStrokeWidth = 0.0f; | 
|  | 759 static const SkScalar kArrowLength = 0.2f; | 
|  | 760 static const SkScalar kEdgeTextSize = 0.1f; | 
|  | 761 static const SkScalar kPointTextSize = 0.02f; | 
|  | 762 | 
|  | 763 static void draw_point(SkCanvas* canvas, const SkPoint& p, SkScalar paramValue, 
     bool stroke) { | 
|  | 764     SkPaint paint; | 
|  | 765     SkASSERT(paramValue <= 1.0f); | 
|  | 766     int gs = int(255*paramValue); | 
|  | 767     paint.setARGB(255, gs, gs, gs); | 
|  | 768 | 
|  | 769     canvas->drawCircle(p.fX, p.fY, kPointRadius, paint); | 
|  | 770 | 
|  | 771     if (stroke) { | 
|  | 772         SkPaint stroke; | 
|  | 773         stroke.setColor(SK_ColorYELLOW); | 
|  | 774         stroke.setStyle(SkPaint::kStroke_Style); | 
|  | 775         stroke.setStrokeWidth(kPointRadius/3.0f); | 
|  | 776         canvas->drawCircle(p.fX, p.fY, kPointRadius, stroke); | 
|  | 777     } | 
|  | 778 } | 
|  | 779 | 
|  | 780 static void draw_line(SkCanvas* canvas, const SkPoint& p0, const SkPoint& p1, Sk
     Color color) { | 
|  | 781     SkPaint p; | 
|  | 782     p.setColor(color); | 
|  | 783 | 
|  | 784     canvas->drawLine(p0.fX, p0.fY, p1.fX, p1.fY, p); | 
|  | 785 } | 
|  | 786 | 
|  | 787 static void draw_arrow(SkCanvas*canvas, const SkPoint& p, const SkPoint &n, | 
|  | 788                        SkScalar len, SkColor color) { | 
|  | 789     SkPaint paint; | 
|  | 790     paint.setColor(color); | 
|  | 791     paint.setStrokeWidth(kArrowStrokeWidth); | 
|  | 792     paint.setStyle(SkPaint::kStroke_Style); | 
|  | 793 | 
|  | 794     canvas->drawLine(p.fX, p.fY, | 
|  | 795                      p.fX + len * n.fX, p.fY + len * n.fY, | 
|  | 796                      paint); | 
|  | 797 } | 
|  | 798 | 
|  | 799 void GrAAConvexTessellator::Ring::draw(SkCanvas* canvas, const GrAAConvexTessell
     ator& tess) const { | 
|  | 800     SkPaint paint; | 
|  | 801     paint.setTextSize(kEdgeTextSize); | 
|  | 802 | 
|  | 803     for (int cur = 0; cur < fPts.count(); ++cur) { | 
|  | 804         int next = (cur + 1) % fPts.count(); | 
|  | 805 | 
|  | 806         draw_line(canvas, | 
|  | 807                   tess.point(fPts[cur].fIndex), | 
|  | 808                   tess.point(fPts[next].fIndex), | 
|  | 809                   SK_ColorGREEN); | 
|  | 810 | 
|  | 811         SkPoint mid = tess.point(fPts[cur].fIndex) + tess.point(fPts[next].fInde
     x); | 
|  | 812         mid.scale(0.5f); | 
|  | 813 | 
|  | 814         if (fPts.count()) { | 
|  | 815             draw_arrow(canvas, mid, fPts[cur].fNorm, kArrowLength, SK_ColorRED); | 
|  | 816             mid.fX += (kArrowLength/2) * fPts[cur].fNorm.fX; | 
|  | 817             mid.fY += (kArrowLength/2) * fPts[cur].fNorm.fY; | 
|  | 818         } | 
|  | 819 | 
|  | 820         SkString num; | 
|  | 821         num.printf("%d", this->origEdgeID(cur)); | 
|  | 822         canvas->drawText(num.c_str(), num.size(), mid.fX, mid.fY, paint); | 
|  | 823 | 
|  | 824         if (fPts.count()) { | 
|  | 825             draw_arrow(canvas, tess.point(fPts[cur].fIndex), fPts[cur].fBisector
     , | 
|  | 826                        kArrowLength, SK_ColorBLUE); | 
|  | 827         } | 
|  | 828     } | 
|  | 829 } | 
|  | 830 | 
|  | 831 void GrAAConvexTessellator::draw(SkCanvas* canvas) const { | 
|  | 832     for (int i = 0; i < fIndices.count(); i += 3) { | 
|  | 833         SkASSERT(fIndices[i] < this->numPts()) ; | 
|  | 834         SkASSERT(fIndices[i+1] < this->numPts()) ; | 
|  | 835         SkASSERT(fIndices[i+2] < this->numPts()) ; | 
|  | 836 | 
|  | 837         draw_line(canvas, | 
|  | 838                   this->point(this->fIndices[i]), this->point(this->fIndices[i+1
     ]), | 
|  | 839                   SK_ColorBLACK); | 
|  | 840         draw_line(canvas, | 
|  | 841                   this->point(this->fIndices[i+1]), this->point(this->fIndices[i
     +2]), | 
|  | 842                   SK_ColorBLACK); | 
|  | 843         draw_line(canvas, | 
|  | 844                   this->point(this->fIndices[i+2]), this->point(this->fIndices[i
     ]), | 
|  | 845                   SK_ColorBLACK); | 
|  | 846     } | 
|  | 847 | 
|  | 848     fInitialRing.draw(canvas, *this); | 
|  | 849     for (int i = 0; i < fRings.count(); ++i) { | 
|  | 850         fRings[i]->draw(canvas, *this); | 
|  | 851     } | 
|  | 852 | 
|  | 853     for (int i = 0; i < this->numPts(); ++i) { | 
|  | 854         draw_point(canvas, | 
|  | 855                    this->point(i), 0.5f + (this->depth(i)/(2*fTargetDepth)), | 
|  | 856                    !this->movable(i)); | 
|  | 857 | 
|  | 858         SkPaint paint; | 
|  | 859         paint.setTextSize(kPointTextSize); | 
|  | 860         paint.setTextAlign(SkPaint::kCenter_Align); | 
|  | 861         if (this->depth(i) <= -fTargetDepth) { | 
|  | 862             paint.setColor(SK_ColorWHITE); | 
|  | 863         } | 
|  | 864 | 
|  | 865         SkString num; | 
|  | 866         num.printf("%d", i); | 
|  | 867         canvas->drawText(num.c_str(), num.size(), | 
|  | 868                          this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f
     ), | 
|  | 869                          paint); | 
|  | 870     } | 
|  | 871 } | 
|  | 872 | 
|  | 873 #endif | 
|  | 874 | 
| OLD | NEW | 
|---|