Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(164)

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

Issue 1180903006: added stroking support to GrAALinearizingConvexPathRenderer (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: debug fixes Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
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 #include "GrPathUtils.h"
14 14
15 // Next steps: 15 // Next steps:
16 // use in AAConvexPathRenderer
17 // add an interactive sample app slide 16 // add an interactive sample app slide
18 // add debug check that all points are suitably far apart 17 // add debug check that all points are suitably far apart
19 // test more degenerate cases 18 // test more degenerate cases
20 19
21 // The tolerance for fusing vertices and eliminating colinear lines (It is in de vice space). 20 // The tolerance for fusing vertices and eliminating colinear lines (It is in de vice space).
22 static const SkScalar kClose = (SK_Scalar1 / 16); 21 static const SkScalar kClose = (SK_Scalar1 / 16);
23 static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose); 22 static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
24 23
robertphillips 2015/06/16 13:13:01 Expand this comment a bit - are they in device spa
ethannicholas 2015/06/16 14:53:29 Done.
24 // tesselation tolerance values
25 static const SkScalar kQuadTolerance = 0.2;
26 static const SkScalar kCubicTolerance = 0.2;
27 static const SkScalar kConicTolerance = 0.5;
28
29 // dot product below which we use a round cap between curve segments
30 static const SkScalar kRoundCapThreshold = 0.8;
31
25 static SkScalar intersect(const SkPoint& p0, const SkPoint& n0, 32 static SkScalar intersect(const SkPoint& p0, const SkPoint& n0,
26 const SkPoint& p1, const SkPoint& n1) { 33 const SkPoint& p1, const SkPoint& n1) {
27 const SkPoint v = p1 - p0; 34 const SkPoint v = p1 - p0;
28
29 SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX; 35 SkScalar perpDot = n0.fX * n1.fY - n0.fY * n1.fX;
30 return (v.fX * n1.fY - v.fY * n1.fX) / perpDot; 36 return (v.fX * n1.fY - v.fY * n1.fX) / perpDot;
31 } 37 }
32 38
33 // This is a special case version of intersect where we have the vector 39 // This is a special case version of intersect where we have the vector
34 // perpendicular to the second line rather than the vector parallel to it. 40 // perpendicular to the second line rather than the vector parallel to it.
35 static SkScalar perp_intersect(const SkPoint& p0, const SkPoint& n0, 41 static SkScalar perp_intersect(const SkPoint& p0, const SkPoint& n0,
36 const SkPoint& p1, const SkPoint& perp) { 42 const SkPoint& p1, const SkPoint& perp) {
37 const SkPoint v = p1 - p0; 43 const SkPoint v = p1 - p0;
38 SkScalar perpDot = n0.dot(perp); 44 SkScalar perpDot = n0.dot(perp);
39 return v.dot(perp) / perpDot; 45 return v.dot(perp) / perpDot;
40 } 46 }
41 47
42 static bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) { 48 static bool duplicate_pt(const SkPoint& p0, const SkPoint& p1) {
43 SkScalar distSq = p0.distanceToSqd(p1); 49 SkScalar distSq = p0.distanceToSqd(p1);
44 return distSq < kCloseSqd; 50 return distSq < kCloseSqd;
45 } 51 }
46 52
47 static SkScalar abs_dist_from_line(const SkPoint& p0, const SkVector& v, const S kPoint& test) { 53 static SkScalar abs_dist_from_line(const SkPoint& p0, const SkVector& v, const S kPoint& test) {
48 SkPoint testV = test - p0; 54 SkPoint testV = test - p0;
49 SkScalar dist = testV.fX * v.fY - testV.fY * v.fX; 55 SkScalar dist = testV.fX * v.fY - testV.fY * v.fX;
50 return SkScalarAbs(dist); 56 return SkScalarAbs(dist);
51 } 57 }
52 58
53 int GrAAConvexTessellator::addPt(const SkPoint& pt, 59 int GrAAConvexTessellator::addPt(const SkPoint& pt,
54 SkScalar depth, 60 SkScalar depth,
61 SkScalar coverage,
55 bool movable, 62 bool movable,
56 bool isCurve) { 63 bool isCurve) {
57 this->validate(); 64 this->validate();
58 65
59 int index = fPts.count(); 66 int index = fPts.count();
60 *fPts.push() = pt; 67 *fPts.push() = pt;
61 *fDepths.push() = depth; 68 *fCoverages.push() = coverage;
62 *fMovable.push() = movable; 69 *fMovable.push() = movable;
63 *fIsCurve.push() = isCurve; 70 *fIsCurve.push() = isCurve;
64 71
65 this->validate(); 72 this->validate();
66 return index; 73 return index;
67 } 74 }
68 75
69 void GrAAConvexTessellator::popLastPt() { 76 void GrAAConvexTessellator::popLastPt() {
70 this->validate(); 77 this->validate();
71 78
72 fPts.pop(); 79 fPts.pop();
73 fDepths.pop(); 80 fCoverages.pop();
74 fMovable.pop(); 81 fMovable.pop();
75 82
76 this->validate(); 83 this->validate();
77 } 84 }
78 85
79 void GrAAConvexTessellator::popFirstPtShuffle() { 86 void GrAAConvexTessellator::popFirstPtShuffle() {
80 this->validate(); 87 this->validate();
81 88
82 fPts.removeShuffle(0); 89 fPts.removeShuffle(0);
83 fDepths.removeShuffle(0); 90 fCoverages.removeShuffle(0);
84 fMovable.removeShuffle(0); 91 fMovable.removeShuffle(0);
85 92
86 this->validate(); 93 this->validate();
87 } 94 }
88 95
89 void GrAAConvexTessellator::updatePt(int index, 96 void GrAAConvexTessellator::updatePt(int index,
90 const SkPoint& pt, 97 const SkPoint& pt,
91 SkScalar depth) { 98 SkScalar depth,
99 SkScalar coverage) {
92 this->validate(); 100 this->validate();
93 SkASSERT(fMovable[index]); 101 SkASSERT(fMovable[index]);
94 102
95 fPts[index] = pt; 103 fPts[index] = pt;
96 fDepths[index] = depth; 104 fCoverages[index] = coverage;
97 } 105 }
98 106
99 void GrAAConvexTessellator::addTri(int i0, int i1, int i2) { 107 void GrAAConvexTessellator::addTri(int i0, int i1, int i2) {
100 if (i0 == i1 || i1 == i2 || i2 == i0) { 108 if (i0 == i1 || i1 == i2 || i2 == i0) {
101 return; 109 return;
102 } 110 }
103 111
104 *fIndices.push() = i0; 112 *fIndices.push() = i0;
105 *fIndices.push() = i1; 113 *fIndices.push() = i1;
106 *fIndices.push() = i2; 114 *fIndices.push() = i2;
107 } 115 }
108 116
109 void GrAAConvexTessellator::rewind() { 117 void GrAAConvexTessellator::rewind() {
110 fPts.rewind(); 118 fPts.rewind();
111 fDepths.rewind(); 119 fCoverages.rewind();
112 fMovable.rewind(); 120 fMovable.rewind();
113 fIndices.rewind(); 121 fIndices.rewind();
114 fNorms.rewind(); 122 fNorms.rewind();
115 fInitialRing.rewind(); 123 fInitialRing.rewind();
116 fCandidateVerts.rewind(); 124 fCandidateVerts.rewind();
117 #if GR_AA_CONVEX_TESSELLATOR_VIZ 125 #if GR_AA_CONVEX_TESSELLATOR_VIZ
118 fRings.rewind(); // TODO: leak in this case! 126 fRings.rewind(); // TODO: leak in this case!
119 #else 127 #else
120 fRings[0].rewind(); 128 fRings[0].rewind();
121 fRings[1].rewind(); 129 fRings[1].rewind();
(...skipping 14 matching lines...) Expand all
136 fBisectors[cur] += other; 144 fBisectors[cur] += other;
137 SkAssertResult(fBisectors[cur].normalize()); 145 SkAssertResult(fBisectors[cur].normalize());
138 } else { 146 } else {
139 fBisectors[cur].negate(); // make the bisector face in 147 fBisectors[cur].negate(); // make the bisector face in
140 } 148 }
141 149
142 SkASSERT(SkScalarNearlyEqual(1.0f, fBisectors[cur].length())); 150 SkASSERT(SkScalarNearlyEqual(1.0f, fBisectors[cur].length()));
143 } 151 }
144 } 152 }
145 153
154 // Create as many rings as we need to (up to a predefined limit) to reach the sp ecified target
155 // depth. If we are in fill mode, the final ring will automatically be fanned.
156 bool GrAAConvexTessellator::createInsetRings(Ring& previousRing, SkScalar initia lDepth,
robertphillips 2015/06/16 13:13:01 tab this line over ?
ethannicholas 2015/06/16 14:53:29 Sorry, been using "two tabs for continuations" for
157 SkScalar initialCoverage, SkScalar targetDepth, SkScalar targetCoverage, Ring** finalRing) {
158 static const int kMaxNumRings = 8;
159
160 if (previousRing.numPts() < 3) {
161 return false;
162 }
163 Ring* currentRing = &previousRing;
164 int i;
165 for (i = 0; i < kMaxNumRings; ++i) {
166 Ring* nextRing = this->getNextRing(currentRing);
167 SkASSERT(nextRing != currentRing);
168
169 bool done = this->createInsetRing(*currentRing, nextRing, initialDepth, initialCoverage,
robertphillips 2015/06/16 13:13:01 tab this line over ?
170 targetDepth, targetCoverage, i == 0);
171 currentRing = nextRing;
172 if (done) {
173 break;
174 }
175 currentRing->init(*this);
176 }
177
178 if (kMaxNumRings == i) {
179 // Bail if we've exceeded the amount of time we want to throw at this.
180 this->terminate(*currentRing);
181 return false;
182 }
183 bool done = currentRing->numPts() >= 3;
184 if (done) {
185 currentRing->init(*this);
186 }
187 *finalRing = currentRing;
188 return done;
189 }
190
146 // The general idea here is to, conceptually, start with the original polygon an d slide 191 // The general idea here is to, conceptually, start with the original polygon an d slide
147 // the vertices along the bisectors until the first intersection. At that 192 // the vertices along the bisectors until the first intersection. At that
148 // point two of the edges collapse and the process repeats on the new polygon. 193 // point two of the edges collapse and the process repeats on the new polygon.
149 // The polygon state is captured in the Ring class while the GrAAConvexTessellat or 194 // The polygon state is captured in the Ring class while the GrAAConvexTessellat or
150 // controls the iteration. The CandidateVerts holds the formative points for the 195 // controls the iteration. The CandidateVerts holds the formative points for the
151 // next ring. 196 // next ring.
152 bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { 197 bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) {
153 static const int kMaxNumRings = 8;
154
155 SkDEBUGCODE(fShouldCheckDepths = true;)
156
157 if (!this->extractFromPath(m, path)) { 198 if (!this->extractFromPath(m, path)) {
158 return false; 199 return false;
159 } 200 }
160 201
161 this->createOuterRing(); 202 SkScalar coverage = 1.0f;
203 if (fStrokeWidth >= 0.0f) {
204 Ring outerStrokeRing;
robertphillips 2015/06/16 13:13:01 What happens when fStrokeWidth is 1.00001 ?
ethannicholas 2015/06/16 14:53:28 I tested it out, and it doesn't appear to cause an
205 this->createOuterRing(fInitialRing, fStrokeWidth / 2 - kAntialiasingRadi us, coverage,
robertphillips 2015/06/16 13:13:00 tab this line over ?
206 &outerStrokeRing);
207 outerStrokeRing.init(*this);
208 Ring outerAARing;
209 this->createOuterRing(outerStrokeRing, kAntialiasingRadius * 2, 0.0f, &o uterAARing);
210 } else {
211 Ring outerAARing;
212 this->createOuterRing(fInitialRing, kAntialiasingRadius, 0.0f, &outerAAR ing);
213 }
162 214
163 // the bisectors are only needed for the computation of the outer ring 215 // the bisectors are only needed for the computation of the outer ring
164 fBisectors.rewind(); 216 fBisectors.rewind();
165 217 if (fStrokeWidth >= 0.0f && fInitialRing.numPts() > 2) {
robertphillips 2015/06/16 13:13:01 Do we actually need to get the Ring* back from cre
ethannicholas 2015/06/16 14:53:29 When stroking, we call createInsetRings twice. The
166 Ring* lastRing = &fInitialRing; 218 Ring* insetStrokeRing;
167 int i; 219 SkScalar strokeDepth = fStrokeWidth / 2 - kAntialiasingRadius;
robertphillips 2015/06/16 13:13:01 this->createInsetRings ?
168 for (i = 0; i < kMaxNumRings; ++i) { 220 if (createInsetRings(fInitialRing, 0.0f, coverage, strokeDepth, coverage ,
169 Ring* nextRing = this->getNextRing(lastRing); 221 &insetStrokeRing)) {
170 222 Ring* insetAARing;
171 if (this->createInsetRing(*lastRing, nextRing)) { 223 createInsetRings(*insetStrokeRing, strokeDepth, coverage, strokeDept h +
172 break; 224 kAntialiasingRadius * 2, 0.0f, &insetAARing);
173 } 225 }
174 226 } else {
175 nextRing->init(*this); 227 Ring* insetAARing;
176 lastRing = nextRing; 228 createInsetRings(fInitialRing, 0.0f, 0.5f, kAntialiasingRadius, 1.0f, &i nsetAARing);
177 } 229 }
178 230
179 if (kMaxNumRings == i) { 231 SkDEBUGCODE(this->validate();)
180 // If we've exceeded the amount of time we want to throw at this, set
181 // the depth of all points in the final ring to 'fTargetDepth' and
182 // create a fan.
183 this->terminate(*lastRing);
184 SkDEBUGCODE(fShouldCheckDepths = false;)
185 }
186
187 #ifdef SK_DEBUG
188 this->validate();
189 if (fShouldCheckDepths) {
190 SkDEBUGCODE(this->checkAllDepths();)
191 }
192 #endif
193 return true; 232 return true;
194 } 233 }
195 234
196 SkScalar GrAAConvexTessellator::computeDepthFromEdge(int edgeIdx, const SkPoint& p) const { 235 SkScalar GrAAConvexTessellator::computeDepthFromEdge(int edgeIdx, const SkPoint& p) const {
197 SkASSERT(edgeIdx < fNorms.count()); 236 SkASSERT(edgeIdx < fNorms.count());
198 237
199 SkPoint v = p - fPts[edgeIdx]; 238 SkPoint v = p - fPts[edgeIdx];
200 SkScalar depth = -fNorms[edgeIdx].dot(v); 239 SkScalar depth = -fNorms[edgeIdx].dot(v);
201 SkASSERT(depth >= 0.0f);
202 return depth; 240 return depth;
203 } 241 }
204 242
205 // Find a point that is 'desiredDepth' away from the 'edgeIdx'-th edge and lies 243 // Find a point that is 'desiredDepth' away from the 'edgeIdx'-th edge and lies
206 // along the 'bisector' from the 'startIdx'-th point. 244 // along the 'bisector' from the 'startIdx'-th point.
207 bool GrAAConvexTessellator::computePtAlongBisector(int startIdx, 245 bool GrAAConvexTessellator::computePtAlongBisector(int startIdx,
208 const SkVector& bisector, 246 const SkVector& bisector,
209 int edgeIdx, 247 int edgeIdx,
210 SkScalar desiredDepth, 248 SkScalar desiredDepth,
211 SkPoint* result) const { 249 SkPoint* result) const {
212 const SkPoint& norm = fNorms[edgeIdx]; 250 const SkPoint& norm = fNorms[edgeIdx];
213 251
214 // First find the point where the edge and the bisector intersect 252 // First find the point where the edge and the bisector intersect
215 SkPoint newP; 253 SkPoint newP;
254
216 SkScalar t = perp_intersect(fPts[startIdx], bisector, fPts[edgeIdx], norm); 255 SkScalar t = perp_intersect(fPts[startIdx], bisector, fPts[edgeIdx], norm);
217 if (SkScalarNearlyEqual(t, 0.0f)) { 256 if (SkScalarNearlyEqual(t, 0.0f)) {
218 // the start point was one of the original ring points 257 // the start point was one of the original ring points
219 SkASSERT(startIdx < fNorms.count()); 258 SkASSERT(startIdx < fPts.count());
220 newP = fPts[startIdx]; 259 newP = fPts[startIdx];
221 } else if (t > 0.0f) { 260 } else if (t < 0.0f) {
222 SkASSERT(t < 0.0f);
223 newP = bisector; 261 newP = bisector;
224 newP.scale(t); 262 newP.scale(t);
225 newP += fPts[startIdx]; 263 newP += fPts[startIdx];
226 } else { 264 } else {
227 return false; 265 return false;
228 } 266 }
229 267
230 // Then offset along the bisector from that point the correct distance 268 // Then offset along the bisector from that point the correct distance
231 t = -desiredDepth / bisector.dot(norm); 269 SkScalar dot = bisector.dot(norm);
232 SkASSERT(t > 0.0f); 270 t = -desiredDepth / dot;
233 *result = bisector; 271 *result = bisector;
234 result->scale(t); 272 result->scale(t);
235 *result += newP; 273 *result += newP;
236 274
237
238 return true; 275 return true;
239 } 276 }
240 277
241 bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat h) { 278 bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat h) {
242 SkASSERT(SkPath::kConvex_Convexity == path.getConvexity()); 279 SkASSERT(SkPath::kConvex_Convexity == path.getConvexity());
243 280
244 // Outer ring: 3*numPts 281 // Outer ring: 3*numPts
245 // Middle ring: numPts 282 // Middle ring: numPts
246 // Presumptive inner ring: numPts 283 // Presumptive inner ring: numPts
247 this->reservePts(5*path.countPoints()); 284 this->reservePts(5*path.countPoints());
248 // Outer ring: 12*numPts 285 // Outer ring: 12*numPts
249 // Middle ring: 0 286 // Middle ring: 0
250 // Presumptive inner ring: 6*numPts + 6 287 // Presumptive inner ring: 6*numPts + 6
251 fIndices.setReserve(18*path.countPoints() + 6); 288 fIndices.setReserve(18*path.countPoints() + 6);
252 289
253 fNorms.setReserve(path.countPoints()); 290 fNorms.setReserve(path.countPoints());
254 291
255 SkDEBUGCODE(fMinCross = SK_ScalarMax;)
256 SkDEBUGCODE(fMaxCross = -SK_ScalarMax;)
257
258 // TODO: is there a faster way to extract the points from the path? Perhaps 292 // TODO: is there a faster way to extract the points from the path? Perhaps
259 // get all the points via a new entry point, transform them all in bulk 293 // get all the points via a new entry point, transform them all in bulk
260 // and then walk them to find duplicates? 294 // and then walk them to find duplicates?
261 SkPath::Iter iter(path, true); 295 SkPath::Iter iter(path, true);
262 SkPoint pts[4]; 296 SkPoint pts[4];
263 SkPath::Verb verb; 297 SkPath::Verb verb;
264 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 298 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
265 switch (verb) { 299 switch (verb) {
266 case SkPath::kLine_Verb: 300 case SkPath::kLine_Verb:
267 this->lineTo(m, pts[1], false); 301 this->lineTo(m, pts[1], false);
268 break; 302 break;
269 case SkPath::kQuad_Verb: 303 case SkPath::kQuad_Verb:
270 this->quadTo(m, pts); 304 this->quadTo(m, pts);
271 break; 305 break;
272 case SkPath::kCubic_Verb: 306 case SkPath::kCubic_Verb:
273 this->cubicTo(m, pts); 307 this->cubicTo(m, pts);
274 break; 308 break;
275 case SkPath::kConic_Verb: 309 case SkPath::kConic_Verb:
276 this->conicTo(m, pts, iter.conicWeight()); 310 this->conicTo(m, pts, iter.conicWeight());
277 break; 311 break;
278 case SkPath::kMove_Verb: 312 case SkPath::kMove_Verb:
279 case SkPath::kClose_Verb: 313 case SkPath::kClose_Verb:
280 case SkPath::kDone_Verb: 314 case SkPath::kDone_Verb:
281 break; 315 break;
282 } 316 }
283 } 317 }
284 318
285 if (this->numPts() < 3) { 319 if (this->numPts() < 2) {
286 return false; 320 return false;
287 } 321 }
288 322
289 // check if last point is a duplicate of the first point. If so, remove it. 323 // check if last point is a duplicate of the first point. If so, remove it.
290 if (duplicate_pt(fPts[this->numPts()-1], fPts[0])) { 324 if (duplicate_pt(fPts[this->numPts()-1], fPts[0])) {
291 this->popLastPt(); 325 this->popLastPt();
292 fNorms.pop(); 326 fNorms.pop();
293 } 327 }
294 328
295 SkASSERT(fPts.count() == fNorms.count()+1); 329 SkASSERT(fPts.count() == fNorms.count()+1);
296 if (this->numPts() >= 3 && 330 if (this->numPts() >= 3) {
robertphillips 2015/06/16 13:13:00 Don't we still want to remove the last point if it
ethannicholas 2015/06/16 14:53:29 Oops, hadn't meant to leave that commented out.
297 abs_dist_from_line(fPts.top(), fNorms.top(), fPts[0]) < kClose) { 331 /* if (abs_dist_from_line(fPts.top(), fNorms.top(), fPts[0]) < kClose) {
298 // The last point is on the line from the second to last to the first po int. 332 // The last point is on the line from the second to last to the firs t point.
299 this->popLastPt(); 333 this->popLastPt();
300 fNorms.pop(); 334 fNorms.pop();
335 }*/
336
337 *fNorms.push() = fPts[0] - fPts.top();
338 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top());
339 SkASSERT(len > 0.0f);
340 SkASSERT(fPts.count() == fNorms.count());
301 } 341 }
302 342
303 if (this->numPts() < 3) { 343 if (this->numPts() >= 3 && abs_dist_from_line(fPts[0], fNorms.top(), fPts[1] ) < kClose) {
304 return false;
305 }
306
307 *fNorms.push() = fPts[0] - fPts.top();
308 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top());
309 SkASSERT(len > 0.0f);
310 SkASSERT(fPts.count() == fNorms.count());
311
312 if (abs_dist_from_line(fPts[0], fNorms.top(), fPts[1]) < kClose) {
313 // The first point is on the line from the last to the second. 344 // The first point is on the line from the last to the second.
314 this->popFirstPtShuffle(); 345 this->popFirstPtShuffle();
315 fNorms.removeShuffle(0); 346 fNorms.removeShuffle(0);
316 fNorms[0] = fPts[1] - fPts[0]; 347 fNorms[0] = fPts[1] - fPts[0];
317 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms[0]); 348 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms[0]);
318 SkASSERT(len > 0.0f); 349 SkASSERT(len > 0.0f);
319 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[0].length())); 350 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[0].length()));
320 } 351 }
321 352
322 if (this->numPts() < 3) { 353 if (this->numPts() >= 3) {
354 // Check the cross product of the final trio
355 SkScalar cross = SkPoint::CrossProduct(fNorms[0], fNorms.top());
356 if (cross > 0.0f) {
357 fSide = SkPoint::kRight_Side;
358 } else {
359 fSide = SkPoint::kLeft_Side;
360 }
361
362 // Make all the normals face outwards rather than along the edge
363 for (int cur = 0; cur < fNorms.count(); ++cur) {
364 fNorms[cur].setOrthog(fNorms[cur], fSide);
365 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length()));
366 }
367
368 this->computeBisectors();
369 } else if (this->numPts() == 2) {
370 // We've got two points, so we're degenerate.
371 if (fStrokeWidth < 0.0f) {
372 // it's a fill, so we don't need to worry about degenerate paths
373 return false;
374 }
375 // For stroking, we still need to process the degenerate path, so fix it up
376 fSide = SkPoint::kLeft_Side;
377
378 // Make all the normals face outwards rather than along the edge
379 for (int cur = 0; cur < fNorms.count(); ++cur) {
380 fNorms[cur].setOrthog(fNorms[cur], fSide);
381 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length()));
382 }
383
robertphillips 2015/06/16 13:13:01 SkPoint::Make ?
384 fNorms.push({ -fNorms[0].fX, -fNorms[0].fY });
385 // we won't actually use the bisectors, so just push zeroes
386 fBisectors.push({ 0, 0 });
387 fBisectors.push({ 0, 0 });
388 } else {
323 return false; 389 return false;
324 } 390 }
325 391
326 // Check the cross product of the final trio
327 SkScalar cross = SkPoint::CrossProduct(fNorms[0], fNorms.top());
328 SkDEBUGCODE(fMaxCross = SkTMax(fMaxCross, cross));
329 SkDEBUGCODE(fMinCross = SkTMin(fMinCross, cross));
330 SkASSERT((fMaxCross >= 0.0f) == (fMinCross >= 0.0f));
331 if (cross > 0.0f) {
332 fSide = SkPoint::kRight_Side;
333 } else {
334 fSide = SkPoint::kLeft_Side;
335 }
336
337 // Make all the normals face outwards rather than along the edge
338 for (int cur = 0; cur < fNorms.count(); ++cur) {
339 fNorms[cur].setOrthog(fNorms[cur], fSide);
340 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[cur].length()));
341 }
342
343 this->computeBisectors();
344
345 fCandidateVerts.setReserve(this->numPts()); 392 fCandidateVerts.setReserve(this->numPts());
346 fInitialRing.setReserve(this->numPts()); 393 fInitialRing.setReserve(this->numPts());
347 for (int i = 0; i < this->numPts(); ++i) { 394 for (int i = 0; i < this->numPts(); ++i) {
348 fInitialRing.addIdx(i, i); 395 fInitialRing.addIdx(i, i);
349 } 396 }
350 fInitialRing.init(fNorms, fBisectors); 397 fInitialRing.init(fNorms, fBisectors);
351 398
352 this->validate(); 399 this->validate();
353 return true; 400 return true;
354 } 401 }
355 402
356 GrAAConvexTessellator::Ring* GrAAConvexTessellator::getNextRing(Ring* lastRing) { 403 GrAAConvexTessellator::Ring* GrAAConvexTessellator::getNextRing(Ring* lastRing) {
357 #if GR_AA_CONVEX_TESSELLATOR_VIZ 404 #if GR_AA_CONVEX_TESSELLATOR_VIZ
358 Ring* ring = *fRings.push() = SkNEW(Ring); 405 Ring* ring = *fRings.push() = SkNEW(Ring);
359 ring->setReserve(fInitialRing.numPts()); 406 ring->setReserve(fInitialRing.numPts());
360 ring->rewind(); 407 ring->rewind();
361 return ring; 408 return ring;
362 #else 409 #else
363 // Flip flop back and forth between fRings[0] & fRings[1] 410 // Flip flop back and forth between fRings[0] & fRings[1]
364 int nextRing = (lastRing == &fRings[0]) ? 1 : 0; 411 int nextRing = (lastRing == &fRings[0]) ? 1 : 0;
365 fRings[nextRing].setReserve(fInitialRing.numPts()); 412 fRings[nextRing].setReserve(fInitialRing.numPts());
366 fRings[nextRing].rewind(); 413 fRings[nextRing].rewind();
367 return &fRings[nextRing]; 414 return &fRings[nextRing];
368 #endif 415 #endif
369 } 416 }
370 417
371 void GrAAConvexTessellator::fanRing(const Ring& ring) { 418 void GrAAConvexTessellator::fanRing(const Ring& ring) {
372 // fan out from point 0 419 // fan out from point 0
373 for (int cur = 1; cur < ring.numPts()-1; ++cur) { 420 int startIdx = ring.index(0);
374 this->addTri(ring.index(0), ring.index(cur), ring.index(cur+1)); 421 for (int cur = ring.numPts() - 2; cur >= 0; --cur) {
422 this->addTri(startIdx, ring.index(cur), ring.index(cur + 1));
375 } 423 }
376 } 424 }
377 425
378 void GrAAConvexTessellator::createOuterRing() { 426 void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o utset,
379 // For now, we're only generating one outer ring (at the start). This 427 SkScalar coverage, Ring* nextRing) {
380 // could be relaxed for stroking use cases. 428 const int numPts = previousRing.numPts();
381 SkASSERT(0 == fIndices.count()); 429 if (numPts == 0) {
382 SkASSERT(fPts.count() == fNorms.count()); 430 return;
383 431 }
384 const int numPts = fPts.count();
385 432
386 int prev = numPts - 1; 433 int prev = numPts - 1;
387 int lastPerpIdx = -1, firstPerpIdx = -1, newIdx0, newIdx1, newIdx2; 434 int lastPerpIdx = -1, firstPerpIdx = -1;
435
robertphillips 2015/06/16 13:13:01 Make outsetSq const ?
436 SkScalar outsetSq = SkScalarMul(outset, outset);
437 SkScalar miterLimitSq = SkScalarMul(outset, fMiterLimit);
438 miterLimitSq = SkScalarMul(miterLimitSq, miterLimitSq);
388 for (int cur = 0; cur < numPts; ++cur) { 439 for (int cur = 0; cur < numPts; ++cur) {
389 if (fIsCurve[cur]) { 440 int originalIdx = previousRing.index(cur);
390 // Inside a curve, we assume that the curvature is shallow enough (d ue to tesselation) 441 // For each vertex of the original polygon we add at least two points to the
391 // that we only need one corner point. Mathematically, the distance the corner point 442 // outset polygon - one extending perpendicular to each impinging edge. Connecting these
392 // gets shifted out should depend on the angle between the two line segments (as in 443 // two points yields a bevel join. We need one additional point for a mi tered join, and
393 // mitering), but again due to tesselation we assume that this angle is small and 444 // a round join requires one or more points depending upon curvature.
394 // therefore the correction factor is negligible and we do not bothe r with it.
395 445
396 // The bisector outset point 446 // The perpendicular point for the last edge
397 SkPoint temp = fBisectors[cur]; 447 SkPoint normal1 = previousRing.norm(prev);
398 temp.scale(-fTargetDepth); // the bisectors point in 448 SkPoint perp1 = normal1;
399 temp += fPts[cur]; 449 perp1.scale(outset);
450 perp1 += this->point(originalIdx);
400 451
401 // double-check our "sufficiently flat" assumption; we want the bise ctor point to be 452 // The perpendicular point for the next edge.
402 // close to the normal point. 453 SkPoint normal2 = previousRing.norm(cur);
403 #define kFlatnessTolerance 1.0f 454 SkPoint perp2 = normal2;
404 SkDEBUGCODE(SkPoint prevNormal = fNorms[prev];) 455 perp2.scale(outset);
405 SkDEBUGCODE(prevNormal.scale(fTargetDepth);) 456 perp2 += fPts[originalIdx];
406 SkDEBUGCODE(prevNormal += fPts[cur];)
407 SkASSERT((temp - prevNormal).length() < kFlatnessTolerance);
408 457
409 newIdx1 = this->addPt(temp, -fTargetDepth, false, true); 458 bool isCurve = fIsCurve[originalIdx];
410 459
411 if (0 == cur) { 460 // We know it isn't a duplicate of the prior point (since it and this
412 // Store the index of the first perpendicular point to finish up 461 // one are just perpendicular offsets from the non-merged polygon points )
413 firstPerpIdx = newIdx1; 462 int perp1Idx = this->addPt(perp1, -outset, coverage, false, isCurve);
414 SkASSERT(-1 == lastPerpIdx); 463 nextRing->addIdx(perp1Idx, originalIdx);
464
465 int perp2Idx;
466 // For very shallow angles all the corner points could fuse.
467 if (duplicate_pt(perp2, this->point(perp1Idx))) {
468 perp2Idx = perp1Idx;
469 } else {
470 perp2Idx = this->addPt(perp2, -outset, coverage, false, isCurve);
471 }
472
473 if (perp2Idx != perp1Idx) {
474 if (isCurve) {
475 // bevel or round depending upon curvature
476 SkScalar dotProd = normal1.dot(normal2);
477 if (dotProd < kRoundCapThreshold) {
478 // Currently we "round" by creating a single extra point, wh ich produces
479 // good results for common cases. For thick strokes with hig h curvature, we will
480 // need to add more points; for the time being we simply fal l back to software
481 // rendering for thick strokes.
482 SkPoint miter = previousRing.bisector(cur);
483 miter.setLength(-outset);
484 miter += fPts[originalIdx];
485
486 // For very shallow angles all the corner points could fuse
487 if (!duplicate_pt(miter, this->point(perp1Idx))) {
488 int miterIdx;
489 miterIdx = this->addPt(miter, -outset, coverage, false, false);
490 nextRing->addIdx(miterIdx, originalIdx);
491 // The two triangles for the corner
492 this->addTri(originalIdx, perp1Idx, miterIdx);
493 this->addTri(originalIdx, miterIdx, perp2Idx);
494 }
495 } else {
496 this->addTri(originalIdx, perp1Idx, perp2Idx);
497 }
415 } else { 498 } else {
416 // The triangles for the previous edge 499 switch (fJoin) {
417 this->addTri(prev, newIdx1, cur); 500 case SkPaint::Join::kMiter_Join: {
418 this->addTri(prev, lastPerpIdx, newIdx1); 501 // The bisector outset point
502 SkPoint miter = previousRing.bisector(cur);
503 SkScalar dotProd = normal1.dot(normal2);
504 SkScalar sinHalfAngleSq = SkScalarHalf(SK_Scalar1 + dotP rod);
505 SkScalar lengthSq = outsetSq / sinHalfAngleSq;
506 if (lengthSq > miterLimitSq) {
robertphillips 2015/06/16 13:13:01 Shouldn't we just cap the miter in this case - not
ethannicholas 2015/06/16 14:53:29 As far as I can tell, what I am doing is visually
507 goto bevel;
508 }
509 miter.setLength(-SkScalarSqrt(lengthSq));
510 miter += fPts[originalIdx];
511
512 // For very shallow angles all the corner points could f use
513 if (!duplicate_pt(miter, this->point(perp1Idx))) {
514 int miterIdx;
515 miterIdx = this->addPt(miter, -outset, coverage, fal se, false);
516 nextRing->addIdx(miterIdx, originalIdx);
517 // The two triangles for the corner
518 this->addTri(originalIdx, perp1Idx, miterIdx);
519 this->addTri(originalIdx, miterIdx, perp2Idx);
520 }
521 break;
522 }
523 case SkPaint::Join::kBevel_Join:
524 bevel:
525 this->addTri(originalIdx, perp1Idx, perp2Idx);
526 break;
527 default:
528 // kRound_Join is unsupported for now. GrAALinearizingCo nvexPathRenderer is
529 // only willing to draw mitered or beveled, so we should never get here.
530 SkASSERT(false);
531 }
419 } 532 }
420 533
421 prev = cur; 534 nextRing->addIdx(perp2Idx, originalIdx);
422 // Track the last perpendicular outset point so we can construct the
423 // trailing edge triangles.
424 lastPerpIdx = newIdx1;
425 } 535 }
426 else {
427 // For each vertex of the original polygon we add three points to th e
428 // outset polygon - one extending perpendicular to each impinging ed ge
429 // and one along the bisector. Two triangles are added for each corn er
430 // and two are added along each edge.
431 536
432 // The perpendicular point for the last edge 537 if (0 == cur) {
433 SkPoint temp = fNorms[prev]; 538 // Store the index of the first perpendicular point to finish up
434 temp.scale(fTargetDepth); 539 firstPerpIdx = perp1Idx;
435 temp += fPts[cur]; 540 SkASSERT(-1 == lastPerpIdx);
541 } else {
542 // The triangles for the previous edge
543 int prevIdx = previousRing.index(prev);
544 this->addTri(prevIdx, perp1Idx, originalIdx);
545 this->addTri(prevIdx, lastPerpIdx, perp1Idx);
546 }
436 547
437 // We know it isn't a duplicate of the prior point (since it and thi s 548 // Track the last perpendicular outset point so we can construct the
438 // one are just perpendicular offsets from the non-merged polygon po ints) 549 // trailing edge triangles.
439 newIdx0 = this->addPt(temp, -fTargetDepth, false, false); 550 lastPerpIdx = perp2Idx;
440 551 prev = cur;
441 // The bisector outset point
442 temp = fBisectors[cur];
443 temp.scale(-fTargetDepth); // the bisectors point in
444 temp += fPts[cur];
445
446 // For very shallow angles all the corner points could fuse
447 if (duplicate_pt(temp, this->point(newIdx0))) {
448 newIdx1 = newIdx0;
449 } else {
450 newIdx1 = this->addPt(temp, -fTargetDepth, false, false);
451 }
452
453 // The perpendicular point for the next edge.
454 temp = fNorms[cur];
455 temp.scale(fTargetDepth);
456 temp += fPts[cur];
457
458 // For very shallow angles all the corner points could fuse.
459 if (duplicate_pt(temp, this->point(newIdx1))) {
460 newIdx2 = newIdx1;
461 } else {
462 newIdx2 = this->addPt(temp, -fTargetDepth, false, false);
463 }
464
465 if (0 == cur) {
466 // Store the index of the first perpendicular point to finish up
467 firstPerpIdx = newIdx0;
468 SkASSERT(-1 == lastPerpIdx);
469 } else {
470 // The triangles for the previous edge
471 this->addTri(prev, newIdx0, cur);
472 this->addTri(prev, lastPerpIdx, newIdx0);
473 }
474
475 // The two triangles for the corner
476 this->addTri(cur, newIdx0, newIdx1);
477 this->addTri(cur, newIdx1, newIdx2);
478
479 prev = cur;
480 // Track the last perpendicular outset point so we can construct the
481 // trailing edge triangles.
482 lastPerpIdx = newIdx2;
483 }
484 } 552 }
485 553
486 // pick up the final edge rect 554 // pick up the final edge rect
487 this->addTri(numPts - 1, firstPerpIdx, 0); 555 int lastIdx = previousRing.index(numPts - 1);
488 this->addTri(numPts - 1, lastPerpIdx, firstPerpIdx); 556 this->addTri(lastIdx, firstPerpIdx, previousRing.index(0));
557 this->addTri(lastIdx, lastPerpIdx, firstPerpIdx);
489 558
490 this->validate(); 559 this->validate();
491 } 560 }
492 561
493 // Something went wrong in the creation of the next ring. Mark the last good 562 // Something went wrong in the creation of the next ring. If we're filling the s hape, just go ahead
494 // ring as being at the desired depth and fan it. 563 // and fan it.
495 void GrAAConvexTessellator::terminate(const Ring& ring) { 564 void GrAAConvexTessellator::terminate(const Ring& ring) {
496 for (int i = 0; i < ring.numPts(); ++i) { 565 if (fStrokeWidth < 0.0f) {
497 fDepths[ring.index(i)] = fTargetDepth; 566 this->fanRing(ring);
498 } 567 }
568 }
499 569
robertphillips 2015/06/16 13:13:01 compute_coverage since static ?
ethannicholas 2015/06/16 14:53:29 Done.
500 this->fanRing(ring); 570 static SkScalar computeCoverage(SkScalar depth, SkScalar initialDepth, SkScalar initialCoverage,
robertphillips 2015/06/16 13:13:01 tab this over ?
571 SkScalar targetDepth, SkScalar targetCoverage) {
572 if (SkScalarNearlyEqual(initialDepth, targetDepth)) {
573 return targetCoverage;
574 }
575 SkScalar result = (depth - initialDepth) / (targetDepth - initialDepth) *
576 (targetCoverage - initialCoverage) + initialCoverage;
577 SkASSERT(result >= 0.0f && result <= 1.0f);
578 return result;
501 } 579 }
502 580
503 // return true when processing is complete 581 // return true when processing is complete
504 bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing ) { 582 bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing ,
robertphillips 2015/06/16 13:13:01 tab these lines over ?
583 SkScalar initialDepth, SkScalar initialCoverage, SkScalar targetDepth,
584 SkScalar targetCoverage, bool forceNew) {
505 bool done = false; 585 bool done = false;
506 586
507 fCandidateVerts.rewind(); 587 fCandidateVerts.rewind();
508 588
509 // Loop through all the points in the ring and find the intersection with th e smallest depth 589 // Loop through all the points in the ring and find the intersection with th e smallest depth
510 SkScalar minDist = SK_ScalarMax, minT = 0.0f; 590 SkScalar minDist = SK_ScalarMax, minT = 0.0f;
511 int minEdgeIdx = -1; 591 int minEdgeIdx = -1;
512 592
513 for (int cur = 0; cur < lastRing.numPts(); ++cur) { 593 for (int cur = 0; cur < lastRing.numPts(); ++cur) {
514 int next = (cur + 1) % lastRing.numPts(); 594 int next = (cur + 1) % lastRing.numPts();
515
516 SkScalar t = intersect(this->point(lastRing.index(cur)), lastRing.bisec tor(cur), 595 SkScalar t = intersect(this->point(lastRing.index(cur)), lastRing.bisec tor(cur),
517 this->point(lastRing.index(next)), lastRing.bisec tor(next)); 596 this->point(lastRing.index(next)), lastRing.bisec tor(next));
518 SkScalar dist = -t * lastRing.norm(cur).dot(lastRing.bisector(cur)); 597 SkScalar dist = -t * lastRing.norm(cur).dot(lastRing.bisector(cur));
519 598
520 if (minDist > dist) { 599 if (minDist > dist) {
521 minDist = dist; 600 minDist = dist;
522 minT = t; 601 minT = t;
523 minEdgeIdx = cur; 602 minEdgeIdx = cur;
524 } 603 }
525 } 604 }
526 605
606 if (minEdgeIdx == -1) {
607 return false;
608 }
527 SkPoint newPt = lastRing.bisector(minEdgeIdx); 609 SkPoint newPt = lastRing.bisector(minEdgeIdx);
528 newPt.scale(minT); 610 newPt.scale(minT);
529 newPt += this->point(lastRing.index(minEdgeIdx)); 611 newPt += this->point(lastRing.index(minEdgeIdx));
530 612
531 SkScalar depth = this->computeDepthFromEdge(lastRing.origEdgeID(minEdgeIdx), newPt); 613 SkScalar depth = this->computeDepthFromEdge(lastRing.origEdgeID(minEdgeIdx), newPt);
532 if (depth >= fTargetDepth) { 614 if (depth >= targetDepth) {
533 // None of the bisectors intersect before reaching the desired depth. 615 // None of the bisectors intersect before reaching the desired depth.
534 // Just step them all to the desired depth 616 // Just step them all to the desired depth
535 depth = fTargetDepth; 617 depth = targetDepth;
536 done = true; 618 done = true;
537 } 619 }
538 620
539 // 'dst' stores where each point in the last ring maps to/transforms into 621 // 'dst' stores where each point in the last ring maps to/transforms into
540 // in the next ring. 622 // in the next ring.
541 SkTDArray<int> dst; 623 SkTDArray<int> dst;
542 dst.setCount(lastRing.numPts()); 624 dst.setCount(lastRing.numPts());
543 625
544 // Create the first point (who compares with no one) 626 // Create the first point (who compares with no one)
545 if (!this->computePtAlongBisector(lastRing.index(0), 627 if (!this->computePtAlongBisector(lastRing.index(0),
546 lastRing.bisector(0), 628 lastRing.bisector(0),
547 lastRing.origEdgeID(0), 629 lastRing.origEdgeID(0),
548 depth, &newPt)) { 630 depth, &newPt)) {
549 this->terminate(lastRing); 631 this->terminate(lastRing);
550 SkDEBUGCODE(fShouldCheckDepths = false;)
551 return true; 632 return true;
552 } 633 }
553 dst[0] = fCandidateVerts.addNewPt(newPt, 634 dst[0] = fCandidateVerts.addNewPt(newPt,
554 lastRing.index(0), lastRing.origEdgeID(0), 635 lastRing.index(0), lastRing.origEdgeID(0),
555 !this->movable(lastRing.index(0))); 636 !this->movable(lastRing.index(0)));
556 637
557 // Handle the middle points (who only compare with the prior point) 638 // Handle the middle points (who only compare with the prior point)
558 for (int cur = 1; cur < lastRing.numPts()-1; ++cur) { 639 for (int cur = 1; cur < lastRing.numPts()-1; ++cur) {
559 if (!this->computePtAlongBisector(lastRing.index(cur), 640 if (!this->computePtAlongBisector(lastRing.index(cur),
560 lastRing.bisector(cur), 641 lastRing.bisector(cur),
561 lastRing.origEdgeID(cur), 642 lastRing.origEdgeID(cur),
562 depth, &newPt)) { 643 depth, &newPt)) {
563 this->terminate(lastRing); 644 this->terminate(lastRing);
564 SkDEBUGCODE(fShouldCheckDepths = false;)
565 return true; 645 return true;
566 } 646 }
567 if (!duplicate_pt(newPt, fCandidateVerts.lastPoint())) { 647 if (!duplicate_pt(newPt, fCandidateVerts.lastPoint())) {
568 dst[cur] = fCandidateVerts.addNewPt(newPt, 648 dst[cur] = fCandidateVerts.addNewPt(newPt,
569 lastRing.index(cur), lastRing.or igEdgeID(cur), 649 lastRing.index(cur), lastRing.or igEdgeID(cur),
570 !this->movable(lastRing.index(cu r))); 650 !this->movable(lastRing.index(cu r)));
571 } else { 651 } else {
572 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); 652 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur));
573 } 653 }
574 } 654 }
575 655
576 // Check on the last point (handling the wrap around) 656 // Check on the last point (handling the wrap around)
577 int cur = lastRing.numPts()-1; 657 int cur = lastRing.numPts()-1;
578 if (!this->computePtAlongBisector(lastRing.index(cur), 658 if (!this->computePtAlongBisector(lastRing.index(cur),
579 lastRing.bisector(cur), 659 lastRing.bisector(cur),
580 lastRing.origEdgeID(cur), 660 lastRing.origEdgeID(cur),
581 depth, &newPt)) { 661 depth, &newPt)) {
582 this->terminate(lastRing); 662 this->terminate(lastRing);
583 SkDEBUGCODE(fShouldCheckDepths = false;)
584 return true; 663 return true;
585 } 664 }
586 bool dupPrev = duplicate_pt(newPt, fCandidateVerts.lastPoint()); 665 bool dupPrev = duplicate_pt(newPt, fCandidateVerts.lastPoint());
587 bool dupNext = duplicate_pt(newPt, fCandidateVerts.firstPoint()); 666 bool dupNext = duplicate_pt(newPt, fCandidateVerts.firstPoint());
588 667
589 if (!dupPrev && !dupNext) { 668 if (!dupPrev && !dupNext) {
590 dst[cur] = fCandidateVerts.addNewPt(newPt, 669 dst[cur] = fCandidateVerts.addNewPt(newPt,
591 lastRing.index(cur), lastRing.origEd geID(cur), 670 lastRing.index(cur), lastRing.origEd geID(cur),
592 !this->movable(lastRing.index(cur))) ; 671 !this->movable(lastRing.index(cur))) ;
593 } else if (dupPrev && !dupNext) { 672 } else if (dupPrev && !dupNext) {
594 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); 673 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur));
595 } else if (!dupPrev && dupNext) { 674 } else if (!dupPrev && dupNext) {
596 dst[cur] = fCandidateVerts.fuseWithNext(); 675 dst[cur] = fCandidateVerts.fuseWithNext();
597 } else { 676 } else {
598 bool dupPrevVsNext = duplicate_pt(fCandidateVerts.firstPoint(), fCandida teVerts.lastPoint()); 677 bool dupPrevVsNext = duplicate_pt(fCandidateVerts.firstPoint(), fCandida teVerts.lastPoint());
599 678
600 if (!dupPrevVsNext) { 679 if (!dupPrevVsNext) {
601 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); 680 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur));
602 } else { 681 } else {
603 dst[cur] = dst[cur-1] = fCandidateVerts.fuseWithBoth(); 682 dst[cur] = dst[cur-1] = fCandidateVerts.fuseWithBoth();
604 } 683 }
605 } 684 }
606 685
607 // Fold the new ring's points into the global pool 686 // Fold the new ring's points into the global pool
608 for (int i = 0; i < fCandidateVerts.numPts(); ++i) { 687 for (int i = 0; i < fCandidateVerts.numPts(); ++i) {
609 int newIdx; 688 int newIdx;
610 if (fCandidateVerts.needsToBeNew(i)) { 689 if (fCandidateVerts.needsToBeNew(i) || forceNew) {
611 // if the originating index is still valid then this point wasn't 690 // if the originating index is still valid then this point wasn't
612 // fused (and is thus movable) 691 // fused (and is thus movable)
robertphillips 2015/06/16 13:13:01 Is there any downside to splitting this into 2 sta
613 newIdx = this->addPt(fCandidateVerts.point(i), depth, 692 newIdx = this->addPt(fCandidateVerts.point(i), depth,
robertphillips 2015/06/16 13:13:01 this->computeCoverage
693 computeCoverage(depth, initialDepth, initialCov erage,
robertphillips 2015/06/16 13:13:01 tab this line over ?
694 targetDepth, targetCoverage),
614 fCandidateVerts.originatingIdx(i) != -1, false) ; 695 fCandidateVerts.originatingIdx(i) != -1, false) ;
615 } else { 696 } else {
616 SkASSERT(fCandidateVerts.originatingIdx(i) != -1); 697 SkASSERT(fCandidateVerts.originatingIdx(i) != -1);
617 this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.po int(i), depth); 698 this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.po int(i), depth,
robertphillips 2015/06/16 13:13:01 tab this over ?
699 targetCoverage);
618 newIdx = fCandidateVerts.originatingIdx(i); 700 newIdx = fCandidateVerts.originatingIdx(i);
619 } 701 }
620 702
621 nextRing->addIdx(newIdx, fCandidateVerts.origEdge(i)); 703 nextRing->addIdx(newIdx, fCandidateVerts.origEdge(i));
622 } 704 }
623 705
624 // 'dst' currently has indices into the ring. Remap these to be indices 706 // 'dst' currently has indices into the ring. Remap these to be indices
625 // into the global pool since the triangulation operates in that space. 707 // into the global pool since the triangulation operates in that space.
626 for (int i = 0; i < dst.count(); ++i) { 708 for (int i = 0; i < dst.count(); ++i) {
627 dst[i] = nextRing->index(dst[i]); 709 dst[i] = nextRing->index(dst[i]);
628 } 710 }
629 711
630 for (int cur = 0; cur < lastRing.numPts(); ++cur) { 712 for (int cur = 0; cur < lastRing.numPts(); ++cur) {
631 int next = (cur + 1) % lastRing.numPts(); 713 int next = (cur + 1) % lastRing.numPts();
632 714
633 this->addTri(lastRing.index(cur), lastRing.index(next), dst[next]); 715 this->addTri(lastRing.index(cur), lastRing.index(next), dst[next]);
634 this->addTri(lastRing.index(cur), dst[next], dst[cur]); 716 this->addTri(lastRing.index(cur), dst[next], dst[cur]);
635 } 717 }
636 718
637 if (done) { 719 if (done && fStrokeWidth < 0.0f) {
720 // fill
638 this->fanRing(*nextRing); 721 this->fanRing(*nextRing);
639 } 722 }
640 723
641 if (nextRing->numPts() < 3) { 724 if (nextRing->numPts() < 3) {
642 done = true; 725 done = true;
643 } 726 }
644
645 return done; 727 return done;
646 } 728 }
647 729
648 void GrAAConvexTessellator::validate() const { 730 void GrAAConvexTessellator::validate() const {
649 SkASSERT(fPts.count() == fDepths.count());
650 SkASSERT(fPts.count() == fMovable.count()); 731 SkASSERT(fPts.count() == fMovable.count());
651 SkASSERT(0 == (fIndices.count() % 3)); 732 SkASSERT(0 == (fIndices.count() % 3));
652 } 733 }
653 734
654 ////////////////////////////////////////////////////////////////////////////// 735 //////////////////////////////////////////////////////////////////////////////
655 void GrAAConvexTessellator::Ring::init(const GrAAConvexTessellator& tess) { 736 void GrAAConvexTessellator::Ring::init(const GrAAConvexTessellator& tess) {
656 this->computeNormals(tess); 737 this->computeNormals(tess);
657 this->computeBisectors(tess); 738 this->computeBisectors(tess);
658 SkASSERT(this->isConvex(tess));
659 } 739 }
660 740
661 void GrAAConvexTessellator::Ring::init(const SkTDArray<SkVector>& norms, 741 void GrAAConvexTessellator::Ring::init(const SkTDArray<SkVector>& norms,
662 const SkTDArray<SkVector>& bisectors) { 742 const SkTDArray<SkVector>& bisectors) {
663 for (int i = 0; i < fPts.count(); ++i) { 743 for (int i = 0; i < fPts.count(); ++i) {
664 fPts[i].fNorm = norms[i]; 744 fPts[i].fNorm = norms[i];
665 fPts[i].fBisector = bisectors[i]; 745 fPts[i].fBisector = bisectors[i];
666 } 746 }
667 } 747 }
668 748
669 // Compute the outward facing normal at each vertex. 749 // Compute the outward facing normal at each vertex.
670 void GrAAConvexTessellator::Ring::computeNormals(const GrAAConvexTessellator& te ss) { 750 void GrAAConvexTessellator::Ring::computeNormals(const GrAAConvexTessellator& te ss) {
671 for (int cur = 0; cur < fPts.count(); ++cur) { 751 for (int cur = 0; cur < fPts.count(); ++cur) {
672 int next = (cur + 1) % fPts.count(); 752 int next = (cur + 1) % fPts.count();
673 753
674 fPts[cur].fNorm = tess.point(fPts[next].fIndex) - tess.point(fPts[cur].f Index); 754 fPts[cur].fNorm = tess.point(fPts[next].fIndex) - tess.point(fPts[cur].f Index);
675 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fPts[cur].fNorm); 755 SkPoint::Normalize(&fPts[cur].fNorm);
676 SkASSERT(len > 0.0f);
677 fPts[cur].fNorm.setOrthog(fPts[cur].fNorm, tess.side()); 756 fPts[cur].fNorm.setOrthog(fPts[cur].fNorm, tess.side());
678
679 SkASSERT(SkScalarNearlyEqual(1.0f, fPts[cur].fNorm.length()));
680 } 757 }
681 } 758 }
682 759
683 void GrAAConvexTessellator::Ring::computeBisectors(const GrAAConvexTessellator& tess) { 760 void GrAAConvexTessellator::Ring::computeBisectors(const GrAAConvexTessellator& tess) {
684 int prev = fPts.count() - 1; 761 int prev = fPts.count() - 1;
685 for (int cur = 0; cur < fPts.count(); prev = cur, ++cur) { 762 for (int cur = 0; cur < fPts.count(); prev = cur, ++cur) {
686 fPts[cur].fBisector = fPts[cur].fNorm + fPts[prev].fNorm; 763 fPts[cur].fBisector = fPts[cur].fNorm + fPts[prev].fNorm;
687 if (!fPts[cur].fBisector.normalize()) { 764 if (!fPts[cur].fBisector.normalize()) {
688 SkASSERT(SkPoint::kLeft_Side == tess.side() || SkPoint::kRight_Side == tess.side()); 765 SkASSERT(SkPoint::kLeft_Side == tess.side() || SkPoint::kRight_Side == tess.side());
689 fPts[cur].fBisector.setOrthog(fPts[cur].fNorm, (SkPoint::Side)-tess. side()); 766 fPts[cur].fBisector.setOrthog(fPts[cur].fNorm, (SkPoint::Side)-tess. side());
690 SkVector other; 767 SkVector other;
691 other.setOrthog(fPts[prev].fNorm, tess.side()); 768 other.setOrthog(fPts[prev].fNorm, tess.side());
692 fPts[cur].fBisector += other; 769 fPts[cur].fBisector += other;
693 SkAssertResult(fPts[cur].fBisector.normalize()); 770 SkAssertResult(fPts[cur].fBisector.normalize());
694 } else { 771 } else {
695 fPts[cur].fBisector.negate(); // make the bisector face in 772 fPts[cur].fBisector.negate(); // make the bisector face in
696 } 773 }
697 774 }
698 SkASSERT(SkScalarNearlyEqual(1.0f, fPts[cur].fBisector.length()));
699 }
700 } 775 }
701 776
702 ////////////////////////////////////////////////////////////////////////////// 777 //////////////////////////////////////////////////////////////////////////////
703 #ifdef SK_DEBUG 778 #ifdef SK_DEBUG
704 // Is this ring convex? 779 // Is this ring convex?
705 bool GrAAConvexTessellator::Ring::isConvex(const GrAAConvexTessellator& tess) co nst { 780 bool GrAAConvexTessellator::Ring::isConvex(const GrAAConvexTessellator& tess) co nst {
706 if (fPts.count() < 3) { 781 if (fPts.count() < 3) {
707 return false; 782 return true;
708 } 783 }
709 784
710 SkPoint prev = tess.point(fPts[0].fIndex) - tess.point(fPts.top().fIndex); 785 SkPoint prev = tess.point(fPts[0].fIndex) - tess.point(fPts.top().fIndex);
711 SkPoint cur = tess.point(fPts[1].fIndex) - tess.point(fPts[0].fIndex); 786 SkPoint cur = tess.point(fPts[1].fIndex) - tess.point(fPts[0].fIndex);
712 SkScalar minDot = prev.fX * cur.fY - prev.fY * cur.fX; 787 SkScalar minDot = prev.fX * cur.fY - prev.fY * cur.fX;
713 SkScalar maxDot = minDot; 788 SkScalar maxDot = minDot;
714 789
715 prev = cur; 790 prev = cur;
716 for (int i = 1; i < fPts.count(); ++i) { 791 for (int i = 1; i < fPts.count(); ++i) {
717 int next = (i + 1) % fPts.count(); 792 int next = (i + 1) % fPts.count();
718 793
719 cur = tess.point(fPts[next].fIndex) - tess.point(fPts[i].fIndex); 794 cur = tess.point(fPts[next].fIndex) - tess.point(fPts[i].fIndex);
720 SkScalar dot = prev.fX * cur.fY - prev.fY * cur.fX; 795 SkScalar dot = prev.fX * cur.fY - prev.fY * cur.fX;
721 796
722 minDot = SkMinScalar(minDot, dot); 797 minDot = SkMinScalar(minDot, dot);
723 maxDot = SkMaxScalar(maxDot, dot); 798 maxDot = SkMaxScalar(maxDot, dot);
724 799
725 prev = cur; 800 prev = cur;
726 } 801 }
727 802
728 return (maxDot > 0.0f) == (minDot >= 0.0f); 803 if (SkScalarNearlyEqual(maxDot, 0.0f, 0.005f)) {
804 maxDot = 0;
805 }
806 if (SkScalarNearlyEqual(minDot, 0.0f, 0.005f)) {
807 minDot = 0;
808 }
809 return (maxDot >= 0.0f) == (minDot >= 0.0f);
729 } 810 }
730 811
731 static SkScalar capsule_depth(const SkPoint& p0, const SkPoint& p1, 812 static SkScalar capsule_depth(const SkPoint& p0, const SkPoint& p1,
732 const SkPoint& test, SkPoint::Side side, 813 const SkPoint& test, SkPoint::Side side,
733 int* sign) { 814 int* sign) {
734 *sign = -1; 815 *sign = -1;
735 SkPoint edge = p1 - p0; 816 SkPoint edge = p1 - p0;
736 SkScalar len = SkPoint::Normalize(&edge); 817 SkScalar len = SkPoint::Normalize(&edge);
737 818
738 SkPoint testVec = test - p0; 819 SkPoint testVec = test - p0;
(...skipping 30 matching lines...) Expand all
769 SkASSERT(dist >= 0.0f); 850 SkASSERT(dist >= 0.0f);
770 851
771 if (minDist > dist) { 852 if (minDist > dist) {
772 minDist = dist; 853 minDist = dist;
773 closestSign = sign; 854 closestSign = sign;
774 } 855 }
775 } 856 }
776 857
777 return closestSign * minDist; 858 return closestSign * minDist;
778 } 859 }
779
780 // Verify that the incrementally computed depths are close to the actual depths.
781 void GrAAConvexTessellator::checkAllDepths() const {
782 for (int cur = 0; cur < this->numPts(); ++cur) {
robertphillips 2015/06/16 13:13:01 So, can computeRealDepth go too ?
ethannicholas 2015/06/16 14:53:29 Looks like it.
783 SkScalar realDepth = this->computeRealDepth(this->point(cur));
784 SkScalar computedDepth = this->depth(cur);
785 SkASSERT(SkScalarNearlyEqual(realDepth, computedDepth, 0.01f));
786 }
787 }
788 #endif 860 #endif
789 861
790 #define kQuadTolerance 0.2f
791 #define kCubicTolerance 0.2f
792 #define kConicTolerance 0.5f
793
794 void GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, bool isCurve) { 862 void GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, bool isCurve) {
795 m.mapPoints(&p, 1); 863 m.mapPoints(&p, 1);
796 if (this->numPts() > 0 && duplicate_pt(p, this->lastPoint())) { 864 if (this->numPts() > 0 && duplicate_pt(p, this->lastPoint())) {
797 return; 865 return;
798 } 866 }
799 867
800 SkASSERT(fPts.count() <= 1 || fPts.count() == fNorms.count()+1); 868 SkASSERT(fPts.count() <= 1 || fPts.count() == fNorms.count()+1);
801 if (this->numPts() >= 2 && 869 if (this->numPts() >= 2 &&
802 abs_dist_from_line(fPts.top(), fNorms.top(), p) < kClose) { 870 abs_dist_from_line(fPts.top(), fNorms.top(), p) < kClose) {
803 // The old last point is on the line from the second to last to the new point 871 // The old last point is on the line from the second to last to the new point
804 this->popLastPt(); 872 this->popLastPt();
805 fNorms.pop(); 873 fNorms.pop();
806 fIsCurve.pop(); 874 fIsCurve.pop();
807 } 875 }
808 this->addPt(p, 0.0f, false, isCurve); 876 SkScalar initialRingCoverage = fStrokeWidth < 0.0f ? 0.5f : 1.0f;
877 this->addPt(p, 0.0f, initialRingCoverage, false, isCurve);
809 if (this->numPts() > 1) { 878 if (this->numPts() > 1) {
810 *fNorms.push() = fPts.top() - fPts[fPts.count()-2]; 879 *fNorms.push() = fPts.top() - fPts[fPts.count()-2];
811 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top()); 880 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top());
812 SkASSERT(len > 0.0f); 881 SkASSERT(len > 0.0f);
813 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms.top().length())); 882 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms.top().length()));
814 } 883 }
815 SkDEBUGCODE(
816 if (this->numPts() >= 3) {
817 int cur = this->numPts()-1;
818 SkScalar cross = SkPoint::CrossProduct(fNorms[cur-1], fNorms[cur-2]) ;
819 fMaxCross = SkTMax(fMaxCross, cross);
820 fMinCross = SkTMin(fMinCross, cross);
821 }
822 )
823 } 884 }
824 885
825 void GrAAConvexTessellator::quadTo(const SkMatrix& m, SkPoint pts[3]) { 886 void GrAAConvexTessellator::quadTo(const SkMatrix& m, SkPoint pts[3]) {
826 int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance); 887 int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
827 fPointBuffer.setReserve(maxCount); 888 fPointBuffer.setReserve(maxCount);
828 SkPoint* target = fPointBuffer.begin(); 889 SkPoint* target = fPointBuffer.begin();
829 int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], 890 int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
830 kQuadTolerance, &target, maxCount); 891 kQuadTolerance, &target, maxCount);
831 fPointBuffer.setCount(count); 892 fPointBuffer.setCount(count);
832 for (int i = 0; i < count; i++) { 893 for (int i = 0; i < count; i++) {
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
958 SK_ColorBLACK); 1019 SK_ColorBLACK);
959 } 1020 }
960 1021
961 fInitialRing.draw(canvas, *this); 1022 fInitialRing.draw(canvas, *this);
962 for (int i = 0; i < fRings.count(); ++i) { 1023 for (int i = 0; i < fRings.count(); ++i) {
963 fRings[i]->draw(canvas, *this); 1024 fRings[i]->draw(canvas, *this);
964 } 1025 }
965 1026
966 for (int i = 0; i < this->numPts(); ++i) { 1027 for (int i = 0; i < this->numPts(); ++i) {
967 draw_point(canvas, 1028 draw_point(canvas,
968 this->point(i), 0.5f + (this->depth(i)/(2*fTargetDepth)), 1029 this->point(i), 0.5f + (this->depth(i)/(2 * kAntialiasingRadi us)),
969 !this->movable(i)); 1030 !this->movable(i));
970 1031
971 SkPaint paint; 1032 SkPaint paint;
972 paint.setTextSize(kPointTextSize); 1033 paint.setTextSize(kPointTextSize);
973 paint.setTextAlign(SkPaint::kCenter_Align); 1034 paint.setTextAlign(SkPaint::kCenter_Align);
974 if (this->depth(i) <= -fTargetDepth) { 1035 if (this->depth(i) <= -kAntialiasingRadius) {
975 paint.setColor(SK_ColorWHITE); 1036 paint.setColor(SK_ColorWHITE);
976 } 1037 }
977 1038
978 SkString num; 1039 SkString num;
979 num.printf("%d", i); 1040 num.printf("%d", i);
980 canvas->drawText(num.c_str(), num.size(), 1041 canvas->drawText(num.c_str(), num.size(),
981 this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f ), 1042 this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f ),
982 paint); 1043 paint);
983 } 1044 }
984 } 1045 }
985 1046
986 #endif 1047 #endif
987 1048
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698