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 |