Home | History | Annotate | Download | only in src
      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