static void add_quads(const SkPoint p[3],
                      int subdiv,
                      const SkMatrix* toDevice,
                      const SkMatrix* toSrc,
                      BezierVertex** vert) {
    SkASSERT(subdiv >= 0);
    if (subdiv) {
        SkPoint newP[5];
        SkChopQuadAtHalf(p, newP);
        add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert);
        add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert);
    } else {
        bloat_quad(p, toDevice, toSrc, *vert);
        set_uv_quad(p, *vert);
        *vert += kQuadNumVertices;
    }
}
bool GrAAHairLinePathRenderer::createGeom(
            const SkPath& path,
            GrDrawTarget* target,
            int* lineCnt,
            int* quadCnt,
            GrDrawTarget::AutoReleaseGeometry* arg) {
    const GrDrawState& drawState = target->getDrawState();
    int rtHeight = drawState.getRenderTarget()->height();

    GrIRect devClipBounds;
    target->getClip()->getConservativeBounds(drawState.getRenderTarget(),
                                             &devClipBounds);

    GrVertexLayout layout = GrDrawState::kEdge_VertexLayoutBit;
    SkMatrix viewM = drawState.getViewMatrix();

    PREALLOC_PTARRAY(128) lines;
    PREALLOC_PTARRAY(128) quads;
    IntArray qSubdivs;
    *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds,
                                        &lines, &quads, &qSubdivs);

    *lineCnt = lines.count() / 2;
    int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt;

    GrAssert(sizeof(Vertex) == GrDrawState::VertexSize(layout));

    if (!arg->set(target, layout, vertCnt, 0)) {
        return false;
    }

    Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices());

    const SkMatrix* toDevice = NULL;
    const SkMatrix* toSrc = NULL;
    SkMatrix ivm;

    if (viewM.hasPerspective()) {
        if (viewM.invert(&ivm)) {
            toDevice = &viewM;
            toSrc = &ivm;
        }
    }

    for (int i = 0; i < *lineCnt; ++i) {
        add_line(&lines[2*i], rtHeight, toSrc, &verts);
    }

    int unsubdivQuadCnt = quads.count() / 3;
    for (int i = 0; i < unsubdivQuadCnt; ++i) {
        GrAssert(qSubdivs[i] >= 0);
        add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts);
    }

    return true;
}
void AAHairlineBatch::generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline) {
    // Setup the viewmatrix and localmatrix for the GrGeometryProcessor.
    SkMatrix invert;
    if (!this->viewMatrix().invert(&invert)) {
        return;
    }

    // we will transform to identity space if the viewmatrix does not have perspective
    bool hasPerspective = this->viewMatrix().hasPerspective();
    const SkMatrix* geometryProcessorViewM = &SkMatrix::I();
    const SkMatrix* geometryProcessorLocalM = &invert;
    const SkMatrix* toDevice = NULL;
    const SkMatrix* toSrc = NULL;
    if (hasPerspective) {
        geometryProcessorViewM = &this->viewMatrix();
        geometryProcessorLocalM = &SkMatrix::I();
        toDevice = &this->viewMatrix();
        toSrc = &invert;
    }

    // Setup geometry processors for worst case
    uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType |
                       GrDefaultGeoProcFactory::kCoverage_GPType;

    SkAutoTUnref<const GrGeometryProcessor> lineGP(
            GrDefaultGeoProcFactory::Create(gpFlags,
                                            this->color(),
                                            this->usesLocalCoords(),
                                            this->coverageIgnored(),
                                            *geometryProcessorViewM,
                                            *geometryProcessorLocalM,
                                            this->coverage()));

    SkAutoTUnref<const GrGeometryProcessor> quadGP(
            GrQuadEffect::Create(this->color(),
                                 *geometryProcessorViewM,
                                 kHairlineAA_GrProcessorEdgeType,
                                 batchTarget->caps(),
                                 *geometryProcessorLocalM,
                                 this->usesLocalCoords(),
                                 this->coverage()));

    SkAutoTUnref<const GrGeometryProcessor> conicGP(
            GrConicEffect::Create(this->color(),
                                  *geometryProcessorViewM,
                                  kHairlineAA_GrProcessorEdgeType,
                                  batchTarget->caps(),
                                  *geometryProcessorLocalM,
                                  this->usesLocalCoords(),
                                  this->coverage()));

    // This is hand inlined for maximum performance.
    PREALLOC_PTARRAY(128) lines;
    PREALLOC_PTARRAY(128) quads;
    PREALLOC_PTARRAY(128) conics;
    IntArray qSubdivs;
    FloatArray cWeights;
    int quadCount = 0;

    int instanceCount = fGeoData.count();
    for (int i = 0; i < instanceCount; i++) {
        const Geometry& args = fGeoData[i];
        quadCount += gather_lines_and_quads(args.fPath, args.fViewMatrix, args.fDevClipBounds,
                                            &lines, &quads, &conics, &qSubdivs, &cWeights);
    }

    int lineCount = lines.count() / 2;
    int conicCount = conics.count() / 3;

    // do lines first
    if (lineCount) {
        SkAutoTUnref<const GrIndexBuffer> linesIndexBuffer(
            ref_lines_index_buffer(batchTarget->resourceProvider()));
        batchTarget->initDraw(lineGP, pipeline);

        const GrVertexBuffer* vertexBuffer;
        int firstVertex;

        size_t vertexStride = lineGP->getVertexStride();
        int vertexCount = kLineSegNumVertices * lineCount;
        LineVertex* verts = reinterpret_cast<LineVertex*>(
            batchTarget->makeVertSpace(vertexStride, vertexCount, &vertexBuffer, &firstVertex));

        if (!verts|| !linesIndexBuffer) {
            SkDebugf("Could not allocate vertices\n");
            return;
        }

        SkASSERT(lineGP->getVertexStride() == sizeof(LineVertex));

        for (int i = 0; i < lineCount; ++i) {
            add_line(&lines[2*i], toSrc, this->coverage(), &verts);
        }

        {
            GrVertices vertices;
            vertices.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, linesIndexBuffer,
                                   firstVertex, kLineSegNumVertices, kIdxsPerLineSeg, lineCount,
                                   kLineSegsNumInIdxBuffer);
            batchTarget->draw(vertices);
        }
    }

    if (quadCount || conicCount) {
        const GrVertexBuffer* vertexBuffer;
        int firstVertex;

        SkAutoTUnref<const GrIndexBuffer> quadsIndexBuffer(
            ref_quads_index_buffer(batchTarget->resourceProvider()));

        size_t vertexStride = sizeof(BezierVertex);
        int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * conicCount;
        void *vertices = batchTarget->makeVertSpace(vertexStride, vertexCount,
                                                    &vertexBuffer, &firstVertex);

        if (!vertices || !quadsIndexBuffer) {
            SkDebugf("Could not allocate vertices\n");
            return;
        }

        // Setup vertices
        BezierVertex* verts = reinterpret_cast<BezierVertex*>(vertices);

        int unsubdivQuadCnt = quads.count() / 3;
        for (int i = 0; i < unsubdivQuadCnt; ++i) {
            SkASSERT(qSubdivs[i] >= 0);
            add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts);
        }

        // Start Conics
        for (int i = 0; i < conicCount; ++i) {
            add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts);
        }

        if (quadCount > 0) {
            batchTarget->initDraw(quadGP, pipeline);

            {
                GrVertices verts;
                verts.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer,
                                    firstVertex, kQuadNumVertices, kIdxsPerQuad, quadCount,
                                    kQuadsNumInIdxBuffer);
                batchTarget->draw(verts);
                firstVertex += quadCount * kQuadNumVertices;
           }
        }

        if (conicCount > 0) {
            batchTarget->initDraw(conicGP, pipeline);

            {
                GrVertices verts;
                verts.initInstanced(kTriangles_GrPrimitiveType, vertexBuffer, quadsIndexBuffer,
                                    firstVertex, kQuadNumVertices, kIdxsPerQuad, conicCount,
                                    kQuadsNumInIdxBuffer);
                batchTarget->draw(verts);
            }
        }
    }
}
bool GrAAHairLinePathRenderer::createGeom(GrDrawTarget::StageBitfield stages) {

    int rtHeight = fTarget->getRenderTarget()->height();

    GrIRect clip;
    if (fTarget->getClip().hasConservativeBounds()) {
        GrRect clipRect =  fTarget->getClip().getConservativeBounds();
        clipRect.roundOut(&clip);
    } else {
        clip.setLargest();
    }

    // If none of the inputs that affect generation of path geometry have
    // have changed since last previous path draw then we can reuse the
    // previous geoemtry.
    if (stages == fPreviousStages &&
        fPreviousViewMatrix == fTarget->getViewMatrix() &&
        fPreviousTranslate == fTranslate &&
        rtHeight == fPreviousRTHeight &&
        fClipRect == clip) {
        return true;
    }

    GrVertexLayout layout = GrDrawTarget::kEdge_VertexLayoutBit;
    for (int s = 0; s < GrDrawState::kNumStages; ++s) {
        if ((1 << s) & stages) {
            layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s);
        }
    }

    GrMatrix viewM = fTarget->getViewMatrix();

    PREALLOC_PTARRAY(128) lines;
    PREALLOC_PTARRAY(128) quads;
    IntArray qSubdivs;
    fQuadCnt = generate_lines_and_quads(*fPath, viewM, fTranslate, clip,
                                        &lines, &quads, &qSubdivs);

    fLineSegmentCnt = lines.count() / 2;
    int vertCnt = kVertsPerLineSeg * fLineSegmentCnt + kVertsPerQuad * fQuadCnt;

    GrAssert(sizeof(Vertex) == GrDrawTarget::VertexSize(layout));

    Vertex* verts;
    if (!fTarget->reserveVertexSpace(layout, vertCnt, (void**)&verts)) {
        return false;
    }
    Vertex* base = verts;

    const GrMatrix* toDevice = NULL;
    const GrMatrix* toSrc = NULL;
    GrMatrix ivm;

    if (viewM.hasPerspective()) {
        if (viewM.invert(&ivm)) {
            toDevice = &viewM;
            toSrc = &ivm;
        }
    }

    for (int i = 0; i < fLineSegmentCnt; ++i) {
        add_line(&lines[2*i], rtHeight, toSrc, &verts);
    }

    int unsubdivQuadCnt = quads.count() / 3;
    for (int i = 0; i < unsubdivQuadCnt; ++i) {
        GrAssert(qSubdivs[i] >= 0);
        add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts);
    }

    fPreviousStages = stages;
    fPreviousViewMatrix = fTarget->getViewMatrix();
    fPreviousRTHeight = rtHeight;
    fClipRect = clip;
    fPreviousTranslate = fTranslate;
    return true;
}
bool GrAAHairLinePathRenderer::createBezierGeom(
                                          const SkPath& path,
                                          GrDrawTarget* target,
                                          const PtArray& quads,
                                          int quadCnt,
                                          const PtArray& conics,
                                          int conicCnt,
                                          const IntArray& qSubdivs,
                                          const FloatArray& cWeights,
                                          GrDrawTarget::AutoReleaseGeometry* arg,
                                          SkRect* devBounds) {
    GrDrawState* drawState = target->drawState();

    const SkMatrix& viewM = drawState->getViewMatrix();

    int vertCnt = kVertsPerQuad * quadCnt + kVertsPerQuad * conicCnt;

    int vAttribCnt = SK_ARRAY_COUNT(gHairlineBezierAttribs);
    target->drawState()->setVertexAttribs<gHairlineBezierAttribs>(vAttribCnt, sizeof(BezierVertex));

    if (!arg->set(target, vertCnt, 0)) {
        return false;
    }

    BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg->vertices());

    const SkMatrix* toDevice = NULL;
    const SkMatrix* toSrc = NULL;
    SkMatrix ivm;

    if (viewM.hasPerspective()) {
        if (viewM.invert(&ivm)) {
            toDevice = &viewM;
            toSrc = &ivm;
        }
    }

    // Seed the dev bounds with some pts known to be inside. Each quad and conic grows the bounding
    // box to include its vertices.
    SkPoint seedPts[2];
    if (quadCnt) {
        seedPts[0] = quads[0];
        seedPts[1] = quads[2];
    } else if (conicCnt) {
        seedPts[0] = conics[0];
        seedPts[1] = conics[2];
    }
    if (toDevice) {
        toDevice->mapPoints(seedPts, 2);
    }
    devBounds->set(seedPts[0], seedPts[1]);

    int unsubdivQuadCnt = quads.count() / 3;
    for (int i = 0; i < unsubdivQuadCnt; ++i) {
        SkASSERT(qSubdivs[i] >= 0);
        add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds);
    }

    // Start Conics
    for (int i = 0; i < conicCnt; ++i) {
        add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds);
    }
    return true;
}
int main (int argc, char *argv[])
{
  if (argc != 2) usage (argv[0]);

  std::string twopt_table_file = argv[1];

  Npoint_Functions::Pixel_Quadrilaterals_Rhombic<int> q;
  Npoint_Functions::Twopt_Table<int> twopt_table;
  twopt_table.read_file (twopt_table_file);
  Npoint_Functions::Pixel_Triangles_Equilateral<int> triangles;
  triangles.find_triangles (twopt_table);
  q.initialize (triangles);

  /* Build the list of pixels storing information about their base pixel as
   * this is needed for the transformations. */
  std::vector<PixelInfo> pixel_list;
  {
    std::vector<int> pl0, pl4;
    myHealpix::base0_list (q.Nside(), pl0);
    myHealpix::base4_list (q.Nside(), pl4);
    pixel_list.resize(pl0.size()+pl4.size());
    for (size_t j=0; j < pl0.size(); ++j) {
      pixel_list[j].pixnum = pl0[j];
      pixel_list[j].basepix = PixelInfo::BASE0;
    }      
    for (size_t j=0; j < pl4.size(); ++j) {
      pixel_list[j+pl0.size()].pixnum = pl4[j];
      pixel_list[j+pl0.size()].basepix = PixelInfo::BASE4;
    }      
  }

#pragma omp parallel shared (pixel_list) firstprivate (q)
  {
    std::vector<int> tri;
    std::vector<int> thirdpt;
    thirdpt.reserve(1000);
    int pix;
    
    PixelTrans pixtrans (q.Nside(), q.Scheme());

    /* Buffer space.  We save the quadrilaterals in a buffer and then
     * write them out all at once.  This is done so that we don't have
     * threads fighting each other to get write access.  We can't have them
     * all write at once.
     */
    // Number of quad space we want to reserve.  This is a bit under 500MB.
    const size_t Nbuf = 30000000;
    simple_vector<int> quad_buf(4*Nbuf);
    
#pragma omp for schedule(dynamic,1)
    for (size_t j=0; j < pixel_list.size(); ++j) {
      pix = pixel_list[j].pixnum; // shorthand
      q.initialize(pix);
      while (q.next(tri, thirdpt)) {
        // First add the quads.
        add_quads (tri, thirdpt, quad_buf);
        // Next shift by base pixel 3 times.
        for (int n=0; n < 3; ++n) {
          pixtrans.shift_by_base (tri);
          pixtrans.shift_by_base (thirdpt);
          add_quads (tri, thirdpt, quad_buf);
        }
        // Then reflect through z=0 line
        pixtrans.reflect_through_z0 (tri);
        pixtrans.reflect_through_z0 (thirdpt);
        add_quads (tri, thirdpt, quad_buf);
        // and shift by base pixel 3 times.
        for (int n=0; n < 3; ++n) {
          pixtrans.shift_by_base (tri);
          pixtrans.shift_by_base (thirdpt);
          add_quads (tri, thirdpt, quad_buf);
        }

        // If we have a base0 pixel we are done
        if (pixel_list[j].basepix == PixelInfo::BASE0) continue;

        // Otherwise we have more transformations to do.
        // Reflect through z-axis
        pixtrans.reflect_through_zaxis (tri);
        pixtrans.reflect_through_zaxis (thirdpt);
        add_quads (tri, thirdpt, quad_buf);
        // and shift by base pixel 3 times.
        for (int n=0; n < 3; ++n) {
          pixtrans.shift_by_base (tri);
          pixtrans.shift_by_base (thirdpt);
          add_quads (tri, thirdpt, quad_buf);
        }
        // Then reflect through z=0 line
        pixtrans.reflect_through_z0 (tri);
        pixtrans.reflect_through_z0 (thirdpt);
        add_quads (tri, thirdpt, quad_buf);
        // and shift by base pixel 3 times.
        for (int n=0; n < 3; ++n) {
          pixtrans.shift_by_base (tri);
          pixtrans.shift_by_base (thirdpt);
          add_quads (tri, thirdpt, quad_buf);
        }
      }
    }
    write_quad_buffer (quad_buf);
  }

  return 0;
}