aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/gpu/GrOvalRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gpu/GrOvalRenderer.cpp')
-rw-r--r--src/gpu/GrOvalRenderer.cpp137
1 files changed, 77 insertions, 60 deletions
diff --git a/src/gpu/GrOvalRenderer.cpp b/src/gpu/GrOvalRenderer.cpp
index 61f27f4b90..731964c2d7 100644
--- a/src/gpu/GrOvalRenderer.cpp
+++ b/src/gpu/GrOvalRenderer.cpp
@@ -21,19 +21,18 @@ SK_DEFINE_INST_COUNT(GrOvalRenderer)
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 @@ inline bool circle_stays_circle(const SkMatrix& m) {
/**
* 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 @@ public:
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 @@ GrEffectRef* CircleEdgeEffect::TestCreate(SkMWCRandom* random,
/**
* 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 @@ public:
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());
-
- // 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");
+ builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetsName, attr1Name->c_str());
+
+ // 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 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target,
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 @@ void GrOvalRenderer::drawCircle(GrDrawTarget* target,
);
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 @@ void GrOvalRenderer::drawEllipse(GrDrawTarget* target,
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;
+
+ SkRect bounds = SkRect::MakeLTRB(
+ center.fX - xRadius,
+ center.fY - yRadius,
+ center.fX + xRadius,
+ center.fY + yRadius
+ );
- SkScalar L = -xRadius;
- SkScalar R = +xRadius;
- SkScalar T = -yRadius;
- SkScalar B = +yRadius;
+ // 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);
- // 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;
-
- 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);
-
- target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4);
+ 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);
+
+ 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);
+
+ target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds);
}