diff options
Diffstat (limited to 'src/gpu/GrOvalRenderer.cpp')
-rw-r--r-- | src/gpu/GrOvalRenderer.cpp | 137 |
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); } |