| Index: src/gpu/GrOvalRenderer.cpp
|
| ===================================================================
|
| --- src/gpu/GrOvalRenderer.cpp (revision 8491)
|
| +++ src/gpu/GrOvalRenderer.cpp (working copy)
|
| @@ -7,8 +7,10 @@
|
|
|
| #include "GrOvalRenderer.h"
|
|
|
| -#include "effects/GrCircleEdgeEffect.h"
|
| -#include "effects/GrEllipseEdgeEffect.h"
|
| +#include "GrEffect.h"
|
| +#include "gl/GrGLEffect.h"
|
| +#include "gl/GrGLSL.h"
|
| +#include "GrTBackendEffectFactory.h"
|
|
|
| #include "GrDrawState.h"
|
| #include "GrDrawTarget.h"
|
| @@ -40,6 +42,253 @@
|
|
|
| }
|
|
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +/**
|
| + * 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).
|
| + */
|
| +
|
| +class CircleEdgeEffect : public GrEffect {
|
| +public:
|
| + static GrEffectRef* Create(bool stroke) {
|
| + // we go through this so we only have one copy of each effect (stroked/filled)
|
| + static SkAutoTUnref<GrEffectRef> gCircleStrokeEdgeEffectRef(
|
| + CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEffect, (true)))));
|
| + static SkAutoTUnref<GrEffectRef> gCircleFillEdgeEffectRef(
|
| + CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEffect, (false)))));
|
| +
|
| + if (stroke) {
|
| + gCircleStrokeEdgeEffectRef.get()->ref();
|
| + return gCircleStrokeEdgeEffectRef;
|
| + } else {
|
| + gCircleFillEdgeEffectRef.get()->ref();
|
| + return gCircleFillEdgeEffectRef;
|
| + }
|
| + }
|
| +
|
| + virtual void getConstantColorComponents(GrColor* color,
|
| + uint32_t* validFlags) const SK_OVERRIDE {
|
| + *validFlags = 0;
|
| + }
|
| +
|
| + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
|
| + return GrTBackendEffectFactory<CircleEdgeEffect>::getInstance();
|
| + }
|
| +
|
| + virtual ~CircleEdgeEffect() {}
|
| +
|
| + static const char* Name() { return "CircleEdge"; }
|
| +
|
| + inline bool isStroked() const { return fStroke; }
|
| +
|
| + class GLEffect : public GrGLEffect {
|
| + public:
|
| + GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
|
| + : INHERITED (factory) {}
|
| +
|
| + virtual void emitCode(GrGLShaderBuilder* builder,
|
| + const GrDrawEffect& drawEffect,
|
| + EffectKey key,
|
| + const char* outputColor,
|
| + const char* inputColor,
|
| + const TextureSamplerArray& samplers) SK_OVERRIDE {
|
| + const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleEdgeEffect>();
|
| + const char *vsName, *fsName;
|
| + builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName);
|
| +
|
| + const SkString* attrName =
|
| + 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 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());
|
| + }
|
| +
|
| + static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
|
| + const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleEdgeEffect>();
|
| +
|
| + return circleEffect.isStroked() ? 0x1 : 0x0;
|
| + }
|
| +
|
| + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {}
|
| +
|
| + private:
|
| + typedef GrGLEffect INHERITED;
|
| + };
|
| +
|
| +
|
| +private:
|
| + CircleEdgeEffect(bool stroke) : GrEffect() {
|
| + this->addVertexAttrib(kVec4f_GrSLType);
|
| + fStroke = stroke;
|
| + }
|
| +
|
| + virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
|
| + const CircleEdgeEffect& cee = CastEffect<CircleEdgeEffect>(other);
|
| + return cee.fStroke == fStroke;
|
| + }
|
| +
|
| + bool fStroke;
|
| +
|
| + GR_DECLARE_EFFECT_TEST;
|
| +
|
| + typedef GrEffect INHERITED;
|
| +};
|
| +
|
| +GR_DEFINE_EFFECT_TEST(CircleEdgeEffect);
|
| +
|
| +GrEffectRef* CircleEdgeEffect::TestCreate(SkMWCRandom* random,
|
| + GrContext* context,
|
| + const GrDrawTargetCaps&,
|
| + GrTexture* textures[]) {
|
| + return CircleEdgeEffect::Create(random->nextBool());
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +/**
|
| + * 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).
|
| + */
|
| +
|
| +class EllipseEdgeEffect : public GrEffect {
|
| +public:
|
| + static GrEffectRef* Create(bool stroke) {
|
| + // we go through this so we only have one copy of each effect (stroked/filled)
|
| + static SkAutoTUnref<GrEffectRef> gEllipseStrokeEdgeEffectRef(
|
| + CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEffect, (true)))));
|
| + static SkAutoTUnref<GrEffectRef> gEllipseFillEdgeEffectRef(
|
| + CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEffect, (false)))));
|
| +
|
| + if (stroke) {
|
| + gEllipseStrokeEdgeEffectRef.get()->ref();
|
| + return gEllipseStrokeEdgeEffectRef;
|
| + } else {
|
| + gEllipseFillEdgeEffectRef.get()->ref();
|
| + return gEllipseFillEdgeEffectRef;
|
| + }
|
| + }
|
| +
|
| + virtual void getConstantColorComponents(GrColor* color,
|
| + uint32_t* validFlags) const SK_OVERRIDE {
|
| + *validFlags = 0;
|
| + }
|
| +
|
| + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE {
|
| + return GrTBackendEffectFactory<EllipseEdgeEffect>::getInstance();
|
| + }
|
| +
|
| + virtual ~EllipseEdgeEffect() {}
|
| +
|
| + static const char* Name() { return "EllipseEdge"; }
|
| +
|
| + inline bool isStroked() const { return fStroke; }
|
| +
|
| + class GLEffect : public GrGLEffect {
|
| + public:
|
| + GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&)
|
| + : INHERITED (factory) {}
|
| +
|
| + virtual void emitCode(GrGLShaderBuilder* builder,
|
| + const GrDrawEffect& drawEffect,
|
| + EffectKey key,
|
| + const char* outputColor,
|
| + const char* inputColor,
|
| + const TextureSamplerArray& samplers) SK_OVERRIDE {
|
| + const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<EllipseEdgeEffect>();
|
| +
|
| + const char *vsCenterName, *fsCenterName;
|
| + const char *vsEdgeName, *fsEdgeName;
|
| +
|
| + builder->addVarying(kVec2f_GrSLType, "EllipseCenter", &vsCenterName, &fsCenterName);
|
| + const SkString* attr0Name =
|
| + builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]);
|
| + builder->vsCodeAppendf("\t%s = %s;\n", vsCenterName, attr0Name->c_str());
|
| +
|
| + builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsEdgeName, &fsEdgeName);
|
| + 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");
|
| + // compare outer lengths against xOuterRadius
|
| + builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0, 1.0);\n",
|
| + fsEdgeName);
|
| +
|
| + if (ellipseEffect.isStroked()) {
|
| + builder->fsCodeAppendf("\tinnerOffset.y *= %s.w;\n", fsEdgeName);
|
| + builder->fsCodeAppend("\tfloat dInner = length(innerOffset);\n");
|
| +
|
| + // compare inner lengths against xInnerRadius
|
| + builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.z, 0.0, 1.0);\n",
|
| + fsEdgeName);
|
| + builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n");
|
| + }
|
| +
|
| + SkString modulate;
|
| + GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha");
|
| + builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str());
|
| + }
|
| +
|
| + static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) {
|
| + const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<EllipseEdgeEffect>();
|
| +
|
| + return ellipseEffect.isStroked() ? 0x1 : 0x0;
|
| + }
|
| +
|
| + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE {
|
| + }
|
| +
|
| + private:
|
| + typedef GrGLEffect INHERITED;
|
| + };
|
| +
|
| +private:
|
| + EllipseEdgeEffect(bool stroke) : GrEffect() {
|
| + this->addVertexAttrib(kVec2f_GrSLType);
|
| + this->addVertexAttrib(kVec4f_GrSLType);
|
| + fStroke = stroke;
|
| + }
|
| +
|
| + virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE {
|
| + const EllipseEdgeEffect& eee = CastEffect<EllipseEdgeEffect>(other);
|
| + return eee.fStroke == fStroke;
|
| + }
|
| +
|
| + bool fStroke;
|
| +
|
| + GR_DECLARE_EFFECT_TEST;
|
| +
|
| + typedef GrEffect INHERITED;
|
| +};
|
| +
|
| +GR_DEFINE_EFFECT_TEST(EllipseEdgeEffect);
|
| +
|
| +GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random,
|
| + GrContext* context,
|
| + const GrDrawTargetCaps&,
|
| + GrTexture* textures[]) {
|
| + return EllipseEdgeEffect::Create(random->nextBool());
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, const GrPaint& paint,
|
| const GrRect& oval, const SkStrokeRec& stroke)
|
| {
|
| @@ -108,7 +357,7 @@
|
| kEdgeEffectStage = GrPaint::kTotalStages,
|
| };
|
|
|
| - GrEffectRef* effect = GrCircleEdgeEffect::Create(isStroked);
|
| + GrEffectRef* effect = CircleEdgeEffect::Create(isStroked);
|
| static const int kCircleEdgeAttrIndex = 1;
|
| drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref();
|
|
|
| @@ -207,7 +456,7 @@
|
| kEdgeEffectStage = GrPaint::kTotalStages,
|
| };
|
|
|
| - GrEffectRef* effect = GrEllipseEdgeEffect::Create(isStroked);
|
| + GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked);
|
| static const int kEllipseCenterAttrIndex = 1;
|
| static const int kEllipseEdgeAttrIndex = 2;
|
| drawState->setEffect(kEdgeEffectStage, effect,
|
|
|