blob: 5c5a50e6726d69bb2b0d504c82ef82e687fbfb3d [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +000010#include "GrTesselatedPathRenderer.h"
11
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +000012#include "GrPathUtils.h"
reed@google.com07f3ee12011-05-16 17:21:57 +000013#include "GrPoint.h"
14#include "GrTDArray.h"
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +000015
bsalomon@google.com3582bf92011-06-30 21:32:31 +000016#include "SkTemplates.h"
17
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +000018#include <limits.h>
senorblanco@chromium.org1fa803d2011-05-25 14:46:17 +000019#include <sk_glu.h>
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +000020
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +000021typedef GrTDArray<GrDrawTarget::Edge> GrEdgeArray;
22typedef GrTDArray<GrPoint> GrPointArray;
23typedef GrTDArray<uint16_t> GrIndexArray;
24typedef void (*TESSCB)();
25
26// limit the allowable vertex range to approximately half of the representable
27// IEEE exponent in order to avoid overflow when doing multiplies between
28// vertex components,
bsalomon@google.comee435122011-07-01 14:57:55 +000029const float kMaxVertexValue = 1e18f;
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +000030
31static inline GrDrawTarget::Edge computeEdge(const GrPoint& p,
32 const GrPoint& q,
33 float sign) {
34 GrVec tangent = GrVec::Make(p.fY - q.fY, q.fX - p.fX);
35 float scale = sign / tangent.length();
36 float cross2 = p.fX * q.fY - q.fX * p.fY;
37 return GrDrawTarget::Edge(tangent.fX * scale,
38 tangent.fY * scale,
39 cross2 * scale);
40}
41
42static inline GrPoint sanitizePoint(const GrPoint& pt) {
43 GrPoint r;
44 r.fX = SkScalarPin(pt.fX, -kMaxVertexValue, kMaxVertexValue);
45 r.fY = SkScalarPin(pt.fY, -kMaxVertexValue, kMaxVertexValue);
46 return r;
47}
48
49class GrTess {
50public:
51 GrTess(int count, unsigned winding_rule) {
52 fTess = Sk_gluNewTess();
53 Sk_gluTessProperty(fTess, GLU_TESS_WINDING_RULE, winding_rule);
54 Sk_gluTessNormal(fTess, 0.0f, 0.0f, 1.0f);
55 Sk_gluTessCallback(fTess, GLU_TESS_BEGIN_DATA, (TESSCB) &beginCB);
56 Sk_gluTessCallback(fTess, GLU_TESS_VERTEX_DATA, (TESSCB) &vertexCB);
57 Sk_gluTessCallback(fTess, GLU_TESS_END_DATA, (TESSCB) &endCB);
58 Sk_gluTessCallback(fTess, GLU_TESS_EDGE_FLAG_DATA, (TESSCB) &edgeFlagCB);
59 Sk_gluTessCallback(fTess, GLU_TESS_COMBINE_DATA, (TESSCB) &combineCB);
60 fInVertices = new double[count * 3];
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +000061 }
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +000062 ~GrTess() {
63 Sk_gluDeleteTess(fTess);
64 delete[] fInVertices;
65 }
66 void addVertex(const GrPoint& pt, int index) {
67 if (index > USHRT_MAX) return;
68 double* inVertex = &fInVertices[index * 3];
69 inVertex[0] = pt.fX;
70 inVertex[1] = pt.fY;
71 inVertex[2] = 0.0;
72 *fVertices.append() = pt;
73 Sk_gluTessVertex(fTess, inVertex, reinterpret_cast<void*>(index));
74 }
75 void addVertices(const GrPoint* points, const uint16_t* contours, int numContours) {
76 Sk_gluTessBeginPolygon(fTess, this);
77 size_t i = 0;
78 for (int j = 0; j < numContours; ++j) {
79 Sk_gluTessBeginContour(fTess);
80 size_t end = i + contours[j];
81 for (; i < end; ++i) {
82 addVertex(points[i], i);
83 }
84 Sk_gluTessEndContour(fTess);
85 }
86 Sk_gluTessEndPolygon(fTess);
87 }
88 GLUtesselator* tess() { return fTess; }
89 const GrPointArray& vertices() const { return fVertices; }
90protected:
91 virtual void begin(GLenum type) = 0;
92 virtual void vertex(int index) = 0;
93 virtual void edgeFlag(bool flag) = 0;
94 virtual void end() = 0;
95 virtual int combine(GLdouble coords[3], int vertexIndices[4],
96 GLfloat weight[4]) = 0;
97 static void beginCB(GLenum type, void* data) {
98 static_cast<GrTess*>(data)->begin(type);
99 }
100 static void vertexCB(void* vertexData, void* data) {
101 static_cast<GrTess*>(data)->vertex(reinterpret_cast<long>(vertexData));
102 }
103 static void edgeFlagCB(GLboolean flag, void* data) {
104 static_cast<GrTess*>(data)->edgeFlag(flag != 0);
105 }
106 static void endCB(void* data) {
107 static_cast<GrTess*>(data)->end();
108 }
109 static void combineCB(GLdouble coords[3], void* vertexData[4],
110 GLfloat weight[4], void **outData, void* data) {
111 int vertexIndex[4];
112 vertexIndex[0] = reinterpret_cast<long>(vertexData[0]);
113 vertexIndex[1] = reinterpret_cast<long>(vertexData[1]);
114 vertexIndex[2] = reinterpret_cast<long>(vertexData[2]);
115 vertexIndex[3] = reinterpret_cast<long>(vertexData[3]);
116 GrTess* tess = static_cast<GrTess*>(data);
117 int outIndex = tess->combine(coords, vertexIndex, weight);
118 *reinterpret_cast<long*>(outData) = outIndex;
119 }
120protected:
121 GLUtesselator* fTess;
122 GrPointArray fVertices;
123 double* fInVertices;
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000124};
125
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000126class GrPolygonTess : public GrTess {
127public:
128 GrPolygonTess(int count, unsigned winding_rule)
129 : GrTess(count, winding_rule) {
130 }
131 ~GrPolygonTess() {
132 }
133 const GrIndexArray& indices() const { return fIndices; }
134protected:
135 virtual void begin(GLenum type) {
136 GR_DEBUGASSERT(type == GL_TRIANGLES);
137 }
138 virtual void vertex(int index) {
139 *fIndices.append() = index;
140 }
141 virtual void edgeFlag(bool flag) {}
142 virtual void end() {}
143 virtual int combine(GLdouble coords[3], int vertexIndices[4],
144 GLfloat weight[4]) {
145 int index = fVertices.count();
146 GrPoint p = GrPoint::Make(static_cast<float>(coords[0]),
147 static_cast<float>(coords[1]));
148 *fVertices.append() = p;
149 return index;
150 }
151protected:
152 GrIndexArray fIndices;
153};
154
155class GrEdgePolygonTess : public GrPolygonTess {
156public:
157 GrEdgePolygonTess(int count, unsigned winding_rule, const SkMatrix& matrix)
158 : GrPolygonTess(count, winding_rule),
159 fMatrix(matrix),
160 fEdgeFlag(false),
161 fEdgeVertex(-1),
162 fTriStartVertex(-1),
163 fEdges(NULL) {
164 }
165 ~GrEdgePolygonTess() {
166 delete[] fEdges;
167 }
168 const GrDrawTarget::Edge* edges() const { return fEdges; }
169private:
170 void addEdge(int index0, int index1) {
171 GrPoint p = fVertices[index0];
172 GrPoint q = fVertices[index1];
173 fMatrix.mapPoints(&p, 1);
174 fMatrix.mapPoints(&q, 1);
175 p = sanitizePoint(p);
176 q = sanitizePoint(q);
177 if (p == q) return;
178 GrDrawTarget::Edge edge = computeEdge(p, q, 1.0f);
179 fEdges[index0 * 2 + 1] = edge;
180 fEdges[index1 * 2] = edge;
181 }
182 virtual void begin(GLenum type) {
183 GR_DEBUGASSERT(type == GL_TRIANGLES);
184 int count = fVertices.count() * 2;
185 fEdges = new GrDrawTarget::Edge[count];
186 memset(fEdges, 0, count * sizeof(GrDrawTarget::Edge));
187 }
188 virtual void edgeFlag(bool flag) {
189 fEdgeFlag = flag;
190 }
191 virtual void vertex(int index) {
192 bool triStart = fIndices.count() % 3 == 0;
193 GrPolygonTess::vertex(index);
194 if (fEdgeVertex != -1) {
195 if (triStart) {
196 addEdge(fEdgeVertex, fTriStartVertex);
197 } else {
198 addEdge(fEdgeVertex, index);
199 }
200 }
201 if (triStart) {
202 fTriStartVertex = index;
203 }
204 if (fEdgeFlag) {
205 fEdgeVertex = index;
206 } else {
207 fEdgeVertex = -1;
208 }
209 }
210 virtual void end() {
211 if (fEdgeVertex != -1) {
212 addEdge(fEdgeVertex, fTriStartVertex);
213 }
214 }
215 GrMatrix fMatrix;
216 bool fEdgeFlag;
217 int fEdgeVertex, fTriStartVertex;
218 GrDrawTarget::Edge* fEdges;
219};
220
221class GrBoundaryTess : public GrTess {
222public:
223 GrBoundaryTess(int count, unsigned winding_rule)
224 : GrTess(count, winding_rule),
225 fContourStart(0) {
226 Sk_gluTessProperty(fTess, GLU_TESS_BOUNDARY_ONLY, 1);
227 }
228 ~GrBoundaryTess() {
229 }
230 GrPointArray& contourPoints() { return fContourPoints; }
231 const GrIndexArray& contours() const { return fContours; }
232private:
233 virtual void begin(GLenum type) {
234 fContourStart = fContourPoints.count();
235 }
236 virtual void vertex(int index) {
237 *fContourPoints.append() = fVertices.at(index);
238 }
239 virtual void edgeFlag(bool flag) {}
240 virtual void end() {
241 *fContours.append() = fContourPoints.count() - fContourStart;
242 }
243 virtual int combine(GLdouble coords[3], int vertexIndices[4],
244 GLfloat weight[4]) {
245 int index = fVertices.count();
246 *fVertices.append() = GrPoint::Make(static_cast<float>(coords[0]),
247 static_cast<float>(coords[1]));
248 return index;
249 }
250 GrPointArray fContourPoints;
251 GrIndexArray fContours;
252 size_t fContourStart;
253};
254
255static bool nearlyEqual(float a, float b) {
256 return fabsf(a - b) < 0.0001f;
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000257}
258
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000259static bool nearlyEqual(const GrPoint& a, const GrPoint& b) {
260 return nearlyEqual(a.fX, b.fX) && nearlyEqual(a.fY, b.fY);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000261}
262
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000263static bool parallel(const GrDrawTarget::Edge& a, const GrDrawTarget::Edge& b) {
264 return (nearlyEqual(a.fX, b.fX) && nearlyEqual(a.fY, b.fY)) ||
265 (nearlyEqual(a.fX, -b.fX) && nearlyEqual(a.fY, -b.fY));
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000266}
267
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000268static unsigned fill_type_to_glu_winding_rule(GrPathFill fill) {
269 switch (fill) {
270 case kWinding_PathFill:
271 return GLU_TESS_WINDING_NONZERO;
272 case kEvenOdd_PathFill:
273 return GLU_TESS_WINDING_ODD;
274 case kInverseWinding_PathFill:
275 return GLU_TESS_WINDING_POSITIVE;
276 case kInverseEvenOdd_PathFill:
277 return GLU_TESS_WINDING_ODD;
278 case kHairLine_PathFill:
279 return GLU_TESS_WINDING_NONZERO; // FIXME: handle this
280 default:
281 GrAssert(!"Unknown path fill!");
282 return 0;
283 }
284}
285
286GrTesselatedPathRenderer::GrTesselatedPathRenderer() {
287}
288
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000289static bool isCCW(const GrPoint* pts, int count) {
290 GrVec v1, v2;
291 do {
292 v1 = pts[1] - pts[0];
293 v2 = pts[2] - pts[1];
294 pts++;
295 count--;
296 } while (nearlyEqual(v1, v2) && count > 3);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000297 return v1.cross(v2) < 0;
298}
299
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000300static bool validEdge(const GrDrawTarget::Edge& edge) {
301 return !(edge.fX == 0.0f && edge.fY == 0.0f && edge.fZ == 0.0f);
302}
303
304static size_t computeEdgesAndIntersect(const GrMatrix& matrix,
305 const GrMatrix& inverse,
306 GrPoint* vertices,
307 size_t numVertices,
308 GrEdgeArray* edges,
309 float sign) {
310 if (numVertices < 3) {
311 return 0;
312 }
senorblanco@chromium.orgff174b32011-05-16 16:59:57 +0000313 matrix.mapPoints(vertices, numVertices);
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000314 if (sign == 0.0f) {
315 sign = isCCW(vertices, numVertices) ? -1.0f : 1.0f;
316 }
317 GrPoint p = sanitizePoint(vertices[numVertices - 1]);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000318 for (size_t i = 0; i < numVertices; ++i) {
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000319 GrPoint q = sanitizePoint(vertices[i]);
320 if (p == q) {
321 continue;
322 }
323 GrDrawTarget::Edge edge = computeEdge(p, q, sign);
324 edge.fZ += 0.5f; // Offset by half a pixel along the tangent.
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000325 *edges->append() = edge;
326 p = q;
327 }
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000328 int count = edges->count();
329 if (count == 0) {
330 return 0;
331 }
332 GrDrawTarget::Edge prev_edge = edges->at(0);
333 for (int i = 0; i < count; ++i) {
334 GrDrawTarget::Edge edge = edges->at(i < count - 1 ? i + 1 : 0);
335 if (parallel(edge, prev_edge)) {
336 // 3 points are collinear; offset by half the tangent instead
337 vertices[i].fX -= edge.fX * 0.5f;
338 vertices[i].fY -= edge.fY * 0.5f;
339 } else {
340 vertices[i] = prev_edge.intersect(edge);
341 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000342 inverse.mapPoints(&vertices[i], 1);
343 prev_edge = edge;
344 }
345 return edges->count();
346}
347
bsalomon@google.comee435122011-07-01 14:57:55 +0000348void GrTesselatedPathRenderer::drawPath(GrDrawTarget::StageBitfield stages) {
349 GrDrawTarget::AutoStateRestore asr(fTarget);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000350 // face culling doesn't make sense here
bsalomon@google.comee435122011-07-01 14:57:55 +0000351 GrAssert(GrDrawTarget::kBoth_DrawFace == fTarget->getDrawFace());
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000352
bsalomon@google.comee435122011-07-01 14:57:55 +0000353 GrMatrix viewM = fTarget->getViewMatrix();
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000354
bsalomon@google.com181e9bd2011-09-07 18:42:30 +0000355 GrScalar tol = GR_Scalar1;
bsalomon@google.com38396322011-09-09 19:32:04 +0000356 tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, fPath->getBounds());
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000357 GrScalar tolSqd = GrMul(tol, tol);
358
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000359 int subpathCnt;
bsalomon@google.comee435122011-07-01 14:57:55 +0000360 int maxPts = GrPathUtils::worstCasePointCount(*fPath, &subpathCnt, tol);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000361
362 GrVertexLayout layout = 0;
363 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) {
364 if ((1 << s) & stages) {
365 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
366 }
367 }
368
bsalomon@google.comfa6ac932011-10-05 19:57:55 +0000369 bool inverted = GrIsFillInverted(fFill);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000370 if (inverted) {
371 maxPts += 4;
372 subpathCnt++;
373 }
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000374 if (maxPts > USHRT_MAX) {
375 return;
376 }
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000377 SkAutoSTMalloc<8, GrPoint> baseMem(maxPts);
378 GrPoint* base = baseMem;
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000379 GrPoint* vert = base;
380 GrPoint* subpathBase = base;
381
bsalomon@google.com3582bf92011-06-30 21:32:31 +0000382 SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000383
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000384 GrPoint pts[4];
bsalomon@google.comee435122011-07-01 14:57:55 +0000385 SkPath::Iter iter(*fPath, false);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000386
387 bool first = true;
388 int subpath = 0;
389
390 for (;;) {
reed@google.com07f3ee12011-05-16 17:21:57 +0000391 switch (iter.next(pts)) {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000392 case kMove_PathCmd:
393 if (!first) {
394 subpathVertCount[subpath] = vert-subpathBase;
395 subpathBase = vert;
396 ++subpath;
397 }
398 *vert = pts[0];
399 vert++;
400 break;
401 case kLine_PathCmd:
402 *vert = pts[1];
403 vert++;
404 break;
405 case kQuadratic_PathCmd: {
406 GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2],
407 tolSqd, &vert,
408 GrPathUtils::quadraticPointCount(pts, tol));
409 break;
410 }
411 case kCubic_PathCmd: {
412 GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3],
413 tolSqd, &vert,
414 GrPathUtils::cubicPointCount(pts, tol));
415 break;
416 }
417 case kClose_PathCmd:
418 break;
419 case kEnd_PathCmd:
420 subpathVertCount[subpath] = vert-subpathBase;
421 ++subpath; // this could be only in debug
422 goto FINISHED;
423 }
424 first = false;
425 }
426FINISHED:
bsalomon@google.comee435122011-07-01 14:57:55 +0000427 if (0 != fTranslate.fX || 0 != fTranslate.fY) {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000428 for (int i = 0; i < vert - base; i++) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000429 base[i].offset(fTranslate.fX, fTranslate.fY);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000430 }
431 }
432
433 if (inverted) {
434 GrRect bounds;
bsalomon@google.comee435122011-07-01 14:57:55 +0000435 GrAssert(NULL != fTarget->getRenderTarget());
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000436 bounds.setLTRB(0, 0,
bsalomon@google.comee435122011-07-01 14:57:55 +0000437 GrIntToScalar(fTarget->getRenderTarget()->width()),
438 GrIntToScalar(fTarget->getRenderTarget()->height()));
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000439 GrMatrix vmi;
bsalomon@google.comee435122011-07-01 14:57:55 +0000440 if (fTarget->getViewInverse(&vmi)) {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000441 vmi.mapRect(&bounds);
442 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000443 *vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop);
444 *vert++ = GrPoint::Make(bounds.fLeft, bounds.fBottom);
445 *vert++ = GrPoint::Make(bounds.fRight, bounds.fBottom);
446 *vert++ = GrPoint::Make(bounds.fRight, bounds.fTop);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000447 subpathVertCount[subpath++] = 4;
448 }
449
450 GrAssert(subpath == subpathCnt);
451 GrAssert((vert - base) <= maxPts);
452
453 size_t count = vert - base;
454
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000455 if (count < 3) {
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000456 return;
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000457 }
458
bsalomon@google.comee435122011-07-01 14:57:55 +0000459 if (subpathCnt == 1 && !inverted && fPath->isConvex()) {
bsalomon@google.com289533a2011-10-27 12:34:25 +0000460 if (fAntiAlias) {
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000461 GrEdgeArray edges;
bsalomon@google.comee435122011-07-01 14:57:55 +0000462 GrMatrix inverse, matrix = fTarget->getViewMatrix();
463 fTarget->getViewInverse(&inverse);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000464
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000465 count = computeEdgesAndIntersect(matrix, inverse, base, count, &edges, 0.0f);
bsalomon@google.comee435122011-07-01 14:57:55 +0000466 size_t maxEdges = fTarget->getMaxEdges();
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000467 if (count == 0) {
468 return;
469 }
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000470 if (count <= maxEdges) {
471 // All edges fit; upload all edges and draw all verts as a fan
bsalomon@google.comee435122011-07-01 14:57:55 +0000472 fTarget->setVertexSourceToArray(layout, base, count);
473 fTarget->setEdgeAAData(&edges[0], count);
474 fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000475 } else {
476 // Upload "maxEdges" edges and verts at a time, and draw as
477 // separate fans
478 for (size_t i = 0; i < count - 2; i += maxEdges - 2) {
479 edges[i] = edges[0];
480 base[i] = base[0];
481 int size = GR_CT_MIN(count - i, maxEdges);
bsalomon@google.comee435122011-07-01 14:57:55 +0000482 fTarget->setVertexSourceToArray(layout, &base[i], size);
483 fTarget->setEdgeAAData(&edges[i], size);
484 fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size);
senorblanco@chromium.orgef3913b2011-05-19 17:11:07 +0000485 }
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000486 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000487 fTarget->setEdgeAAData(NULL, 0);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000488 } else {
bsalomon@google.comee435122011-07-01 14:57:55 +0000489 fTarget->setVertexSourceToArray(layout, base, count);
490 fTarget->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count);
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000491 }
senorblanco@chromium.orgcf3edc92011-03-29 17:42:30 +0000492 return;
493 }
494
bsalomon@google.com289533a2011-10-27 12:34:25 +0000495 if (fAntiAlias) {
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000496 // Run the tesselator once to get the boundaries.
bsalomon@google.comee435122011-07-01 14:57:55 +0000497 GrBoundaryTess btess(count, fill_type_to_glu_winding_rule(fFill));
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000498 btess.addVertices(base, subpathVertCount, subpathCnt);
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000499
bsalomon@google.comee435122011-07-01 14:57:55 +0000500 GrMatrix inverse, matrix = fTarget->getViewMatrix();
501 if (!fTarget->getViewInverse(&inverse)) {
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000502 return;
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000503 }
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000504
505 if (btess.vertices().count() > USHRT_MAX) {
506 return;
507 }
508
509 // Inflate the boundary, and run the tesselator again to generate
510 // interior polys.
511 const GrPointArray& contourPoints = btess.contourPoints();
512 const GrIndexArray& contours = btess.contours();
513 GrEdgePolygonTess ptess(contourPoints.count(), GLU_TESS_WINDING_NONZERO, matrix);
514
515 size_t i = 0;
516 Sk_gluTessBeginPolygon(ptess.tess(), &ptess);
517 for (int contour = 0; contour < contours.count(); ++contour) {
518 int count = contours[contour];
519 GrEdgeArray edges;
520 int newCount = computeEdgesAndIntersect(matrix, inverse, &btess.contourPoints()[i], count, &edges, 1.0f);
521 Sk_gluTessBeginContour(ptess.tess());
522 for (int j = 0; j < newCount; j++) {
523 ptess.addVertex(contourPoints[i + j], ptess.vertices().count());
524 }
525 i += count;
526 Sk_gluTessEndContour(ptess.tess());
527 }
528
529 Sk_gluTessEndPolygon(ptess.tess());
530
531 if (ptess.vertices().count() > USHRT_MAX) {
532 return;
533 }
534
535 // Draw the resulting polys and upload their edge data.
bsalomon@google.comee435122011-07-01 14:57:55 +0000536 fTarget->enableState(GrDrawTarget::kEdgeAAConcave_StateBit);
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000537 const GrPointArray& vertices = ptess.vertices();
538 const GrIndexArray& indices = ptess.indices();
539 const GrDrawTarget::Edge* edges = ptess.edges();
540 GR_DEBUGASSERT(indices.count() % 3 == 0);
541 for (int i = 0; i < indices.count(); i += 3) {
542 GrPoint tri_verts[3];
543 int index0 = indices[i];
544 int index1 = indices[i + 1];
545 int index2 = indices[i + 2];
546 tri_verts[0] = vertices[index0];
547 tri_verts[1] = vertices[index1];
548 tri_verts[2] = vertices[index2];
549 GrDrawTarget::Edge tri_edges[6];
550 int t = 0;
551 const GrDrawTarget::Edge& edge0 = edges[index0 * 2];
552 const GrDrawTarget::Edge& edge1 = edges[index0 * 2 + 1];
553 const GrDrawTarget::Edge& edge2 = edges[index1 * 2];
554 const GrDrawTarget::Edge& edge3 = edges[index1 * 2 + 1];
555 const GrDrawTarget::Edge& edge4 = edges[index2 * 2];
556 const GrDrawTarget::Edge& edge5 = edges[index2 * 2 + 1];
557 if (validEdge(edge0) && validEdge(edge1)) {
558 tri_edges[t++] = edge0;
559 tri_edges[t++] = edge1;
560 }
561 if (validEdge(edge2) && validEdge(edge3)) {
562 tri_edges[t++] = edge2;
563 tri_edges[t++] = edge3;
564 }
565 if (validEdge(edge4) && validEdge(edge5)) {
566 tri_edges[t++] = edge4;
567 tri_edges[t++] = edge5;
568 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000569 fTarget->setEdgeAAData(&tri_edges[0], t);
570 fTarget->setVertexSourceToArray(layout, &tri_verts[0], 3);
571 fTarget->drawNonIndexed(kTriangles_PrimitiveType, 0, 3);
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000572 }
bsalomon@google.comee435122011-07-01 14:57:55 +0000573 fTarget->setEdgeAAData(NULL, 0);
574 fTarget->disableState(GrDrawTarget::kEdgeAAConcave_StateBit);
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000575 return;
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000576 }
577
bsalomon@google.comee435122011-07-01 14:57:55 +0000578 GrPolygonTess ptess(count, fill_type_to_glu_winding_rule(fFill));
senorblanco@chromium.org129b8e32011-06-15 17:52:09 +0000579 ptess.addVertices(base, subpathVertCount, subpathCnt);
580 const GrPointArray& vertices = ptess.vertices();
581 const GrIndexArray& indices = ptess.indices();
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000582 if (indices.count() > 0) {
bsalomon@google.comee435122011-07-01 14:57:55 +0000583 fTarget->setVertexSourceToArray(layout, vertices.begin(), vertices.count());
584 fTarget->setIndexSourceToArray(indices.begin(), indices.count());
585 fTarget->drawIndexed(kTriangles_PrimitiveType,
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000586 0,
587 0,
588 vertices.count(),
589 indices.count());
590 }
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000591}
592
bsalomon@google.com289533a2011-10-27 12:34:25 +0000593bool GrTesselatedPathRenderer::canDrawPath(const GrDrawTarget::Caps& caps,
bsalomon@google.comaeb21602011-08-30 18:13:44 +0000594 const SkPath& path,
bsalomon@google.com289533a2011-10-27 12:34:25 +0000595 GrPathFill fill,
596 bool antiAlias) const {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000597 return kHairLine_PathFill != fill;
598}
599
bsalomon@google.comee435122011-07-01 14:57:55 +0000600void GrTesselatedPathRenderer::drawPathToStencil() {
senorblanco@chromium.org9d18b782011-03-28 20:47:09 +0000601 GrAlwaysAssert(!"multipass stencil should not be needed");
602}
senorblanco@chromium.org92e0f222011-05-12 15:49:15 +0000603