1 /* 2 Copyright 2011 Google Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 #include "GrTesselatedPathRenderer.h" 18 19 #include "GrMemory.h" 20 #include "GrPathUtils.h" 21 #include "GrPoint.h" 22 #include "GrTDArray.h" 23 24 #include <sk_glu.h> 25 26 struct PolygonData { 27 PolygonData(GrTDArray<GrPoint>* vertices, GrTDArray<short>* indices) 28 : fVertices(vertices) 29 , fIndices(indices) 30 { 31 } 32 GrTDArray<GrPoint>* fVertices; 33 GrTDArray<short>* fIndices; 34 }; 35 36 static void beginData(GLenum type, void* data) 37 { 38 GR_DEBUGASSERT(type == GL_TRIANGLES); 39 } 40 41 static void edgeFlagData(GLboolean flag, void* data) 42 { 43 } 44 45 static void vertexData(void* vertexData, void* data) 46 { 47 short* end = static_cast<PolygonData*>(data)->fIndices->append(); 48 *end = reinterpret_cast<long>(vertexData); 49 } 50 51 static void endData(void* data) 52 { 53 } 54 55 static void combineData(GLdouble coords[3], void* vertexData[4], 56 GLfloat weight[4], void **outData, void* data) 57 { 58 PolygonData* polygonData = static_cast<PolygonData*>(data); 59 int index = polygonData->fVertices->count(); 60 *polygonData->fVertices->append() = GrPoint::Make(static_cast<float>(coords[0]), 61 static_cast<float>(coords[1])); 62 *outData = reinterpret_cast<void*>(index); 63 } 64 65 typedef void (*TESSCB)(); 66 67 static unsigned fill_type_to_glu_winding_rule(GrPathFill fill) { 68 switch (fill) { 69 case kWinding_PathFill: 70 return GLU_TESS_WINDING_NONZERO; 71 case kEvenOdd_PathFill: 72 return GLU_TESS_WINDING_ODD; 73 case kInverseWinding_PathFill: 74 return GLU_TESS_WINDING_POSITIVE; 75 case kInverseEvenOdd_PathFill: 76 return GLU_TESS_WINDING_ODD; 77 case kHairLine_PathFill: 78 return GLU_TESS_WINDING_NONZERO; // FIXME: handle this 79 default: 80 GrAssert(!"Unknown path fill!"); 81 return 0; 82 } 83 } 84 85 GrTesselatedPathRenderer::GrTesselatedPathRenderer() { 86 } 87 88 typedef GrTDArray<GrDrawTarget::Edge> EdgeArray; 89 90 bool isCCW(const GrPoint* pts) 91 { 92 GrVec v1 = pts[1] - pts[0]; 93 GrVec v2 = pts[2] - pts[1]; 94 return v1.cross(v2) < 0; 95 } 96 97 static size_t computeEdgesAndOffsetVertices(const GrMatrix& matrix, 98 const GrMatrix& inverse, 99 GrPoint* vertices, 100 size_t numVertices, 101 EdgeArray* edges) 102 { 103 matrix.mapPoints(vertices, numVertices); 104 GrPoint p = vertices[numVertices - 1]; 105 float sign = isCCW(vertices) ? -1.0f : 1.0f; 106 for (size_t i = 0; i < numVertices; ++i) { 107 GrPoint q = vertices[i]; 108 if (p == q) continue; 109 GrVec tangent = GrVec::Make(p.fY - q.fY, q.fX - p.fX); 110 float scale = sign / tangent.length(); 111 float cross2 = p.fX * q.fY - q.fX * p.fY; 112 GrDrawTarget::Edge edge(tangent.fX * scale, 113 tangent.fY * scale, 114 cross2 * scale + 0.5f); 115 *edges->append() = edge; 116 p = q; 117 } 118 GrDrawTarget::Edge prev_edge = *edges->back(); 119 for (int i = 0; i < edges->count(); ++i) { 120 GrDrawTarget::Edge edge = edges->at(i); 121 vertices[i] = prev_edge.intersect(edge); 122 inverse.mapPoints(&vertices[i], 1); 123 prev_edge = edge; 124 } 125 return edges->count(); 126 } 127 128 void GrTesselatedPathRenderer::drawPath(GrDrawTarget* target, 129 GrDrawTarget::StageBitfield stages, 130 const GrPath& path, 131 GrPathFill fill, 132 const GrPoint* translate) { 133 GrDrawTarget::AutoStateRestore asr(target); 134 // face culling doesn't make sense here 135 GrAssert(GrDrawTarget::kBoth_DrawFace == target->getDrawFace()); 136 137 GrMatrix viewM = target->getViewMatrix(); 138 // In order to tesselate the path we get a bound on how much the matrix can 139 // stretch when mapping to screen coordinates. 140 GrScalar stretch = viewM.getMaxStretch(); 141 bool useStretch = stretch > 0; 142 GrScalar tol = GrPathUtils::gTolerance; 143 144 if (!useStretch) { 145 // TODO: deal with perspective in some better way. 146 tol /= 10; 147 } else { 148 tol = GrScalarDiv(tol, stretch); 149 } 150 GrScalar tolSqd = GrMul(tol, tol); 151 152 int subpathCnt; 153 int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol); 154 155 GrVertexLayout layout = 0; 156 for (int s = 0; s < GrDrawTarget::kNumStages; ++s) { 157 if ((1 << s) & stages) { 158 layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s); 159 } 160 } 161 162 bool inverted = IsFillInverted(fill); 163 if (inverted) { 164 maxPts += 4; 165 subpathCnt++; 166 } 167 GrPoint* base = new GrPoint[maxPts]; 168 GrPoint* vert = base; 169 GrPoint* subpathBase = base; 170 171 GrAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt); 172 173 GrPoint pts[4]; 174 SkPath::Iter iter(path, true); 175 176 bool first = true; 177 int subpath = 0; 178 179 for (;;) { 180 switch (iter.next(pts)) { 181 case kMove_PathCmd: 182 if (!first) { 183 subpathVertCount[subpath] = vert-subpathBase; 184 subpathBase = vert; 185 ++subpath; 186 } 187 *vert = pts[0]; 188 vert++; 189 break; 190 case kLine_PathCmd: 191 *vert = pts[1]; 192 vert++; 193 break; 194 case kQuadratic_PathCmd: { 195 GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], 196 tolSqd, &vert, 197 GrPathUtils::quadraticPointCount(pts, tol)); 198 break; 199 } 200 case kCubic_PathCmd: { 201 GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], 202 tolSqd, &vert, 203 GrPathUtils::cubicPointCount(pts, tol)); 204 break; 205 } 206 case kClose_PathCmd: 207 break; 208 case kEnd_PathCmd: 209 subpathVertCount[subpath] = vert-subpathBase; 210 ++subpath; // this could be only in debug 211 goto FINISHED; 212 } 213 first = false; 214 } 215 FINISHED: 216 if (translate) { 217 for (int i = 0; i < vert - base; i++) { 218 base[i].offset(translate->fX, translate->fY); 219 } 220 } 221 222 if (inverted) { 223 GrRect bounds; 224 GrAssert(NULL != target->getRenderTarget()); 225 bounds.setLTRB(0, 0, 226 GrIntToScalar(target->getRenderTarget()->width()), 227 GrIntToScalar(target->getRenderTarget()->height())); 228 GrMatrix vmi; 229 if (target->getViewInverse(&vmi)) { 230 vmi.mapRect(&bounds); 231 } 232 *vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop); 233 *vert++ = GrPoint::Make(bounds.fLeft, bounds.fBottom); 234 *vert++ = GrPoint::Make(bounds.fRight, bounds.fBottom); 235 *vert++ = GrPoint::Make(bounds.fRight, bounds.fTop); 236 subpathVertCount[subpath++] = 4; 237 } 238 239 GrAssert(subpath == subpathCnt); 240 GrAssert((vert - base) <= maxPts); 241 242 size_t count = vert - base; 243 244 if (count < 3) { 245 delete[] base; 246 return; 247 } 248 249 if (subpathCnt == 1 && !inverted && path.isConvex()) { 250 if (target->isAntialiasState()) { 251 EdgeArray edges; 252 GrMatrix inverse, matrix = target->getViewMatrix(); 253 target->getViewInverse(&inverse); 254 255 count = computeEdgesAndOffsetVertices(matrix, inverse, base, count, &edges); 256 size_t maxEdges = target->getMaxEdges(); 257 if (count <= maxEdges) { 258 // All edges fit; upload all edges and draw all verts as a fan 259 target->setVertexSourceToArray(layout, base, count); 260 target->setEdgeAAData(&edges[0], count); 261 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count); 262 } else { 263 // Upload "maxEdges" edges and verts at a time, and draw as 264 // separate fans 265 for (size_t i = 0; i < count - 2; i += maxEdges - 2) { 266 edges[i] = edges[0]; 267 base[i] = base[0]; 268 int size = GR_CT_MIN(count - i, maxEdges); 269 target->setVertexSourceToArray(layout, &base[i], size); 270 target->setEdgeAAData(&edges[i], size); 271 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size); 272 } 273 } 274 target->setEdgeAAData(NULL, 0); 275 } else { 276 target->setVertexSourceToArray(layout, base, count); 277 target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count); 278 } 279 delete[] base; 280 return; 281 } 282 283 // FIXME: This copy could be removed if we had (templated?) versions of 284 // generate_*_point above that wrote directly into doubles. 285 double* inVertices = new double[count * 3]; 286 for (size_t i = 0; i < count; ++i) { 287 inVertices[i * 3] = base[i].fX; 288 inVertices[i * 3 + 1] = base[i].fY; 289 inVertices[i * 3 + 2] = 1.0; 290 } 291 292 GLUtesselator* tess = Sk_gluNewTess(); 293 unsigned windingRule = fill_type_to_glu_winding_rule(fill); 294 Sk_gluTessProperty(tess, GLU_TESS_WINDING_RULE, windingRule); 295 Sk_gluTessCallback(tess, GLU_TESS_BEGIN_DATA, (TESSCB) &beginData); 296 Sk_gluTessCallback(tess, GLU_TESS_VERTEX_DATA, (TESSCB) &vertexData); 297 Sk_gluTessCallback(tess, GLU_TESS_END_DATA, (TESSCB) &endData); 298 Sk_gluTessCallback(tess, GLU_TESS_EDGE_FLAG_DATA, (TESSCB) &edgeFlagData); 299 Sk_gluTessCallback(tess, GLU_TESS_COMBINE_DATA, (TESSCB) &combineData); 300 GrTDArray<short> indices; 301 GrTDArray<GrPoint> vertices; 302 PolygonData data(&vertices, &indices); 303 304 Sk_gluTessBeginPolygon(tess, &data); 305 size_t i = 0; 306 for (int sp = 0; sp < subpathCnt; ++sp) { 307 Sk_gluTessBeginContour(tess); 308 int start = i; 309 size_t end = start + subpathVertCount[sp]; 310 for (; i < end; ++i) { 311 double* inVertex = &inVertices[i * 3]; 312 *vertices.append() = GrPoint::Make(inVertex[0], inVertex[1]); 313 Sk_gluTessVertex(tess, inVertex, reinterpret_cast<void*>(i)); 314 } 315 Sk_gluTessEndContour(tess); 316 } 317 318 Sk_gluTessEndPolygon(tess); 319 Sk_gluDeleteTess(tess); 320 321 if (indices.count() > 0) { 322 target->setVertexSourceToArray(layout, vertices.begin(), vertices.count()); 323 target->setIndexSourceToArray(indices.begin(), indices.count()); 324 target->drawIndexed(kTriangles_PrimitiveType, 325 0, 326 0, 327 vertices.count(), 328 indices.count()); 329 } 330 delete[] inVertices; 331 delete[] base; 332 } 333 334 bool GrTesselatedPathRenderer::canDrawPath(const GrDrawTarget* target, 335 const SkPath& path, 336 GrPathFill fill) const { 337 return kHairLine_PathFill != fill; 338 } 339 340 void GrTesselatedPathRenderer::drawPathToStencil(GrDrawTarget* target, 341 const SkPath& path, 342 GrPathFill fill, 343 const GrPoint* translate) { 344 GrAlwaysAssert(!"multipass stencil should not be needed"); 345 } 346 347 bool GrTesselatedPathRenderer::supportsAA(GrDrawTarget* target, 348 const SkPath& path, 349 GrPathFill fill) { 350 int subpathCnt = 0; 351 int tol = GrPathUtils::gTolerance; 352 GrPathUtils::worstCasePointCount(path, &subpathCnt, tol); 353 return (subpathCnt == 1 && 354 !IsFillInverted(fill) && 355 path.isConvex()); 356 } 357