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

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

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

Powered by Google App Engine
This is Rietveld 408576698