OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 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 "GrOvalRenderer.h" | 8 #include "GrOvalRenderer.h" |
9 | 9 |
10 #include "GrProcessor.h" | 10 #include "GrProcessor.h" |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
46 | 46 |
47 inline bool circle_stays_circle(const SkMatrix& m) { | 47 inline bool circle_stays_circle(const SkMatrix& m) { |
48 return m.isSimilarity(); | 48 return m.isSimilarity(); |
49 } | 49 } |
50 | 50 |
51 } | 51 } |
52 | 52 |
53 /////////////////////////////////////////////////////////////////////////////// | 53 /////////////////////////////////////////////////////////////////////////////// |
54 | 54 |
55 /** | 55 /** |
56 * The output of this effect is a modulation of the input color and coverage for
a circle, | 56 * The output of this effect is a modulation of the input color and coverage for
a circle. It |
57 * specified as offset_x, offset_y (both from center point), outer radius and in
ner radius. | 57 * operates in a space normalized by the circle radius (outer radius in the case
of a stroke) |
| 58 * with origin at the circle center. Two vertex attributes are used: |
| 59 * vec2f : position in device space of the bounding geometry vertices |
| 60 * vec4f : (p.xy, outerRad, innerRad) |
| 61 * p is the position in the normalized space. |
| 62 * outerRad is the outerRadius in device space. |
| 63 * innerRad is the innerRadius in normalized space (ignored if not s
troking). |
58 */ | 64 */ |
59 | 65 |
60 class CircleEdgeEffect : public GrGeometryProcessor { | 66 class CircleEdgeEffect : public GrGeometryProcessor { |
61 public: | 67 public: |
62 static GrGeometryProcessor* Create(GrColor color, bool stroke) { | 68 static GrGeometryProcessor* Create(GrColor color, bool stroke) { |
63 return SkNEW_ARGS(CircleEdgeEffect, (color, stroke)); | 69 return SkNEW_ARGS(CircleEdgeEffect, (color, stroke)); |
64 } | 70 } |
65 | 71 |
66 const GrAttribute* inPosition() const { return fInPosition; } | 72 const GrAttribute* inPosition() const { return fInPosition; } |
67 const GrAttribute* inCircleEdge() const { return fInCircleEdge; } | 73 const GrAttribute* inCircleEdge() const { return fInCircleEdge; } |
(...skipping 19 matching lines...) Expand all Loading... |
87 // setup coord outputs | 93 // setup coord outputs |
88 vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), ce.i
nPosition()->fName); | 94 vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), ce.i
nPosition()->fName); |
89 vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), ce.inPo
sition()->fName); | 95 vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), ce.inPo
sition()->fName); |
90 | 96 |
91 // setup position varying | 97 // setup position varying |
92 vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPositi
on(), | 98 vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPositi
on(), |
93 vsBuilder->uViewM(), ce.inPosition()->fName); | 99 vsBuilder->uViewM(), ce.inPosition()->fName); |
94 | 100 |
95 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde
r(); | 101 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilde
r(); |
96 fsBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn()); | 102 fsBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn()); |
97 fsBuilder->codeAppendf("float edgeAlpha = clamp(%s.z - d, 0.0, 1.0);
", v.fsIn()); | 103 fsBuilder->codeAppendf("float edgeAlpha = clamp(%s.z * (1.0 - d), 0.
0, 1.0);", v.fsIn()); |
98 if (ce.isStroked()) { | 104 if (ce.isStroked()) { |
99 fsBuilder->codeAppendf("float innerAlpha = clamp(d - %s.w, 0.0,
1.0);", | 105 fsBuilder->codeAppendf("float innerAlpha = clamp(%s.z * (d - %s.
w), 0.0, 1.0);", |
100 v.fsIn()); | 106 v.fsIn(), v.fsIn()); |
101 fsBuilder->codeAppend("edgeAlpha *= innerAlpha;"); | 107 fsBuilder->codeAppend("edgeAlpha *= innerAlpha;"); |
102 } | 108 } |
103 | 109 |
104 fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage
); | 110 fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage
); |
105 } | 111 } |
106 | 112 |
107 static void GenKey(const GrGeometryProcessor& processor, | 113 static void GenKey(const GrGeometryProcessor& processor, |
108 const GrBatchTracker&, | 114 const GrBatchTracker&, |
109 const GrGLCaps&, | 115 const GrGLCaps&, |
110 GrProcessorKeyBuilder* b) { | 116 GrProcessorKeyBuilder* b) { |
(...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
567 | 573 |
568 GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(), 0); | 574 GrDrawTarget::AutoReleaseGeometry geo(target, 4, gp->getVertexStride(), 0); |
569 SkASSERT(gp->getVertexStride() == sizeof(CircleVertex)); | 575 SkASSERT(gp->getVertexStride() == sizeof(CircleVertex)); |
570 if (!geo.succeeded()) { | 576 if (!geo.succeeded()) { |
571 SkDebugf("Failed to get space for vertices!\n"); | 577 SkDebugf("Failed to get space for vertices!\n"); |
572 return; | 578 return; |
573 } | 579 } |
574 | 580 |
575 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); | 581 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); |
576 | 582 |
577 // The radii are outset for two reasons. First, it allows the shader to simp
ly perform | 583 // The radii are outset for two reasons. First, it allows the shader to simp
ly perform simpler |
578 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is use
d to compute the | 584 // computation because the computed alpha is zero, rather than 50%, at the r
adius. |
579 // verts of the bounding box that is rendered and the outset ensures the box
will cover all | 585 // Second, the outer radius is used to compute the verts of the bounding box
that is rendered |
580 // pixels partially covered by the circle. | 586 // and the outset ensures the box will cover all partially covered by the ci
rcle. |
581 outerRadius += SK_ScalarHalf; | 587 outerRadius += SK_ScalarHalf; |
582 innerRadius -= SK_ScalarHalf; | 588 innerRadius -= SK_ScalarHalf; |
583 | 589 |
584 SkRect bounds = SkRect::MakeLTRB( | 590 SkRect bounds = SkRect::MakeLTRB( |
585 center.fX - outerRadius, | 591 center.fX - outerRadius, |
586 center.fY - outerRadius, | 592 center.fY - outerRadius, |
587 center.fX + outerRadius, | 593 center.fX + outerRadius, |
588 center.fY + outerRadius | 594 center.fY + outerRadius |
589 ); | 595 ); |
590 | 596 |
| 597 // The inner radius in the vertex data must be specified in normalized space
. |
| 598 innerRadius = innerRadius / outerRadius; |
591 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); | 599 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); |
592 verts[0].fOffset = SkPoint::Make(-outerRadius, -outerRadius); | 600 verts[0].fOffset = SkPoint::Make(-1, -1); |
593 verts[0].fOuterRadius = outerRadius; | 601 verts[0].fOuterRadius = outerRadius; |
594 verts[0].fInnerRadius = innerRadius; | 602 verts[0].fInnerRadius = innerRadius; |
595 | 603 |
596 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); | 604 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); |
597 verts[1].fOffset = SkPoint::Make(-outerRadius, outerRadius); | 605 verts[1].fOffset = SkPoint::Make(-1, 1); |
598 verts[1].fOuterRadius = outerRadius; | 606 verts[1].fOuterRadius = outerRadius; |
599 verts[1].fInnerRadius = innerRadius; | 607 verts[1].fInnerRadius = innerRadius; |
600 | 608 |
601 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); | 609 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); |
602 verts[2].fOffset = SkPoint::Make(outerRadius, outerRadius); | 610 verts[2].fOffset = SkPoint::Make(1, 1); |
603 verts[2].fOuterRadius = outerRadius; | 611 verts[2].fOuterRadius = outerRadius; |
604 verts[2].fInnerRadius = innerRadius; | 612 verts[2].fInnerRadius = innerRadius; |
605 | 613 |
606 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); | 614 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); |
607 verts[3].fOffset = SkPoint::Make(outerRadius, -outerRadius); | 615 verts[3].fOffset = SkPoint::Make(1, -1); |
608 verts[3].fOuterRadius = outerRadius; | 616 verts[3].fOuterRadius = outerRadius; |
609 verts[3].fInnerRadius = innerRadius; | 617 verts[3].fInnerRadius = innerRadius; |
610 | 618 |
611 target->setIndexSourceToBuffer(context->getGpu()->getQuadIndexBuffer()); | 619 target->setIndexSourceToBuffer(context->getGpu()->getQuadIndexBuffer()); |
612 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 4, 6,
&bounds); | 620 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 4, 6,
&bounds); |
613 target->resetIndexSource(); | 621 target->resetIndexSource(); |
614 } | 622 } |
615 | 623 |
616 /////////////////////////////////////////////////////////////////////////////// | 624 /////////////////////////////////////////////////////////////////////////////// |
617 | 625 |
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1082 | 1090 |
1083 GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStrid
e(), 0); | 1091 GrDrawTarget::AutoReleaseGeometry geo(target, 16, effect->getVertexStrid
e(), 0); |
1084 SkASSERT(effect->getVertexStride() == sizeof(CircleVertex)); | 1092 SkASSERT(effect->getVertexStride() == sizeof(CircleVertex)); |
1085 if (!geo.succeeded()) { | 1093 if (!geo.succeeded()) { |
1086 SkDebugf("Failed to get space for vertices!\n"); | 1094 SkDebugf("Failed to get space for vertices!\n"); |
1087 return false; | 1095 return false; |
1088 } | 1096 } |
1089 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); | 1097 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); |
1090 | 1098 |
1091 // The radii are outset for two reasons. First, it allows the shader to
simply perform | 1099 // The radii are outset for two reasons. First, it allows the shader to
simply perform |
1092 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is
used to compute the | 1100 // simpler computation because the computed alpha is zero, rather than 5
0%, at the radius. |
1093 // verts of the bounding box that is rendered and the outset ensures the
box will cover all | 1101 // Second, the outer radius is used to compute the verts of the bounding
box that is |
1094 // pixels partially covered by the circle. | 1102 // rendered and the outset ensures the box will cover all partially cove
red by the rrect |
| 1103 // corners. |
1095 outerRadius += SK_ScalarHalf; | 1104 outerRadius += SK_ScalarHalf; |
1096 innerRadius -= SK_ScalarHalf; | 1105 innerRadius -= SK_ScalarHalf; |
1097 | 1106 |
1098 // Expand the rect so all the pixels will be captured. | 1107 // Expand the rect so all the pixels will be captured. |
1099 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); | 1108 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); |
1100 | 1109 |
1101 SkScalar yCoords[4] = { | 1110 SkScalar yCoords[4] = { |
1102 bounds.fTop, | 1111 bounds.fTop, |
1103 bounds.fTop + outerRadius, | 1112 bounds.fTop + outerRadius, |
1104 bounds.fBottom - outerRadius, | 1113 bounds.fBottom - outerRadius, |
1105 bounds.fBottom | 1114 bounds.fBottom |
1106 }; | 1115 }; |
1107 SkScalar yOuterRadii[4] = { | 1116 SkScalar yOuterRadii[4] = {-1, 0, 0, 1 }; |
1108 -outerRadius, | 1117 // The inner radius in the vertex data must be specified in normalized s
pace. |
1109 0, | 1118 innerRadius = innerRadius / outerRadius; |
1110 0, | |
1111 outerRadius | |
1112 }; | |
1113 for (int i = 0; i < 4; ++i) { | 1119 for (int i = 0; i < 4; ++i) { |
1114 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); | 1120 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); |
1115 verts->fOffset = SkPoint::Make(-outerRadius, yOuterRadii[i]); | 1121 verts->fOffset = SkPoint::Make(-1, yOuterRadii[i]); |
1116 verts->fOuterRadius = outerRadius; | 1122 verts->fOuterRadius = outerRadius; |
1117 verts->fInnerRadius = innerRadius; | 1123 verts->fInnerRadius = innerRadius; |
1118 verts++; | 1124 verts++; |
1119 | 1125 |
1120 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]); | 1126 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]); |
1121 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); | 1127 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); |
1122 verts->fOuterRadius = outerRadius; | 1128 verts->fOuterRadius = outerRadius; |
1123 verts->fInnerRadius = innerRadius; | 1129 verts->fInnerRadius = innerRadius; |
1124 verts++; | 1130 verts++; |
1125 | 1131 |
1126 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i])
; | 1132 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i])
; |
1127 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); | 1133 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); |
1128 verts->fOuterRadius = outerRadius; | 1134 verts->fOuterRadius = outerRadius; |
1129 verts->fInnerRadius = innerRadius; | 1135 verts->fInnerRadius = innerRadius; |
1130 verts++; | 1136 verts++; |
1131 | 1137 |
1132 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); | 1138 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); |
1133 verts->fOffset = SkPoint::Make(outerRadius, yOuterRadii[i]); | 1139 verts->fOffset = SkPoint::Make(1, yOuterRadii[i]); |
1134 verts->fOuterRadius = outerRadius; | 1140 verts->fOuterRadius = outerRadius; |
1135 verts->fInnerRadius = innerRadius; | 1141 verts->fInnerRadius = innerRadius; |
1136 verts++; | 1142 verts++; |
1137 } | 1143 } |
1138 | 1144 |
1139 // drop out the middle quad if we're stroked | 1145 // drop out the middle quad if we're stroked |
1140 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 : | 1146 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 : |
1141 SK_ARRAY_COUNT(gRRectIndices); | 1147 SK_ARRAY_COUNT(gRRectIndices); |
1142 target->setIndexSourceToBuffer(indexBuffer); | 1148 target->setIndexSourceToBuffer(indexBuffer); |
1143 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 1
6, indexCnt, | 1149 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 1
6, indexCnt, |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1247 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 : | 1253 int indexCnt = isStrokeOnly ? SK_ARRAY_COUNT(gRRectIndices) - 6 : |
1248 SK_ARRAY_COUNT(gRRectIndices); | 1254 SK_ARRAY_COUNT(gRRectIndices); |
1249 target->setIndexSourceToBuffer(indexBuffer); | 1255 target->setIndexSourceToBuffer(indexBuffer); |
1250 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 1
6, indexCnt, | 1256 target->drawIndexedInstances(drawState, kTriangles_GrPrimitiveType, 1, 1
6, indexCnt, |
1251 &bounds); | 1257 &bounds); |
1252 } | 1258 } |
1253 | 1259 |
1254 target->resetIndexSource(); | 1260 target->resetIndexSource(); |
1255 return true; | 1261 return true; |
1256 } | 1262 } |
OLD | NEW |