GrOptDrawState::GrOptDrawState(const GrDrawState& drawState, BlendOptFlags blendOptFlags, GrBlendCoeff optSrcCoeff, GrBlendCoeff optDstCoeff, const GrDrawTargetCaps& caps) : INHERITED(drawState) { fColor = drawState.getColor(); fCoverage = drawState.getCoverage(); fViewMatrix = drawState.getViewMatrix(); fBlendConstant = drawState.getBlendConstant(); fFlagBits = drawState.getFlagBits(); fVAPtr = drawState.getVertexAttribs(); fVACount = drawState.getVertexAttribCount(); fVAStride = drawState.getVertexStride(); fStencilSettings = drawState.getStencil(); fDrawFace = drawState.getDrawFace(); fBlendOptFlags = blendOptFlags; fSrcBlend = optSrcCoeff; fDstBlend = optDstCoeff; memcpy(fFixedFunctionVertexAttribIndices, drawState.getFixedFunctionVertexAttribIndices(), sizeof(fFixedFunctionVertexAttribIndices)); fInputColorIsUsed = true; fInputCoverageIsUsed = true; if (drawState.hasGeometryProcessor()) { fGeometryProcessor.reset(SkNEW_ARGS(GrGeometryStage, (*drawState.getGeometryProcessor()))); } else { fGeometryProcessor.reset(NULL); } this->copyEffectiveColorStages(drawState); this->copyEffectiveCoverageStages(drawState); this->adjustFromBlendOpts(); this->getStageStats(); this->setOutputStateInfo(caps); };
bool GrTesselatedPathRenderer::onDrawPath(const SkPath& path, GrPathFill fill, const GrVec* translate, GrDrawTarget* target, GrDrawState::StageMask stageMask, bool antiAlias) { GrDrawTarget::AutoStateRestore asr(target); GrDrawState* drawState = target->drawState(); // face culling doesn't make sense here GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace()); GrMatrix viewM = drawState->getViewMatrix(); GrScalar tol = GR_Scalar1; tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds()); GrScalar tolSqd = GrMul(tol, tol); int subpathCnt; int maxPts = GrPathUtils::worstCasePointCount(path, &subpathCnt, tol); GrVertexLayout layout = 0; for (int s = 0; s < GrDrawState::kNumStages; ++s) { if ((1 << s) & stageMask) { layout |= GrDrawTarget::StagePosAsTexCoordVertexLayoutBit(s); } } bool inverted = GrIsFillInverted(fill); if (inverted) { maxPts += 4; subpathCnt++; } if (maxPts > USHRT_MAX) { return false; } SkAutoSTMalloc<8, GrPoint> baseMem(maxPts); GrPoint* base = baseMem; GrPoint* vert = base; GrPoint* subpathBase = base; SkAutoSTMalloc<8, uint16_t> subpathVertCount(subpathCnt); GrPoint pts[4]; SkPath::Iter iter(path, false); bool first = true; int subpath = 0; for (;;) { switch (iter.next(pts)) { case kMove_PathCmd: if (!first) { subpathVertCount[subpath] = vert-subpathBase; subpathBase = vert; ++subpath; } *vert = pts[0]; vert++; break; case kLine_PathCmd: *vert = pts[1]; vert++; break; case kQuadratic_PathCmd: { GrPathUtils::generateQuadraticPoints(pts[0], pts[1], pts[2], tolSqd, &vert, GrPathUtils::quadraticPointCount(pts, tol)); break; } case kCubic_PathCmd: { GrPathUtils::generateCubicPoints(pts[0], pts[1], pts[2], pts[3], tolSqd, &vert, GrPathUtils::cubicPointCount(pts, tol)); break; } case kClose_PathCmd: break; case kEnd_PathCmd: subpathVertCount[subpath] = vert-subpathBase; ++subpath; // this could be only in debug goto FINISHED; } first = false; } FINISHED: if (NULL != translate && 0 != translate->fX && 0 != translate->fY) { for (int i = 0; i < vert - base; i++) { base[i].offset(translate->fX, translate->fY); } } if (inverted) { GrRect bounds; GrAssert(NULL != drawState->getRenderTarget()); bounds.setLTRB(0, 0, GrIntToScalar(drawState->getRenderTarget()->width()), GrIntToScalar(drawState->getRenderTarget()->height())); GrMatrix vmi; if (drawState->getViewInverse(&vmi)) { vmi.mapRect(&bounds); } *vert++ = GrPoint::Make(bounds.fLeft, bounds.fTop); *vert++ = GrPoint::Make(bounds.fLeft, bounds.fBottom); *vert++ = GrPoint::Make(bounds.fRight, bounds.fBottom); *vert++ = GrPoint::Make(bounds.fRight, bounds.fTop); subpathVertCount[subpath++] = 4; } GrAssert(subpath == subpathCnt); GrAssert((vert - base) <= maxPts); size_t count = vert - base; if (count < 3) { return true; } if (subpathCnt == 1 && !inverted && path.isConvex()) { if (antiAlias) { GrEdgeArray edges; GrMatrix inverse, matrix = drawState->getViewMatrix(); drawState->getViewInverse(&inverse); count = computeEdgesAndIntersect(matrix, inverse, base, count, &edges, 0.0f); size_t maxEdges = target->getMaxEdges(); if (count == 0) { return true; } if (count <= maxEdges) { // All edges fit; upload all edges and draw all verts as a fan target->setVertexSourceToArray(layout, base, count); drawState->setEdgeAAData(&edges[0], count); target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count); } else { // Upload "maxEdges" edges and verts at a time, and draw as // separate fans for (size_t i = 0; i < count - 2; i += maxEdges - 2) { edges[i] = edges[0]; base[i] = base[0]; int size = GR_CT_MIN(count - i, maxEdges); target->setVertexSourceToArray(layout, &base[i], size); drawState->setEdgeAAData(&edges[i], size); target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, size); } } drawState->setEdgeAAData(NULL, 0); } else { target->setVertexSourceToArray(layout, base, count); target->drawNonIndexed(kTriangleFan_PrimitiveType, 0, count); } return true; } if (antiAlias) { // Run the tesselator once to get the boundaries. GrBoundaryTess btess(count, fill_type_to_glu_winding_rule(fill)); btess.addVertices(base, subpathVertCount, subpathCnt); GrMatrix inverse, matrix = drawState->getViewMatrix(); if (!drawState->getViewInverse(&inverse)) { return false; } if (btess.vertices().count() > USHRT_MAX) { return false; } // Inflate the boundary, and run the tesselator again to generate // interior polys. const GrPointArray& contourPoints = btess.contourPoints(); const GrIndexArray& contours = btess.contours(); GrEdgePolygonTess ptess(contourPoints.count(), GLU_TESS_WINDING_NONZERO, matrix); size_t i = 0; Sk_gluTessBeginPolygon(ptess.tess(), &ptess); for (int contour = 0; contour < contours.count(); ++contour) { int count = contours[contour]; GrEdgeArray edges; int newCount = computeEdgesAndIntersect(matrix, inverse, &btess.contourPoints()[i], count, &edges, 1.0f); Sk_gluTessBeginContour(ptess.tess()); for (int j = 0; j < newCount; j++) { ptess.addVertex(contourPoints[i + j], ptess.vertices().count()); } i += count; Sk_gluTessEndContour(ptess.tess()); } Sk_gluTessEndPolygon(ptess.tess()); if (ptess.vertices().count() > USHRT_MAX) { return false; } // Draw the resulting polys and upload their edge data. drawState->enableState(GrDrawState::kEdgeAAConcave_StateBit); const GrPointArray& vertices = ptess.vertices(); const GrIndexArray& indices = ptess.indices(); const GrDrawState::Edge* edges = ptess.edges(); GR_DEBUGASSERT(indices.count() % 3 == 0); for (int i = 0; i < indices.count(); i += 3) { GrPoint tri_verts[3]; int index0 = indices[i]; int index1 = indices[i + 1]; int index2 = indices[i + 2]; tri_verts[0] = vertices[index0]; tri_verts[1] = vertices[index1]; tri_verts[2] = vertices[index2]; GrDrawState::Edge tri_edges[6]; int t = 0; const GrDrawState::Edge& edge0 = edges[index0 * 2]; const GrDrawState::Edge& edge1 = edges[index0 * 2 + 1]; const GrDrawState::Edge& edge2 = edges[index1 * 2]; const GrDrawState::Edge& edge3 = edges[index1 * 2 + 1]; const GrDrawState::Edge& edge4 = edges[index2 * 2]; const GrDrawState::Edge& edge5 = edges[index2 * 2 + 1]; if (validEdge(edge0) && validEdge(edge1)) { tri_edges[t++] = edge0; tri_edges[t++] = edge1; } if (validEdge(edge2) && validEdge(edge3)) { tri_edges[t++] = edge2; tri_edges[t++] = edge3; } if (validEdge(edge4) && validEdge(edge5)) { tri_edges[t++] = edge4; tri_edges[t++] = edge5; } drawState->setEdgeAAData(&tri_edges[0], t); target->setVertexSourceToArray(layout, &tri_verts[0], 3); target->drawNonIndexed(kTriangles_PrimitiveType, 0, 3); } drawState->setEdgeAAData(NULL, 0); drawState->disableState(GrDrawState::kEdgeAAConcave_StateBit); return true; } GrPolygonTess ptess(count, fill_type_to_glu_winding_rule(fill)); ptess.addVertices(base, subpathVertCount, subpathCnt); const GrPointArray& vertices = ptess.vertices(); const GrIndexArray& indices = ptess.indices(); if (indices.count() > 0) { target->setVertexSourceToArray(layout, vertices.begin(), vertices.count()); target->setIndexSourceToArray(indices.begin(), indices.count()); target->drawIndexed(kTriangles_PrimitiveType, 0, 0, vertices.count(), indices.count()); } return true; }
bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path, const SkStrokeRec& origStroke, GrDrawTarget* target, bool stencilOnly) { SkMatrix viewM = target->getDrawState().getViewMatrix(); SkTCopyOnFirstWrite<SkStrokeRec> stroke(origStroke); SkScalar hairlineCoverage; if (IsStrokeHairlineOrEquivalent(*stroke, target->getDrawState().getViewMatrix(), &hairlineCoverage)) { uint8_t newCoverage = SkScalarRoundToInt(hairlineCoverage * target->getDrawState().getCoverage()); target->drawState()->setCoverage(newCoverage); if (!stroke->isHairlineStyle()) { stroke.writable()->setHairlineStyle(); } } SkScalar tol = SK_Scalar1; tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds()); int vertexCnt; int indexCnt; GrPrimitiveType primType; GrDrawTarget::AutoReleaseGeometry arg; if (!this->createGeom(path, *stroke, tol, target, &primType, &vertexCnt, &indexCnt, &arg)) { return false; } SkASSERT(NULL != target); GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit); GrDrawState* drawState = target->drawState(); bool colorWritesWereDisabled = drawState->isColorWriteDisabled(); // face culling doesn't make sense here SkASSERT(GrDrawState::kBoth_DrawFace == drawState->getDrawFace()); int passCount = 0; const GrStencilSettings* passes[3]; GrDrawState::DrawFace drawFace[3]; bool reverse = false; bool lastPassIsBounds; if (stroke->isHairlineStyle()) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } lastPassIsBounds = false; drawFace[0] = GrDrawState::kBoth_DrawFace; } else { if (single_pass_path(path, *stroke)) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } drawFace[0] = GrDrawState::kBoth_DrawFace; lastPassIsBounds = false; } else { switch (path.getFillType()) { case SkPath::kInverseEvenOdd_FillType: reverse = true; // fallthrough case SkPath::kEvenOdd_FillType: passes[0] = &gEOStencilPass; if (stencilOnly) { passCount = 1; lastPassIsBounds = false; } else { passCount = 2; lastPassIsBounds = true; if (reverse) { passes[1] = &gInvEOColorPass; } else { passes[1] = &gEOColorPass; } } drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace; break; case SkPath::kInverseWinding_FillType: reverse = true; // fallthrough case SkPath::kWinding_FillType: if (fSeparateStencil) { if (fStencilWrapOps) { passes[0] = &gWindStencilSeparateWithWrap; } else { passes[0] = &gWindStencilSeparateNoWrap; } passCount = 2; drawFace[0] = GrDrawState::kBoth_DrawFace; } else { if (fStencilWrapOps) { passes[0] = &gWindSingleStencilWithWrapInc; passes[1] = &gWindSingleStencilWithWrapDec; } else { passes[0] = &gWindSingleStencilNoWrapInc; passes[1] = &gWindSingleStencilNoWrapDec; } // which is cw and which is ccw is arbitrary. drawFace[0] = GrDrawState::kCW_DrawFace; drawFace[1] = GrDrawState::kCCW_DrawFace; passCount = 3; } if (stencilOnly) { lastPassIsBounds = false; --passCount; } else { lastPassIsBounds = true; drawFace[passCount-1] = GrDrawState::kBoth_DrawFace; if (reverse) { passes[passCount-1] = &gInvWindColorPass; } else { passes[passCount-1] = &gWindColorPass; } } break; default: SkDEBUGFAIL("Unknown path fFill!"); return false; } } } SkRect devBounds; GetPathDevBounds(path, drawState->getRenderTarget(), viewM, &devBounds); for (int p = 0; p < passCount; ++p) { drawState->setDrawFace(drawFace[p]); if (NULL != passes[p]) { *drawState->stencil() = *passes[p]; } if (lastPassIsBounds && (p == passCount-1)) { if (!colorWritesWereDisabled) { drawState->disableState(GrDrawState::kNoColorWrites_StateBit); } SkRect bounds; GrDrawState::AutoViewMatrixRestore avmr; if (reverse) { SkASSERT(NULL != drawState->getRenderTarget()); // draw over the dev bounds (which will be the whole dst surface for inv fill). bounds = devBounds; SkMatrix vmi; // mapRect through persp matrix may not be correct if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) { vmi.mapRect(&bounds); } else { avmr.setIdentity(drawState); } } else { bounds = path.getBounds(); } GrDrawTarget::AutoGeometryAndStatePush agasp(target, GrDrawTarget::kPreserve_ASRInit); target->drawSimpleRect(bounds, NULL); } else { if (passCount > 1) { drawState->enableState(GrDrawState::kNoColorWrites_StateBit); } if (indexCnt) { target->drawIndexed(primType, 0, 0, vertexCnt, indexCnt, &devBounds); } else { target->drawNonIndexed(primType, 0, vertexCnt, &devBounds); } } } return true; }
bool GrDefaultPathRenderer::internalDrawPath(const SkPath& path, GrPathFill fill, GrDrawTarget* target, bool stencilOnly) { GrMatrix viewM = target->getDrawState().getViewMatrix(); GrScalar tol = GR_Scalar1; tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, path.getBounds()); int vertexCnt; int indexCnt; GrPrimitiveType primType; GrDrawTarget::AutoReleaseGeometry arg; if (!this->createGeom(path, fill, tol, target, &primType, &vertexCnt, &indexCnt, &arg)) { return false; } GrAssert(NULL != target); GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit); GrDrawState* drawState = target->drawState(); bool colorWritesWereDisabled = drawState->isColorWriteDisabled(); // face culling doesn't make sense here GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace()); int passCount = 0; const GrStencilSettings* passes[3]; GrDrawState::DrawFace drawFace[3]; bool reverse = false; bool lastPassIsBounds; if (kHairLine_GrPathFill == fill) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } lastPassIsBounds = false; drawFace[0] = GrDrawState::kBoth_DrawFace; } else { if (single_pass_path(path, fill)) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } drawFace[0] = GrDrawState::kBoth_DrawFace; lastPassIsBounds = false; } else { switch (fill) { case kInverseEvenOdd_GrPathFill: reverse = true; // fallthrough case kEvenOdd_GrPathFill: passes[0] = &gEOStencilPass; if (stencilOnly) { passCount = 1; lastPassIsBounds = false; } else { passCount = 2; lastPassIsBounds = true; if (reverse) { passes[1] = &gInvEOColorPass; } else { passes[1] = &gEOColorPass; } } drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace; break; case kInverseWinding_GrPathFill: reverse = true; // fallthrough case kWinding_GrPathFill: if (fSeparateStencil) { if (fStencilWrapOps) { passes[0] = &gWindStencilSeparateWithWrap; } else { passes[0] = &gWindStencilSeparateNoWrap; } passCount = 2; drawFace[0] = GrDrawState::kBoth_DrawFace; } else { if (fStencilWrapOps) { passes[0] = &gWindSingleStencilWithWrapInc; passes[1] = &gWindSingleStencilWithWrapDec; } else { passes[0] = &gWindSingleStencilNoWrapInc; passes[1] = &gWindSingleStencilNoWrapDec; } // which is cw and which is ccw is arbitrary. drawFace[0] = GrDrawState::kCW_DrawFace; drawFace[1] = GrDrawState::kCCW_DrawFace; passCount = 3; } if (stencilOnly) { lastPassIsBounds = false; --passCount; } else { lastPassIsBounds = true; drawFace[passCount-1] = GrDrawState::kBoth_DrawFace; if (reverse) { passes[passCount-1] = &gInvWindColorPass; } else { passes[passCount-1] = &gWindColorPass; } } break; default: GrAssert(!"Unknown path fFill!"); return false; } } } { for (int p = 0; p < passCount; ++p) { drawState->setDrawFace(drawFace[p]); if (NULL != passes[p]) { *drawState->stencil() = *passes[p]; } if (lastPassIsBounds && (p == passCount-1)) { if (!colorWritesWereDisabled) { drawState->disableState(GrDrawState::kNoColorWrites_StateBit); } GrRect bounds; GrDrawState::AutoDeviceCoordDraw adcd; if (reverse) { GrAssert(NULL != drawState->getRenderTarget()); // draw over the whole world. bounds.setLTRB(0, 0, GrIntToScalar(drawState->getRenderTarget()->width()), GrIntToScalar(drawState->getRenderTarget()->height())); GrMatrix vmi; // mapRect through persp matrix may not be correct if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) { vmi.mapRect(&bounds); } else { adcd.set(drawState); } } else { bounds = path.getBounds(); } GrDrawTarget::AutoGeometryPush agp(target); target->drawSimpleRect(bounds, NULL); } else { if (passCount > 1) { drawState->enableState(GrDrawState::kNoColorWrites_StateBit); } if (indexCnt) { target->drawIndexed(primType, 0, 0, vertexCnt, indexCnt); } else { target->drawNonIndexed(primType, 0, vertexCnt); } } } } return true; }
void GrDefaultPathRenderer::onDrawPath(GrDrawState::StageMask stageMask, bool stencilOnly) { GrMatrix viewM = fTarget->getDrawState().getViewMatrix(); GrScalar tol = GR_Scalar1; tol = GrPathUtils::scaleToleranceToSrc(tol, viewM, fPath->getBounds()); GrDrawState* drawState = fTarget->drawState(); // FIXME: It's really dumb that we recreate the verts for a new vertex // layout. We only do that because the GrDrawTarget API doesn't allow // us to change the vertex layout after reserveVertexSpace(). We won't // actually change the vertex data when the layout changes since all the // stages reference the positions (rather than having separate tex coords) // and we don't ever have per-vert colors. In practice our call sites // won't change the stages in use inside a setPath / removePath pair. But // it is a silly limitation of the GrDrawTarget design that should be fixed. if (tol != fPreviousSrcTol || stageMask != fPreviousStages) { if (!this->createGeom(tol, stageMask)) { return; } } GrAssert(NULL != fTarget); GrDrawTarget::AutoStateRestore asr(fTarget); bool colorWritesWereDisabled = drawState->isColorWriteDisabled(); // face culling doesn't make sense here GrAssert(GrDrawState::kBoth_DrawFace == drawState->getDrawFace()); int passCount = 0; const GrStencilSettings* passes[3]; GrDrawState::DrawFace drawFace[3]; bool reverse = false; bool lastPassIsBounds; if (kHairLine_PathFill == fFill) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } lastPassIsBounds = false; drawFace[0] = GrDrawState::kBoth_DrawFace; } else { if (single_pass_path(*fTarget, *fPath, fFill)) { passCount = 1; if (stencilOnly) { passes[0] = &gDirectToStencil; } else { passes[0] = NULL; } drawFace[0] = GrDrawState::kBoth_DrawFace; lastPassIsBounds = false; } else { switch (fFill) { case kInverseEvenOdd_PathFill: reverse = true; // fallthrough case kEvenOdd_PathFill: passes[0] = &gEOStencilPass; if (stencilOnly) { passCount = 1; lastPassIsBounds = false; } else { passCount = 2; lastPassIsBounds = true; if (reverse) { passes[1] = &gInvEOColorPass; } else { passes[1] = &gEOColorPass; } } drawFace[0] = drawFace[1] = GrDrawState::kBoth_DrawFace; break; case kInverseWinding_PathFill: reverse = true; // fallthrough case kWinding_PathFill: if (fSeparateStencil) { if (fStencilWrapOps) { passes[0] = &gWindStencilSeparateWithWrap; } else { passes[0] = &gWindStencilSeparateNoWrap; } passCount = 2; drawFace[0] = GrDrawState::kBoth_DrawFace; } else { if (fStencilWrapOps) { passes[0] = &gWindSingleStencilWithWrapInc; passes[1] = &gWindSingleStencilWithWrapDec; } else { passes[0] = &gWindSingleStencilNoWrapInc; passes[1] = &gWindSingleStencilNoWrapDec; } // which is cw and which is ccw is arbitrary. drawFace[0] = GrDrawState::kCW_DrawFace; drawFace[1] = GrDrawState::kCCW_DrawFace; passCount = 3; } if (stencilOnly) { lastPassIsBounds = false; --passCount; } else { lastPassIsBounds = true; drawFace[passCount-1] = GrDrawState::kBoth_DrawFace; if (reverse) { passes[passCount-1] = &gInvWindColorPass; } else { passes[passCount-1] = &gWindColorPass; } } break; default: GrAssert(!"Unknown path fFill!"); return; } } } { for (int p = 0; p < passCount; ++p) { drawState->setDrawFace(drawFace[p]); if (NULL != passes[p]) { *drawState->stencil() = *passes[p]; } if (lastPassIsBounds && (p == passCount-1)) { if (!colorWritesWereDisabled) { drawState->disableState(GrDrawState::kNoColorWrites_StateBit); } GrRect bounds; if (reverse) { GrAssert(NULL != drawState->getRenderTarget()); // draw over the whole world. bounds.setLTRB(0, 0, GrIntToScalar(drawState->getRenderTarget()->width()), GrIntToScalar(drawState->getRenderTarget()->height())); GrMatrix vmi; // mapRect through persp matrix may not be correct if (!drawState->getViewMatrix().hasPerspective() && drawState->getViewInverse(&vmi)) { vmi.mapRect(&bounds); } else { if (stageMask) { if (!drawState->getViewInverse(&vmi)) { GrPrintf("Could not invert matrix."); return; } drawState->preConcatSamplerMatrices(stageMask, vmi); } drawState->setViewMatrix(GrMatrix::I()); } } else { bounds = fPath->getBounds(); bounds.offset(fTranslate); } GrDrawTarget::AutoGeometryPush agp(fTarget); fTarget->drawSimpleRect(bounds, NULL, stageMask); } else { if (passCount > 1) { drawState->enableState(GrDrawState::kNoColorWrites_StateBit); } if (fUseIndexedDraw) { fTarget->drawIndexed(fPrimitiveType, 0, 0, fVertexCnt, fIndexCnt); } else { int baseVertex = 0; for (int sp = 0; sp < fSubpathCount; ++sp) { fTarget->drawNonIndexed(fPrimitiveType, baseVertex, fSubpathVertCount[sp]); baseVertex += fSubpathVertCount[sp]; } } } } } }