| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrAAHairLinePathRenderer.h" | 8 #include "GrAAHairLinePathRenderer.h" |
| 9 | 9 |
| 10 #include "GrContext.h" | 10 #include "GrContext.h" |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 | 21 |
| 22 #include "effects/GrBezierEffect.h" | 22 #include "effects/GrBezierEffect.h" |
| 23 | 23 |
| 24 namespace { | 24 namespace { |
| 25 // quadratics are rendered as 5-sided polys in order to bound the | 25 // quadratics are rendered as 5-sided polys in order to bound the |
| 26 // AA stroke around the center-curve. See comments in push_quad_index_buffer and | 26 // AA stroke around the center-curve. See comments in push_quad_index_buffer and |
| 27 // bloat_quad. Quadratics and conics share an index buffer | 27 // bloat_quad. Quadratics and conics share an index buffer |
| 28 static const int kVertsPerQuad = 5; | 28 static const int kVertsPerQuad = 5; |
| 29 static const int kIdxsPerQuad = 9; | 29 static const int kIdxsPerQuad = 9; |
| 30 | 30 |
| 31 // lines are rendered as: |
| 32 // *______________* |
| 33 // |\ -_______ /| |
| 34 // | \ \ / | |
| 35 // | *--------* | |
| 36 // | / ______/ \ | |
| 37 // */_-__________\* |
| 38 // For: 6 vertices and 18 indices (for 6 triangles) |
| 31 static const int kVertsPerLineSeg = 6; | 39 static const int kVertsPerLineSeg = 6; |
| 32 static const int kIdxsPerLineSeg = 12; | 40 static const int kIdxsPerLineSeg = 18; |
| 33 | 41 |
| 34 static const int kNumQuadsInIdxBuffer = 256; | 42 static const int kNumQuadsInIdxBuffer = 256; |
| 35 static const size_t kQuadIdxSBufize = kIdxsPerQuad * | 43 static const size_t kQuadIdxSBufize = kIdxsPerQuad * |
| 36 sizeof(uint16_t) * | 44 sizeof(uint16_t) * |
| 37 kNumQuadsInIdxBuffer; | 45 kNumQuadsInIdxBuffer; |
| 38 | 46 |
| 39 static const int kNumLineSegsInIdxBuffer = 256; | 47 static const int kNumLineSegsInIdxBuffer = 256; |
| 40 static const size_t kLineSegIdxSBufize = kIdxsPerLineSeg * | 48 static const size_t kLineSegIdxSBufize = kIdxsPerLineSeg * |
| 41 sizeof(uint16_t) * | 49 sizeof(uint16_t) * |
| 42 kNumLineSegsInIdxBuffer; | 50 kNumLineSegsInIdxBuffer; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 } | 91 } |
| 84 } | 92 } |
| 85 | 93 |
| 86 static bool push_line_index_data(GrIndexBuffer* lIdxBuffer) { | 94 static bool push_line_index_data(GrIndexBuffer* lIdxBuffer) { |
| 87 uint16_t* data = (uint16_t*) lIdxBuffer->lock(); | 95 uint16_t* data = (uint16_t*) lIdxBuffer->lock(); |
| 88 bool tempData = NULL == data; | 96 bool tempData = NULL == data; |
| 89 if (tempData) { | 97 if (tempData) { |
| 90 data = SkNEW_ARRAY(uint16_t, kNumLineSegsInIdxBuffer * kIdxsPerLineSeg); | 98 data = SkNEW_ARRAY(uint16_t, kNumLineSegsInIdxBuffer * kIdxsPerLineSeg); |
| 91 } | 99 } |
| 92 for (int i = 0; i < kNumLineSegsInIdxBuffer; ++i) { | 100 for (int i = 0; i < kNumLineSegsInIdxBuffer; ++i) { |
| 93 // Each line segment is rendered as two quads, with alpha = 1 along the | 101 // Each line segment is rendered as two quads and two triangles. |
| 94 // spine of the segment, and alpha = 0 along the outer edges, represente
d | 102 // p0 and p1 have alpha = 1 while all other points have alpha = 0. |
| 95 // horizontally (i.e., the line equation is t*(p1-p0) + p0) | 103 // The four external points are offset 1 pixel perpendicular to the |
| 104 // line and half a pixel parallel to the line. |
| 96 // | 105 // |
| 97 // p4 p5 | 106 // p4 p5 |
| 98 // p0 p1 | 107 // p0 p1 |
| 99 // p2 p3 | 108 // p2 p3 |
| 100 // | 109 // |
| 101 // Each is drawn as four triangles specified by these 12 indices: | 110 // Each is drawn as six triangles specified by these 18 indices: |
| 102 int baseIdx = i * kIdxsPerLineSeg; | 111 int baseIdx = i * kIdxsPerLineSeg; |
| 103 uint16_t baseVert = (uint16_t)(i * kVertsPerLineSeg); | 112 uint16_t baseVert = (uint16_t)(i * kVertsPerLineSeg); |
| 104 data[0 + baseIdx] = baseVert + 0; // p0 | 113 data[0 + baseIdx] = baseVert + 0; |
| 105 data[1 + baseIdx] = baseVert + 1; // p1 | 114 data[1 + baseIdx] = baseVert + 1; |
| 106 data[2 + baseIdx] = baseVert + 2; // p2 | 115 data[2 + baseIdx] = baseVert + 3; |
| 107 | 116 |
| 108 data[3 + baseIdx] = baseVert + 2; // p2 | 117 data[3 + baseIdx] = baseVert + 0; |
| 109 data[4 + baseIdx] = baseVert + 1; // p1 | 118 data[4 + baseIdx] = baseVert + 3; |
| 110 data[5 + baseIdx] = baseVert + 3; // p3 | 119 data[5 + baseIdx] = baseVert + 2; |
| 111 | 120 |
| 112 data[6 + baseIdx] = baseVert + 0; // p0 | 121 data[6 + baseIdx] = baseVert + 0; |
| 113 data[7 + baseIdx] = baseVert + 5; // p5 | 122 data[7 + baseIdx] = baseVert + 4; |
| 114 data[8 + baseIdx] = baseVert + 1; // p1 | 123 data[8 + baseIdx] = baseVert + 5; |
| 115 | 124 |
| 116 data[9 + baseIdx] = baseVert + 0; // p0 | 125 data[9 + baseIdx] = baseVert + 0; |
| 117 data[10+ baseIdx] = baseVert + 4; // p4 | 126 data[10+ baseIdx] = baseVert + 5; |
| 118 data[11+ baseIdx] = baseVert + 5; // p5 | 127 data[11+ baseIdx] = baseVert + 1; |
| 128 |
| 129 data[12 + baseIdx] = baseVert + 0; |
| 130 data[13 + baseIdx] = baseVert + 2; |
| 131 data[14 + baseIdx] = baseVert + 4; |
| 132 |
| 133 data[15 + baseIdx] = baseVert + 1; |
| 134 data[16 + baseIdx] = baseVert + 5; |
| 135 data[17 + baseIdx] = baseVert + 3; |
| 119 } | 136 } |
| 120 if (tempData) { | 137 if (tempData) { |
| 121 bool ret = lIdxBuffer->updateData(data, kLineSegIdxSBufize); | 138 bool ret = lIdxBuffer->updateData(data, kLineSegIdxSBufize); |
| 122 delete[] data; | 139 delete[] data; |
| 123 return ret; | 140 return ret; |
| 124 } else { | 141 } else { |
| 125 lIdxBuffer->unlock(); | 142 lIdxBuffer->unlock(); |
| 126 return true; | 143 return true; |
| 127 } | 144 } |
| 128 } | 145 } |
| (...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 642 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds); | 659 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds); |
| 643 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds); | 660 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds); |
| 644 } else { | 661 } else { |
| 645 bloat_quad(p, toDevice, toSrc, *vert, devBounds); | 662 bloat_quad(p, toDevice, toSrc, *vert, devBounds); |
| 646 set_uv_quad(p, *vert); | 663 set_uv_quad(p, *vert); |
| 647 *vert += kVertsPerQuad; | 664 *vert += kVertsPerQuad; |
| 648 } | 665 } |
| 649 } | 666 } |
| 650 | 667 |
| 651 void add_line(const SkPoint p[2], | 668 void add_line(const SkPoint p[2], |
| 652 int rtHeight, | |
| 653 const SkMatrix* toSrc, | 669 const SkMatrix* toSrc, |
| 654 GrColor coverage, | 670 GrColor coverage, |
| 655 LineVertex** vert) { | 671 LineVertex** vert) { |
| 656 const SkPoint& a = p[0]; | 672 const SkPoint& a = p[0]; |
| 657 const SkPoint& b = p[1]; | 673 const SkPoint& b = p[1]; |
| 658 | 674 |
| 659 SkVector orthVec = b; | 675 SkVector ortho, vec = b; |
| 660 orthVec -= a; | 676 vec -= a; |
| 661 | 677 |
| 662 if (orthVec.setLength(SK_Scalar1)) { | 678 if (vec.setLength(SK_ScalarHalf)) { |
| 663 orthVec.setOrthog(orthVec); | 679 // Create a vector orthogonal to 'vec' and of unit length |
| 680 ortho.fX = 2.0f * vec.fY; |
| 681 ortho.fY = -2.0f * vec.fX; |
| 664 | 682 |
| 665 for (int i = 0; i < kVertsPerLineSeg; ++i) { | 683 (*vert)[0].fPos = a; |
| 666 (*vert)[i].fPos = (i & 0x1) ? b : a; | 684 (*vert)[0].fCoverage = coverage; |
| 667 if (i & 0x2) { | 685 (*vert)[1].fPos = b; |
| 668 (*vert)[i].fPos += orthVec; | 686 (*vert)[1].fCoverage = coverage; |
| 669 (*vert)[i].fCoverage = 0; | 687 (*vert)[2].fPos = a - vec + ortho; |
| 670 } else if (i & 0x4) { | 688 (*vert)[2].fCoverage = 0; |
| 671 (*vert)[i].fPos -= orthVec; | 689 (*vert)[3].fPos = b + vec + ortho; |
| 672 (*vert)[i].fCoverage = 0; | 690 (*vert)[3].fCoverage = 0; |
| 673 } else { | 691 (*vert)[4].fPos = a - vec - ortho; |
| 674 (*vert)[i].fCoverage = coverage; | 692 (*vert)[4].fCoverage = 0; |
| 675 } | 693 (*vert)[5].fPos = b + vec - ortho; |
| 676 } | 694 (*vert)[5].fCoverage = 0; |
| 695 |
| 677 if (NULL != toSrc) { | 696 if (NULL != toSrc) { |
| 678 toSrc->mapPointsWithStride(&(*vert)->fPos, | 697 toSrc->mapPointsWithStride(&(*vert)->fPos, |
| 679 sizeof(LineVertex), | 698 sizeof(LineVertex), |
| 680 kVertsPerLineSeg); | 699 kVertsPerLineSeg); |
| 681 } | 700 } |
| 682 } else { | 701 } else { |
| 683 // just make it degenerate and likely offscreen | 702 // just make it degenerate and likely offscreen |
| 684 for (int i = 0; i < kVertsPerLineSeg; ++i) { | 703 for (int i = 0; i < kVertsPerLineSeg; ++i) { |
| 685 (*vert)[i].fPos.set(SK_ScalarMax, SK_ScalarMax); | 704 (*vert)[i].fPos.set(SK_ScalarMax, SK_ScalarMax); |
| 686 } | 705 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 702 }; | 721 }; |
| 703 | 722 |
| 704 // position + coverage | 723 // position + coverage |
| 705 extern const GrVertexAttrib gHairlineLineAttribs[] = { | 724 extern const GrVertexAttrib gHairlineLineAttribs[] = { |
| 706 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBindin
g}, | 725 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBindin
g}, |
| 707 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBindin
g}, | 726 {kVec4ub_GrVertexAttribType, sizeof(GrPoint), kCoverage_GrVertexAttribBindin
g}, |
| 708 }; | 727 }; |
| 709 | 728 |
| 710 }; | 729 }; |
| 711 | 730 |
| 712 bool GrAAHairLinePathRenderer::createLineGeom( | 731 bool GrAAHairLinePathRenderer::createLineGeom(const SkPath& path, |
| 713 const SkPath& path, | 732 GrDrawTarget* target, |
| 714 GrDrawTarget* target, | 733 const PtArray& lines, |
| 715 const PtArray& lines, | 734 int lineCnt, |
| 716 int lineCnt, | 735 GrDrawTarget::AutoReleaseGeometry*
arg, |
| 717 GrDrawTarget::AutoReleaseGeometry* arg, | 736 SkRect* devBounds) { |
| 718 SkRect* devBounds) { | |
| 719 GrDrawState* drawState = target->drawState(); | 737 GrDrawState* drawState = target->drawState(); |
| 720 int rtHeight = drawState->getRenderTarget()->height(); | |
| 721 | 738 |
| 722 const SkMatrix& viewM = drawState->getViewMatrix(); | 739 const SkMatrix& viewM = drawState->getViewMatrix(); |
| 723 | 740 |
| 724 devBounds->outset(SK_Scalar1, SK_Scalar1); | 741 devBounds->outset(SK_Scalar1, SK_Scalar1); |
| 725 | 742 |
| 726 int vertCnt = kVertsPerLineSeg * lineCnt; | 743 int vertCnt = kVertsPerLineSeg * lineCnt; |
| 727 | 744 |
| 728 target->drawState()->setVertexAttribs<gHairlineLineAttribs>(SK_ARRAY_COUNT(g
HairlineLineAttribs)); | 745 drawState->setVertexAttribs<gHairlineLineAttribs>(SK_ARRAY_COUNT(gHairlineLi
neAttribs)); |
| 729 SkASSERT(sizeof(LineVertex) == target->getDrawState().getVertexSize()); | 746 SkASSERT(sizeof(LineVertex) == drawState->getVertexSize()); |
| 730 | 747 |
| 731 if (!arg->set(target, vertCnt, 0)) { | 748 if (!arg->set(target, vertCnt, 0)) { |
| 732 return false; | 749 return false; |
| 733 } | 750 } |
| 734 | 751 |
| 735 LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices()); | 752 LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices()); |
| 736 | 753 |
| 737 const SkMatrix* toSrc = NULL; | 754 const SkMatrix* toSrc = NULL; |
| 738 SkMatrix ivm; | 755 SkMatrix ivm; |
| 739 | 756 |
| 740 if (viewM.hasPerspective()) { | 757 if (viewM.hasPerspective()) { |
| 741 if (viewM.invert(&ivm)) { | 758 if (viewM.invert(&ivm)) { |
| 742 toSrc = &ivm; | 759 toSrc = &ivm; |
| 743 } | 760 } |
| 744 } | 761 } |
| 745 devBounds->set(lines.begin(), lines.count()); | 762 devBounds->set(lines.begin(), lines.count()); |
| 746 for (int i = 0; i < lineCnt; ++i) { | 763 for (int i = 0; i < lineCnt; ++i) { |
| 747 add_line(&lines[2*i], rtHeight, toSrc, drawState->getCoverage(), &verts)
; | 764 add_line(&lines[2*i], toSrc, drawState->getCoverage(), &verts); |
| 748 } | 765 } |
| 749 // All the verts computed by add_line are within unit distance of the end po
ints. Add a little | 766 // All the verts computed by add_line are within unit distance of the end po
ints. Add a little |
| 750 // extra to account for vector normalization precision. | 767 // extra to account for vector normalization precision. |
| 751 static const SkScalar kOutset = SK_Scalar1 + SK_Scalar1 / 20; | 768 static const SkScalar kOutset = SK_Scalar1 + SK_Scalar1 / 20; |
| 752 devBounds->outset(kOutset, kOutset); | 769 devBounds->outset(kOutset, kOutset); |
| 753 | 770 |
| 754 return true; | 771 return true; |
| 755 } | 772 } |
| 756 | 773 |
| 757 bool GrAAHairLinePathRenderer::createBezierGeom( | 774 bool GrAAHairLinePathRenderer::createBezierGeom( |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 903 target, | 920 target, |
| 904 lines, | 921 lines, |
| 905 lineCnt, | 922 lineCnt, |
| 906 &arg, | 923 &arg, |
| 907 &devBounds)) { | 924 &devBounds)) { |
| 908 return false; | 925 return false; |
| 909 } | 926 } |
| 910 | 927 |
| 911 GrDrawTarget::AutoStateRestore asr; | 928 GrDrawTarget::AutoStateRestore asr; |
| 912 | 929 |
| 913 // createGeom transforms the geometry to device space when the matrix do
es not have | 930 // createLineGeom transforms the geometry to device space when the matri
x does not have |
| 914 // perspective. | 931 // perspective. |
| 915 if (target->getDrawState().getViewMatrix().hasPerspective()) { | 932 if (target->getDrawState().getViewMatrix().hasPerspective()) { |
| 916 asr.set(target, GrDrawTarget::kPreserve_ASRInit); | 933 asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
| 917 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { | 934 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
| 918 return false; | 935 return false; |
| 919 } | 936 } |
| 920 GrDrawState* drawState = target->drawState(); | 937 GrDrawState* drawState = target->drawState(); |
| 921 | 938 |
| 922 // Check devBounds | 939 // Check devBounds |
| 923 SkASSERT(check_bounds<LineVertex>(drawState, devBounds, arg.vertices(), | 940 SkASSERT(check_bounds<LineVertex>(drawState, devBounds, arg.vertices(), |
| 924 kVertsPerLineSeg * lineCnt)); | 941 kVertsPerLineSeg * lineCnt)); |
| 925 | 942 |
| 926 { | 943 { |
| 927 GrDrawState::AutoRestoreEffects are(drawState); | 944 GrDrawState::AutoRestoreEffects are(drawState); |
| 928 target->setIndexSourceToBuffer(fLinesIndexBuffer); | 945 target->setIndexSourceToBuffer(fLinesIndexBuffer); |
| 929 int lines = 0; | 946 int lines = 0; |
| 930 while (lines < lineCnt) { | 947 while (lines < lineCnt) { |
| 931 int n = GrMin(lineCnt - lines, kNumLineSegsInIdxBuffer); | 948 int n = GrMin(lineCnt - lines, kNumLineSegsInIdxBuffer); |
| 932 target->drawIndexed(kTriangles_GrPrimitiveType, | 949 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 933 kVertsPerLineSeg*lines, // startV | 950 kVertsPerLineSeg*lines, // startV |
| 934 0, // startI | 951 0, // startI |
| 935 kVertsPerLineSeg*n, // vCount | 952 kVertsPerLineSeg*n, // vCount |
| 936 kIdxsPerLineSeg*n, | 953 kIdxsPerLineSeg*n, // iCount |
| 937 &devBounds); // iCount | 954 &devBounds); |
| 938 lines += n; | 955 lines += n; |
| 939 } | 956 } |
| 940 } | 957 } |
| 941 } | 958 } |
| 942 | 959 |
| 943 // then quadratics/conics | 960 // then quadratics/conics |
| 944 if (quadCnt || conicCnt) { | 961 if (quadCnt || conicCnt) { |
| 945 GrDrawTarget::AutoReleaseGeometry arg; | 962 GrDrawTarget::AutoReleaseGeometry arg; |
| 946 SkRect devBounds; | 963 SkRect devBounds; |
| 947 | 964 |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1012 &devBounds); | 1029 &devBounds); |
| 1013 conics += n; | 1030 conics += n; |
| 1014 } | 1031 } |
| 1015 } | 1032 } |
| 1016 } | 1033 } |
| 1017 | 1034 |
| 1018 target->resetIndexSource(); | 1035 target->resetIndexSource(); |
| 1019 | 1036 |
| 1020 return true; | 1037 return true; |
| 1021 } | 1038 } |
| OLD | NEW |