OLD | NEW |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "GrAAHairLinePathRenderer.h" | 9 #include "GrAAHairLinePathRenderer.h" |
10 | 10 |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
353 wInv = SkScalarInvert(wInv); | 353 wInv = SkScalarInvert(wInv); |
354 | 354 |
355 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); | 355 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); |
356 result->fX = SkScalarMul(result->fX, wInv); | 356 result->fX = SkScalarMul(result->fX, wInv); |
357 | 357 |
358 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); | 358 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); |
359 result->fY = SkScalarMul(result->fY, wInv); | 359 result->fY = SkScalarMul(result->fY, wInv); |
360 } | 360 } |
361 | 361 |
362 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, | 362 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
363 const SkMatrix* toSrc, Vertex verts[kVertsPerQuad]) { | 363 const SkMatrix* toSrc, Vertex verts[kVertsPerQuad], |
364 SkRect* devBounds) { | |
364 GrAssert(!toDevice == !toSrc); | 365 GrAssert(!toDevice == !toSrc); |
365 // original quad is specified by tri a,b,c | 366 // original quad is specified by tri a,b,c |
366 SkPoint a = qpts[0]; | 367 SkPoint a = qpts[0]; |
367 SkPoint b = qpts[1]; | 368 SkPoint b = qpts[1]; |
368 SkPoint c = qpts[2]; | 369 SkPoint c = qpts[2]; |
369 | 370 |
370 // this should be in the src space, not dev coords, when we have perspective | 371 // this should be in the src space, not dev coords, when we have perspective |
371 GrPathUtils::QuadUVMatrix DevToUV(qpts); | 372 GrPathUtils::QuadUVMatrix DevToUV(qpts); |
372 | 373 |
373 if (toDevice) { | 374 if (toDevice) { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
420 a0.fPos = a; | 421 a0.fPos = a; |
421 a0.fPos += abN; | 422 a0.fPos += abN; |
422 a1.fPos = a; | 423 a1.fPos = a; |
423 a1.fPos -= abN; | 424 a1.fPos -= abN; |
424 | 425 |
425 c0.fPos = c; | 426 c0.fPos = c; |
426 c0.fPos += cbN; | 427 c0.fPos += cbN; |
427 c1.fPos = c; | 428 c1.fPos = c; |
428 c1.fPos -= cbN; | 429 c1.fPos -= cbN; |
429 | 430 |
431 // This point may not be within 1 pixel of a control point. We update the bo unding box to | |
432 // include it. | |
430 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); | 433 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); |
434 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); | |
431 | 435 |
432 if (toSrc) { | 436 if (toSrc) { |
433 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad ); | 437 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad ); |
434 } | 438 } |
435 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); | 439 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); |
436 } | 440 } |
437 | 441 |
438 void add_quads(const SkPoint p[3], | 442 void add_quads(const SkPoint p[3], |
439 int subdiv, | 443 int subdiv, |
440 const SkMatrix* toDevice, | 444 const SkMatrix* toDevice, |
441 const SkMatrix* toSrc, | 445 const SkMatrix* toSrc, |
442 Vertex** vert) { | 446 Vertex** vert, |
447 SkRect* devBounds) { | |
443 GrAssert(subdiv >= 0); | 448 GrAssert(subdiv >= 0); |
444 if (subdiv) { | 449 if (subdiv) { |
445 SkPoint newP[5]; | 450 SkPoint newP[5]; |
446 SkChopQuadAtHalf(p, newP); | 451 SkChopQuadAtHalf(p, newP); |
447 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert); | 452 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds); |
448 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert); | 453 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds); |
449 } else { | 454 } else { |
450 bloat_quad(p, toDevice, toSrc, *vert); | 455 bloat_quad(p, toDevice, toSrc, *vert, devBounds); |
451 *vert += kVertsPerQuad; | 456 *vert += kVertsPerQuad; |
452 } | 457 } |
453 } | 458 } |
454 | 459 |
455 void add_line(const SkPoint p[2], | 460 void add_line(const SkPoint p[2], |
456 int rtHeight, | 461 int rtHeight, |
457 const SkMatrix* toSrc, | 462 const SkMatrix* toSrc, |
458 Vertex** vert) { | 463 Vertex** vert) { |
459 const SkPoint& a = p[0]; | 464 const SkPoint& a = p[0]; |
460 const SkPoint& b = p[1]; | 465 const SkPoint& b = p[1]; |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
697 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g} | 702 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin g} |
698 }; | 703 }; |
699 | 704 |
700 }; | 705 }; |
701 | 706 |
702 bool GrAAHairLinePathRenderer::createGeom( | 707 bool GrAAHairLinePathRenderer::createGeom( |
703 const SkPath& path, | 708 const SkPath& path, |
704 GrDrawTarget* target, | 709 GrDrawTarget* target, |
705 int* lineCnt, | 710 int* lineCnt, |
706 int* quadCnt, | 711 int* quadCnt, |
707 GrDrawTarget::AutoReleaseGeometry* arg) { | 712 GrDrawTarget::AutoReleaseGeometry* arg, |
713 SkRect* devBounds) { | |
708 GrDrawState* drawState = target->drawState(); | 714 GrDrawState* drawState = target->drawState(); |
709 int rtHeight = drawState->getRenderTarget()->height(); | 715 int rtHeight = drawState->getRenderTarget()->height(); |
710 | 716 |
711 GrIRect devClipBounds; | 717 GrIRect devClipBounds; |
712 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), | 718 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), |
713 &devClipBounds); | 719 &devClipBounds); |
714 | 720 |
715 SkMatrix viewM = drawState->getViewMatrix(); | 721 SkMatrix viewM = drawState->getViewMatrix(); |
716 | 722 |
723 // All the vertices that we compute are within 1 of path control points with the exception of | |
724 // one of the bounding vertices for each quad. The add_quads() function will update the bounds | |
725 // for each quad added. | |
726 *devBounds = path.getBounds(); | |
727 viewM.mapRect(devBounds); | |
728 devBounds->outset(SK_Scalar1, SK_Scalar1); | |
729 | |
717 PREALLOC_PTARRAY(128) lines; | 730 PREALLOC_PTARRAY(128) lines; |
718 PREALLOC_PTARRAY(128) quads; | 731 PREALLOC_PTARRAY(128) quads; |
719 IntArray qSubdivs; | 732 IntArray qSubdivs; |
720 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, | 733 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, |
721 &lines, &quads, &qSubdivs); | 734 &lines, &quads, &qSubdivs); |
722 | 735 |
723 *lineCnt = lines.count() / 2; | 736 *lineCnt = lines.count() / 2; |
724 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt; | 737 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt; |
725 | 738 |
726 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair lineAttribs)); | 739 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair lineAttribs)); |
(...skipping 16 matching lines...) Expand all Loading... | |
743 } | 756 } |
744 } | 757 } |
745 | 758 |
746 for (int i = 0; i < *lineCnt; ++i) { | 759 for (int i = 0; i < *lineCnt; ++i) { |
747 add_line(&lines[2*i], rtHeight, toSrc, &verts); | 760 add_line(&lines[2*i], rtHeight, toSrc, &verts); |
748 } | 761 } |
749 | 762 |
750 int unsubdivQuadCnt = quads.count() / 3; | 763 int unsubdivQuadCnt = quads.count() / 3; |
751 for (int i = 0; i < unsubdivQuadCnt; ++i) { | 764 for (int i = 0; i < unsubdivQuadCnt; ++i) { |
752 GrAssert(qSubdivs[i] >= 0); | 765 GrAssert(qSubdivs[i] >= 0); |
753 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts); | 766 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); |
754 } | 767 } |
755 | 768 |
756 return true; | 769 return true; |
757 } | 770 } |
758 | 771 |
759 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, | 772 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, |
760 const SkStrokeRec& stroke, | 773 const SkStrokeRec& stroke, |
761 const GrDrawTarget* target, | 774 const GrDrawTarget* target, |
762 bool antiAlias) const { | 775 bool antiAlias) const { |
763 if (!stroke.isHairlineStyle() || !antiAlias) { | 776 if (!stroke.isHairlineStyle() || !antiAlias) { |
(...skipping 10 matching lines...) Expand all Loading... | |
774 } | 787 } |
775 | 788 |
776 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, | 789 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
777 const SkStrokeRec&, | 790 const SkStrokeRec&, |
778 GrDrawTarget* target, | 791 GrDrawTarget* target, |
779 bool antiAlias) { | 792 bool antiAlias) { |
780 | 793 |
781 int lineCnt; | 794 int lineCnt; |
782 int quadCnt; | 795 int quadCnt; |
783 GrDrawTarget::AutoReleaseGeometry arg; | 796 GrDrawTarget::AutoReleaseGeometry arg; |
797 SkRect devBounds; | |
798 | |
784 if (!this->createGeom(path, | 799 if (!this->createGeom(path, |
785 target, | 800 target, |
786 &lineCnt, | 801 &lineCnt, |
787 &quadCnt, | 802 &quadCnt, |
788 &arg)) { | 803 &arg, |
804 &devBounds)) { | |
789 return false; | 805 return false; |
790 } | 806 } |
791 | 807 |
792 GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit); | 808 GrDrawTarget::AutoStateRestore asr(target, GrDrawTarget::kPreserve_ASRInit); |
793 GrDrawState* drawState = target->drawState(); | 809 GrDrawState* drawState = target->drawState(); |
794 | 810 |
795 GrDrawState::AutoDeviceCoordDraw adcd; | 811 GrDrawState::AutoDeviceCoordDraw adcd; |
796 // createGeom transforms the geometry to device space when the matrix does n ot have | 812 // createGeom transforms the geometry to device space when the matrix does n ot have |
797 // perspective. | 813 // perspective. |
798 if (!drawState->getViewMatrix().hasPerspective()) { | 814 if (!drawState->getViewMatrix().hasPerspective()) { |
(...skipping 10 matching lines...) Expand all Loading... | |
809 // the edge effects share this stage with glyph rendering | 825 // the edge effects share this stage with glyph rendering |
810 // (kGlyphMaskStage in GrTextContext) && SW path rendering | 826 // (kGlyphMaskStage in GrTextContext) && SW path rendering |
811 // (kPathMaskStage in GrSWMaskHelper) | 827 // (kPathMaskStage in GrSWMaskHelper) |
812 kEdgeEffectStage = GrPaint::kTotalStages, | 828 kEdgeEffectStage = GrPaint::kTotalStages, |
813 }; | 829 }; |
814 static const int kEdgeAttrIndex = 1; | 830 static const int kEdgeAttrIndex = 1; |
815 | 831 |
816 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); | 832 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); |
817 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); | 833 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); |
818 | 834 |
835 // Check devBounds | |
836 #if GR_DEBUG | |
robertphillips
2013/05/20 13:50:42
I have needed an SkRect::contains with a tolerance
| |
837 SkRect tolDevBounds = devBounds; | |
838 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); | |
839 SkRect actualBounds; | |
840 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); | |
841 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt; | |
842 bool first = true; | |
843 for (int i = 0; i < vCount; ++i) { | |
844 SkPoint pos = verts[i].fPos; | |
845 // This is a hack to workaround the fact that we move some degenerate se gments offscreen. | |
846 if (SK_ScalarMax == pos.fX) { | |
847 continue; | |
848 } | |
849 drawState->getViewMatrix().mapPoints(&pos, 1); | |
850 if (first) { | |
851 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); | |
852 first = false; | |
853 } else { | |
854 actualBounds.growToInclude(pos.fX, pos.fY); | |
855 } | |
856 } | |
857 if (!first) { | |
858 GrAssert(tolDevBounds.contains(actualBounds)); | |
859 } | |
860 #endif | |
861 | |
819 target->setIndexSourceToBuffer(fLinesIndexBuffer); | 862 target->setIndexSourceToBuffer(fLinesIndexBuffer); |
820 int lines = 0; | 863 int lines = 0; |
821 int nBufLines = fLinesIndexBuffer->maxQuads(); | 864 int nBufLines = fLinesIndexBuffer->maxQuads(); |
822 drawState->setEffect(kEdgeEffectStage, hairLineEffect, kEdgeAttrIndex)->unre f(); | 865 drawState->setEffect(kEdgeEffectStage, hairLineEffect, kEdgeAttrIndex)->unre f(); |
823 while (lines < lineCnt) { | 866 while (lines < lineCnt) { |
824 int n = GrMin(lineCnt - lines, nBufLines); | 867 int n = GrMin(lineCnt - lines, nBufLines); |
825 target->drawIndexed(kTriangles_GrPrimitiveType, | 868 target->drawIndexed(kTriangles_GrPrimitiveType, |
826 kVertsPerLineSeg*lines, // startV | 869 kVertsPerLineSeg*lines, // startV |
827 0, // startI | 870 0, // startI |
828 kVertsPerLineSeg*n, // vCount | 871 kVertsPerLineSeg*n, // vCount |
829 kIdxsPerLineSeg*n); // iCount | 872 kIdxsPerLineSeg*n, |
873 &devBounds); // iCount | |
830 lines += n; | 874 lines += n; |
831 } | 875 } |
832 | 876 |
833 target->setIndexSourceToBuffer(fQuadsIndexBuffer); | 877 target->setIndexSourceToBuffer(fQuadsIndexBuffer); |
834 int quads = 0; | 878 int quads = 0; |
835 drawState->setEffect(kEdgeEffectStage, hairQuadEffect, kEdgeAttrIndex)->unre f(); | 879 drawState->setEffect(kEdgeEffectStage, hairQuadEffect, kEdgeAttrIndex)->unre f(); |
836 while (quads < quadCnt) { | 880 while (quads < quadCnt) { |
837 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); | 881 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); |
838 target->drawIndexed(kTriangles_GrPrimitiveType, | 882 target->drawIndexed(kTriangles_GrPrimitiveType, |
839 4 * lineCnt + kVertsPerQuad*quads, // startV | 883 4 * lineCnt + kVertsPerQuad*quads, // startV |
840 0, // startI | 884 0, // startI |
841 kVertsPerQuad*n, // vCount | 885 kVertsPerQuad*n, // vCount |
842 kIdxsPerQuad*n); // iCount | 886 kIdxsPerQuad*n, // iCount |
887 &devBounds); | |
843 quads += n; | 888 quads += n; |
844 } | 889 } |
845 target->resetIndexSource(); | 890 target->resetIndexSource(); |
846 | 891 |
847 return true; | 892 return true; |
848 } | 893 } |
OLD | NEW |