OLD | NEW |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "GrAAHairLinePathRenderer.h" | 9 #include "GrAAHairLinePathRenderer.h" |
10 | 10 |
11 #include "GrContext.h" | 11 #include "GrContext.h" |
12 #include "GrDrawState.h" | 12 #include "GrDrawState.h" |
13 #include "GrDrawTargetCaps.h" | 13 #include "GrDrawTargetCaps.h" |
14 #include "GrEffect.h" | 14 #include "GrEffect.h" |
15 #include "GrGpu.h" | 15 #include "GrGpu.h" |
16 #include "GrIndexBuffer.h" | 16 #include "GrIndexBuffer.h" |
17 #include "GrPathUtils.h" | 17 #include "GrPathUtils.h" |
18 #include "GrTBackendEffectFactory.h" | 18 #include "GrTBackendEffectFactory.h" |
19 #include "SkGeometry.h" | 19 #include "SkGeometry.h" |
20 #include "SkStroke.h" | 20 #include "SkStroke.h" |
21 #include "SkTemplates.h" | 21 #include "SkTemplates.h" |
22 | 22 |
23 #include "gl/GrGLEffect.h" | 23 #include "gl/GrGLEffect.h" |
24 #include "gl/GrGLSL.h" | 24 #include "gl/GrGLSL.h" |
25 | 25 |
26 namespace { | 26 namespace { |
27 // quadratics are rendered as 5-sided polys in order to bound the | 27 // quadratics are rendered as 5-sided polys in order to bound the |
28 // AA stroke around the center-curve. See comments in push_quad_index_buffer and | 28 // AA stroke around the center-curve. See comments in push_quad_index_buffer and |
29 // bloat_quad. | 29 // bloat_quad. Quadratics and conics share an index buffer |
30 static const int kVertsPerQuad = 5; | 30 static const int kVertsPerQuad = 5; |
31 static const int kIdxsPerQuad = 9; | 31 static const int kIdxsPerQuad = 9; |
32 | 32 |
33 static const int kVertsPerLineSeg = 4; | 33 static const int kVertsPerLineSeg = 4; |
34 static const int kIdxsPerLineSeg = 6; | 34 static const int kIdxsPerLineSeg = 6; |
35 | 35 |
36 static const int kNumQuadsInIdxBuffer = 256; | 36 static const int kNumQuadsInIdxBuffer = 256; |
37 static const size_t kQuadIdxSBufize = kIdxsPerQuad * | 37 static const size_t kQuadIdxSBufize = kIdxsPerQuad * |
38 sizeof(uint16_t) * | 38 sizeof(uint16_t) * |
39 kNumQuadsInIdxBuffer; | 39 kNumQuadsInIdxBuffer; |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
110 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { | 110 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { |
111 fLinesIndexBuffer->unref(); | 111 fLinesIndexBuffer->unref(); |
112 fQuadsIndexBuffer->unref(); | 112 fQuadsIndexBuffer->unref(); |
113 } | 113 } |
114 | 114 |
115 namespace { | 115 namespace { |
116 | 116 |
117 typedef SkTArray<SkPoint, true> PtArray; | 117 typedef SkTArray<SkPoint, true> PtArray; |
118 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> | 118 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> |
119 typedef SkTArray<int, true> IntArray; | 119 typedef SkTArray<int, true> IntArray; |
120 typedef SkTArray<float, true> FloatArray; | |
120 | 121 |
121 // Takes 178th time of logf on Z600 / VC2010 | 122 // Takes 178th time of logf on Z600 / VC2010 |
122 int get_float_exp(float x) { | 123 int get_float_exp(float x) { |
123 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); | 124 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); |
124 #if GR_DEBUG | 125 #if GR_DEBUG |
125 static bool tested; | 126 static bool tested; |
126 if (!tested) { | 127 if (!tested) { |
127 tested = true; | 128 tested = true; |
128 GrAssert(get_float_exp(0.25f) == -2); | 129 GrAssert(get_float_exp(0.25f) == -2); |
129 GrAssert(get_float_exp(0.3f) == -2); | 130 GrAssert(get_float_exp(0.3f) == -2); |
130 GrAssert(get_float_exp(0.5f) == -1); | 131 GrAssert(get_float_exp(0.5f) == -1); |
131 GrAssert(get_float_exp(1.f) == 0); | 132 GrAssert(get_float_exp(1.f) == 0); |
132 GrAssert(get_float_exp(2.f) == 1); | 133 GrAssert(get_float_exp(2.f) == 1); |
133 GrAssert(get_float_exp(2.5f) == 1); | 134 GrAssert(get_float_exp(2.5f) == 1); |
134 GrAssert(get_float_exp(8.f) == 3); | 135 GrAssert(get_float_exp(8.f) == 3); |
135 GrAssert(get_float_exp(100.f) == 6); | 136 GrAssert(get_float_exp(100.f) == 6); |
136 GrAssert(get_float_exp(1000.f) == 9); | 137 GrAssert(get_float_exp(1000.f) == 9); |
137 GrAssert(get_float_exp(1024.f) == 10); | 138 GrAssert(get_float_exp(1024.f) == 10); |
138 GrAssert(get_float_exp(3000000.f) == 21); | 139 GrAssert(get_float_exp(3000000.f) == 21); |
139 } | 140 } |
140 #endif | 141 #endif |
141 const int* iptr = (const int*)&x; | 142 const int* iptr = (const int*)&x; |
142 return (((*iptr) & 0x7f800000) >> 23) - 127; | 143 return (((*iptr) & 0x7f800000) >> 23) - 127; |
143 } | 144 } |
144 | 145 |
146 // Uses the max curvature function for quads to estimate | |
147 // where to chop the conic. If the max curvature is not | |
148 // found along the curve segment it will return 1 and | |
149 // dst[0] is the orginal conic. If it returns 2 the dst[0] | |
150 // and dst[1] are the two new conics. | |
151 int chop_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { | |
152 SkScalar t = SkFindQuadMaxCurvature(src); | |
153 if (t == 0) { | |
154 if (dst) { | |
155 dst[0].set(src, weight); | |
156 } | |
157 return 1; | |
158 } else { | |
159 if (dst) { | |
160 SkConic conic; | |
161 conic.set(src, weight); | |
162 conic.chopAt(t, dst); | |
163 } | |
164 return 2; | |
165 } | |
166 } | |
167 | |
168 // returns 0 if quad/conic is degen or close to it | |
169 // in this case approx the path with lines | |
170 // otherwise returns 1 | |
171 int is_degen_quad_or_conic(const SkPoint p[3]) { | |
172 static const SkScalar gDegenerateToLineTol = SK_Scalar1; | |
173 static const SkScalar gDegenerateToLineTolSqd = | |
174 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); | |
175 | |
176 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || | |
177 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { | |
178 return 1; | |
179 } | |
180 | |
181 SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); | |
182 if (dsqd < gDegenerateToLineTolSqd) { | |
183 return 1; | |
184 } | |
185 | |
186 if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { | |
187 return 1; | |
188 } | |
189 return 0; | |
190 } | |
191 | |
145 // we subdivide the quads to avoid huge overfill | 192 // we subdivide the quads to avoid huge overfill |
146 // if it returns -1 then should be drawn as lines | 193 // if it returns -1 then should be drawn as lines |
147 int num_quad_subdivs(const SkPoint p[3]) { | 194 int num_quad_subdivs(const SkPoint p[3]) { |
148 static const SkScalar gDegenerateToLineTol = SK_Scalar1; | 195 static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
149 static const SkScalar gDegenerateToLineTolSqd = | 196 static const SkScalar gDegenerateToLineTolSqd = |
150 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); | 197 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
151 | 198 |
152 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || | 199 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || |
153 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { | 200 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { |
154 return -1; | 201 return -1; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
200 * Quads are recorded in device space unless m contains | 247 * Quads are recorded in device space unless m contains |
201 * perspective, then in they are in src space. We do this because we will | 248 * perspective, then in they are in src space. We do this because we will |
202 * subdivide large quads to reduce over-fill. This subdivision has to be | 249 * subdivide large quads to reduce over-fill. This subdivision has to be |
203 * performed before applying the perspective matrix. | 250 * performed before applying the perspective matrix. |
204 */ | 251 */ |
205 int generate_lines_and_quads(const SkPath& path, | 252 int generate_lines_and_quads(const SkPath& path, |
206 const SkMatrix& m, | 253 const SkMatrix& m, |
207 const GrIRect& devClipBounds, | 254 const GrIRect& devClipBounds, |
208 PtArray* lines, | 255 PtArray* lines, |
209 PtArray* quads, | 256 PtArray* quads, |
210 IntArray* quadSubdivCnts) { | 257 PtArray* conics, |
258 IntArray* quadSubdivCnts, | |
259 FloatArray* conicWeights) { | |
211 SkPath::Iter iter(path, false); | 260 SkPath::Iter iter(path, false); |
212 | 261 |
213 int totalQuadCount = 0; | 262 int totalQuadCount = 0; |
214 GrRect bounds; | 263 GrRect bounds; |
215 GrIRect ibounds; | 264 GrIRect ibounds; |
216 | 265 |
217 bool persp = m.hasPerspective(); | 266 bool persp = m.hasPerspective(); |
218 | 267 |
219 for (;;) { | 268 for (;;) { |
220 GrPoint pathPts[4]; | 269 GrPoint pathPts[4]; |
221 GrPoint devPts[4]; | 270 GrPoint devPts[4]; |
222 SkPath::Verb verb = iter.next(pathPts); | 271 SkPath::Verb verb = iter.next(pathPts); |
223 switch (verb) { | 272 switch (verb) { |
224 case SkPath::kConic_Verb: | 273 case SkPath::kConic_Verb: { |
225 SkASSERT(0); | 274 SkConic dst[2]; |
275 int conicCnt = chop_conic(pathPts, dst, iter.conicWeight()); | |
276 for (int i = 0; i < conicCnt; ++i) { | |
277 SkPoint* chopPnts = dst[i].fPts; | |
278 m.mapPoints(devPts, chopPnts, 3); | |
279 bounds.setBounds(devPts, 3); | |
280 bounds.outset(SK_Scalar1, SK_Scalar1); | |
281 bounds.roundOut(&ibounds); | |
282 if (SkIRect::Intersects(devClipBounds, ibounds)) { | |
283 if (is_degen_quad_or_conic(devPts)) { | |
284 SkPoint* pts = lines->push_back_n(4); | |
285 pts[0] = devPts[0]; | |
286 pts[1] = devPts[1]; | |
287 pts[2] = devPts[1]; | |
288 pts[3] = devPts[2]; | |
289 } else { | |
290 // when in perspective keep conics in src space | |
291 SkPoint* cPts = persp ? chopPnts : devPts; | |
292 SkPoint* pts = conics->push_back_n(3); | |
293 pts[0] = cPts[0]; | |
294 pts[1] = cPts[1]; | |
295 pts[2] = cPts[2]; | |
296 conicWeights->push_back() = dst[i].fW; | |
297 } | |
298 } | |
299 } | |
300 } | |
226 break; | 301 break; |
bsalomon
2013/07/11 18:48:38
I think we put the break inside the last }
| |
227 case SkPath::kMove_Verb: | 302 case SkPath::kMove_Verb: |
228 break; | 303 break; |
229 case SkPath::kLine_Verb: | 304 case SkPath::kLine_Verb: |
230 m.mapPoints(devPts, pathPts, 2); | 305 m.mapPoints(devPts, pathPts, 2); |
231 bounds.setBounds(devPts, 2); | 306 bounds.setBounds(devPts, 2); |
232 bounds.outset(SK_Scalar1, SK_Scalar1); | 307 bounds.outset(SK_Scalar1, SK_Scalar1); |
233 bounds.roundOut(&ibounds); | 308 bounds.roundOut(&ibounds); |
234 if (SkIRect::Intersects(devClipBounds, ibounds)) { | 309 if (SkIRect::Intersects(devClipBounds, ibounds)) { |
235 SkPoint* pts = lines->push_back_n(2); | 310 SkPoint* pts = lines->push_back_n(2); |
236 pts[0] = devPts[0]; | 311 pts[0] = devPts[0]; |
237 pts[1] = devPts[1]; | 312 pts[1] = devPts[1]; |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
341 } | 416 } |
342 | 417 |
343 struct Vertex { | 418 struct Vertex { |
344 GrPoint fPos; | 419 GrPoint fPos; |
345 union { | 420 union { |
346 struct { | 421 struct { |
347 SkScalar fA; | 422 SkScalar fA; |
348 SkScalar fB; | 423 SkScalar fB; |
349 SkScalar fC; | 424 SkScalar fC; |
350 } fLine; | 425 } fLine; |
426 struct { | |
427 SkScalar fA; | |
428 SkScalar fB; | |
429 SkScalar fC; | |
430 SkScalar fD; | |
431 SkScalar fE; | |
432 SkScalar fF; | |
433 } fConic; | |
351 GrVec fQuadCoord; | 434 GrVec fQuadCoord; |
352 struct { | 435 struct { |
353 SkScalar fBogus[4]; | 436 SkScalar fBogus[6]; |
354 }; | 437 }; |
355 }; | 438 }; |
356 }; | 439 }; |
357 GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); | 440 |
441 GR_STATIC_ASSERT(sizeof(Vertex) == 4 * sizeof(GrPoint)); | |
358 | 442 |
359 void intersect_lines(const SkPoint& ptA, const SkVector& normA, | 443 void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
360 const SkPoint& ptB, const SkVector& normB, | 444 const SkPoint& ptB, const SkVector& normB, |
361 SkPoint* result) { | 445 SkPoint* result) { |
362 | 446 |
363 SkScalar lineAW = -normA.dot(ptA); | 447 SkScalar lineAW = -normA.dot(ptA); |
364 SkScalar lineBW = -normB.dot(ptB); | 448 SkScalar lineBW = -normB.dot(ptB); |
365 | 449 |
366 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - | 450 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - |
367 SkScalarMul(normA.fY, normB.fX); | 451 SkScalarMul(normA.fY, normB.fX); |
368 wInv = SkScalarInvert(wInv); | 452 wInv = SkScalarInvert(wInv); |
369 | 453 |
370 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); | 454 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); |
371 result->fX = SkScalarMul(result->fX, wInv); | 455 result->fX = SkScalarMul(result->fX, wInv); |
372 | 456 |
373 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); | 457 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); |
374 result->fY = SkScalarMul(result->fY, wInv); | 458 result->fY = SkScalarMul(result->fY, wInv); |
375 } | 459 } |
376 | 460 |
377 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, | 461 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
447 // include it. | 531 // include it. |
448 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); | 532 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); |
449 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); | 533 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); |
450 | 534 |
451 if (toSrc) { | 535 if (toSrc) { |
452 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad ); | 536 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad ); |
453 } | 537 } |
454 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); | 538 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); |
455 } | 539 } |
456 | 540 |
541 | |
542 // Input Parametric: | |
543 // P(t) = (P0*(1-t)^2 + 2*w*P1*t*(1-t) + P2*t^2) / (1-t)^2 + 2*w*t*(1-t) + t^2) | |
544 // Output Implicit: | |
545 // Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0 | |
546 // A = 4w^2*(y0-y1)(y1-y2)-(y0-y2)^2 | |
547 // B = 4w^2*((x0-x1)(y2-y1)+(x1-x2)(y1-y0)) + 2(x0-x2)(y0-y2) | |
548 // C = 4w^2(x0-x1)(x1-x2) - (x0-x2)^2 | |
549 // D = 4w^2((x0y1-x1y0)(y1-y2)+(x1y2-x2y1)(y0-y1)) + 2(y2-y0)(x0y2-x2y0) | |
550 // E = 4w^2((y0x1-y1x0)(x1-x2)+(y1x2-y2x1)(x0-x1)) + 2(x2-x0)(y0x2-y2x0) | |
551 // F = 4w^2(x1y2-x2y1)(x0y1-x1y0) - (x2y0-x0y2)^2 | |
552 | |
553 void set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerQuad], const flo at weight) { | |
554 const float ww4 = 4 * weight * weight; | |
555 const float x0Mx1 = p[0].fX - p[1].fX; | |
556 const float x1Mx2 = p[1].fX - p[2].fX; | |
557 const float x0Mx2 = p[0].fX - p[2].fX; | |
558 const float y0My1 = p[0].fY - p[1].fY; | |
559 const float y1My2 = p[1].fY - p[2].fY; | |
560 const float y0My2 = p[0].fY - p[2].fY; | |
561 const float x0y1Mx1y0 = p[0].fX*p[1].fY - p[1].fX*p[0].fY; | |
562 const float x1y2Mx2y1 = p[1].fX*p[2].fY - p[2].fX*p[1].fY; | |
563 const float x0y2Mx2y0 = p[0].fX*p[2].fY - p[2].fX*p[0].fY; | |
564 const float a = ww4 * y0My1 * y1My2 - y0My2 * y0My2; | |
565 const float b = -ww4 * (x0Mx1 * y1My2 + x1Mx2 * y0My1) + 2 * x0Mx2 * y0My2; | |
566 const float c = ww4 * x0Mx1 * x1Mx2 - x0Mx2 * x0Mx2; | |
567 const float d = ww4 * (x0y1Mx1y0 * y1My2 + x1y2Mx2y1 * y0My1) - 2 * y0My2 * x0y2Mx2y0; | |
568 const float e = -ww4 * (x0y1Mx1y0 * x1Mx2 + x1y2Mx2y1 * x0Mx1) + 2 * x0Mx2 * x0y2Mx2y0; | |
569 const float f = ww4 * x1y2Mx2y1 * x0y1Mx1y0 - x0y2Mx2y0 * x0y2Mx2y0; | |
570 | |
571 for (int i = 0; i < kVertsPerQuad; ++i) { | |
572 verts[i].fConic.fA = a/f; | |
573 verts[i].fConic.fB = b/f; | |
574 verts[i].fConic.fC = c/f; | |
575 verts[i].fConic.fD = d/f; | |
576 verts[i].fConic.fE = e/f; | |
577 verts[i].fConic.fF = f/f; | |
578 } | |
579 } | |
580 | |
581 void add_conics(const SkPoint p[3], | |
582 float weight, | |
583 const SkMatrix* toDevice, | |
584 const SkMatrix* toSrc, | |
585 Vertex** vert, | |
586 SkRect* devBounds) { | |
587 bloat_quad(p, toDevice, toSrc, *vert, devBounds); | |
588 set_conic_coeffs(p, *vert, weight); | |
589 *vert += kVertsPerQuad; | |
590 } | |
591 | |
457 void add_quads(const SkPoint p[3], | 592 void add_quads(const SkPoint p[3], |
458 int subdiv, | 593 int subdiv, |
459 const SkMatrix* toDevice, | 594 const SkMatrix* toDevice, |
460 const SkMatrix* toSrc, | 595 const SkMatrix* toSrc, |
461 Vertex** vert, | 596 Vertex** vert, |
462 SkRect* devBounds) { | 597 SkRect* devBounds) { |
463 GrAssert(subdiv >= 0); | 598 GrAssert(subdiv >= 0); |
464 if (subdiv) { | 599 if (subdiv) { |
465 SkPoint newP[5]; | 600 SkPoint newP[5]; |
466 SkChopQuadAtHalf(p, newP); | 601 SkChopQuadAtHalf(p, newP); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
508 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); | 643 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); |
509 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); | 644 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); |
510 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); | 645 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); |
511 } | 646 } |
512 | 647 |
513 *vert += kVertsPerLineSeg; | 648 *vert += kVertsPerLineSeg; |
514 } | 649 } |
515 | 650 |
516 } | 651 } |
517 | 652 |
653 /** | |
654 * The output of this effect is a hairline edge for conics. | |
655 * Conics specified by implicit equation Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0. | |
656 * A, B, C, D are the first vec4 of vertex attributes and | |
657 * E and F are the vec2 attached to 2nd vertex attrribute. | |
658 * Coverage is max(0, 1-distance). | |
659 */ | |
660 class HairConicEdgeEffect : public GrEffect { | |
661 public: | |
662 static GrEffectRef* Create() { | |
663 GR_CREATE_STATIC_EFFECT(gHairConicEdgeEffect, HairConicEdgeEffect, ()); | |
664 gHairConicEdgeEffect->ref(); | |
665 return gHairConicEdgeEffect; | |
666 } | |
667 | |
668 virtual ~HairConicEdgeEffect() {} | |
669 | |
670 static const char* Name() { return "HairConicEdge"; } | |
671 | |
672 virtual void getConstantColorComponents(GrColor* color, | |
673 uint32_t* validFlags) const SK_OVERR IDE { | |
674 *validFlags = 0; | |
675 } | |
676 | |
677 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | |
678 return GrTBackendEffectFactory<HairConicEdgeEffect>::getInstance(); | |
679 } | |
680 | |
681 class GLEffect : public GrGLEffect { | |
682 public: | |
683 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) | |
684 : INHERITED (factory) {} | |
685 | |
686 virtual void emitCode(GrGLShaderBuilder* builder, | |
687 const GrDrawEffect& drawEffect, | |
688 EffectKey key, | |
689 const char* outputColor, | |
690 const char* inputColor, | |
691 const TextureSamplerArray& samplers) SK_OVERRIDE { | |
692 const char *vsCoeffABCDName, *fsCoeffABCDName; | |
693 const char *vsCoeffEFName, *fsCoeffEFName; | |
694 | |
695 SkAssertResult(builder->enableFeature( | |
696 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); | |
697 builder->addVarying(kVec4f_GrSLType, "ConicCoeffsABCD", | |
698 &vsCoeffABCDName, &fsCoeffABCDName); | |
699 const SkString* attr0Name = | |
700 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); | |
701 builder->vsCodeAppendf("\t%s = %s;\n", vsCoeffABCDName, attr0Name->c _str()); | |
702 | |
703 builder->addVarying(kVec2f_GrSLType, "ConicCoeffsEF", | |
704 &vsCoeffEFName, &fsCoeffEFName); | |
705 const SkString* attr1Name = | |
706 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]); | |
707 builder->vsCodeAppendf("\t%s = %s;\n", vsCoeffEFName, attr1Name->c_s tr()); | |
708 | |
709 // Based on Gustavson 2006: "Beyond the Pixel: towards infinite reso lution textures" | |
710 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); | |
711 | |
712 builder->fsCodeAppendf("\t\tvec3 uv1 = vec3(%s.xy, 1);\n", builder-> fragmentPosition()); | |
713 builder->fsCodeAppend("\t\tvec3 u2uvv2 = uv1.xxy * uv1.xyy;\n"); | |
714 builder->fsCodeAppendf("\t\tvec3 ABC = %s.xyz;\n", fsCoeffABCDName); | |
715 builder->fsCodeAppendf("\t\tvec3 DEF = vec3(%s.w, %s.xy);\n", | |
716 fsCoeffABCDName, fsCoeffEFName); | |
717 | |
718 builder->fsCodeAppend("\t\tfloat dfdx = dot(uv1,vec3(2.0*ABC.x,ABC.y ,DEF.x));\n"); | |
719 builder->fsCodeAppend("\t\tfloat dfdy = dot(uv1,vec3(ABC.y, 2.0*ABC. z,DEF.y));\n"); | |
720 builder->fsCodeAppend("\t\tfloat gF = dfdx*dfdx + dfdy*dfdy;\n"); | |
721 builder->fsCodeAppend("\t\tedgeAlpha = dot(ABC,u2uvv2) + dot(DEF,uv1 );\n"); | |
722 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / gF );\n"); | |
723 builder->fsCodeAppend("\t\tedgeAlpha = max((1.0 - edgeAlpha), 0.0);\ n"); | |
724 // Add line below for smooth cubic ramp | |
725 // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2 .0*edgeAlpha);\n"); | |
726 | |
727 SkString modulate; | |
728 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); | |
729 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); | |
730 } | |
731 | |
732 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { | |
733 return 0x0; | |
734 } | |
735 | |
736 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_ OVERRIDE {} | |
737 | |
738 private: | |
739 typedef GrGLEffect INHERITED; | |
740 }; | |
741 | |
742 private: | |
743 HairConicEdgeEffect() { | |
744 this->addVertexAttrib(kVec4f_GrSLType); | |
745 this->addVertexAttrib(kVec2f_GrSLType); | |
746 this->setWillReadFragmentPosition(); | |
747 } | |
748 | |
749 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { | |
750 return true; | |
751 } | |
752 | |
753 GR_DECLARE_EFFECT_TEST; | |
754 | |
755 typedef GrEffect INHERITED; | |
756 }; | |
757 | |
758 GR_DEFINE_EFFECT_TEST(HairConicEdgeEffect); | |
759 | |
760 GrEffectRef* HairConicEdgeEffect::TestCreate(SkMWCRandom* random, | |
761 GrContext*, | |
762 const GrDrawTargetCaps& caps, | |
763 GrTexture*[]) { | |
764 return HairConicEdgeEffect::Create(); | |
765 } | |
518 /////////////////////////////////////////////////////////////////////////////// | 766 /////////////////////////////////////////////////////////////////////////////// |
519 | 767 |
520 /** | 768 /** |
521 * The output of this effect is a hairline edge for quadratics. | 769 * The output of this effect is a hairline edge for quadratics. |
522 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first | 770 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first |
523 * two components of the vertex attribute. Uses unsigned distance. | 771 * two components of the vertex attribute. Uses unsigned distance. |
524 * Coverage is min(0, 1-distance). 3rd & 4th component unused. | 772 * Coverage is min(0, 1-distance). 3rd & 4th component unused. |
525 * Requires shader derivative instruction support. | 773 * Requires shader derivative instruction support. |
526 */ | 774 */ |
527 class HairQuadEdgeEffect : public GrEffect { | 775 class HairQuadEdgeEffect : public GrEffect { |
(...skipping 28 matching lines...) Expand all Loading... | |
556 EffectKey key, | 804 EffectKey key, |
557 const char* outputColor, | 805 const char* outputColor, |
558 const char* inputColor, | 806 const char* inputColor, |
559 const TextureSamplerArray& samplers) SK_OVERRIDE { | 807 const TextureSamplerArray& samplers) SK_OVERRIDE { |
560 const char *vsName, *fsName; | 808 const char *vsName, *fsName; |
561 const SkString* attrName = | 809 const SkString* attrName = |
562 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); | 810 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); |
563 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); | 811 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); |
564 | 812 |
565 SkAssertResult(builder->enableFeature( | 813 SkAssertResult(builder->enableFeature( |
566 GrGLShaderBuilder::kStandardDeriva tives_GLSLFeature)); | 814 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); |
567 builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsNam e); | 815 builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsNam e); |
568 | 816 |
569 builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName); | 817 builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName); |
570 builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName); | 818 builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName); |
571 builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx. y,\n" | 819 builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx. y,\n" |
572 "\t\t 2.0*%s.x*duvdy.x - duvdy. y);\n", | 820 "\t\t 2.0*%s.x*duvdy.x - duvdy. y);\n", |
573 fsName, fsName); | 821 fsName, fsName); |
574 builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsNa me, fsName, | 822 builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsNa me, fsName, |
575 fsName); | 823 fsName); |
576 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / do t(gF, gF));\n"); | 824 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / do t(gF, gF));\n"); |
(...skipping 30 matching lines...) Expand all Loading... | |
607 typedef GrEffect INHERITED; | 855 typedef GrEffect INHERITED; |
608 }; | 856 }; |
609 | 857 |
610 GR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect); | 858 GR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect); |
611 | 859 |
612 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, | 860 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, |
613 GrContext*, | 861 GrContext*, |
614 const GrDrawTargetCaps& caps, | 862 const GrDrawTargetCaps& caps, |
615 GrTexture*[]) { | 863 GrTexture*[]) { |
616 // Doesn't work without derivative instructions. | 864 // Doesn't work without derivative instructions. |
617 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; } | 865 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; |
866 } | |
618 | 867 |
619 /////////////////////////////////////////////////////////////////////////////// | 868 /////////////////////////////////////////////////////////////////////////////// |
620 | 869 |
621 /** | 870 /** |
622 * The output of this effect is a 1-pixel wide line. | 871 * The output of this effect is a 1-pixel wide line. |
623 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u nused. | 872 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u nused. |
624 */ | 873 */ |
625 class HairLineEdgeEffect : public GrEffect { | 874 class HairLineEdgeEffect : public GrEffect { |
626 public: | 875 public: |
627 | 876 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
710 /////////////////////////////////////////////////////////////////////////////// | 959 /////////////////////////////////////////////////////////////////////////////// |
711 | 960 |
712 namespace { | 961 namespace { |
713 | 962 |
714 // position + edge | 963 // position + edge |
715 extern const GrVertexAttrib gHairlineAttribs[] = { | 964 extern const GrVertexAttrib gHairlineAttribs[] = { |
716 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing}, | 965 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing}, |
717 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g} | 966 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g} |
718 }; | 967 }; |
719 | 968 |
969 // Conic | |
970 // position + ABCD + EF | |
971 extern const GrVertexAttrib gConicVertexAttribs[] = { | |
972 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind ing }, | |
973 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g }, | |
974 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBindin g } | |
975 }; | |
720 }; | 976 }; |
721 | 977 |
722 bool GrAAHairLinePathRenderer::createGeom( | 978 bool GrAAHairLinePathRenderer::createGeom( |
723 const SkPath& path, | 979 const SkPath& path, |
724 GrDrawTarget* target, | 980 GrDrawTarget* target, |
725 int* lineCnt, | 981 int* lineCnt, |
726 int* quadCnt, | 982 int* quadCnt, |
983 int* conicCnt, | |
727 GrDrawTarget::AutoReleaseGeometry* arg, | 984 GrDrawTarget::AutoReleaseGeometry* arg, |
728 SkRect* devBounds) { | 985 SkRect* devBounds) { |
729 GrDrawState* drawState = target->drawState(); | 986 GrDrawState* drawState = target->drawState(); |
730 int rtHeight = drawState->getRenderTarget()->height(); | 987 int rtHeight = drawState->getRenderTarget()->height(); |
731 | 988 |
732 GrIRect devClipBounds; | 989 GrIRect devClipBounds; |
733 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds); | 990 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC lipBounds); |
734 | 991 |
735 SkMatrix viewM = drawState->getViewMatrix(); | 992 SkMatrix viewM = drawState->getViewMatrix(); |
736 | 993 |
737 // All the vertices that we compute are within 1 of path control points with the exception of | 994 // All the vertices that we compute are within 1 of path control points with the exception of |
738 // one of the bounding vertices for each quad. The add_quads() function will update the bounds | 995 // one of the bounding vertices for each quad. The add_quads() function will update the bounds |
739 // for each quad added. | 996 // for each quad added. |
740 *devBounds = path.getBounds(); | 997 *devBounds = path.getBounds(); |
741 viewM.mapRect(devBounds); | 998 viewM.mapRect(devBounds); |
742 devBounds->outset(SK_Scalar1, SK_Scalar1); | 999 devBounds->outset(SK_Scalar1, SK_Scalar1); |
743 | 1000 |
744 PREALLOC_PTARRAY(128) lines; | 1001 PREALLOC_PTARRAY(128) lines; |
745 PREALLOC_PTARRAY(128) quads; | 1002 PREALLOC_PTARRAY(128) quads; |
1003 PREALLOC_PTARRAY(128) conics; | |
746 IntArray qSubdivs; | 1004 IntArray qSubdivs; |
1005 FloatArray cWeights; | |
747 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, | 1006 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, |
748 &lines, &quads, &qSubdivs); | 1007 &lines, &quads, &conics, &qSubdivs, &cWe ights); |
749 | 1008 |
750 *lineCnt = lines.count() / 2; | 1009 *lineCnt = lines.count() / 2; |
751 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt; | 1010 *conicCnt = conics.count() / 3; |
1011 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + | |
1012 kVertsPerQuad * *conicCnt; | |
752 | 1013 |
753 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair lineAttribs)); | 1014 target->drawState()->setVertexAttribs<gConicVertexAttribs>(SK_ARRAY_COUNT(gC onicVertexAttribs)); |
754 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); | 1015 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); |
755 | 1016 |
756 if (!arg->set(target, vertCnt, 0)) { | 1017 if (!arg->set(target, vertCnt, 0)) { |
757 return false; | 1018 return false; |
758 } | 1019 } |
759 | 1020 |
760 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); | 1021 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); |
761 | 1022 |
762 const SkMatrix* toDevice = NULL; | 1023 const SkMatrix* toDevice = NULL; |
763 const SkMatrix* toSrc = NULL; | 1024 const SkMatrix* toSrc = NULL; |
764 SkMatrix ivm; | 1025 SkMatrix ivm; |
765 | 1026 |
766 if (viewM.hasPerspective()) { | 1027 if (viewM.hasPerspective()) { |
767 if (viewM.invert(&ivm)) { | 1028 if (viewM.invert(&ivm)) { |
768 toDevice = &viewM; | 1029 toDevice = &viewM; |
769 toSrc = &ivm; | 1030 toSrc = &ivm; |
770 } | 1031 } |
771 } | 1032 } |
772 | 1033 |
773 for (int i = 0; i < *lineCnt; ++i) { | 1034 for (int i = 0; i < *lineCnt; ++i) { |
774 add_line(&lines[2*i], rtHeight, toSrc, &verts); | 1035 add_line(&lines[2*i], rtHeight, toSrc, &verts); |
775 } | 1036 } |
776 | 1037 |
777 int unsubdivQuadCnt = quads.count() / 3; | 1038 int unsubdivQuadCnt = quads.count() / 3; |
778 for (int i = 0; i < unsubdivQuadCnt; ++i) { | 1039 for (int i = 0; i < unsubdivQuadCnt; ++i) { |
779 GrAssert(qSubdivs[i] >= 0); | 1040 GrAssert(qSubdivs[i] >= 0); |
780 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); | 1041 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); |
781 } | 1042 } |
782 | 1043 |
1044 // Start Conics | |
1045 for (int i = 0; i < *conicCnt; ++i) { | |
1046 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds ); | |
1047 } | |
783 return true; | 1048 return true; |
784 } | 1049 } |
785 | 1050 |
786 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, | 1051 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, |
787 const SkStrokeRec& stroke, | 1052 const SkStrokeRec& stroke, |
788 const GrDrawTarget* target, | 1053 const GrDrawTarget* target, |
789 bool antiAlias) const { | 1054 bool antiAlias) const { |
790 if (!stroke.isHairlineStyle() || !antiAlias) { | 1055 if (!stroke.isHairlineStyle() || !antiAlias) { |
791 return false; | 1056 return false; |
792 } | 1057 } |
793 | 1058 |
794 static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask | | 1059 static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask | |
795 SkPath::kQuad_SegmentMask; | 1060 SkPath::kQuad_SegmentMask; |
796 if (!target->caps()->shaderDerivativeSupport() && | 1061 if (!target->caps()->shaderDerivativeSupport() && |
797 (gReqDerivMask & path.getSegmentMasks())) { | 1062 (gReqDerivMask & path.getSegmentMasks())) { |
798 return false; | 1063 return false; |
799 } | 1064 } |
800 return true; | 1065 return true; |
801 } | 1066 } |
802 | 1067 |
803 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, | 1068 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
804 const SkStrokeRec&, | 1069 const SkStrokeRec&, |
805 GrDrawTarget* target, | 1070 GrDrawTarget* target, |
806 bool antiAlias) { | 1071 bool antiAlias) { |
807 | 1072 |
808 int lineCnt; | 1073 int lineCnt; |
809 int quadCnt; | 1074 int quadCnt; |
1075 int conicCnt; | |
810 GrDrawTarget::AutoReleaseGeometry arg; | 1076 GrDrawTarget::AutoReleaseGeometry arg; |
811 SkRect devBounds; | 1077 SkRect devBounds; |
812 | 1078 |
813 if (!this->createGeom(path, | 1079 if (!this->createGeom(path, |
814 target, | 1080 target, |
815 &lineCnt, | 1081 &lineCnt, |
816 &quadCnt, | 1082 &quadCnt, |
1083 &conicCnt, | |
817 &arg, | 1084 &arg, |
818 &devBounds)) { | 1085 &devBounds)) { |
819 return false; | 1086 return false; |
820 } | 1087 } |
821 | 1088 |
822 GrDrawTarget::AutoStateRestore asr; | 1089 GrDrawTarget::AutoStateRestore asr; |
823 | 1090 |
824 // createGeom transforms the geometry to device space when the matrix does n ot have | 1091 // createGeom transforms the geometry to device space when the matrix does n ot have |
825 // perspective. | 1092 // perspective. |
826 if (target->getDrawState().getViewMatrix().hasPerspective()) { | 1093 if (target->getDrawState().getViewMatrix().hasPerspective()) { |
827 asr.set(target, GrDrawTarget::kPreserve_ASRInit); | 1094 asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
828 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { | 1095 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
829 return false; | 1096 return false; |
830 } | 1097 } |
831 GrDrawState* drawState = target->drawState(); | 1098 GrDrawState* drawState = target->drawState(); |
832 | 1099 |
833 // TODO: See whether rendering lines as degenerate quads improves perf | 1100 // TODO: See whether rendering lines as degenerate quads improves perf |
834 // when we have a mix | 1101 // when we have a mix |
835 | 1102 |
836 enum { | 1103 enum { |
837 // the edge effects share this stage with glyph rendering | 1104 // the edge effects share this stage with glyph rendering |
838 // (kGlyphMaskStage in GrTextContext) && SW path rendering | 1105 // (kGlyphMaskStage in GrTextContext) && SW path rendering |
839 // (kPathMaskStage in GrSWMaskHelper) | 1106 // (kPathMaskStage in GrSWMaskHelper) |
840 kEdgeEffectStage = GrPaint::kTotalStages, | 1107 kEdgeEffectStage = GrPaint::kTotalStages, |
841 }; | 1108 }; |
842 static const int kEdgeAttrIndex = 1; | 1109 static const int kEdgeAttrIndex = 1; |
843 | 1110 |
844 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); | 1111 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); |
845 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); | 1112 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); |
1113 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); | |
846 | 1114 |
847 // Check devBounds | 1115 // Check devBounds |
848 #if GR_DEBUG | 1116 #if GR_DEBUG |
849 SkRect tolDevBounds = devBounds; | 1117 SkRect tolDevBounds = devBounds; |
850 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); | 1118 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); |
851 SkRect actualBounds; | 1119 SkRect actualBounds; |
852 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); | 1120 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); |
853 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt; | 1121 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPe rQuad * conicCnt; |
854 bool first = true; | 1122 bool first = true; |
855 for (int i = 0; i < vCount; ++i) { | 1123 for (int i = 0; i < vCount; ++i) { |
856 SkPoint pos = verts[i].fPos; | 1124 SkPoint pos = verts[i].fPos; |
857 // This is a hack to workaround the fact that we move some degenerate se gments offscreen. | 1125 // This is a hack to workaround the fact that we move some degenerate se gments offscreen. |
858 if (SK_ScalarMax == pos.fX) { | 1126 if (SK_ScalarMax == pos.fX) { |
859 continue; | 1127 continue; |
860 } | 1128 } |
861 drawState->getViewMatrix().mapPoints(&pos, 1); | 1129 drawState->getViewMatrix().mapPoints(&pos, 1); |
862 if (first) { | 1130 if (first) { |
863 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); | 1131 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); |
(...skipping 18 matching lines...) Expand all Loading... | |
882 target->drawIndexed(kTriangles_GrPrimitiveType, | 1150 target->drawIndexed(kTriangles_GrPrimitiveType, |
883 kVertsPerLineSeg*lines, // startV | 1151 kVertsPerLineSeg*lines, // startV |
884 0, // startI | 1152 0, // startI |
885 kVertsPerLineSeg*n, // vCount | 1153 kVertsPerLineSeg*n, // vCount |
886 kIdxsPerLineSeg*n, | 1154 kIdxsPerLineSeg*n, |
887 &devBounds); // iCount | 1155 &devBounds); // iCount |
888 lines += n; | 1156 lines += n; |
889 } | 1157 } |
890 } | 1158 } |
891 | 1159 |
892 target->setIndexSourceToBuffer(fQuadsIndexBuffer); | 1160 { |
893 int quads = 0; | 1161 GrDrawState::AutoRestoreEffects are(drawState); |
894 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); | 1162 target->setIndexSourceToBuffer(fQuadsIndexBuffer); |
895 while (quads < quadCnt) { | 1163 int quads = 0; |
896 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); | 1164 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); |
897 target->drawIndexed(kTriangles_GrPrimitiveType, | 1165 while (quads < quadCnt) { |
898 4 * lineCnt + kVertsPerQuad*quads, // startV | 1166 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); |
899 0, // startI | 1167 target->drawIndexed(kTriangles_GrPrimitiveType, |
900 kVertsPerQuad*n, // vCount | 1168 kVertsPerLineSeg * lineCnt + kVertsPerQuad*quads , // startV |
bsalomon
2013/07/11 18:48:38
can we realign the comments (here and below)?
| |
901 kIdxsPerQuad*n, // iCount | 1169 0, // startI |
902 &devBounds); | 1170 kVertsPerQuad*n, // vCount |
903 quads += n; | 1171 kIdxsPerQuad*n, // iCount |
1172 &devBounds); | |
1173 quads += n; | |
1174 } | |
1175 } | |
1176 | |
1177 { | |
1178 GrDrawState::AutoRestoreEffects are(drawState); | |
1179 int conics = 0; | |
1180 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); | |
1181 while (conics < conicCnt) { | |
1182 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); | |
1183 target->drawIndexed(kTriangles_GrPrimitiveType, | |
1184 kVertsPerLineSeg*lineCnt + | |
1185 kVertsPerQuad*(quadCnt + conics), // startV | |
1186 0, // startI | |
1187 kVertsPerQuad*n, // vCount | |
1188 kIdxsPerQuad*n, // iCount | |
1189 &devBounds); | |
1190 conics += n; | |
1191 } | |
904 } | 1192 } |
905 target->resetIndexSource(); | 1193 target->resetIndexSource(); |
906 | 1194 |
907 return true; | 1195 return true; |
908 } | 1196 } |
1197 | |
OLD | NEW |