| 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 void intersect2(const SkPoint& p0, const SkPoint& n0, |
| 25 const SkPoint& p1, const SkPoint& n1, |
| 26 SkScalar* t0) { |
| 27 SkASSERT(SkScalarNearlyEqual(n0.lengthSqd(), 1.0f)); |
| 28 SkASSERT(SkScalarNearlyEqual(n1.lengthSqd(), 1.0f)); |
| 29 |
| 30 const SkPoint v = p1 - p0; |
| 31 |
| 32 SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX; |
| 33 *t0 = (v.fX * n1.fY - v.fY * n1.fX) / perpDot; |
| 34 |
| 35 if (*t0 < 0.0f) { |
| 36 *t0 = 100000; |
| 37 } |
| 38 // SkASSERT(*t0 >= 0.0f); |
| 39 } |
| 40 |
| 41 static void intersect(const SkPoint& p0, const SkPoint& n0, |
| 42 const SkPoint& p1, const SkPoint& n1, |
| 43 SkScalar* t0, SkScalar* t1) { |
| 44 SkASSERT(SkScalarNearlyEqual(n0.lengthSqd(), 1.0f)); |
| 45 SkASSERT(SkScalarNearlyEqual(n1.lengthSqd(), 1.0f)); |
| 46 |
| 47 const SkPoint v = p1 - p0; |
| 48 |
| 49 SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX; |
| 50 *t0 = (v.fX * n1.fY - v.fY * n1.fX) / perpDot; |
| 51 *t1 = (v.fX * n0.fY - v.fY * n0.fX) / perpDot; |
| 52 |
| 53 SkASSERT(*t0 >= 0.0f && *t1 >= 0.0f); |
| 54 } |
| 55 |
| 56 // This is a special case version of intersect where we have the vector |
| 57 // perpendicular to the second line rather than the vector parallel to it. |
| 58 static SkScalar perp_intersect(const SkPoint& p0, const SkPoint& n0, |
| 59 const SkPoint& p1, const SkPoint& perp) { |
| 60 SkASSERT(SkScalarNearlyEqual(n0.lengthSqd(), 1.0f)); |
| 61 SkASSERT(SkScalarNearlyEqual(perp.lengthSqd(), 1.0f)); |
| 62 |
| 63 const SkPoint v = p1 - p0; |
| 64 SkScalar perpDot = n0.dot(perp); |
| 65 return v.dot(perp) / perpDot; |
| 66 } |
| 67 |
| 68 static bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) { |
| 69 SkScalar distSq = p0.distanceToSqd(p1); |
| 70 return distSq < kCloseSqd; |
| 71 } |
| 72 |
| 73 static SkScalar abs_dist_from_line(const SkPoint& p0, const SkPoint& p1, const S
kPoint& test) { |
| 74 // TODO: update this to use the normals computed for a ring rather than reco
mputing |
| 75 SkPoint v = p1 - p0; |
| 76 v.normalize(); |
| 77 |
| 78 SkPoint testV = test - p0; |
| 79 SkScalar dist = testV.fX * v.fY - testV.fY * v.fX; |
| 80 return SkScalarAbs(dist); |
| 81 } |
| 82 |
| 83 int GrAAConvexTessellator::addPt(const SkPoint& pt, SkScalar depth) { |
| 84 this->validate(); |
| 85 |
| 86 int index = fPts.count(); |
| 87 *fPts.push() = pt; |
| 88 *fDepths.push() = depth; |
| 89 |
| 90 this->validate(); |
| 91 return index; |
| 92 } |
| 93 |
| 94 void GrAAConvexTessellator::popLastPt() { |
| 95 this->validate(); |
| 96 |
| 97 fPts.pop(); |
| 98 fDepths.pop(); |
| 99 |
| 100 this->validate(); |
| 101 } |
| 102 |
| 103 void GrAAConvexTessellator::popFirstPtShuffle() { |
| 104 this->validate(); |
| 105 |
| 106 fPts.removeShuffle(0); |
| 107 fDepths.removeShuffle(0); |
| 108 |
| 109 this->validate(); |
| 110 } |
| 111 |
| 112 void GrAAConvexTessellator::addTri(int i0, int i1, int i2) { |
| 113 if (i0 == i1 || i1 == i2 || i2 == i0) { |
| 114 return; |
| 115 } |
| 116 |
| 117 *fIndices.push() = i0; |
| 118 *fIndices.push() = i1; |
| 119 *fIndices.push() = i2; |
| 120 } |
| 121 |
| 122 void GrAAConvexTessellator::rewind() { |
| 123 fPts.rewind(); |
| 124 fDepths.rewind(); |
| 125 fIndices.rewind(); |
| 126 fNorms.rewind(); |
| 127 fBisectors.rewind(); |
| 128 |
| 129 fPQueue.rewind(); |
| 130 fVerts1.rewind(); |
| 131 } |
| 132 |
| 133 void GrAAConvexTessellator::computeNormals() { |
| 134 int numPts = this->numPts(); |
| 135 |
| 136 fNorms.setCount(numPts); |
| 137 |
| 138 for (int cur = 0; cur < numPts; ++cur) { |
| 139 int next = (cur + 1) % numPts; |
| 140 |
| 141 fNorms[cur] = fPts[next] - fPts[cur]; |
| 142 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms[cur]); |
| 143 SkASSERT(len > 0.0f); |
| 144 fNorms[cur].setOrthog(fNorms[cur], fSide); |
| 145 |
| 146 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); |
| 147 } |
| 148 } |
| 149 |
| 150 void GrAAConvexTessellator::computeBisectors() { |
| 151 fBisectors.setCount(fNorms.count()); |
| 152 |
| 153 int prev = fBisectors.count() - 1; |
| 154 for (int cur = 0; cur < fBisectors.count(); prev = cur, ++cur) { |
| 155 fBisectors[cur] = fNorms[cur] + fNorms[prev]; |
| 156 fBisectors[cur].normalize(); |
| 157 fBisectors[cur].negate(); // make the bisector face in |
| 158 |
| 159 SkASSERT(SkScalarNearlyEqual(1.0f, fBisectors[cur].length())); |
| 160 } |
| 161 } |
| 162 |
| 163 // The general idea here is to, conceptually, start with the original polygon an
d slide |
| 164 // the vertices along the bisectors until the first intersection. At that |
| 165 // point two of the edges collapse and the process repeats on the new polygon. |
| 166 bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { |
| 167 if (!this->extractFromPath(m, path)) { |
| 168 return false; |
| 169 } |
| 170 |
| 171 this->computeNormals(); |
| 172 this->computeBisectors(); |
| 173 this->initPQueue(); |
| 174 |
| 175 this->createOuterRing(); |
| 176 this->createInsetRing(); |
| 177 |
| 178 this->validate(); |
| 179 SkDEBUGCODE(this->checkAllDepths();) |
| 180 return true; |
| 181 } |
| 182 |
| 183 SkScalar GrAAConvexTessellator::computeDepthFromEdge(int edgeIdx, const SkPoint&
p) const { |
| 184 SkASSERT(edgeIdx < fNorms.count()); |
| 185 |
| 186 SkPoint v = p - fPts[edgeIdx]; |
| 187 SkScalar depth = -fNorms[edgeIdx].dot(v); |
| 188 SkASSERT(depth >= 0.0f); |
| 189 return depth; |
| 190 } |
| 191 |
| 192 // Find a point that is 'desiredDepth' away from the 'edgeIdx'-th edge and lies |
| 193 // along the 'bisector' from the 'startIdx'-th point. |
| 194 SkPoint GrAAConvexTessellator::computePtAlongBisector(int startIdx, |
| 195 const SkVector& bisector, |
| 196 int edgeIdx, |
| 197 SkScalar desiredDepth) con
st { |
| 198 const SkPoint& norm = fNorms[edgeIdx]; |
| 199 |
| 200 // First find the point where the edge and the bisector intersect |
| 201 SkPoint newP; |
| 202 SkScalar t = perp_intersect(fPts[startIdx], bisector, fPts[edgeIdx], norm); |
| 203 if (SkScalarNearlyEqual(t, 0.0f)) { |
| 204 // the start point was one of the original ring points |
| 205 SkASSERT(startIdx < fNorms.count()); |
| 206 newP = fPts[startIdx]; |
| 207 } else { |
| 208 SkASSERT(t < 0.0f); |
| 209 newP = bisector; |
| 210 newP.scale(t); |
| 211 newP += fPts[startIdx]; |
| 212 } |
| 213 |
| 214 // Then offset along the bisector from that point the correct distance |
| 215 t = -desiredDepth / bisector.dot(norm); |
| 216 SkASSERT(t > 0.0f); |
| 217 SkPoint result = bisector; |
| 218 result.scale(t); |
| 219 result += newP; |
| 220 |
| 221 return result; |
| 222 } |
| 223 |
| 224 bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat
h) { |
| 225 SkASSERT(SkPath::kLine_SegmentMask == path.getSegmentMasks()); |
| 226 SkASSERT(SkPath::kConvex_Convexity == path.getConvexity()); |
| 227 |
| 228 // Outer ring: 3*numPts |
| 229 // Middle ring: numPts |
| 230 // Presumptive inner ring: numPts |
| 231 this->reservePts(5*path.countPoints()); |
| 232 // Outer ring: 12*numPts |
| 233 // Middle ring: 0 |
| 234 // Presumptive inner ring: 6*numPts + 6 |
| 235 fIndices.setReserve(18*path.countPoints() + 6); |
| 236 |
| 237 SkScalar minCross = SK_ScalarMax, maxCross = -SK_ScalarMax; |
| 238 |
| 239 SkPath::Iter iter(path, true); |
| 240 SkPoint pts[4]; |
| 241 SkPath::Verb verb; |
| 242 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { |
| 243 switch (verb) { |
| 244 case SkPath::kLine_Verb: |
| 245 m.mapPoints(&pts[1], 1); |
| 246 if (this->numPts() > 0 && duplicate_pt(pts[1], fPts.top())) { |
| 247 continue; |
| 248 } |
| 249 |
| 250 if (this->numPts() >= 2 && |
| 251 abs_dist_from_line(fPts[this->numPts()-1], fPts[this->numPts
()-2], pts[1]) < |
| 252 kClose) { |
| 253 // The old last point is on the line from the second to last
to the new point |
| 254 this->popLastPt(); |
| 255 } |
| 256 |
| 257 this->addPt(pts[1], 0.0f); |
| 258 |
| 259 if (this->numPts() >= 3) { |
| 260 int cur = this->numPts()-1; |
| 261 |
| 262 SkScalar cross = SkPoint::CrossProduct(fPts[cur] - fPts[cur-
1], |
| 263 fPts[cur-1] - fPts[cu
r-2]); |
| 264 if (maxCross < cross) { |
| 265 maxCross = cross; |
| 266 } |
| 267 if (minCross > cross) { |
| 268 minCross = cross; |
| 269 } |
| 270 } |
| 271 break; |
| 272 case SkPath::kQuad_Verb: |
| 273 case SkPath::kConic_Verb: |
| 274 case SkPath::kCubic_Verb: |
| 275 SkASSERT(false); |
| 276 break; |
| 277 case SkPath::kMove_Verb: |
| 278 case SkPath::kClose_Verb: |
| 279 case SkPath::kDone_Verb: |
| 280 break; |
| 281 } |
| 282 } |
| 283 |
| 284 if (!this->numPts()) { |
| 285 return false; |
| 286 } |
| 287 |
| 288 // check if last point is a duplicate of the first point. If so, remove it. |
| 289 if (duplicate_pt(fPts[this->numPts()-1], fPts[0])) { |
| 290 this->popLastPt(); |
| 291 } |
| 292 |
| 293 if (this->numPts() >= 3 && |
| 294 abs_dist_from_line(fPts[this->numPts()-1], fPts[this->numPts()-2], fPts[
0]) < kClose) { |
| 295 // The last point is on the line from the second to last to the first po
int. |
| 296 this->popLastPt(); |
| 297 } |
| 298 |
| 299 if (this->numPts() >= 3 && |
| 300 abs_dist_from_line(fPts[0], fPts[this->numPts()-1], fPts[1]) < kClose) { |
| 301 // The first point is on the line from the last to the second. |
| 302 this->popFirstPtShuffle(); |
| 303 } |
| 304 |
| 305 if (this->numPts() < 3) { |
| 306 return false; |
| 307 } |
| 308 |
| 309 // Check the cross produce of the final trio |
| 310 SkScalar cross = SkPoint::CrossProduct(fPts[1] - fPts[0], fPts[0] - fPts[fPt
s.count()-1]); |
| 311 if (maxCross < cross) { |
| 312 maxCross = cross; |
| 313 } |
| 314 if (minCross > cross) { |
| 315 minCross = cross; |
| 316 } |
| 317 |
| 318 if (maxCross > 0.0f) { |
| 319 SkASSERT(minCross >= 0.0f); |
| 320 fSide = SkPoint::kRight_Side; |
| 321 } else { |
| 322 SkASSERT(minCross <= 0.0f); |
| 323 fSide = SkPoint::kLeft_Side; |
| 324 } |
| 325 |
| 326 this->validate(); |
| 327 return true; |
| 328 } |
| 329 |
| 330 void GrAAConvexTessellator::createOuterRing() { |
| 331 // For now, we're only generating one outer ring (at the start). This |
| 332 // could be relaxed for stroking use cases. |
| 333 SkASSERT(0 == fIndices.count()); |
| 334 SkASSERT(fPts.count() == fNorms.count()); |
| 335 |
| 336 const int numPts = fPts.count(); |
| 337 |
| 338 // For each vertex of the original polygon we add three points to the |
| 339 // outset polygon - one extending perpendicular to each impinging edge |
| 340 // and one along the bisector. Two triangles are added for each corner |
| 341 // and two are added along each edge. |
| 342 int prev = numPts - 1; |
| 343 int lastPerpIdx = -1, firstPerpIdx, newIdx0, newIdx1, newIdx2; |
| 344 for (int cur = 0; cur < numPts; ++cur) { |
| 345 // The perpendicular point for the last edge |
| 346 SkPoint temp = fNorms[prev]; |
| 347 temp.scale(fTargetDepth); |
| 348 temp += fPts[cur]; |
| 349 |
| 350 // We know it isn't a duplicate of the prior point (since it and this |
| 351 // one are just perpendicular offsets from the non-merged polygon points
) |
| 352 newIdx0 = this->addPt(temp, -fTargetDepth); |
| 353 |
| 354 // The bisector outset point |
| 355 temp = fBisectors[cur]; |
| 356 temp.scale(-fTargetDepth); // the bisectors point in |
| 357 temp += fPts[cur]; |
| 358 |
| 359 // For very shallow angles all the corner points could fuse |
| 360 if (duplicate_pt(temp, fPts[newIdx0])) { |
| 361 newIdx1 = newIdx0; |
| 362 } else { |
| 363 newIdx1 = this->addPt(temp, -fTargetDepth); |
| 364 } |
| 365 |
| 366 // The perpendicular point for the next edge. |
| 367 temp = fNorms[cur]; |
| 368 temp.scale(fTargetDepth); |
| 369 temp += fPts[cur]; |
| 370 |
| 371 // For very shallow angles all the corner points could fuse. |
| 372 if (duplicate_pt(temp, fPts[newIdx1])) { |
| 373 newIdx2 = newIdx1; |
| 374 } else { |
| 375 newIdx2 = this->addPt(temp, -fTargetDepth); |
| 376 } |
| 377 |
| 378 if (0 == cur) { |
| 379 // Store the index of the first perpendicular point to finish up |
| 380 firstPerpIdx = newIdx0; |
| 381 SkASSERT(-1 == lastPerpIdx); |
| 382 } else { |
| 383 // The triangles for the previous edge |
| 384 this->addTri(prev, newIdx0, cur); |
| 385 this->addTri(prev, lastPerpIdx, newIdx0); |
| 386 } |
| 387 |
| 388 // The two triangles for the corner |
| 389 this->addTri(cur, newIdx0, newIdx1); |
| 390 this->addTri(cur, newIdx1, newIdx2); |
| 391 |
| 392 prev = cur; |
| 393 // Track the last perpendicular outset point so we can construct the |
| 394 // trailing edge triangles. |
| 395 lastPerpIdx = newIdx2; |
| 396 } |
| 397 |
| 398 // pick up the final edge rect |
| 399 this->addTri(numPts-1, firstPerpIdx, 0); |
| 400 this->addTri(numPts-1, lastPerpIdx, firstPerpIdx); |
| 401 |
| 402 this->validate(); |
| 403 } |
| 404 |
| 405 |
| 406 void GrAAConvexTessellator::stepAllIn() { |
| 407 #if 1 |
| 408 //SkASSERT(fPQueue.count() >= 3); |
| 409 |
| 410 // 'dst' is the index into the vertex array each point in the last ring |
| 411 // maps to/transforms into in the next ring. |
| 412 SkTDArray<int> dst; |
| 413 dst.setCount(fVerts1.count()); |
| 414 SkTDArray<SkPoint> pts; |
| 415 pts.setReserve(fVerts1.count()); |
| 416 |
| 417 GrVertInfo* first = &fVerts1[0]; |
| 418 |
| 419 // Check on the first point (who compares with no one) |
| 420 SkPoint newPt = this->computePtAlongBisector(first->originatingPt(), |
| 421 first->bisector(), |
| 422 first->edgeId(), |
| 423 fTargetDepth); |
| 424 dst[0] = 0; |
| 425 *pts.push() = newPt; |
| 426 |
| 427 GrVertInfo* cur; |
| 428 int i; |
| 429 // Handle the middle points (who only compare with the prior point) |
| 430 for (i = 1, cur = first->next(); cur != first->prev(); ++i, cur=cur->next())
{ |
| 431 newPt = this->computePtAlongBisector(cur->originatingPt(), |
| 432 cur->bisector(), |
| 433 cur->edgeId(), |
| 434 fTargetDepth); |
| 435 if (!duplicate_pt(newPt, pts.top())) { |
| 436 dst[i] = pts.count(); |
| 437 *pts.push() = newPt; |
| 438 } else { |
| 439 dst[i] = pts.count()-1; |
| 440 } |
| 441 } |
| 442 SkASSERT(i == fVerts1.count()-1); |
| 443 |
| 444 // Check on the last point (handling the wrap around) |
| 445 newPt = this->computePtAlongBisector(first->prev()->originatingPt(), |
| 446 first->prev()->bisector(), |
| 447 first->prev()->edgeId(), |
| 448 fTargetDepth); |
| 449 bool dupPrev = duplicate_pt(newPt, pts.top()); |
| 450 bool dupNext = duplicate_pt(newPt, pts[0]); |
| 451 |
| 452 if (!dupPrev && !dupNext) { |
| 453 dst.top() = pts.count(); |
| 454 *pts.push() = newPt; |
| 455 } else if (dupPrev && !dupNext) { |
| 456 dst.top() = pts.count()-1; |
| 457 } else if (!dupPrev && dupNext) { |
| 458 dst.top() = 0; |
| 459 } else { |
| 460 bool dupPrevVsNext = duplicate_pt(pts[0], pts.top()); |
| 461 |
| 462 if (!dupPrevVsNext) { |
| 463 dst.top() = pts.count()-1; |
| 464 } else { |
| 465 if (pts.count() > 1) { |
| 466 pts.pop(); |
| 467 } |
| 468 |
| 469 dst.top() = 0; |
| 470 dst[dst.count()-2] = 0; |
| 471 } |
| 472 } |
| 473 |
| 474 SkTDArray<int> remap; // yuck |
| 475 remap.setCount(pts.count()); |
| 476 |
| 477 // Fold the new ring's points into the global pool |
| 478 for (int i = 0; i < pts.count(); ++i) { |
| 479 remap[i] = this->addPt(pts[i], fTargetDepth); |
| 480 } |
| 481 |
| 482 // 'dst' currently has indices into the ring. Remap these to be indices |
| 483 // into the global pool since the triangulation operates in that space. |
| 484 for (int i = 0; i < dst.count(); ++i) { |
| 485 dst[i] = remap[dst[i]]; |
| 486 } |
| 487 |
| 488 this->addTri(first->originatingPt(), first->next()->originatingPt(), dst[0])
; |
| 489 this->addTri(dst[0], first->next()->originatingPt(), dst[1]); |
| 490 |
| 491 for (i = 1, cur = first->next(); cur != first; ++i, cur=cur->next()) { |
| 492 this->addTri(cur->originatingPt(), cur->next()->originatingPt(), dst[i])
; |
| 493 this->addTri(dst[i], cur->next()->originatingPt(), dst[(i+1)%dst.count()
]); |
| 494 } |
| 495 |
| 496 // fan out from point 0 |
| 497 for (int cur = 1; cur < remap.count()-1; ++cur) { |
| 498 this->addTri(remap[0], remap[cur], remap[cur+1]); |
| 499 } |
| 500 #endif |
| 501 } |
| 502 |
| 503 static void add_to_dll(GrCandidateVert* prev, GrCandidateVert* newV, GrCandidate
Vert* next) { |
| 504 SkASSERT(newV); |
| 505 |
| 506 newV->setPrev(prev); |
| 507 newV->setNext(next); |
| 508 |
| 509 if (prev) { |
| 510 prev->setNext(newV); |
| 511 } |
| 512 if (next) { |
| 513 next->setPrev(newV); |
| 514 } |
| 515 } |
| 516 |
| 517 static void rm_from_dll(GrCandidateVert* v) { |
| 518 if (v->prev()) { |
| 519 v->prev()->setNext(v->next()); |
| 520 } |
| 521 if (v->next()) { |
| 522 v->next()->setPrev(v->prev()); |
| 523 } |
| 524 } |
| 525 |
| 526 void GrAAConvexTessellator::createCandidate(GrVertInfo* v, GrCandidateVert** pre
v, |
| 527 GrCandidateVert* next, bool checkNex
t){ |
| 528 SkScalar tPrev, tNext; |
| 529 intersect2(this->point(v->originatingPt()), v->bisector(), |
| 530 this->point(v->prev()->originatingPt()), v->prev()->bisector(), |
| 531 &tPrev); |
| 532 intersect2(this->point(v->originatingPt()), v->bisector(), |
| 533 this->point(v->next()->originatingPt()), v->next()->bisector(), |
| 534 &tNext); |
| 535 |
| 536 SkScalar t; |
| 537 GrVertInfo* prevSubsumed, *nextSubsumed; |
| 538 if (tPrev < tNext) { |
| 539 t = tPrev; |
| 540 prevSubsumed = v->prev(); |
| 541 nextSubsumed = v; |
| 542 } else { |
| 543 t = tNext; |
| 544 prevSubsumed = v; |
| 545 nextSubsumed = v->next(); |
| 546 } |
| 547 |
| 548 SkPoint newPt = v->bisector(); |
| 549 newPt.scale(t); |
| 550 newPt += this->point(v->originatingPt()); |
| 551 |
| 552 SkScalar depth = this->computeDepthFromEdge(v->edgeId(), newPt); |
| 553 |
| 554 if (SkScalarNearlyEqual(depth, (*prev)->depth(), kClose) && |
| 555 duplicate_pt((*prev)->pt(), newPt)) { |
| 556 (*prev)->setNextSubsumed(v); |
| 557 (*prev)->recomputeBi(); |
| 558 return; |
| 559 } |
| 560 |
| 561 if (checkNext && SkScalarNearlyEqual(depth, next->depth(), kClose) && |
| 562 duplicate_pt(next->pt(), newPt)) { |
| 563 next->setPrevSubsumed(v); |
| 564 next->recomputeBi(); |
| 565 return; |
| 566 } |
| 567 |
| 568 GrCandidateVert* newI = this->get(); |
| 569 |
| 570 newI->setPt(newPt); |
| 571 newI->setBisector(v->bisector()); |
| 572 newI->setDepth(depth); |
| 573 newI->setOriginatingPt(v->originatingPt()); |
| 574 newI->setPrevSubsumed(prevSubsumed); |
| 575 newI->setNextSubsumed(nextSubsumed); |
| 576 add_to_dll(*prev, newI, next); |
| 577 |
| 578 fPQueue.insert(newI); |
| 579 *prev = newI; |
| 580 } |
| 581 |
| 582 void GrAAConvexTessellator::recompute(GrCandidateVert* v) { |
| 583 |
| 584 GrVertInfo* from = v->prevSubsumed(); |
| 585 GrVertInfo* to = v->nextSubsumed(); |
| 586 |
| 587 GrCandidateVert* trailing = v->prev(); |
| 588 GrCandidateVert* leading = v->next(); |
| 589 |
| 590 // First retract 'v' |
| 591 rm_from_dll(v); |
| 592 fPQueue.remove(v); |
| 593 this->release(v); |
| 594 |
| 595 for (GrVertInfo* cur = from; cur != to; cur = cur->next()) { |
| 596 this->createCandidate(cur, &trailing, leading, false); |
| 597 } |
| 598 |
| 599 this->createCandidate(to, &trailing, leading, true); |
| 600 } |
| 601 |
| 602 void GrAAConvexTessellator::initPQueue() { |
| 603 |
| 604 fVerts1.setCount(fPts.count()); |
| 605 fCandidates1.setCount(fPts.count()); |
| 606 for (int i = fPts.count()-1; i >= 0; --i) { |
| 607 fCandidates1[i].setOriginatingPt(i); |
| 608 this->release(&fCandidates1[i]); |
| 609 } |
| 610 fPQueue.setReserve(fPts.count()); |
| 611 |
| 612 int prev = fPts.count()-1; |
| 613 for (int cur = 0; cur < fPts.count(); prev = cur, ++cur) { |
| 614 int next = (cur + 1) % fPts.count(); |
| 615 |
| 616 fVerts1[cur].setOriginatingPt(cur); |
| 617 fVerts1[cur].setPrev(&fVerts1[prev]); |
| 618 fVerts1[cur].setNext(&fVerts1[next]); |
| 619 |
| 620 fVerts1[cur].setBisector(fBisectors[cur]); |
| 621 fVerts1[cur].setEdgeId(cur); |
| 622 } |
| 623 |
| 624 SkScalar tTemp, tPrev, tNext; |
| 625 intersect(fPts.top(), fBisectors.top(), |
| 626 fPts[0], fBisectors[0], |
| 627 &tTemp, &tPrev); |
| 628 |
| 629 GrCandidateVert* prevI = NULL; |
| 630 |
| 631 // Add all the candidate points to a priority queue sorted by the depth of t
he first |
| 632 // intersection between the bisector of its originating point and its two ne
ighbor's bisectors |
| 633 for (int cur = 0; cur < fPts.count(); ++cur) { |
| 634 int next = (cur + 1) % fPts.count(); |
| 635 |
| 636 intersect(fPts[cur], fBisectors[cur], |
| 637 fPts[next], fBisectors[next], |
| 638 &tNext, &tTemp); |
| 639 |
| 640 SkScalar t; |
| 641 GrVertInfo* prevSubsumed, *nextSubsumed; |
| 642 if (tPrev < tNext) { |
| 643 t = tPrev; |
| 644 prevSubsumed = fVerts1[cur].prev(); |
| 645 nextSubsumed = &fVerts1[cur]; |
| 646 } else { |
| 647 t = tNext; |
| 648 prevSubsumed = &fVerts1[cur]; |
| 649 nextSubsumed = fVerts1[cur].next(); |
| 650 } |
| 651 |
| 652 SkPoint newPt = fBisectors[cur]; |
| 653 newPt.scale(t); |
| 654 newPt += fPts[cur]; |
| 655 |
| 656 SkScalar depth = this->computeDepthFromEdge(cur, newPt); |
| 657 |
| 658 if (prevI && duplicate_pt(prevI->pt(), newPt)) { |
| 659 SkASSERT(SkScalarNearlyEqual(prevI->depth(), depth)); |
| 660 // fuse with prior |
| 661 prevI->setNextSubsumed(nextSubsumed); |
| 662 SkVector newBi = prevI->prevSubsumed()->bisector(); |
| 663 newBi += prevI->nextSubsumed()->bisector(); |
| 664 newBi.normalize(); |
| 665 prevI->setBisector(newBi); |
| 666 tPrev = tTemp; |
| 667 continue; |
| 668 } |
| 669 |
| 670 GrCandidateVert* newI = this->get(); |
| 671 |
| 672 newI->setPt(newPt); |
| 673 newI->setBisector(fBisectors[cur]); |
| 674 newI->setDepth(depth); |
| 675 newI->setOriginatingPt(cur); |
| 676 newI->setPrevSubsumed(prevSubsumed); |
| 677 newI->setNextSubsumed(nextSubsumed); |
| 678 add_to_dll(prevI, newI, NULL); |
| 679 |
| 680 fPQueue.insert(newI); |
| 681 |
| 682 prevI = newI; |
| 683 tPrev = tTemp; |
| 684 } |
| 685 |
| 686 prevI->setNext(&fCandidates1[0]); |
| 687 fCandidates1[0].setPrev(prevI); |
| 688 |
| 689 if (fCandidates1.count() > 1) { |
| 690 if (duplicate_pt(prevI->pt(), fCandidates1[0].pt())) { |
| 691 SkASSERT(SkScalarNearlyEqual(prevI->depth(), fCandidates1[0].depth()
)); |
| 692 |
| 693 fCandidates1[0].setPrevSubsumed(prevI->prevSubsumed()); |
| 694 SkVector newBi = fCandidates1[0].prevSubsumed()->bisector(); |
| 695 newBi += fCandidates1[0].nextSubsumed()->bisector(); |
| 696 newBi.normalize(); |
| 697 fCandidates1[0].setBisector(newBi); |
| 698 rm_from_dll(prevI); |
| 699 fPQueue.remove(prevI); |
| 700 this->release(prevI); |
| 701 } |
| 702 } |
| 703 } |
| 704 |
| 705 static void rm_from_dllV(GrVertInfo* v) { |
| 706 v->prev()->setNext(v->next()); |
| 707 v->next()->setPrev(v->prev()); |
| 708 v->setNext(NULL); |
| 709 v->setPrev(NULL); |
| 710 } |
| 711 |
| 712 static void add_to_dllV(GrVertInfo* v, GrVertInfo* prev, GrVertInfo* next) { |
| 713 v->setPrev(prev); |
| 714 v->setNext(next); |
| 715 |
| 716 prev->setNext(v); |
| 717 next->setPrev(v); |
| 718 } |
| 719 |
| 720 void GrAAConvexTessellator::removeDups(GrVertInfo* start, int* trailingIdx) { |
| 721 #if 0 |
| 722 GrVertInfo* next; |
| 723 for (GrVertInfo* cur = start->next(); cur != start; cur = next) { |
| 724 next = cur->next(); |
| 725 |
| 726 if (!duplicate_pt(start->newPt(), cur->newPt())) { |
| 727 return; // found a non-duplicate |
| 728 } |
| 729 |
| 730 SkASSERT(SkScalarNearlyEqual(start->depth(), cur->depth(), kClose)); |
| 731 this->addTri(*trailingIdx, cur->index1(), start->index1()); |
| 732 fPQueue.remove(cur); |
| 733 *trailingIdx = cur->index1(); |
| 734 rm_from_dll(cur); |
| 735 } |
| 736 #endif |
| 737 } |
| 738 |
| 739 void GrAAConvexTessellator::removeDups2(GrVertInfo* start, int* trailingIdx) { |
| 740 #if 0 |
| 741 GrVertInfo* prev; |
| 742 for (GrVertInfo* cur = start->next(); cur != start; cur = prev) { |
| 743 prev = cur->prev(); |
| 744 |
| 745 if (!duplicate_pt(start->newPt(), cur->newPt())) { |
| 746 return; // found a non-duplicate |
| 747 } |
| 748 |
| 749 SkASSERT(SkScalarNearlyEqual(start->depth(), cur->depth())); |
| 750 this->addTri(*trailingIdx, cur->index1(), start->index1()); |
| 751 fPQueue.remove(cur); |
| 752 *trailingIdx = cur->index1(); |
| 753 rm_from_dll(cur); |
| 754 } |
| 755 #endif |
| 756 } |
| 757 |
| 758 void GrAAConvexTessellator::createInsetRing() { |
| 759 |
| 760 #if 0 |
| 761 while (fPQueue.count()) { |
| 762 GrCandidateVert* curI = fPQueue.peek(); |
| 763 |
| 764 int newIdx = this->addPt(curI->pt(), curI->depth()); |
| 765 SkDebugf("newIdx %d\n", newIdx); |
| 766 |
| 767 fPQueue.pop(); |
| 768 } |
| 769 |
| 770 return; |
| 771 #endif |
| 772 |
| 773 int floob = 0; |
| 774 while (fPQueue.count() && floob < 4) { |
| 775 floob++; |
| 776 |
| 777 GrCandidateVert* curI = fPQueue.peek(); |
| 778 fPQueue.pop(); |
| 779 rm_from_dll(curI); |
| 780 |
| 781 if (curI->depth() >= fTargetDepth) { |
| 782 // None of the bisectors intersect before reaching the desired depth
. |
| 783 // Just step them all to the desired depth |
| 784 this->stepAllIn(); |
| 785 return; |
| 786 } |
| 787 |
| 788 |
| 789 int newIdx = this->addPt(curI->pt(), curI->depth()); |
| 790 |
| 791 GrVertInfo* prev = curI->prevSubsumed(); |
| 792 GrVertInfo* next = curI->nextSubsumed(); |
| 793 int newEdgeId = next->edgeId(); |
| 794 GrVertInfo* pp = prev->prev(); |
| 795 GrVertInfo* nn = next->next(); |
| 796 |
| 797 #if 0 |
| 798 SkVector newBisector = prev->bisector(); |
| 799 newBisector += next->bisector(); |
| 800 newBisector.normalize(); |
| 801 #endif |
| 802 |
| 803 if (!fPQueue.count()) { |
| 804 GrVertInfo* foo = prev; |
| 805 do { |
| 806 this->addTri(foo->originatingPt(), foo->next()->originatingPt(),
newIdx); |
| 807 foo = foo->next(); |
| 808 } while (foo != next); |
| 809 return; |
| 810 } |
| 811 |
| 812 bool nextNeedsRecompute = false, prevNeedsRecompute = false; |
| 813 if (curI->next()->prevSubsumed() == next) { |
| 814 curI->next()->setPrevSubsumed(nn); |
| 815 nextNeedsRecompute = true; |
| 816 } |
| 817 if (curI->prev()->nextSubsumed() == prev) { |
| 818 curI->prev()->setNextSubsumed(pp); |
| 819 prevNeedsRecompute = true; |
| 820 } |
| 821 |
| 822 this->addTri(pp->originatingPt(), pp->next()->originatingPt(), newIdx); |
| 823 this->addTri(nn->prev()->originatingPt(), nn->originatingPt(), newIdx); |
| 824 |
| 825 GrVertInfo *cur = prev, *next2; |
| 826 do { |
| 827 next2 = cur->next(); |
| 828 this->addTri(cur->originatingPt(), next2->originatingPt(), newIdx); |
| 829 rm_from_dllV(cur); |
| 830 cur = next2; |
| 831 } while (cur != nn); |
| 832 |
| 833 GrVertInfo* newV = prev; // recycle prev - let next and all the ones in
between lie fallow |
| 834 newV->setOriginatingPt(newIdx); |
| 835 newV->setBisector(curI->bisector()); |
| 836 newV->setEdgeId(newEdgeId); |
| 837 add_to_dllV(newV, pp, nn); |
| 838 |
| 839 { |
| 840 SkScalar tPrev, tNext; |
| 841 intersect2(curI->pt(), curI->bisector(), |
| 842 this->point(pp->originatingPt()), pp->bisector(), |
| 843 &tPrev); |
| 844 intersect2(curI->pt(), curI->bisector(), |
| 845 this->point(nn->originatingPt()), nn->bisector(), |
| 846 &tNext); |
| 847 |
| 848 SkScalar t; |
| 849 GrVertInfo* prevSubsumed, *nextSubsumed; |
| 850 if (tPrev < tNext) { |
| 851 t = tPrev; |
| 852 prevSubsumed = pp; |
| 853 nextSubsumed = newV; |
| 854 } else { |
| 855 t = tNext; |
| 856 prevSubsumed = newV; |
| 857 nextSubsumed = nn; |
| 858 } |
| 859 |
| 860 SkPoint newPt = newV->bisector(); |
| 861 newPt.scale(t); |
| 862 newPt += this->point(newV->originatingPt()); |
| 863 |
| 864 SkScalar depth = this->computeDepthFromEdge(newV->edgeId(), newPt); |
| 865 |
| 866 if (!prevNeedsRecompute && |
| 867 SkScalarNearlyEqual(depth, curI->prev()->depth(), kClose) && |
| 868 duplicate_pt(curI->prev()->pt(), newPt)) { |
| 869 curI->prev()->setNextSubsumed(newV); |
| 870 curI->prev()->recomputeBi(); |
| 871 continue; |
| 872 } |
| 873 |
| 874 if (!nextNeedsRecompute && |
| 875 SkScalarNearlyEqual(depth, curI->next()->depth(), kClose) && |
| 876 duplicate_pt(curI->next()->pt(), newPt)) { |
| 877 curI->next()->setPrevSubsumed(newV); |
| 878 curI->next()->recomputeBi(); |
| 879 continue; |
| 880 } |
| 881 |
| 882 GrCandidateVert* newI = curI; // recycle curI |
| 883 |
| 884 newI->setPt(newPt); |
| 885 newI->setBisector(newV->bisector()); |
| 886 newI->setDepth(depth); |
| 887 newI->setOriginatingPt(newIdx); |
| 888 newI->setPrevSubsumed(prevSubsumed); |
| 889 newI->setNextSubsumed(nextSubsumed); |
| 890 add_to_dll(newI->prev(), newI, newI->next()); |
| 891 |
| 892 fPQueue.insert(newI); |
| 893 |
| 894 if (nextNeedsRecompute) { |
| 895 this->recompute(newI->next()); |
| 896 } |
| 897 if (prevNeedsRecompute) { |
| 898 this->recompute(newI->prev()); |
| 899 } |
| 900 } |
| 901 |
| 902 #if 0 |
| 903 fPQueue.remove(curVert); |
| 904 fPQueue.remove(otherVert); |
| 905 rm_from_dll(otherVert); |
| 906 #endif |
| 907 |
| 908 #if 0 |
| 909 int dyingCurIdx = curVert->index1(); |
| 910 int newIdx = this->addPt(curVert->newPt(), curVert->depth()); |
| 911 |
| 912 if (curVert->wasNext()) { |
| 913 this->addTri(dyingCurIdx, otherVert->index1(), newIdx); // tri for t
he dying edge |
| 914 } else { |
| 915 this->addTri(otherVert->index1(), dyingCurIdx, newIdx); // tri for t
he dying edge |
| 916 } |
| 917 |
| 918 curVert->setIndex(newIdx); |
| 919 |
| 920 int trailingIdx = curVert->prev()->index1(); |
| 921 int leadingIdx = curVert->next()->index1(); |
| 922 |
| 923 this->removeDups(curVert, &leadingIdx); |
| 924 this->removeDups2(curVert, &trailingIdx); |
| 925 |
| 926 if (curVert->wasNext()) { |
| 927 this->addTri(trailingIdx, dyingCurIdx, newIdx); |
| 928 this->addTri(newIdx, otherVert->index1(), leadingIdx); |
| 929 } else { |
| 930 this->addTri(trailingIdx, otherVert->index1(), newIdx); |
| 931 this->addTri(newIdx, dyingCurIdx, leadingIdx); |
| 932 } |
| 933 |
| 934 if (fPQueue.count() < 2) { |
| 935 break; |
| 936 } |
| 937 |
| 938 curVert->setBisector(newBisector); |
| 939 curVert->setEdgeId(newEdgeId); |
| 940 curVert->computeIntersection(*this); |
| 941 |
| 942 fPQueue.insert(curVert); |
| 943 #endif |
| 944 } |
| 945 |
| 946 while (fPQueue.count()) { |
| 947 GrCandidateVert* curI = fPQueue.peek(); |
| 948 |
| 949 int newIdx = this->addPt(curI->pt(), curI->depth()); |
| 950 SkDebugf("newIdx %d\n", newIdx); |
| 951 |
| 952 fPQueue.pop(); |
| 953 } |
| 954 |
| 955 } |
| 956 |
| 957 void GrAAConvexTessellator::validate() const { |
| 958 SkASSERT(fPts.count() == fDepths.count()); |
| 959 SkASSERT(0 == (fIndices.count() % 3)); |
| 960 } |
| 961 |
| 962 ////////////////////////////////////////////////////////////////////////////// |
| 963 void GrVertInfo::updateGeometry(const GrAAConvexTessellator& tess) { |
| 964 SkVector prevV = tess.point(fPrev->originatingPt()) - tess.point(fIndex1); |
| 965 SkVector nextV = tess.point(fNext->originatingPt()) - tess.point(fIndex1); |
| 966 |
| 967 nextV.normalize(); |
| 968 prevV.normalize(); |
| 969 prevV += nextV; |
| 970 fBisector = prevV; |
| 971 fBisector.normalize(); |
| 972 } |
| 973 |
| 974 |
| 975 void GrCandidateVert::recomputeBi() { |
| 976 SkVector newBi = this->prevSubsumed()->bisector(); |
| 977 newBi += this->nextSubsumed()->bisector(); |
| 978 newBi.normalize(); |
| 979 this->setBisector(newBi); |
| 980 } |
| 981 |
| 982 void GrCandidateVert::computeIntersection() { |
| 983 #if 0 |
| 984 SkScalar tPrev, tNext; |
| 985 intersect2(fPt, fBisector, |
| 986 fPrev->fPt, fPrev->fBisector, |
| 987 &tPrev); |
| 988 intersect2(fPt, fBisector, |
| 989 fNext->fPt, fNext->fBisector, |
| 990 &tNext); |
| 991 SkScalar t = SkMinScalar(tPrev, tNext); |
| 992 if (tPrev < tNext) { |
| 993 fWasNext = false; |
| 994 } else { |
| 995 fWasNext = true; |
| 996 } |
| 997 |
| 998 fNewPt = fBisector; |
| 999 fNewPt.scale(t); |
| 1000 fNewPt += tess.point(fIndex1); |
| 1001 |
| 1002 fDepth = tess.computeDepthFromEdge(fEdgeId, fNewPt); |
| 1003 #endif |
| 1004 } |
| 1005 |
| 1006 #if 0 |
| 1007 void GrVertInfo::computeIntersection(const GrAAConvexTessellator& tess) { |
| 1008 SkScalar tPrev, tNext; |
| 1009 intersect2(tess.point(fIndex1), fBisector, |
| 1010 tess.point(fPrev->index1()), fPrev->bisector(), |
| 1011 &tPrev); |
| 1012 intersect2(tess.point(fIndex1), fBisector, |
| 1013 tess.point(fNext->index1()), fNext->bisector(), |
| 1014 &tNext); |
| 1015 SkScalar t = SkMinScalar(tPrev, tNext); |
| 1016 if (tPrev < tNext) { |
| 1017 fWasNext = false; |
| 1018 } else { |
| 1019 fWasNext = true; |
| 1020 } |
| 1021 |
| 1022 fNewPt = fBisector; |
| 1023 fNewPt.scale(t); |
| 1024 fNewPt += tess.point(fIndex1); |
| 1025 |
| 1026 fDepth = tess.computeDepthFromEdge(fEdgeId, fNewPt); |
| 1027 } |
| 1028 #endif |
| 1029 |
| 1030 ////////////////////////////////////////////////////////////////////////////// |
| 1031 #ifdef SK_DEBUG |
| 1032 #if 0 |
| 1033 // Is this ring convex? |
| 1034 bool GrRing::isConvex(const GrAAConvexTessellator& tess) const { |
| 1035 if (fIndices.count() < 3) { |
| 1036 return false; |
| 1037 } |
| 1038 |
| 1039 SkPoint prev = tess.point(fIndices[0]) - tess.point(fIndices[fIndices.count(
)-1]); |
| 1040 SkPoint cur = tess.point(fIndices[1]) - tess.point(fIndices[0]); |
| 1041 SkScalar minDot = prev.fX * cur.fY - prev.fY * cur.fX; |
| 1042 SkScalar maxDot = minDot; |
| 1043 |
| 1044 prev = cur; |
| 1045 for (int i = 1; i < fIndices.count(); ++i) { |
| 1046 int next = (i + 1) % fIndices.count(); |
| 1047 |
| 1048 cur = tess.point(fIndices[next]) - tess.point(fIndices[i]); |
| 1049 SkScalar dot = prev.fX * cur.fY - prev.fY * cur.fX; |
| 1050 |
| 1051 minDot = SkMinScalar(minDot, dot); |
| 1052 maxDot = SkMaxScalar(maxDot, dot); |
| 1053 |
| 1054 prev = cur; |
| 1055 } |
| 1056 |
| 1057 return (maxDot > 0.0f) == (minDot >= 0.0f); |
| 1058 } |
| 1059 #endif |
| 1060 |
| 1061 static SkScalar capsule_depth(const SkPoint& p0, const SkPoint& p1, |
| 1062 const SkPoint& test, SkPoint::Side side, |
| 1063 int* sign) { |
| 1064 *sign = -1; |
| 1065 SkPoint edge = p1 - p0; |
| 1066 SkScalar len = SkPoint::Normalize(&edge); |
| 1067 |
| 1068 SkPoint testVec = test - p0; |
| 1069 |
| 1070 SkScalar d0 = edge.dot(testVec); |
| 1071 if (d0 < 0.0f) { |
| 1072 return SkPoint::Distance(p0, test); |
| 1073 } |
| 1074 if (d0 > len) { |
| 1075 return SkPoint::Distance(p1, test); |
| 1076 } |
| 1077 |
| 1078 SkScalar perpDist = testVec.fY * edge.fX - testVec.fX * edge.fY; |
| 1079 if (SkPoint::kRight_Side == side) { |
| 1080 perpDist = -perpDist; |
| 1081 } |
| 1082 |
| 1083 if (perpDist < 0.0f) { |
| 1084 perpDist = -perpDist; |
| 1085 } else { |
| 1086 *sign = 1; |
| 1087 } |
| 1088 return perpDist; |
| 1089 } |
| 1090 |
| 1091 SkScalar GrAAConvexTessellator::computeRealDepth(const SkPoint& p) const { |
| 1092 SkScalar minDist = SK_ScalarMax; |
| 1093 int closestEdge, closestSign, sign; |
| 1094 |
| 1095 for (int edge = 0; edge < fNorms.count(); ++edge) { |
| 1096 SkScalar dist = capsule_depth(fPts[edge], |
| 1097 fPts[(edge+1) % fNorms.count()], |
| 1098 p, fSide, &sign); |
| 1099 SkASSERT(dist >= 0.0f); |
| 1100 |
| 1101 if (minDist > dist) { |
| 1102 minDist = dist; |
| 1103 closestEdge = edge; |
| 1104 closestSign = sign; |
| 1105 } |
| 1106 } |
| 1107 |
| 1108 return closestSign * minDist; |
| 1109 } |
| 1110 |
| 1111 // Verify that the incrementally computed depths are close to the actual depths. |
| 1112 void GrAAConvexTessellator::checkAllDepths() const { |
| 1113 for (int cur = 0; cur < this->numPts(); ++cur) { |
| 1114 SkScalar realDepth = this->computeRealDepth(this->point(cur)); |
| 1115 realDepth++; |
| 1116 // SkASSERT(SkScalarNearlyEqual(realDepth, this->depth(cur))); |
| 1117 } |
| 1118 } |
| 1119 #endif |
| 1120 |
| 1121 ////////////////////////////////////////////////////////////////////////////// |
| 1122 #if GR_AA_CONVEX_TESSELLATOR_VIZ |
| 1123 static const SkScalar kPointRadius = 0.02f; |
| 1124 static const SkScalar kArrowStrokeWidth = 0.0f; |
| 1125 static const SkScalar kArrowLength = 0.1f; |
| 1126 static const SkScalar kEdgeTextSize = 0.2f; |
| 1127 static const SkScalar kPointTextSize = 0.02f; |
| 1128 |
| 1129 static void draw_point(SkCanvas* canvas, const SkPoint& p, SkScalar paramValue)
{ |
| 1130 SkPaint paint; |
| 1131 if (paramValue > 1.0f) { |
| 1132 //SkASSERT(0); |
| 1133 paramValue = 1.0f; |
| 1134 } |
| 1135 int gs = int(255*paramValue); |
| 1136 paint.setARGB(255, gs, gs, gs); |
| 1137 |
| 1138 canvas->drawCircle(p.fX, p.fY, kPointRadius, paint); |
| 1139 } |
| 1140 |
| 1141 static void draw_line(SkCanvas* canvas, const SkPoint& p0, const SkPoint& p1, Sk
Color color) { |
| 1142 SkPaint p; |
| 1143 p.setColor(color); |
| 1144 |
| 1145 canvas->drawLine(p0.fX, p0.fY, p1.fX, p1.fY, p); |
| 1146 } |
| 1147 |
| 1148 static void draw_arrow(SkCanvas*canvas, const SkPoint& p, const SkPoint &n, |
| 1149 SkScalar len, SkColor color) { |
| 1150 SkPaint paint; |
| 1151 paint.setColor(color); |
| 1152 paint.setStrokeWidth(kArrowStrokeWidth); |
| 1153 paint.setStyle(SkPaint::kStroke_Style); |
| 1154 |
| 1155 canvas->drawLine(p.fX, p.fY, |
| 1156 p.fX + len * n.fX, p.fY + len * n.fY, |
| 1157 paint); |
| 1158 } |
| 1159 |
| 1160 void GrAAConvexTessellator::drawInitialPoly(SkCanvas* canvas) const { |
| 1161 SkPaint paint; |
| 1162 paint.setTextSize(kEdgeTextSize); |
| 1163 |
| 1164 for (int cur = 0; cur < fNorms.count(); ++cur) { |
| 1165 int next = (cur + 1) % fNorms.count(); |
| 1166 |
| 1167 draw_line(canvas, this->point(cur), this->point(next), SK_ColorGREEN); |
| 1168 |
| 1169 SkPoint mid = this->point(cur) + this->point(next); |
| 1170 mid.scale(0.5f); |
| 1171 |
| 1172 draw_arrow(canvas, mid, fNorms[cur], kArrowLength, SK_ColorRED); |
| 1173 mid.fX += (kArrowLength/2) * fNorms[cur].fX; |
| 1174 mid.fY += (kArrowLength/2) * fNorms[cur].fY; |
| 1175 |
| 1176 SkString num; |
| 1177 num.printf("%d", cur); |
| 1178 canvas->drawText(num.c_str(), num.size(), mid.fX, mid.fY, paint); |
| 1179 |
| 1180 draw_arrow(canvas, this->point(cur), fBisectors[cur], kArrowLength, SK_C
olorBLUE); |
| 1181 } |
| 1182 } |
| 1183 |
| 1184 void GrAAConvexTessellator::draw(SkCanvas* canvas) const { |
| 1185 for (int i = 0; i < fIndices.count(); i += 3) { |
| 1186 SkASSERT(fIndices[i] < this->numPts()) ; |
| 1187 SkASSERT(fIndices[i+1] < this->numPts()) ; |
| 1188 SkASSERT(fIndices[i+2] < this->numPts()) ; |
| 1189 |
| 1190 draw_line(canvas, |
| 1191 this->point(this->fIndices[i]), this->point(this->fIndices[i+1
]), |
| 1192 SK_ColorBLACK); |
| 1193 draw_line(canvas, |
| 1194 this->point(this->fIndices[i+1]), this->point(this->fIndices[i
+2]), |
| 1195 SK_ColorBLACK); |
| 1196 draw_line(canvas, |
| 1197 this->point(this->fIndices[i+2]), this->point(this->fIndices[i
]), |
| 1198 SK_ColorBLACK); |
| 1199 } |
| 1200 |
| 1201 this->drawInitialPoly(canvas); |
| 1202 |
| 1203 for (int i = 0; i < this->numPts(); ++i) { |
| 1204 draw_point(canvas, |
| 1205 this->point(i), 0.5f + (this->depth(i)/(2*fTargetDepth))); |
| 1206 |
| 1207 SkPaint paint; |
| 1208 paint.setTextSize(kPointTextSize); |
| 1209 paint.setTextAlign(SkPaint::kCenter_Align); |
| 1210 if (this->depth(i) <= -fTargetDepth) { |
| 1211 paint.setColor(SK_ColorWHITE); |
| 1212 } |
| 1213 |
| 1214 SkString num; |
| 1215 num.printf("%d", i); |
| 1216 canvas->drawText(num.c_str(), num.size(), |
| 1217 this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f
), |
| 1218 paint); |
| 1219 } |
| 1220 } |
| 1221 |
| 1222 #endif |
| 1223 |
| OLD | NEW |