Chromium Code Reviews

Side by Side Diff: src/gpu/GrAAConvexTessellator.cpp

Issue 1158803002: Added GrAAFlatteningConvexPathRenderer (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fixed minor formatting issues, renamed Flattening to Linearizing, replaced tessellator with new imp… Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff |
OLDNEW
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"
11 #include "SkPoint.h" 11 #include "SkPoint.h"
12 #include "SkString.h" 12 #include "SkString.h"
13 #include "GrPathUtils.h"
13 14
14 // Next steps: 15 // Next steps:
15 // use in AAConvexPathRenderer 16 // use in AAConvexPathRenderer
16 // add an interactive sample app slide 17 // add an interactive sample app slide
17 // add debug check that all points are suitably far apart 18 // add debug check that all points are suitably far apart
18 // test more degenerate cases 19 // test more degenerate cases
19 20
20 // The tolerance for fusing vertices and eliminating colinear lines (It is in de vice space). 21 // 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 kClose = (SK_Scalar1 / 16);
22 static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose); 23 static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
(...skipping 21 matching lines...)
44 } 45 }
45 46
46 static SkScalar abs_dist_from_line(const SkPoint& p0, const SkVector& v, const S kPoint& test) { 47 static SkScalar abs_dist_from_line(const SkPoint& p0, const SkVector& v, const S kPoint& test) {
47 SkPoint testV = test - p0; 48 SkPoint testV = test - p0;
48 SkScalar dist = testV.fX * v.fY - testV.fY * v.fX; 49 SkScalar dist = testV.fX * v.fY - testV.fY * v.fX;
49 return SkScalarAbs(dist); 50 return SkScalarAbs(dist);
50 } 51 }
51 52
52 int GrAAConvexTessellator::addPt(const SkPoint& pt, 53 int GrAAConvexTessellator::addPt(const SkPoint& pt,
53 SkScalar depth, 54 SkScalar depth,
54 bool movable) { 55 bool movable,
56 bool isCurve) {
55 this->validate(); 57 this->validate();
56 58
57 int index = fPts.count(); 59 int index = fPts.count();
58 *fPts.push() = pt; 60 *fPts.push() = pt;
59 *fDepths.push() = depth; 61 *fDepths.push() = depth;
60 *fMovable.push() = movable; 62 *fMovable.push() = movable;
63 *fIsCurve.push() = isCurve;
61 64
62 this->validate(); 65 this->validate();
63 return index; 66 return index;
64 } 67 }
65 68
66 void GrAAConvexTessellator::popLastPt() { 69 void GrAAConvexTessellator::popLastPt() {
67 this->validate(); 70 this->validate();
68 71
69 fPts.pop(); 72 fPts.pop();
70 fDepths.pop(); 73 fDepths.pop();
(...skipping 158 matching lines...)
229 SkASSERT(t > 0.0f); 232 SkASSERT(t > 0.0f);
230 *result = bisector; 233 *result = bisector;
231 result->scale(t); 234 result->scale(t);
232 *result += newP; 235 *result += newP;
233 236
234 237
235 return true; 238 return true;
236 } 239 }
237 240
238 bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat h) { 241 bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat h) {
239 SkASSERT(SkPath::kLine_SegmentMask == path.getSegmentMasks());
240 SkASSERT(SkPath::kConvex_Convexity == path.getConvexity()); 242 SkASSERT(SkPath::kConvex_Convexity == path.getConvexity());
241 243
242 // Outer ring: 3*numPts 244 // Outer ring: 3*numPts
243 // Middle ring: numPts 245 // Middle ring: numPts
244 // Presumptive inner ring: numPts 246 // Presumptive inner ring: numPts
245 this->reservePts(5*path.countPoints()); 247 this->reservePts(5*path.countPoints());
246 // Outer ring: 12*numPts 248 // Outer ring: 12*numPts
247 // Middle ring: 0 249 // Middle ring: 0
248 // Presumptive inner ring: 6*numPts + 6 250 // Presumptive inner ring: 6*numPts + 6
249 fIndices.setReserve(18*path.countPoints() + 6); 251 fIndices.setReserve(18*path.countPoints() + 6);
250 252
251 fNorms.setReserve(path.countPoints()); 253 fNorms.setReserve(path.countPoints());
252 254
253 SkScalar minCross = SK_ScalarMax, maxCross = -SK_ScalarMax;
bsalomon 2015/05/29 15:07:56 I'm not sure how important these were for Rob to d
ethannicholas 2015/06/02 20:20:41 Fixed.
254
255 // TODO: is there a faster way to extract the points from the path? Perhaps 255 // TODO: is there a faster way to extract the points from the path? Perhaps
256 // get all the points via a new entry point, transform them all in bulk 256 // get all the points via a new entry point, transform them all in bulk
257 // and then walk them to find duplicates? 257 // and then walk them to find duplicates?
258 SkPath::Iter iter(path, true); 258 SkPath::Iter iter(path, true);
259 SkPoint pts[4]; 259 SkPoint pts[4];
260 SkPath::Verb verb; 260 SkPath::Verb verb;
261 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 261 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
262 switch (verb) { 262 switch (verb) {
263 case SkPath::kLine_Verb: 263 case SkPath::kLine_Verb:
264 m.mapPoints(&pts[1], 1); 264 this->lineTo(m, pts[1], false);
265 if (this->numPts() > 0 && duplicate_pt(pts[1], this->lastPoint() )) {
266 continue;
267 }
268
269 SkASSERT(fPts.count() <= 1 || fPts.count() == fNorms.count()+1);
270 if (this->numPts() >= 2 &&
271 abs_dist_from_line(fPts.top(), fNorms.top(), pts[1]) < kClos e) {
272 // The old last point is on the line from the second to last to the new point
273 this->popLastPt();
274 fNorms.pop();
275 }
276
277 this->addPt(pts[1], 0.0f, false);
278 if (this->numPts() > 1) {
279 *fNorms.push() = fPts.top() - fPts[fPts.count()-2];
280 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top() );
281 SkASSERT(len > 0.0f);
282 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms.top().length()));
283 }
284
285 if (this->numPts() >= 3) {
286 int cur = this->numPts()-1;
287 SkScalar cross = SkPoint::CrossProduct(fNorms[cur-1], fNorms [cur-2]);
288 maxCross = SkTMax(maxCross, cross);
289 minCross = SkTMin(minCross, cross);
290 }
291 break; 265 break;
292 case SkPath::kQuad_Verb: 266 case SkPath::kQuad_Verb:
267 this->quadTo(m, pts);
268 break;
269 case SkPath::kCubic_Verb:
270 this->cubicTo(m, pts);
271 break;
293 case SkPath::kConic_Verb: 272 case SkPath::kConic_Verb:
294 case SkPath::kCubic_Verb: 273 this->conicTo(m, pts, iter.conicWeight());
295 SkASSERT(false);
296 break; 274 break;
297 case SkPath::kMove_Verb: 275 case SkPath::kMove_Verb:
298 case SkPath::kClose_Verb: 276 case SkPath::kClose_Verb:
299 case SkPath::kDone_Verb: 277 case SkPath::kDone_Verb:
300 break; 278 break;
301 } 279 }
302 } 280 }
303 281
304 if (this->numPts() < 3) { 282 if (this->numPts() < 3) {
305 return false; 283 return false;
(...skipping 31 matching lines...)
337 SkASSERT(len > 0.0f); 315 SkASSERT(len > 0.0f);
338 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[0].length())); 316 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[0].length()));
339 } 317 }
340 318
341 if (this->numPts() < 3) { 319 if (this->numPts() < 3) {
342 return false; 320 return false;
343 } 321 }
344 322
345 // Check the cross produce of the final trio 323 // Check the cross produce of the final trio
346 SkScalar cross = SkPoint::CrossProduct(fNorms[0], fNorms.top()); 324 SkScalar cross = SkPoint::CrossProduct(fNorms[0], fNorms.top());
347 maxCross = SkTMax(maxCross, cross); 325 if (cross > 0.0f) {
348 minCross = SkTMin(minCross, cross);
349
350 if (maxCross > 0.0f) {
351 SkASSERT(minCross >= 0.0f);
352 fSide = SkPoint::kRight_Side; 326 fSide = SkPoint::kRight_Side;
353 } else { 327 } else {
354 SkASSERT(minCross <= 0.0f);
355 fSide = SkPoint::kLeft_Side; 328 fSide = SkPoint::kLeft_Side;
356 } 329 }
357 330
358 // Make all the normals face outwards rather than along the edge 331 // Make all the normals face outwards rather than along the edge
359 for (int cur = 0; cur < fNorms.count(); ++cur) { 332 for (int cur = 0; cur < fNorms.count(); ++cur) {
360 fNorms[cur].setOrthog(fNorms[cur], fSide); 333 fNorms[cur].setOrthog(fNorms[cur], fSide);
361 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length())); 334 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length()));
362 } 335 }
363 336
364 this->computeBisectors(); 337 this->computeBisectors();
(...skipping 32 matching lines...)
397 } 370 }
398 371
399 void GrAAConvexTessellator::createOuterRing() { 372 void GrAAConvexTessellator::createOuterRing() {
400 // For now, we're only generating one outer ring (at the start). This 373 // For now, we're only generating one outer ring (at the start). This
401 // could be relaxed for stroking use cases. 374 // could be relaxed for stroking use cases.
402 SkASSERT(0 == fIndices.count()); 375 SkASSERT(0 == fIndices.count());
403 SkASSERT(fPts.count() == fNorms.count()); 376 SkASSERT(fPts.count() == fNorms.count());
404 377
405 const int numPts = fPts.count(); 378 const int numPts = fPts.count();
406 379
407 // For each vertex of the original polygon we add three points to the
408 // outset polygon - one extending perpendicular to each impinging edge
409 // and one along the bisector. Two triangles are added for each corner
410 // and two are added along each edge.
411 int prev = numPts - 1; 380 int prev = numPts - 1;
412 int lastPerpIdx = -1, firstPerpIdx = -1, newIdx0, newIdx1, newIdx2; 381 int lastPerpIdx = -1, firstPerpIdx = -1, newIdx0, newIdx1, newIdx2;
413 for (int cur = 0; cur < numPts; ++cur) { 382 for (int cur = 0; cur < numPts; ++cur) {
414 // The perpendicular point for the last edge 383 if (fIsCurve[cur]) {
415 SkPoint temp = fNorms[prev]; 384 // Inside a curve, we assume that the curvature is shallow enough (d ue to tesselation)
416 temp.scale(fTargetDepth); 385 // that we only need one corner point. Mathematically, the distance the corner point
417 temp += fPts[cur]; 386 // gets shifted out should depend on the angle between the two line segments (as in
387 // mitering), but again due to tesselation we assume that this angle is small and
388 // therefore the correction factor is negligible and we do not bothe r with it.
418 389
419 // We know it isn't a duplicate of the prior point (since it and this 390 // The bisector outset point
420 // one are just perpendicular offsets from the non-merged polygon points ) 391 SkPoint temp = fBisectors[cur];
421 newIdx0 = this->addPt(temp, -fTargetDepth, false); 392 temp.scale(-fTargetDepth); // the bisectors point in
393 temp += fPts[cur];
422 394
423 // The bisector outset point 395 // double-check our "sufficiently flat" assumption; we want the bise ctor point to be
424 temp = fBisectors[cur]; 396 // close to the normal point.
425 temp.scale(-fTargetDepth); // the bisectors point in 397 #define kFlatnessTolerance 1.0f
426 temp += fPts[cur]; 398 SkDEBUGCODE(SkPoint prevNormal = fNorms[prev];)
399 SkDEBUGCODE(prevNormal.scale(fTargetDepth);)
400 SkDEBUGCODE(prevNormal += fPts[cur];)
401 SkASSERT((temp - prevNormal).length() < kFlatnessTolerance);
427 402
428 // For very shallow angles all the corner points could fuse 403 newIdx1 = this->addPt(temp, -fTargetDepth, false, true);
429 if (duplicate_pt(temp, this->point(newIdx0))) { 404
430 newIdx1 = newIdx0; 405 if (0 == cur) {
431 } else { 406 // Store the index of the first perpendicular point to finish up
432 newIdx1 = this->addPt(temp, -fTargetDepth, false); 407 firstPerpIdx = newIdx1;
408 SkASSERT(-1 == lastPerpIdx);
409 } else {
410 // The triangles for the previous edge
411 this->addTri(prev, newIdx1, cur);
412 this->addTri(prev, lastPerpIdx, newIdx1);
413 }
414
415 prev = cur;
416 // Track the last perpendicular outset point so we can construct the
417 // trailing edge triangles.
418 lastPerpIdx = newIdx1;
433 } 419 }
420 else {
421 // For each vertex of the original polygon we add three points to th e
422 // outset polygon - one extending perpendicular to each impinging ed ge
423 // and one along the bisector. Two triangles are added for each corn er
424 // and two are added along each edge.
434 425
435 // The perpendicular point for the next edge. 426 // The perpendicular point for the last edge
436 temp = fNorms[cur]; 427 SkPoint temp = fNorms[prev];
437 temp.scale(fTargetDepth); 428 temp.scale(fTargetDepth);
438 temp += fPts[cur]; 429 temp += fPts[cur];
439 430
440 // For very shallow angles all the corner points could fuse. 431 // We know it isn't a duplicate of the prior point (since it and thi s
441 if (duplicate_pt(temp, this->point(newIdx1))) { 432 // one are just perpendicular offsets from the non-merged polygon po ints)
442 newIdx2 = newIdx1; 433 newIdx0 = this->addPt(temp, -fTargetDepth, false, false);
443 } else { 434
444 newIdx2 = this->addPt(temp, -fTargetDepth, false); 435 // The bisector outset point
436 temp = fBisectors[cur];
437 temp.scale(-fTargetDepth); // the bisectors point in
438 temp += fPts[cur];
439
440 // For very shallow angles all the corner points could fuse
441 if (duplicate_pt(temp, this->point(newIdx0))) {
442 newIdx1 = newIdx0;
443 } else {
444 newIdx1 = this->addPt(temp, -fTargetDepth, false, false);
445 }
446
447 // The perpendicular point for the next edge.
448 temp = fNorms[cur];
449 temp.scale(fTargetDepth);
450 temp += fPts[cur];
451
452 // For very shallow angles all the corner points could fuse.
453 if (duplicate_pt(temp, this->point(newIdx1))) {
454 newIdx2 = newIdx1;
455 } else {
456 newIdx2 = this->addPt(temp, -fTargetDepth, false, false);
457 }
458
459 if (0 == cur) {
460 // Store the index of the first perpendicular point to finish up
461 firstPerpIdx = newIdx0;
462 SkASSERT(-1 == lastPerpIdx);
463 } else {
464 // The triangles for the previous edge
465 this->addTri(prev, newIdx0, cur);
466 this->addTri(prev, lastPerpIdx, newIdx0);
467 }
468
469 // The two triangles for the corner
470 this->addTri(cur, newIdx0, newIdx1);
471 this->addTri(cur, newIdx1, newIdx2);
472
473 prev = cur;
474 // Track the last perpendicular outset point so we can construct the
475 // trailing edge triangles.
476 lastPerpIdx = newIdx2;
445 } 477 }
446
447 if (0 == cur) {
448 // Store the index of the first perpendicular point to finish up
449 firstPerpIdx = newIdx0;
450 SkASSERT(-1 == lastPerpIdx);
451 } else {
452 // The triangles for the previous edge
453 this->addTri(prev, newIdx0, cur);
454 this->addTri(prev, lastPerpIdx, newIdx0);
455 }
456
457 // The two triangles for the corner
458 this->addTri(cur, newIdx0, newIdx1);
459 this->addTri(cur, newIdx1, newIdx2);
460
461 prev = cur;
462 // Track the last perpendicular outset point so we can construct the
463 // trailing edge triangles.
464 lastPerpIdx = newIdx2;
465 } 478 }
466 479
467 // pick up the final edge rect 480 // pick up the final edge rect
468 this->addTri(numPts-1, firstPerpIdx, 0); 481 this->addTri(numPts - 1, firstPerpIdx, 0);
469 this->addTri(numPts-1, lastPerpIdx, firstPerpIdx); 482 this->addTri(numPts - 1, lastPerpIdx, firstPerpIdx);
470 483
471 this->validate(); 484 this->validate();
472 } 485 }
473 486
474 // Something went wrong in the creation of the next ring. Mark the last good 487 // Something went wrong in the creation of the next ring. Mark the last good
475 // ring as being at the desired depth and fan it. 488 // ring as being at the desired depth and fan it.
476 void GrAAConvexTessellator::terminate(const Ring& ring) { 489 void GrAAConvexTessellator::terminate(const Ring& ring) {
477 for (int i = 0; i < ring.numPts(); ++i) { 490 for (int i = 0; i < ring.numPts(); ++i) {
478 fDepths[ring.index(i)] = fTargetDepth; 491 fDepths[ring.index(i)] = fTargetDepth;
479 } 492 }
(...skipping 105 matching lines...)
585 } 598 }
586 } 599 }
587 600
588 // Fold the new ring's points into the global pool 601 // Fold the new ring's points into the global pool
589 for (int i = 0; i < fCandidateVerts.numPts(); ++i) { 602 for (int i = 0; i < fCandidateVerts.numPts(); ++i) {
590 int newIdx; 603 int newIdx;
591 if (fCandidateVerts.needsToBeNew(i)) { 604 if (fCandidateVerts.needsToBeNew(i)) {
592 // if the originating index is still valid then this point wasn't 605 // if the originating index is still valid then this point wasn't
593 // fused (and is thus movable) 606 // fused (and is thus movable)
594 newIdx = this->addPt(fCandidateVerts.point(i), depth, 607 newIdx = this->addPt(fCandidateVerts.point(i), depth,
595 fCandidateVerts.originatingIdx(i) != -1); 608 fCandidateVerts.originatingIdx(i) != -1, false) ;
596 } else { 609 } else {
597 SkASSERT(fCandidateVerts.originatingIdx(i) != -1); 610 SkASSERT(fCandidateVerts.originatingIdx(i) != -1);
598 this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.po int(i), depth); 611 this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.po int(i), depth);
599 newIdx = fCandidateVerts.originatingIdx(i); 612 newIdx = fCandidateVerts.originatingIdx(i);
600 } 613 }
601 614
602 nextRing->addIdx(newIdx, fCandidateVerts.origEdge(i)); 615 nextRing->addIdx(newIdx, fCandidateVerts.origEdge(i));
603 } 616 }
604 617
605 // 'dst' currently has indices into the ring. Remap these to be indices 618 // 'dst' currently has indices into the ring. Remap these to be indices
(...skipping 155 matching lines...)
761 // Verify that the incrementally computed depths are close to the actual depths. 774 // Verify that the incrementally computed depths are close to the actual depths.
762 void GrAAConvexTessellator::checkAllDepths() const { 775 void GrAAConvexTessellator::checkAllDepths() const {
763 for (int cur = 0; cur < this->numPts(); ++cur) { 776 for (int cur = 0; cur < this->numPts(); ++cur) {
764 SkScalar realDepth = this->computeRealDepth(this->point(cur)); 777 SkScalar realDepth = this->computeRealDepth(this->point(cur));
765 SkScalar computedDepth = this->depth(cur); 778 SkScalar computedDepth = this->depth(cur);
766 SkASSERT(SkScalarNearlyEqual(realDepth, computedDepth, 0.01f)); 779 SkASSERT(SkScalarNearlyEqual(realDepth, computedDepth, 0.01f));
767 } 780 }
768 } 781 }
769 #endif 782 #endif
770 783
784 #define kQuadTolerance 0.2f
785 #define kCubicTolerance 0.2f
786 #define kConicTolerance 0.5f
787
788 void GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, bool isCurve) {
789 m.mapPoints(&p, 1);
790 if (this->numPts() > 0 && duplicate_pt(p, this->lastPoint())) {
791 return;
792 }
793
794 SkASSERT(fPts.count() <= 1 || fPts.count() == fNorms.count()+1);
795 if (this->numPts() >= 2 &&
796 abs_dist_from_line(fPts.top(), fNorms.top(), p) < kClose) {
797 // The old last point is on the line from the second to last to the new point
798 this->popLastPt();
799 fNorms.pop();
800 fIsCurve.pop();
801 }
802 this->addPt(p, 0.0f, false, isCurve);
803 if (this->numPts() > 1) {
804 *fNorms.push() = fPts.top() - fPts[fPts.count()-2];
805 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top());
806 SkASSERT(len > 0.0f);
807 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms.top().length()));
808 }
809 }
810
811 void GrAAConvexTessellator::quadTo(const SkMatrix& m, SkPoint pts[3]) {
812 int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
813 fPointBuffer.setReserve(maxCount);
814 SkPoint* target = fPointBuffer.begin();
815 int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
816 kQuadTolerance, &target, maxCount);
817 fPointBuffer.setCount(count);
818 for (int i = 0; i < count; i++) {
819 lineTo(m, fPointBuffer[i], true);
820 }
821 }
822
823 void GrAAConvexTessellator::cubicTo(const SkMatrix& m, SkPoint pts[4]) {
824 int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
825 fPointBuffer.setReserve(maxCount);
826 SkPoint* target = fPointBuffer.begin();
827 int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
828 kCubicTolerance, &target, maxCount);
829 fPointBuffer.setCount(count);
830 for (int i = 0; i < count; i++) {
831 lineTo(m, fPointBuffer[i], true);
832 }
833 }
834
835 // include down here to avoid compilation errors caused by "-" overload in SkGeo metry.h
836 #include "SkGeometry.h"
837
838 void GrAAConvexTessellator::conicTo(const SkMatrix& m, SkPoint* pts, SkScalar w) {
839 SkAutoConicToQuads quadder;
840 const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
841 SkPoint lastPoint = *(quads++);
842 int count = quadder.countQuads();
843 for (int i = 0; i < count; ++i) {
844 SkPoint quadPts[3];
845 quadPts[0] = lastPoint;
846 quadPts[1] = quads[0];
847 quadPts[2] = i == count - 1 ? pts[2] : quads[1];
848 quadTo(m, quadPts);
849 lastPoint = quadPts[2];
850 quads += 2;
851 }
852 }
853
771 ////////////////////////////////////////////////////////////////////////////// 854 //////////////////////////////////////////////////////////////////////////////
772 #if GR_AA_CONVEX_TESSELLATOR_VIZ 855 #if GR_AA_CONVEX_TESSELLATOR_VIZ
773 static const SkScalar kPointRadius = 0.02f; 856 static const SkScalar kPointRadius = 0.02f;
774 static const SkScalar kArrowStrokeWidth = 0.0f; 857 static const SkScalar kArrowStrokeWidth = 0.0f;
775 static const SkScalar kArrowLength = 0.2f; 858 static const SkScalar kArrowLength = 0.2f;
776 static const SkScalar kEdgeTextSize = 0.1f; 859 static const SkScalar kEdgeTextSize = 0.1f;
777 static const SkScalar kPointTextSize = 0.02f; 860 static const SkScalar kPointTextSize = 0.02f;
778 861
779 static void draw_point(SkCanvas* canvas, const SkPoint& p, SkScalar paramValue, bool stroke) { 862 static void draw_point(SkCanvas* canvas, const SkPoint& p, SkScalar paramValue, bool stroke) {
780 SkPaint paint; 863 SkPaint paint;
(...skipping 100 matching lines...)
881 SkString num; 964 SkString num;
882 num.printf("%d", i); 965 num.printf("%d", i);
883 canvas->drawText(num.c_str(), num.size(), 966 canvas->drawText(num.c_str(), num.size(),
884 this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f ), 967 this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f ),
885 paint); 968 paint);
886 } 969 }
887 } 970 }
888 971
889 #endif 972 #endif
890 973
OLDNEW

Powered by Google App Engine