Index: src/gpu/GrOvalRenderer.cpp |
=================================================================== |
--- src/gpu/GrOvalRenderer.cpp (revision 8596) |
+++ src/gpu/GrOvalRenderer.cpp (working copy) |
@@ -21,19 +21,18 @@ |
namespace { |
struct CircleVertex { |
- GrPoint fPos; |
- GrPoint fCenter; |
+ GrPoint fPos; |
+ GrPoint fOffset; |
SkScalar fOuterRadius; |
SkScalar fInnerRadius; |
}; |
struct EllipseVertex { |
- GrPoint fPos; |
- GrPoint fCenter; |
+ GrPoint fPos; |
SkScalar fOuterXRadius; |
- SkScalar fOuterXYRatio; |
SkScalar fInnerXRadius; |
- SkScalar fInnerXYRatio; |
+ GrPoint fOuterOffset; |
+ GrPoint fInnerOffset; |
}; |
inline bool circle_stays_circle(const SkMatrix& m) { |
@@ -46,8 +45,7 @@ |
/** |
* The output of this effect is a modulation of the input color and coverage for a circle, |
- * specified as center_x, center_y, x_radius, inner radius and outer radius in window space |
- * (y-down). |
+ * specified as offset_x, offset_y (both from center point), outer radius and inner radius. |
*/ |
class CircleEdgeEffect : public GrEffect { |
@@ -102,13 +100,13 @@ |
builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); |
builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); |
- builder->fsCodeAppendf("\tfloat d = distance(%s.xy, %s.xy);\n", |
- builder->fragmentPosition(), fsName); |
+ builder->fsCodeAppendf("\tfloat d = length(%s.xy);\n", fsName); |
builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0);\n", fsName); |
if (circleEffect.isStroked()) { |
builder->fsCodeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0, 1.0);\n", fsName); |
builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n"); |
} |
+ |
SkString modulate; |
GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha"); |
builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()); |
@@ -158,7 +156,7 @@ |
/** |
* The output of this effect is a modulation of the input color and coverage for an axis-aligned |
- * ellipse, specified as center_x, center_y, x_radius, x_radius/y_radius in window space (y-down). |
+ * ellipse, specified as outer and inner radii, and outer and inner offsets from center. |
*/ |
class EllipseEdgeEffect : public GrEffect { |
@@ -207,37 +205,31 @@ |
const TextureSamplerArray& samplers) SK_OVERRIDE { |
const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<EllipseEdgeEffect>(); |
- const char *vsCenterName, *fsCenterName; |
- const char *vsEdgeName, *fsEdgeName; |
+ const char *vsRadiiName, *fsRadiiName; |
+ const char *vsOffsetsName, *fsOffsetsName; |
- builder->addVarying(kVec2f_GrSLType, "EllipseCenter", &vsCenterName, &fsCenterName); |
+ builder->addVarying(kVec2f_GrSLType, "EllipseRadii", &vsRadiiName, &fsRadiiName); |
const SkString* attr0Name = |
builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); |
- builder->vsCodeAppendf("\t%s = %s;\n", vsCenterName, attr0Name->c_str()); |
+ builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr0Name->c_str()); |
- builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsEdgeName, &fsEdgeName); |
+ builder->addVarying(kVec4f_GrSLType, "EllipseOffsets", &vsOffsetsName, &fsOffsetsName); |
const SkString* attr1Name = |
builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[1]); |
- builder->vsCodeAppendf("\t%s = %s;\n", vsEdgeName, attr1Name->c_str()); |
+ builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetsName, attr1Name->c_str()); |
- // translate to origin |
- builder->fsCodeAppendf("\tvec2 outerOffset = (%s.xy - %s.xy);\n", |
- builder->fragmentPosition(), fsCenterName); |
- builder->fsCodeAppend("\tvec2 innerOffset = outerOffset;\n"); |
- // scale y by xRadius/yRadius |
- builder->fsCodeAppendf("\touterOffset.y *= %s.y;\n", fsEdgeName); |
- builder->fsCodeAppend("\tfloat dOuter = length(outerOffset);\n"); |
+ // get length of offset |
+ builder->fsCodeAppendf("\tfloat dOuter = length(%s.xy);\n", fsOffsetsName); |
// compare outer lengths against xOuterRadius |
builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0, 1.0);\n", |
- fsEdgeName); |
+ fsRadiiName); |
if (ellipseEffect.isStroked()) { |
- builder->fsCodeAppendf("\tinnerOffset.y *= %s.w;\n", fsEdgeName); |
- builder->fsCodeAppend("\tfloat dInner = length(innerOffset);\n"); |
+ builder->fsCodeAppendf("\tfloat dInner = length(%s.zw);\n", fsOffsetsName); |
// compare inner lengths against xInnerRadius |
- builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.z, 0.0, 1.0);\n", |
- fsEdgeName); |
+ builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.y, 0.0, 1.0);\n", |
+ fsRadiiName); |
builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n"); |
} |
@@ -384,12 +376,6 @@ |
outerRadius += SK_ScalarHalf; |
innerRadius -= SK_ScalarHalf; |
- for (int i = 0; i < 4; ++i) { |
- verts[i].fCenter = center; |
- verts[i].fOuterRadius = outerRadius; |
- verts[i].fInnerRadius = innerRadius; |
- } |
- |
SkRect bounds = SkRect::MakeLTRB( |
center.fX - outerRadius, |
center.fY - outerRadius, |
@@ -398,9 +384,24 @@ |
); |
verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); |
+ verts[0].fOffset = SkPoint::Make(-outerRadius, -outerRadius); |
+ verts[0].fOuterRadius = outerRadius; |
+ verts[0].fInnerRadius = innerRadius; |
+ |
verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); |
+ verts[1].fOffset = SkPoint::Make(outerRadius, -outerRadius); |
+ verts[1].fOuterRadius = outerRadius; |
+ verts[1].fInnerRadius = innerRadius; |
+ |
verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); |
+ verts[2].fOffset = SkPoint::Make(-outerRadius, outerRadius); |
+ verts[2].fOuterRadius = outerRadius; |
+ verts[2].fInnerRadius = innerRadius; |
+ |
verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); |
+ verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius); |
+ verts[3].fOuterRadius = outerRadius; |
+ verts[3].fInnerRadius = innerRadius; |
target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); |
} |
@@ -495,30 +496,46 @@ |
SkScalar outerRatio = SkScalarDiv(xRadius, yRadius); |
- for (int i = 0; i < 4; ++i) { |
- verts[i].fCenter = center; |
- verts[i].fOuterXRadius = xRadius + 0.5f; |
- verts[i].fOuterXYRatio = outerRatio; |
- verts[i].fInnerXRadius = innerXRadius - 0.5f; |
- verts[i].fInnerXYRatio = innerRatio; |
- } |
+ // We've extended the outer x radius out half a pixel to antialias. |
+ // This will also expand the rect so all the pixels will be captured. |
+ xRadius += SK_ScalarHalf; |
+ yRadius += SK_ScalarHalf; |
+ innerXRadius -= SK_ScalarHalf; |
- SkScalar L = -xRadius; |
- SkScalar R = +xRadius; |
- SkScalar T = -yRadius; |
- SkScalar B = +yRadius; |
+ SkRect bounds = SkRect::MakeLTRB( |
+ center.fX - xRadius, |
+ center.fY - yRadius, |
+ center.fX + xRadius, |
+ center.fY + yRadius |
+ ); |
- // We've extended the outer x radius out half a pixel to antialias. |
- // Expand the drawn rect here so all the pixels will be captured. |
- L += center.fX - SK_ScalarHalf; |
- R += center.fX + SK_ScalarHalf; |
- T += center.fY - SK_ScalarHalf; |
- B += center.fY + SK_ScalarHalf; |
+ // The offsets are created by scaling the y radius by the appropriate ratio. This way we end up |
+ // with a circle equation which can be checked quickly in the shader. We need one offset for |
+ // outer and one for inner because they have different scale factors -- otherwise we end up with |
+ // non-uniform strokes. |
+ verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); |
+ verts[0].fOuterXRadius = xRadius; |
+ verts[0].fInnerXRadius = innerXRadius; |
+ verts[0].fOuterOffset = SkPoint::Make(-xRadius, -outerRatio*yRadius); |
+ verts[0].fInnerOffset = SkPoint::Make(-xRadius, -innerRatio*yRadius); |
- verts[0].fPos = SkPoint::Make(L, T); |
- verts[1].fPos = SkPoint::Make(R, T); |
- verts[2].fPos = SkPoint::Make(L, B); |
- verts[3].fPos = SkPoint::Make(R, B); |
+ verts[1].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); |
+ verts[1].fOuterXRadius = xRadius; |
+ verts[1].fInnerXRadius = innerXRadius; |
+ verts[1].fOuterOffset = SkPoint::Make(xRadius, -outerRatio*yRadius); |
+ verts[1].fInnerOffset = SkPoint::Make(xRadius, -innerRatio*yRadius); |
- target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); |
+ verts[2].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); |
+ verts[2].fOuterXRadius = xRadius; |
+ verts[2].fInnerXRadius = innerXRadius; |
+ verts[2].fOuterOffset = SkPoint::Make(-xRadius, outerRatio*yRadius); |
+ verts[2].fInnerOffset = SkPoint::Make(-xRadius, innerRatio*yRadius); |
+ |
+ verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); |
+ verts[3].fOuterXRadius = xRadius; |
+ verts[3].fInnerXRadius = innerXRadius; |
+ verts[3].fOuterOffset = SkPoint::Make(xRadius, outerRatio*yRadius); |
+ verts[3].fInnerOffset = SkPoint::Make(xRadius, innerRatio*yRadius); |
+ |
robertphillips
2013/04/10 23:18:39
For the rect edge passing the bounds actually slow
|
+ target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); |
} |