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

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: windows build issue 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
« 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
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
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
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,
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
146 // The general idea here is to, conceptually, start with the original polygon an d slide 192 // 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 193 // 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. 194 // 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 195 // 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 196 // controls the iteration. The CandidateVerts holds the formative points for the
151 // next ring. 197 // next ring.
152 bool GrAAConvexTessellator::tessellate(const SkMatrix& m, const SkPath& path) { 198 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)) { 199 if (!this->extractFromPath(m, path)) {
158 return false; 200 return false;
159 } 201 }
160 202
161 this->createOuterRing(); 203 SkScalar coverage = 1.0f;
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 }
162 215
163 // the bisectors are only needed for the computation of the outer ring 216 // the bisectors are only needed for the computation of the outer ring
164 fBisectors.rewind(); 217 fBisectors.rewind();
165 218 if (fStrokeWidth >= 0.0f && fInitialRing.numPts() > 2) {
166 Ring* lastRing = &fInitialRing; 219 Ring* insetStrokeRing;
167 int i; 220 SkScalar strokeDepth = fStrokeWidth / 2 - kAntialiasingRadius;
168 for (i = 0; i < kMaxNumRings; ++i) { 221 if (this->createInsetRings(fInitialRing, 0.0f, coverage, strokeDepth, co verage,
169 Ring* nextRing = this->getNextRing(lastRing); 222 &insetStrokeRing)) {
170 223 Ring* insetAARing;
171 if (this->createInsetRing(*lastRing, nextRing)) { 224 this->createInsetRings(*insetStrokeRing, strokeDepth, coverage, stro keDepth +
172 break; 225 kAntialiasingRadius * 2, 0.0f, &insetAARing);
173 } 226 }
174 227 } else {
175 nextRing->init(*this); 228 Ring* insetAARing;
176 lastRing = nextRing; 229 this->createInsetRings(fInitialRing, 0.0f, 0.5f, kAntialiasingRadius, 1. 0f, &insetAARing);
177 } 230 }
178 231
179 if (kMaxNumRings == i) { 232 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; 233 return true;
194 } 234 }
195 235
196 SkScalar GrAAConvexTessellator::computeDepthFromEdge(int edgeIdx, const SkPoint& p) const { 236 SkScalar GrAAConvexTessellator::computeDepthFromEdge(int edgeIdx, const SkPoint& p) const {
197 SkASSERT(edgeIdx < fNorms.count()); 237 SkASSERT(edgeIdx < fNorms.count());
198 238
199 SkPoint v = p - fPts[edgeIdx]; 239 SkPoint v = p - fPts[edgeIdx];
200 SkScalar depth = -fNorms[edgeIdx].dot(v); 240 SkScalar depth = -fNorms[edgeIdx].dot(v);
201 SkASSERT(depth >= 0.0f);
202 return depth; 241 return depth;
203 } 242 }
204 243
205 // Find a point that is 'desiredDepth' away from the 'edgeIdx'-th edge and lies 244 // Find a point that is 'desiredDepth' away from the 'edgeIdx'-th edge and lies
206 // along the 'bisector' from the 'startIdx'-th point. 245 // along the 'bisector' from the 'startIdx'-th point.
207 bool GrAAConvexTessellator::computePtAlongBisector(int startIdx, 246 bool GrAAConvexTessellator::computePtAlongBisector(int startIdx,
208 const SkVector& bisector, 247 const SkVector& bisector,
209 int edgeIdx, 248 int edgeIdx,
210 SkScalar desiredDepth, 249 SkScalar desiredDepth,
211 SkPoint* result) const { 250 SkPoint* result) const {
212 const SkPoint& norm = fNorms[edgeIdx]; 251 const SkPoint& norm = fNorms[edgeIdx];
213 252
214 // First find the point where the edge and the bisector intersect 253 // First find the point where the edge and the bisector intersect
215 SkPoint newP; 254 SkPoint newP;
255
216 SkScalar t = perp_intersect(fPts[startIdx], bisector, fPts[edgeIdx], norm); 256 SkScalar t = perp_intersect(fPts[startIdx], bisector, fPts[edgeIdx], norm);
217 if (SkScalarNearlyEqual(t, 0.0f)) { 257 if (SkScalarNearlyEqual(t, 0.0f)) {
218 // the start point was one of the original ring points 258 // the start point was one of the original ring points
219 SkASSERT(startIdx < fNorms.count()); 259 SkASSERT(startIdx < fPts.count());
220 newP = fPts[startIdx]; 260 newP = fPts[startIdx];
221 } else if (t > 0.0f) { 261 } else if (t < 0.0f) {
222 SkASSERT(t < 0.0f);
223 newP = bisector; 262 newP = bisector;
224 newP.scale(t); 263 newP.scale(t);
225 newP += fPts[startIdx]; 264 newP += fPts[startIdx];
226 } else { 265 } else {
227 return false; 266 return false;
228 } 267 }
229 268
230 // Then offset along the bisector from that point the correct distance 269 // Then offset along the bisector from that point the correct distance
231 t = -desiredDepth / bisector.dot(norm); 270 SkScalar dot = bisector.dot(norm);
232 SkASSERT(t > 0.0f); 271 t = -desiredDepth / dot;
233 *result = bisector; 272 *result = bisector;
234 result->scale(t); 273 result->scale(t);
235 *result += newP; 274 *result += newP;
236 275
237
238 return true; 276 return true;
239 } 277 }
240 278
241 bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat h) { 279 bool GrAAConvexTessellator::extractFromPath(const SkMatrix& m, const SkPath& pat h) {
242 SkASSERT(SkPath::kConvex_Convexity == path.getConvexity()); 280 SkASSERT(SkPath::kConvex_Convexity == path.getConvexity());
243 281
244 // Outer ring: 3*numPts 282 // Outer ring: 3*numPts
245 // Middle ring: numPts 283 // Middle ring: numPts
246 // Presumptive inner ring: numPts 284 // Presumptive inner ring: numPts
247 this->reservePts(5*path.countPoints()); 285 this->reservePts(5*path.countPoints());
248 // Outer ring: 12*numPts 286 // Outer ring: 12*numPts
249 // Middle ring: 0 287 // Middle ring: 0
250 // Presumptive inner ring: 6*numPts + 6 288 // Presumptive inner ring: 6*numPts + 6
251 fIndices.setReserve(18*path.countPoints() + 6); 289 fIndices.setReserve(18*path.countPoints() + 6);
252 290
253 fNorms.setReserve(path.countPoints()); 291 fNorms.setReserve(path.countPoints());
254 292
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 293 // 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 294 // get all the points via a new entry point, transform them all in bulk
260 // and then walk them to find duplicates? 295 // and then walk them to find duplicates?
261 SkPath::Iter iter(path, true); 296 SkPath::Iter iter(path, true);
262 SkPoint pts[4]; 297 SkPoint pts[4];
263 SkPath::Verb verb; 298 SkPath::Verb verb;
264 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { 299 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
265 switch (verb) { 300 switch (verb) {
266 case SkPath::kLine_Verb: 301 case SkPath::kLine_Verb:
267 this->lineTo(m, pts[1], false); 302 this->lineTo(m, pts[1], false);
268 break; 303 break;
269 case SkPath::kQuad_Verb: 304 case SkPath::kQuad_Verb:
270 this->quadTo(m, pts); 305 this->quadTo(m, pts);
271 break; 306 break;
272 case SkPath::kCubic_Verb: 307 case SkPath::kCubic_Verb:
273 this->cubicTo(m, pts); 308 this->cubicTo(m, pts);
274 break; 309 break;
275 case SkPath::kConic_Verb: 310 case SkPath::kConic_Verb:
276 this->conicTo(m, pts, iter.conicWeight()); 311 this->conicTo(m, pts, iter.conicWeight());
277 break; 312 break;
278 case SkPath::kMove_Verb: 313 case SkPath::kMove_Verb:
279 case SkPath::kClose_Verb: 314 case SkPath::kClose_Verb:
280 case SkPath::kDone_Verb: 315 case SkPath::kDone_Verb:
281 break; 316 break;
282 } 317 }
283 } 318 }
284 319
285 if (this->numPts() < 3) { 320 if (this->numPts() < 2) {
286 return false; 321 return false;
287 } 322 }
288 323
289 // check if last point is a duplicate of the first point. If so, remove it. 324 // 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])) { 325 if (duplicate_pt(fPts[this->numPts()-1], fPts[0])) {
291 this->popLastPt(); 326 this->popLastPt();
292 fNorms.pop(); 327 fNorms.pop();
293 } 328 }
294 329
295 SkASSERT(fPts.count() == fNorms.count()+1); 330 SkASSERT(fPts.count() == fNorms.count()+1);
296 if (this->numPts() >= 3 && 331 if (this->numPts() >= 3) {
297 abs_dist_from_line(fPts.top(), fNorms.top(), fPts[0]) < kClose) { 332 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. 333 // The last point is on the line from the second to last to the firs t point.
299 this->popLastPt(); 334 this->popLastPt();
300 fNorms.pop(); 335 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());
301 } 342 }
302 343
303 if (this->numPts() < 3) { 344 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. 345 // The first point is on the line from the last to the second.
314 this->popFirstPtShuffle(); 346 this->popFirstPtShuffle();
315 fNorms.removeShuffle(0); 347 fNorms.removeShuffle(0);
316 fNorms[0] = fPts[1] - fPts[0]; 348 fNorms[0] = fPts[1] - fPts[0];
317 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms[0]); 349 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms[0]);
318 SkASSERT(len > 0.0f); 350 SkASSERT(len > 0.0f);
319 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[0].length())); 351 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms[0].length()));
320 } 352 }
321 353
322 if (this->numPts() < 3) { 354 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 {
323 return false; 390 return false;
324 } 391 }
325 392
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()); 393 fCandidateVerts.setReserve(this->numPts());
346 fInitialRing.setReserve(this->numPts()); 394 fInitialRing.setReserve(this->numPts());
347 for (int i = 0; i < this->numPts(); ++i) { 395 for (int i = 0; i < this->numPts(); ++i) {
348 fInitialRing.addIdx(i, i); 396 fInitialRing.addIdx(i, i);
349 } 397 }
350 fInitialRing.init(fNorms, fBisectors); 398 fInitialRing.init(fNorms, fBisectors);
351 399
352 this->validate(); 400 this->validate();
353 return true; 401 return true;
354 } 402 }
355 403
356 GrAAConvexTessellator::Ring* GrAAConvexTessellator::getNextRing(Ring* lastRing) { 404 GrAAConvexTessellator::Ring* GrAAConvexTessellator::getNextRing(Ring* lastRing) {
357 #if GR_AA_CONVEX_TESSELLATOR_VIZ 405 #if GR_AA_CONVEX_TESSELLATOR_VIZ
358 Ring* ring = *fRings.push() = SkNEW(Ring); 406 Ring* ring = *fRings.push() = SkNEW(Ring);
359 ring->setReserve(fInitialRing.numPts()); 407 ring->setReserve(fInitialRing.numPts());
360 ring->rewind(); 408 ring->rewind();
361 return ring; 409 return ring;
362 #else 410 #else
363 // Flip flop back and forth between fRings[0] & fRings[1] 411 // Flip flop back and forth between fRings[0] & fRings[1]
364 int nextRing = (lastRing == &fRings[0]) ? 1 : 0; 412 int nextRing = (lastRing == &fRings[0]) ? 1 : 0;
365 fRings[nextRing].setReserve(fInitialRing.numPts()); 413 fRings[nextRing].setReserve(fInitialRing.numPts());
366 fRings[nextRing].rewind(); 414 fRings[nextRing].rewind();
367 return &fRings[nextRing]; 415 return &fRings[nextRing];
368 #endif 416 #endif
369 } 417 }
370 418
371 void GrAAConvexTessellator::fanRing(const Ring& ring) { 419 void GrAAConvexTessellator::fanRing(const Ring& ring) {
372 // fan out from point 0 420 // fan out from point 0
373 for (int cur = 1; cur < ring.numPts()-1; ++cur) { 421 int startIdx = ring.index(0);
374 this->addTri(ring.index(0), ring.index(cur), ring.index(cur+1)); 422 for (int cur = ring.numPts() - 2; cur >= 0; --cur) {
423 this->addTri(startIdx, ring.index(cur), ring.index(cur + 1));
375 } 424 }
376 } 425 }
377 426
378 void GrAAConvexTessellator::createOuterRing() { 427 void GrAAConvexTessellator::createOuterRing(const Ring& previousRing, SkScalar o utset,
379 // For now, we're only generating one outer ring (at the start). This 428 SkScalar coverage, Ring* nextRing) {
380 // could be relaxed for stroking use cases. 429 const int numPts = previousRing.numPts();
381 SkASSERT(0 == fIndices.count()); 430 if (numPts == 0) {
382 SkASSERT(fPts.count() == fNorms.count()); 431 return;
383 432 }
384 const int numPts = fPts.count();
385 433
386 int prev = numPts - 1; 434 int prev = numPts - 1;
387 int lastPerpIdx = -1, firstPerpIdx = -1, newIdx0, newIdx1, newIdx2; 435 int lastPerpIdx = -1, firstPerpIdx = -1;
436
437 const SkScalar outsetSq = SkScalarMul(outset, outset);
438 SkScalar miterLimitSq = SkScalarMul(outset, fMiterLimit);
439 miterLimitSq = SkScalarMul(miterLimitSq, miterLimitSq);
388 for (int cur = 0; cur < numPts; ++cur) { 440 for (int cur = 0; cur < numPts; ++cur) {
389 if (fIsCurve[cur]) { 441 int originalIdx = previousRing.index(cur);
390 // Inside a curve, we assume that the curvature is shallow enough (d ue to tesselation) 442 // 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 443 // 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 444 // 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 445 // 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 446
396 // The bisector outset point 447 // The perpendicular point for the last edge
397 SkPoint temp = fBisectors[cur]; 448 SkPoint normal1 = previousRing.norm(prev);
398 temp.scale(-fTargetDepth); // the bisectors point in 449 SkPoint perp1 = normal1;
399 temp += fPts[cur]; 450 perp1.scale(outset);
451 perp1 += this->point(originalIdx);
400 452
401 // double-check our "sufficiently flat" assumption; we want the bise ctor point to be 453 // The perpendicular point for the next edge.
402 // close to the normal point. 454 SkPoint normal2 = previousRing.norm(cur);
403 #define kFlatnessTolerance 1.0f 455 SkPoint perp2 = normal2;
404 SkDEBUGCODE(SkPoint prevNormal = fNorms[prev];) 456 perp2.scale(outset);
405 SkDEBUGCODE(prevNormal.scale(fTargetDepth);) 457 perp2 += fPts[originalIdx];
406 SkDEBUGCODE(prevNormal += fPts[cur];)
407 SkASSERT((temp - prevNormal).length() < kFlatnessTolerance);
408 458
409 newIdx1 = this->addPt(temp, -fTargetDepth, false, true); 459 bool isCurve = fIsCurve[originalIdx];
410 460
411 if (0 == cur) { 461 // 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 462 // one are just perpendicular offsets from the non-merged polygon points )
413 firstPerpIdx = newIdx1; 463 int perp1Idx = this->addPt(perp1, -outset, coverage, false, isCurve);
414 SkASSERT(-1 == lastPerpIdx); 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 }
415 } else { 499 } else {
416 // The triangles for the previous edge 500 switch (fJoin) {
417 this->addTri(prev, newIdx1, cur); 501 case SkPaint::Join::kMiter_Join: {
418 this->addTri(prev, lastPerpIdx, newIdx1); 502 // The bisector outset point
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 }
419 } 534 }
420 535
421 prev = cur; 536 nextRing->addIdx(perp2Idx, originalIdx);
422 // Track the last perpendicular outset point so we can construct the
423 // trailing edge triangles.
424 lastPerpIdx = newIdx1;
425 } 537 }
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 538
432 // The perpendicular point for the last edge 539 if (0 == cur) {
433 SkPoint temp = fNorms[prev]; 540 // Store the index of the first perpendicular point to finish up
434 temp.scale(fTargetDepth); 541 firstPerpIdx = perp1Idx;
435 temp += fPts[cur]; 542 SkASSERT(-1 == lastPerpIdx);
543 } else {
544 // The triangles for the previous edge
545 int prevIdx = previousRing.index(prev);
546 this->addTri(prevIdx, perp1Idx, originalIdx);
547 this->addTri(prevIdx, lastPerpIdx, perp1Idx);
548 }
436 549
437 // We know it isn't a duplicate of the prior point (since it and thi s 550 // Track the last perpendicular outset point so we can construct the
438 // one are just perpendicular offsets from the non-merged polygon po ints) 551 // trailing edge triangles.
439 newIdx0 = this->addPt(temp, -fTargetDepth, false, false); 552 lastPerpIdx = perp2Idx;
440 553 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 } 554 }
485 555
486 // pick up the final edge rect 556 // pick up the final edge rect
487 this->addTri(numPts - 1, firstPerpIdx, 0); 557 int lastIdx = previousRing.index(numPts - 1);
488 this->addTri(numPts - 1, lastPerpIdx, firstPerpIdx); 558 this->addTri(lastIdx, firstPerpIdx, previousRing.index(0));
559 this->addTri(lastIdx, lastPerpIdx, firstPerpIdx);
489 560
490 this->validate(); 561 this->validate();
491 } 562 }
492 563
493 // Something went wrong in the creation of the next ring. Mark the last good 564 // 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. 565 // and fan it.
495 void GrAAConvexTessellator::terminate(const Ring& ring) { 566 void GrAAConvexTessellator::terminate(const Ring& ring) {
496 for (int i = 0; i < ring.numPts(); ++i) { 567 if (fStrokeWidth < 0.0f) {
497 fDepths[ring.index(i)] = fTargetDepth; 568 this->fanRing(ring);
498 } 569 }
570 }
499 571
500 this->fanRing(ring); 572 static SkScalar compute_coverage(SkScalar depth, SkScalar initialDepth, SkScalar initialCoverage,
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);
501 } 580 }
502 581
503 // return true when processing is complete 582 // return true when processing is complete
504 bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing ) { 583 bool GrAAConvexTessellator::createInsetRing(const Ring& lastRing, Ring* nextRing ,
584 SkScalar initialDepth, SkScalar init ialCoverage,
585 SkScalar targetDepth, SkScalar targe tCoverage,
586 bool forceNew) {
505 bool done = false; 587 bool done = false;
506 588
507 fCandidateVerts.rewind(); 589 fCandidateVerts.rewind();
508 590
509 // Loop through all the points in the ring and find the intersection with th e smallest depth 591 // 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; 592 SkScalar minDist = SK_ScalarMax, minT = 0.0f;
511 int minEdgeIdx = -1; 593 int minEdgeIdx = -1;
512 594
513 for (int cur = 0; cur < lastRing.numPts(); ++cur) { 595 for (int cur = 0; cur < lastRing.numPts(); ++cur) {
514 int next = (cur + 1) % lastRing.numPts(); 596 int next = (cur + 1) % lastRing.numPts();
515
516 SkScalar t = intersect(this->point(lastRing.index(cur)), lastRing.bisec tor(cur), 597 SkScalar t = intersect(this->point(lastRing.index(cur)), lastRing.bisec tor(cur),
517 this->point(lastRing.index(next)), lastRing.bisec tor(next)); 598 this->point(lastRing.index(next)), lastRing.bisec tor(next));
518 SkScalar dist = -t * lastRing.norm(cur).dot(lastRing.bisector(cur)); 599 SkScalar dist = -t * lastRing.norm(cur).dot(lastRing.bisector(cur));
519 600
520 if (minDist > dist) { 601 if (minDist > dist) {
521 minDist = dist; 602 minDist = dist;
522 minT = t; 603 minT = t;
523 minEdgeIdx = cur; 604 minEdgeIdx = cur;
524 } 605 }
525 } 606 }
526 607
608 if (minEdgeIdx == -1) {
609 return false;
610 }
527 SkPoint newPt = lastRing.bisector(minEdgeIdx); 611 SkPoint newPt = lastRing.bisector(minEdgeIdx);
528 newPt.scale(minT); 612 newPt.scale(minT);
529 newPt += this->point(lastRing.index(minEdgeIdx)); 613 newPt += this->point(lastRing.index(minEdgeIdx));
530 614
531 SkScalar depth = this->computeDepthFromEdge(lastRing.origEdgeID(minEdgeIdx), newPt); 615 SkScalar depth = this->computeDepthFromEdge(lastRing.origEdgeID(minEdgeIdx), newPt);
532 if (depth >= fTargetDepth) { 616 if (depth >= targetDepth) {
533 // None of the bisectors intersect before reaching the desired depth. 617 // None of the bisectors intersect before reaching the desired depth.
534 // Just step them all to the desired depth 618 // Just step them all to the desired depth
535 depth = fTargetDepth; 619 depth = targetDepth;
536 done = true; 620 done = true;
537 } 621 }
538 622
539 // 'dst' stores where each point in the last ring maps to/transforms into 623 // 'dst' stores where each point in the last ring maps to/transforms into
540 // in the next ring. 624 // in the next ring.
541 SkTDArray<int> dst; 625 SkTDArray<int> dst;
542 dst.setCount(lastRing.numPts()); 626 dst.setCount(lastRing.numPts());
543 627
544 // Create the first point (who compares with no one) 628 // Create the first point (who compares with no one)
545 if (!this->computePtAlongBisector(lastRing.index(0), 629 if (!this->computePtAlongBisector(lastRing.index(0),
546 lastRing.bisector(0), 630 lastRing.bisector(0),
547 lastRing.origEdgeID(0), 631 lastRing.origEdgeID(0),
548 depth, &newPt)) { 632 depth, &newPt)) {
549 this->terminate(lastRing); 633 this->terminate(lastRing);
550 SkDEBUGCODE(fShouldCheckDepths = false;)
551 return true; 634 return true;
552 } 635 }
553 dst[0] = fCandidateVerts.addNewPt(newPt, 636 dst[0] = fCandidateVerts.addNewPt(newPt,
554 lastRing.index(0), lastRing.origEdgeID(0), 637 lastRing.index(0), lastRing.origEdgeID(0),
555 !this->movable(lastRing.index(0))); 638 !this->movable(lastRing.index(0)));
556 639
557 // Handle the middle points (who only compare with the prior point) 640 // Handle the middle points (who only compare with the prior point)
558 for (int cur = 1; cur < lastRing.numPts()-1; ++cur) { 641 for (int cur = 1; cur < lastRing.numPts()-1; ++cur) {
559 if (!this->computePtAlongBisector(lastRing.index(cur), 642 if (!this->computePtAlongBisector(lastRing.index(cur),
560 lastRing.bisector(cur), 643 lastRing.bisector(cur),
561 lastRing.origEdgeID(cur), 644 lastRing.origEdgeID(cur),
562 depth, &newPt)) { 645 depth, &newPt)) {
563 this->terminate(lastRing); 646 this->terminate(lastRing);
564 SkDEBUGCODE(fShouldCheckDepths = false;)
565 return true; 647 return true;
566 } 648 }
567 if (!duplicate_pt(newPt, fCandidateVerts.lastPoint())) { 649 if (!duplicate_pt(newPt, fCandidateVerts.lastPoint())) {
568 dst[cur] = fCandidateVerts.addNewPt(newPt, 650 dst[cur] = fCandidateVerts.addNewPt(newPt,
569 lastRing.index(cur), lastRing.or igEdgeID(cur), 651 lastRing.index(cur), lastRing.or igEdgeID(cur),
570 !this->movable(lastRing.index(cu r))); 652 !this->movable(lastRing.index(cu r)));
571 } else { 653 } else {
572 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); 654 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur));
573 } 655 }
574 } 656 }
575 657
576 // Check on the last point (handling the wrap around) 658 // Check on the last point (handling the wrap around)
577 int cur = lastRing.numPts()-1; 659 int cur = lastRing.numPts()-1;
578 if (!this->computePtAlongBisector(lastRing.index(cur), 660 if (!this->computePtAlongBisector(lastRing.index(cur),
579 lastRing.bisector(cur), 661 lastRing.bisector(cur),
580 lastRing.origEdgeID(cur), 662 lastRing.origEdgeID(cur),
581 depth, &newPt)) { 663 depth, &newPt)) {
582 this->terminate(lastRing); 664 this->terminate(lastRing);
583 SkDEBUGCODE(fShouldCheckDepths = false;)
584 return true; 665 return true;
585 } 666 }
586 bool dupPrev = duplicate_pt(newPt, fCandidateVerts.lastPoint()); 667 bool dupPrev = duplicate_pt(newPt, fCandidateVerts.lastPoint());
587 bool dupNext = duplicate_pt(newPt, fCandidateVerts.firstPoint()); 668 bool dupNext = duplicate_pt(newPt, fCandidateVerts.firstPoint());
588 669
589 if (!dupPrev && !dupNext) { 670 if (!dupPrev && !dupNext) {
590 dst[cur] = fCandidateVerts.addNewPt(newPt, 671 dst[cur] = fCandidateVerts.addNewPt(newPt,
591 lastRing.index(cur), lastRing.origEd geID(cur), 672 lastRing.index(cur), lastRing.origEd geID(cur),
592 !this->movable(lastRing.index(cur))) ; 673 !this->movable(lastRing.index(cur))) ;
593 } else if (dupPrev && !dupNext) { 674 } else if (dupPrev && !dupNext) {
594 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); 675 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur));
595 } else if (!dupPrev && dupNext) { 676 } else if (!dupPrev && dupNext) {
596 dst[cur] = fCandidateVerts.fuseWithNext(); 677 dst[cur] = fCandidateVerts.fuseWithNext();
597 } else { 678 } else {
598 bool dupPrevVsNext = duplicate_pt(fCandidateVerts.firstPoint(), fCandida teVerts.lastPoint()); 679 bool dupPrevVsNext = duplicate_pt(fCandidateVerts.firstPoint(), fCandida teVerts.lastPoint());
599 680
600 if (!dupPrevVsNext) { 681 if (!dupPrevVsNext) {
601 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur)); 682 dst[cur] = fCandidateVerts.fuseWithPrior(lastRing.origEdgeID(cur));
602 } else { 683 } else {
603 dst[cur] = dst[cur-1] = fCandidateVerts.fuseWithBoth(); 684 dst[cur] = dst[cur-1] = fCandidateVerts.fuseWithBoth();
604 } 685 }
605 } 686 }
606 687
607 // Fold the new ring's points into the global pool 688 // Fold the new ring's points into the global pool
608 for (int i = 0; i < fCandidateVerts.numPts(); ++i) { 689 for (int i = 0; i < fCandidateVerts.numPts(); ++i) {
609 int newIdx; 690 int newIdx;
610 if (fCandidateVerts.needsToBeNew(i)) { 691 if (fCandidateVerts.needsToBeNew(i) || forceNew) {
611 // if the originating index is still valid then this point wasn't 692 // if the originating index is still valid then this point wasn't
612 // fused (and is thus movable) 693 // fused (and is thus movable)
613 newIdx = this->addPt(fCandidateVerts.point(i), depth, 694 SkScalar coverage = compute_coverage(depth, initialDepth, initialCov erage,
695 targetDepth, targetCoverage);
696 newIdx = this->addPt(fCandidateVerts.point(i), depth, coverage,
614 fCandidateVerts.originatingIdx(i) != -1, false) ; 697 fCandidateVerts.originatingIdx(i) != -1, false) ;
615 } else { 698 } else {
616 SkASSERT(fCandidateVerts.originatingIdx(i) != -1); 699 SkASSERT(fCandidateVerts.originatingIdx(i) != -1);
617 this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.po int(i), depth); 700 this->updatePt(fCandidateVerts.originatingIdx(i), fCandidateVerts.po int(i), depth,
701 targetCoverage);
618 newIdx = fCandidateVerts.originatingIdx(i); 702 newIdx = fCandidateVerts.originatingIdx(i);
619 } 703 }
620 704
621 nextRing->addIdx(newIdx, fCandidateVerts.origEdge(i)); 705 nextRing->addIdx(newIdx, fCandidateVerts.origEdge(i));
622 } 706 }
623 707
624 // 'dst' currently has indices into the ring. Remap these to be indices 708 // 'dst' currently has indices into the ring. Remap these to be indices
625 // into the global pool since the triangulation operates in that space. 709 // into the global pool since the triangulation operates in that space.
626 for (int i = 0; i < dst.count(); ++i) { 710 for (int i = 0; i < dst.count(); ++i) {
627 dst[i] = nextRing->index(dst[i]); 711 dst[i] = nextRing->index(dst[i]);
628 } 712 }
629 713
630 for (int cur = 0; cur < lastRing.numPts(); ++cur) { 714 for (int cur = 0; cur < lastRing.numPts(); ++cur) {
631 int next = (cur + 1) % lastRing.numPts(); 715 int next = (cur + 1) % lastRing.numPts();
632 716
633 this->addTri(lastRing.index(cur), lastRing.index(next), dst[next]); 717 this->addTri(lastRing.index(cur), lastRing.index(next), dst[next]);
634 this->addTri(lastRing.index(cur), dst[next], dst[cur]); 718 this->addTri(lastRing.index(cur), dst[next], dst[cur]);
635 } 719 }
636 720
637 if (done) { 721 if (done && fStrokeWidth < 0.0f) {
722 // fill
638 this->fanRing(*nextRing); 723 this->fanRing(*nextRing);
639 } 724 }
640 725
641 if (nextRing->numPts() < 3) { 726 if (nextRing->numPts() < 3) {
642 done = true; 727 done = true;
643 } 728 }
644
645 return done; 729 return done;
646 } 730 }
647 731
648 void GrAAConvexTessellator::validate() const { 732 void GrAAConvexTessellator::validate() const {
649 SkASSERT(fPts.count() == fDepths.count());
650 SkASSERT(fPts.count() == fMovable.count()); 733 SkASSERT(fPts.count() == fMovable.count());
651 SkASSERT(0 == (fIndices.count() % 3)); 734 SkASSERT(0 == (fIndices.count() % 3));
652 } 735 }
653 736
654 ////////////////////////////////////////////////////////////////////////////// 737 //////////////////////////////////////////////////////////////////////////////
655 void GrAAConvexTessellator::Ring::init(const GrAAConvexTessellator& tess) { 738 void GrAAConvexTessellator::Ring::init(const GrAAConvexTessellator& tess) {
656 this->computeNormals(tess); 739 this->computeNormals(tess);
657 this->computeBisectors(tess); 740 this->computeBisectors(tess);
658 SkASSERT(this->isConvex(tess));
659 } 741 }
660 742
661 void GrAAConvexTessellator::Ring::init(const SkTDArray<SkVector>& norms, 743 void GrAAConvexTessellator::Ring::init(const SkTDArray<SkVector>& norms,
662 const SkTDArray<SkVector>& bisectors) { 744 const SkTDArray<SkVector>& bisectors) {
663 for (int i = 0; i < fPts.count(); ++i) { 745 for (int i = 0; i < fPts.count(); ++i) {
664 fPts[i].fNorm = norms[i]; 746 fPts[i].fNorm = norms[i];
665 fPts[i].fBisector = bisectors[i]; 747 fPts[i].fBisector = bisectors[i];
666 } 748 }
667 } 749 }
668 750
669 // Compute the outward facing normal at each vertex. 751 // Compute the outward facing normal at each vertex.
670 void GrAAConvexTessellator::Ring::computeNormals(const GrAAConvexTessellator& te ss) { 752 void GrAAConvexTessellator::Ring::computeNormals(const GrAAConvexTessellator& te ss) {
671 for (int cur = 0; cur < fPts.count(); ++cur) { 753 for (int cur = 0; cur < fPts.count(); ++cur) {
672 int next = (cur + 1) % fPts.count(); 754 int next = (cur + 1) % fPts.count();
673 755
674 fPts[cur].fNorm = tess.point(fPts[next].fIndex) - tess.point(fPts[cur].f Index); 756 fPts[cur].fNorm = tess.point(fPts[next].fIndex) - tess.point(fPts[cur].f Index);
675 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fPts[cur].fNorm); 757 SkPoint::Normalize(&fPts[cur].fNorm);
676 SkASSERT(len > 0.0f);
677 fPts[cur].fNorm.setOrthog(fPts[cur].fNorm, tess.side()); 758 fPts[cur].fNorm.setOrthog(fPts[cur].fNorm, tess.side());
678
679 SkASSERT(SkScalarNearlyEqual(1.0f, fPts[cur].fNorm.length()));
680 } 759 }
681 } 760 }
682 761
683 void GrAAConvexTessellator::Ring::computeBisectors(const GrAAConvexTessellator& tess) { 762 void GrAAConvexTessellator::Ring::computeBisectors(const GrAAConvexTessellator& tess) {
684 int prev = fPts.count() - 1; 763 int prev = fPts.count() - 1;
685 for (int cur = 0; cur < fPts.count(); prev = cur, ++cur) { 764 for (int cur = 0; cur < fPts.count(); prev = cur, ++cur) {
686 fPts[cur].fBisector = fPts[cur].fNorm + fPts[prev].fNorm; 765 fPts[cur].fBisector = fPts[cur].fNorm + fPts[prev].fNorm;
687 if (!fPts[cur].fBisector.normalize()) { 766 if (!fPts[cur].fBisector.normalize()) {
688 SkASSERT(SkPoint::kLeft_Side == tess.side() || SkPoint::kRight_Side == tess.side()); 767 SkASSERT(SkPoint::kLeft_Side == tess.side() || SkPoint::kRight_Side == tess.side());
689 fPts[cur].fBisector.setOrthog(fPts[cur].fNorm, (SkPoint::Side)-tess. side()); 768 fPts[cur].fBisector.setOrthog(fPts[cur].fNorm, (SkPoint::Side)-tess. side());
690 SkVector other; 769 SkVector other;
691 other.setOrthog(fPts[prev].fNorm, tess.side()); 770 other.setOrthog(fPts[prev].fNorm, tess.side());
692 fPts[cur].fBisector += other; 771 fPts[cur].fBisector += other;
693 SkAssertResult(fPts[cur].fBisector.normalize()); 772 SkAssertResult(fPts[cur].fBisector.normalize());
694 } else { 773 } else {
695 fPts[cur].fBisector.negate(); // make the bisector face in 774 fPts[cur].fBisector.negate(); // make the bisector face in
696 } 775 }
697 776 }
698 SkASSERT(SkScalarNearlyEqual(1.0f, fPts[cur].fBisector.length()));
699 }
700 } 777 }
701 778
702 ////////////////////////////////////////////////////////////////////////////// 779 //////////////////////////////////////////////////////////////////////////////
703 #ifdef SK_DEBUG 780 #ifdef SK_DEBUG
704 // Is this ring convex? 781 // Is this ring convex?
705 bool GrAAConvexTessellator::Ring::isConvex(const GrAAConvexTessellator& tess) co nst { 782 bool GrAAConvexTessellator::Ring::isConvex(const GrAAConvexTessellator& tess) co nst {
706 if (fPts.count() < 3) { 783 if (fPts.count() < 3) {
707 return false; 784 return true;
708 } 785 }
709 786
710 SkPoint prev = tess.point(fPts[0].fIndex) - tess.point(fPts.top().fIndex); 787 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); 788 SkPoint cur = tess.point(fPts[1].fIndex) - tess.point(fPts[0].fIndex);
712 SkScalar minDot = prev.fX * cur.fY - prev.fY * cur.fX; 789 SkScalar minDot = prev.fX * cur.fY - prev.fY * cur.fX;
713 SkScalar maxDot = minDot; 790 SkScalar maxDot = minDot;
714 791
715 prev = cur; 792 prev = cur;
716 for (int i = 1; i < fPts.count(); ++i) { 793 for (int i = 1; i < fPts.count(); ++i) {
717 int next = (i + 1) % fPts.count(); 794 int next = (i + 1) % fPts.count();
718 795
719 cur = tess.point(fPts[next].fIndex) - tess.point(fPts[i].fIndex); 796 cur = tess.point(fPts[next].fIndex) - tess.point(fPts[i].fIndex);
720 SkScalar dot = prev.fX * cur.fY - prev.fY * cur.fX; 797 SkScalar dot = prev.fX * cur.fY - prev.fY * cur.fX;
721 798
722 minDot = SkMinScalar(minDot, dot); 799 minDot = SkMinScalar(minDot, dot);
723 maxDot = SkMaxScalar(maxDot, dot); 800 maxDot = SkMaxScalar(maxDot, dot);
724 801
725 prev = cur; 802 prev = cur;
726 } 803 }
727 804
728 return (maxDot > 0.0f) == (minDot >= 0.0f); 805 if (SkScalarNearlyEqual(maxDot, 0.0f, 0.005f)) {
806 maxDot = 0;
807 }
808 if (SkScalarNearlyEqual(minDot, 0.0f, 0.005f)) {
809 minDot = 0;
810 }
811 return (maxDot >= 0.0f) == (minDot >= 0.0f);
729 } 812 }
730 813
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 }
788 #endif 814 #endif
789 815
790 #define kQuadTolerance 0.2f 816 void GrAAConvexTessellator::lineTo(SkPoint p, bool isCurve) {
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);
796 if (this->numPts() > 0 && duplicate_pt(p, this->lastPoint())) { 817 if (this->numPts() > 0 && duplicate_pt(p, this->lastPoint())) {
797 return; 818 return;
798 } 819 }
799 820
800 SkASSERT(fPts.count() <= 1 || fPts.count() == fNorms.count()+1); 821 SkASSERT(fPts.count() <= 1 || fPts.count() == fNorms.count()+1);
801 if (this->numPts() >= 2 && 822 if (this->numPts() >= 2 &&
802 abs_dist_from_line(fPts.top(), fNorms.top(), p) < kClose) { 823 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 824 // The old last point is on the line from the second to last to the new point
804 this->popLastPt(); 825 this->popLastPt();
805 fNorms.pop(); 826 fNorms.pop();
806 fIsCurve.pop(); 827 fIsCurve.pop();
807 } 828 }
808 this->addPt(p, 0.0f, false, isCurve); 829 SkScalar initialRingCoverage = fStrokeWidth < 0.0f ? 0.5f : 1.0f;
830 this->addPt(p, 0.0f, initialRingCoverage, false, isCurve);
809 if (this->numPts() > 1) { 831 if (this->numPts() > 1) {
810 *fNorms.push() = fPts.top() - fPts[fPts.count()-2]; 832 *fNorms.push() = fPts.top() - fPts[fPts.count()-2];
811 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top()); 833 SkDEBUGCODE(SkScalar len =) SkPoint::Normalize(&fNorms.top());
812 SkASSERT(len > 0.0f); 834 SkASSERT(len > 0.0f);
813 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms.top().length())); 835 SkASSERT(SkScalarNearlyEqual(1.0f, fNorms.top().length()));
814 } 836 }
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 } 837 }
824 838
825 void GrAAConvexTessellator::quadTo(const SkMatrix& m, SkPoint pts[3]) { 839 void GrAAConvexTessellator::lineTo(const SkMatrix& m, SkPoint p, bool isCurve) {
840 m.mapPoints(&p, 1);
841 this->lineTo(p, isCurve);
842 }
843
844 void GrAAConvexTessellator::quadTo(SkPoint pts[3]) {
826 int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance); 845 int maxCount = GrPathUtils::quadraticPointCount(pts, kQuadTolerance);
827 fPointBuffer.setReserve(maxCount); 846 fPointBuffer.setReserve(maxCount);
828 SkPoint* target = fPointBuffer.begin(); 847 SkPoint* target = fPointBuffer.begin();
829 int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], 848 int count = GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
830 kQuadTolerance, &target, maxCount); 849 kQuadTolerance, &target, maxCount);
831 fPointBuffer.setCount(count); 850 fPointBuffer.setCount(count);
832 for (int i = 0; i < count; i++) { 851 for (int i = 0; i < count; i++) {
833 lineTo(m, fPointBuffer[i], true); 852 lineTo(fPointBuffer[i], true);
834 } 853 }
835 } 854 }
836 855
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
837 void GrAAConvexTessellator::cubicTo(const SkMatrix& m, SkPoint pts[4]) { 865 void GrAAConvexTessellator::cubicTo(const SkMatrix& m, SkPoint pts[4]) {
866 m.mapPoints(pts, 4);
838 int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance); 867 int maxCount = GrPathUtils::cubicPointCount(pts, kCubicTolerance);
839 fPointBuffer.setReserve(maxCount); 868 fPointBuffer.setReserve(maxCount);
840 SkPoint* target = fPointBuffer.begin(); 869 SkPoint* target = fPointBuffer.begin();
841 int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], 870 int count = GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
842 kCubicTolerance, &target, maxCount); 871 kCubicTolerance, &target, maxCount);
843 fPointBuffer.setCount(count); 872 fPointBuffer.setCount(count);
844 for (int i = 0; i < count; i++) { 873 for (int i = 0; i < count; i++) {
845 lineTo(m, fPointBuffer[i], true); 874 lineTo(fPointBuffer[i], true);
846 } 875 }
847 } 876 }
848 877
849 // include down here to avoid compilation errors caused by "-" overload in SkGeo metry.h 878 // include down here to avoid compilation errors caused by "-" overload in SkGeo metry.h
850 #include "SkGeometry.h" 879 #include "SkGeometry.h"
851 880
852 void GrAAConvexTessellator::conicTo(const SkMatrix& m, SkPoint* pts, SkScalar w) { 881 void GrAAConvexTessellator::conicTo(const SkMatrix& m, SkPoint pts[3], SkScalar w) {
882 m.mapPoints(pts, 3);
853 SkAutoConicToQuads quadder; 883 SkAutoConicToQuads quadder;
854 const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance); 884 const SkPoint* quads = quadder.computeQuads(pts, w, kConicTolerance);
855 SkPoint lastPoint = *(quads++); 885 SkPoint lastPoint = *(quads++);
856 int count = quadder.countQuads(); 886 int count = quadder.countQuads();
857 for (int i = 0; i < count; ++i) { 887 for (int i = 0; i < count; ++i) {
858 SkPoint quadPts[3]; 888 SkPoint quadPts[3];
859 quadPts[0] = lastPoint; 889 quadPts[0] = lastPoint;
860 quadPts[1] = quads[0]; 890 quadPts[1] = quads[0];
861 quadPts[2] = i == count - 1 ? pts[2] : quads[1]; 891 quadPts[2] = i == count - 1 ? pts[2] : quads[1];
862 quadTo(m, quadPts); 892 quadTo(quadPts);
863 lastPoint = quadPts[2]; 893 lastPoint = quadPts[2];
864 quads += 2; 894 quads += 2;
865 } 895 }
866 } 896 }
867 897
868 ////////////////////////////////////////////////////////////////////////////// 898 //////////////////////////////////////////////////////////////////////////////
869 #if GR_AA_CONVEX_TESSELLATOR_VIZ 899 #if GR_AA_CONVEX_TESSELLATOR_VIZ
870 static const SkScalar kPointRadius = 0.02f; 900 static const SkScalar kPointRadius = 0.02f;
871 static const SkScalar kArrowStrokeWidth = 0.0f; 901 static const SkScalar kArrowStrokeWidth = 0.0f;
872 static const SkScalar kArrowLength = 0.2f; 902 static const SkScalar kArrowLength = 0.2f;
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
958 SK_ColorBLACK); 988 SK_ColorBLACK);
959 } 989 }
960 990
961 fInitialRing.draw(canvas, *this); 991 fInitialRing.draw(canvas, *this);
962 for (int i = 0; i < fRings.count(); ++i) { 992 for (int i = 0; i < fRings.count(); ++i) {
963 fRings[i]->draw(canvas, *this); 993 fRings[i]->draw(canvas, *this);
964 } 994 }
965 995
966 for (int i = 0; i < this->numPts(); ++i) { 996 for (int i = 0; i < this->numPts(); ++i) {
967 draw_point(canvas, 997 draw_point(canvas,
968 this->point(i), 0.5f + (this->depth(i)/(2*fTargetDepth)), 998 this->point(i), 0.5f + (this->depth(i)/(2 * kAntialiasingRadi us)),
969 !this->movable(i)); 999 !this->movable(i));
970 1000
971 SkPaint paint; 1001 SkPaint paint;
972 paint.setTextSize(kPointTextSize); 1002 paint.setTextSize(kPointTextSize);
973 paint.setTextAlign(SkPaint::kCenter_Align); 1003 paint.setTextAlign(SkPaint::kCenter_Align);
974 if (this->depth(i) <= -fTargetDepth) { 1004 if (this->depth(i) <= -kAntialiasingRadius) {
975 paint.setColor(SK_ColorWHITE); 1005 paint.setColor(SK_ColorWHITE);
976 } 1006 }
977 1007
978 SkString num; 1008 SkString num;
979 num.printf("%d", i); 1009 num.printf("%d", i);
980 canvas->drawText(num.c_str(), num.size(), 1010 canvas->drawText(num.c_str(), num.size(),
981 this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f ), 1011 this->point(i).fX, this->point(i).fY+(kPointRadius/2.0f ),
982 paint); 1012 paint);
983 } 1013 }
984 } 1014 }
985 1015
986 #endif 1016 #endif
987 1017
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