diff options
author | 2014-03-28 15:58:31 +0000 | |
---|---|---|
committer | 2014-03-28 15:58:31 +0000 | |
commit | 3eedb801e35001df4b7e154edf4fd8da942296a0 (patch) | |
tree | 5f65640d99da509c35fbda634bce6dff54474f68 /src/gpu | |
parent | b556422de723ba176f6b453818c49bd85b836957 (diff) |
Add clip effect for circles
BUG=skia:2181
R=jvanverth@google.com
Author: bsalomon@google.com
Review URL: https://codereview.chromium.org/214153002
git-svn-id: http://skia.googlecode.com/svn/trunk@13974 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/gpu')
-rw-r--r-- | src/gpu/effects/GrOvalEffect.cpp | 193 | ||||
-rw-r--r-- | src/gpu/effects/GrOvalEffect.h | 24 | ||||
-rw-r--r-- | src/gpu/effects/GrRRectEffect.cpp | 17 |
3 files changed, 228 insertions, 6 deletions
diff --git a/src/gpu/effects/GrOvalEffect.cpp b/src/gpu/effects/GrOvalEffect.cpp new file mode 100644 index 0000000000..0a07cfe2dd --- /dev/null +++ b/src/gpu/effects/GrOvalEffect.cpp @@ -0,0 +1,193 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "GrOvalEffect.h" + +#include "gl/GrGLEffect.h" +#include "gl/GrGLSL.h" +#include "GrTBackendEffectFactory.h" + +#include "SkRect.h" + +////////////////////////////////////////////////////////////////////////////// + +class GLCircleEffect; + +class CircleEffect : public GrEffect { +public: + static GrEffectRef* Create(GrEffectEdgeType, const SkPoint& center, SkScalar radius); + + virtual ~CircleEffect() {}; + static const char* Name() { return "Circle"; } + + const SkPoint& getCenter() const { return fCenter; } + SkScalar getRadius() const { return fRadius; } + + GrEffectEdgeType getEdgeType() const { return fEdgeType; } + + typedef GLCircleEffect GLEffect; + + virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; + + virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; + +private: + CircleEffect(GrEffectEdgeType, const SkPoint& center, SkScalar radius); + + virtual bool onIsEqual(const GrEffect&) const SK_OVERRIDE; + + SkPoint fCenter; + SkScalar fRadius; + GrEffectEdgeType fEdgeType; + + GR_DECLARE_EFFECT_TEST; + + typedef GrEffect INHERITED; +}; + +GrEffectRef* CircleEffect::Create(GrEffectEdgeType edgeType, + const SkPoint& center, + SkScalar radius) { + SkASSERT(radius >= 0); + return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEffect, + (edgeType, center, radius)))); +} + +void CircleEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { + *validFlags = 0; +} + +const GrBackendEffectFactory& CircleEffect::getFactory() const { + return GrTBackendEffectFactory<CircleEffect>::getInstance(); +} + +CircleEffect::CircleEffect(GrEffectEdgeType edgeType, const SkPoint& c, SkScalar r) + : fCenter(c) + , fRadius(r) + , fEdgeType(edgeType) { + this->setWillReadFragmentPosition(); +} + +bool CircleEffect::onIsEqual(const GrEffect& other) const { + const CircleEffect& crre = CastEffect<CircleEffect>(other); + return fEdgeType == crre.fEdgeType && fCenter == crre.fCenter && fRadius == crre.fRadius; +} + +////////////////////////////////////////////////////////////////////////////// + +GR_DEFINE_EFFECT_TEST(CircleEffect); + +GrEffectRef* CircleEffect::TestCreate(SkRandom* random, + GrContext*, + const GrDrawTargetCaps& caps, + GrTexture*[]) { + SkPoint center; + center.fX = random->nextRangeScalar(0.f, 1000.f); + center.fY = random->nextRangeScalar(0.f, 1000.f); + SkScalar radius = random->nextRangeF(0.f, 1000.f); + GrEffectEdgeType et; + do { + et = (GrEffectEdgeType)random->nextULessThan(kGrEffectEdgeTypeCnt); + } while (kHairlineAA_GrEffectEdgeType == et); + return CircleEffect::Create(et, center, radius); +} + +////////////////////////////////////////////////////////////////////////////// + +class GLCircleEffect : public GrGLEffect { +public: + GLCircleEffect(const GrBackendEffectFactory&, const GrDrawEffect&); + + virtual void emitCode(GrGLShaderBuilder* builder, + const GrDrawEffect& drawEffect, + EffectKey key, + const char* outputColor, + const char* inputColor, + const TransformedCoordsArray&, + const TextureSamplerArray&) SK_OVERRIDE; + + static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); + + virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE; + +private: + GrGLUniformManager::UniformHandle fCircleUniform; + SkPoint fPrevCenter; + SkScalar fPrevRadius; + + typedef GrGLEffect INHERITED; +}; + +GLCircleEffect::GLCircleEffect(const GrBackendEffectFactory& factory, + const GrDrawEffect& drawEffect) + : INHERITED (factory) { + fPrevRadius = -1.f; +} + +void GLCircleEffect::emitCode(GrGLShaderBuilder* builder, + const GrDrawEffect& drawEffect, + EffectKey key, + const char* outputColor, + const char* inputColor, + const TransformedCoordsArray&, + const TextureSamplerArray& samplers) { + const CircleEffect& ce = drawEffect.castEffect<CircleEffect>(); + const char *circleName; + // The circle uniform is (center.x, center.y, radius + 0.5) + fCircleUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, + kVec3f_GrSLType, + "circle", + &circleName); + const char* fragmentPos = builder->fragmentPosition(); + + SkASSERT(kHairlineAA_GrEffectEdgeType != ce.getEdgeType()); + if (GrEffectEdgeTypeIsInverseFill(ce.getEdgeType())) { + builder->fsCodeAppendf("\t\tfloat d = length(%s.xy - %s.xy) - %s.z;\n", + circleName, fragmentPos, circleName); + } else { + builder->fsCodeAppendf("\t\tfloat d = %s.z - length(%s.xy - %s.xy);\n", + circleName, fragmentPos, circleName); + } + if (GrEffectEdgeTypeIsAA(ce.getEdgeType())) { + builder->fsCodeAppend("\t\td = clamp(d, 0.0, 1.0);\n"); + } else { + builder->fsCodeAppend("\t\td = d > 0.5 ? 1.0 : 0.0;\n"); + } + + builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor, + (GrGLSLExpr4(inputColor) * GrGLSLExpr1("d")).c_str()); +} + +GrGLEffect::EffectKey GLCircleEffect::GenKey(const GrDrawEffect& drawEffect, + const GrGLCaps&) { + const CircleEffect& ce = drawEffect.castEffect<CircleEffect>(); + return ce.getEdgeType(); +} + +void GLCircleEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { + const CircleEffect& ce = drawEffect.castEffect<CircleEffect>(); + if (ce.getRadius() != fPrevRadius || ce.getCenter() != fPrevCenter) { + uman.set3f(fCircleUniform, ce.getCenter().fX, ce.getCenter().fY, ce.getRadius() + 0.5f); + fPrevCenter = ce.getCenter(); + fPrevRadius = ce.getRadius(); + } +} +////////////////////////////////////////////////////////////////////////////// + +GrEffectRef* GrOvalEffect::Create(GrEffectEdgeType edgeType, const SkRect& oval) { + if (kHairlineAA_GrEffectEdgeType == edgeType) { + return NULL; + } + SkScalar w = oval.width(); + SkScalar h = oval.height(); + if (SkScalarNearlyEqual(w, h)) { + w /= 2; + return CircleEffect::Create(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + w), w); + } + + return NULL; +} diff --git a/src/gpu/effects/GrOvalEffect.h b/src/gpu/effects/GrOvalEffect.h new file mode 100644 index 0000000000..796ee5befb --- /dev/null +++ b/src/gpu/effects/GrOvalEffect.h @@ -0,0 +1,24 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef GrOvalEffect_DEFINED +#define GrOvalEffect_DEFINED + +#include "GrTypes.h" +#include "GrTypesPriv.h" + +class GrEffectRef; +struct SkRect; + +namespace GrOvalEffect { + /** + * Creates an effect that performs clipping against an oval. + */ + GrEffectRef* Create(GrEffectEdgeType, const SkRect&); +}; + +#endif diff --git a/src/gpu/effects/GrRRectEffect.cpp b/src/gpu/effects/GrRRectEffect.cpp index eff4aa8649..1e93eb1bdf 100644 --- a/src/gpu/effects/GrRRectEffect.cpp +++ b/src/gpu/effects/GrRRectEffect.cpp @@ -10,6 +10,7 @@ #include "gl/GrGLEffect.h" #include "gl/GrGLSL.h" #include "GrConvexPolyEffect.h" +#include "GrOvalEffect.h" #include "GrTBackendEffectFactory.h" #include "SkRRect.h" @@ -77,7 +78,9 @@ private: GrEffectRef* CircularRRectEffect::Create(GrEffectEdgeType edgeType, uint32_t circularCornerFlags, const SkRRect& rrect) { - SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType); + if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) { + return NULL; + } return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircularRRectEffect, (edgeType, circularCornerFlags, rrect)))); } @@ -410,7 +413,9 @@ private: }; GrEffectRef* EllipticalRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) { - SkASSERT(kFillAA_GrEffectEdgeType == edgeType || kInverseFillAA_GrEffectEdgeType == edgeType); + if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) { + return NULL; + } return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipticalRRectEffect, (edgeType, rrect)))); } @@ -627,14 +632,14 @@ void GLEllipticalRRectEffect::setData(const GrGLUniformManager& uman, ////////////////////////////////////////////////////////////////////////////// GrEffectRef* GrRRectEffect::Create(GrEffectEdgeType edgeType, const SkRRect& rrect) { - if (kFillAA_GrEffectEdgeType != edgeType && kInverseFillAA_GrEffectEdgeType != edgeType) { - return NULL; - } - if (rrect.isRect()) { return GrConvexPolyEffect::Create(edgeType, rrect.getBounds()); } + if (rrect.isOval()) { + return GrOvalEffect::Create(edgeType, rrect.getBounds()); + } + if (rrect.isSimple()) { if (rrect.getSimpleRadii().fX < kRadiusMin || rrect.getSimpleRadii().fY < kRadiusMin) { // In this case the corners are extremely close to rectangular and we collapse the |