Index: src/gpu/effects/GrDashingEffect.cpp |
diff --git a/src/gpu/effects/GrDashingEffect.cpp b/src/gpu/effects/GrDashingEffect.cpp |
index 8d9c08f3f38d943c34fec4698a3caa6886a322cc..49169f1051a45eddc277c066c1ca4190f3bcbc08 100644 |
--- a/src/gpu/effects/GrDashingEffect.cpp |
+++ b/src/gpu/effects/GrDashingEffect.cpp |
@@ -54,7 +54,7 @@ static bool can_fast_path_dash(const SkPoint pts[2], const GrStrokeInfo& strokeI |
SkPaint::Cap cap = strokeInfo.getStrokeRec().getCap(); |
// Current we do don't handle Round or Square cap dashes |
- if (SkPaint::kRound_Cap == cap) { |
+ if (SkPaint::kRound_Cap == cap && info.fIntervals[0] != 0.f) { |
return false; |
} |
@@ -204,7 +204,7 @@ bool GrDashingEffect::DrawDashLine(const SkPoint pts[2], const GrPaint& paint, |
SkScalar perpScale; |
calc_dash_scaling(¶llelScale, &perpScale, vm, ptsRot); |
- bool hasCap = SkPaint::kSquare_Cap == cap && 0 != srcStrokeWidth; |
+ bool hasCap = SkPaint::kButt_Cap != cap && 0 != srcStrokeWidth; |
// We always want to at least stroke out half a pixel on each side in device space |
// so 0.5f / perpScale gives us this min in src space |
@@ -341,8 +341,11 @@ bool GrDashingEffect::DrawDashLine(const SkPoint pts[2], const GrPaint& paint, |
devInfo.fIntervals = devIntervals; |
GrEffectEdgeType edgeType= useAA ? kFillAA_GrEffectEdgeType : |
kFillBW_GrEffectEdgeType; |
+ bool isRoundCap = SkPaint::kRound_Cap == cap; |
+ GrDashingEffect::DashCap capType = isRoundCap ? GrDashingEffect::kRound_DashCap : |
+ GrDashingEffect::kNonRound_DashCap; |
drawState->addCoverageEffect( |
- GrDashingEffect::Create(edgeType, devInfo, strokeWidth), 1)->unref(); |
+ GrDashingEffect::Create(edgeType, devInfo, strokeWidth, capType), 1)->unref(); |
} |
// Set up the vertex data for the line and start/end dashes |
@@ -364,6 +367,11 @@ bool GrDashingEffect::DrawDashLine(const SkPoint pts[2], const GrPaint& paint, |
int curVIdx = 0; |
+ if (SkPaint::kRound_Cap == cap && 0 != srcStrokeWidth) { |
+ // need to adjust this for round caps to correctly set the dashPos attrib on vertices |
+ startOffset -= halfDevStroke; |
+ } |
+ |
// Draw interior part of dashed line |
if (!lineDone) { |
SkPoint devicePts[2]; |
@@ -404,19 +412,230 @@ bool GrDashingEffect::DrawDashLine(const SkPoint pts[2], const GrPaint& paint, |
////////////////////////////////////////////////////////////////////////////// |
+class GLDashingCircleEffect; |
+/* |
+ * This effect will draw a dotted line (defined as a dashed lined with round caps and no on |
+ * interval). The radius of the dots is given by the strokeWidth and the spacing by the DashInfo. |
+ * Both of the previous two parameters are in device space. This effect also requires the setting of |
+ * a vec2 vertex attribute for the the four corners of the bounding rect. This attribute is the |
+ * "dash position" of each vertex. In other words it is the vertex coords (in device space) if we |
+ * transform the line to be horizontal, with the start of line at the origin then shifted to the |
+ * right by half the off interval. The line then goes in the positive x direction. |
+ */ |
+class DashingCircleEffect : public GrVertexEffect { |
+public: |
+ typedef SkPathEffect::DashInfo DashInfo; |
+ |
+ static GrEffectRef* Create(GrEffectEdgeType edgeType, const DashInfo& info, |
+ SkScalar radius); |
+ |
+ virtual ~DashingCircleEffect(); |
+ |
+ static const char* Name() { return "DashingCircleEffect"; } |
+ |
+ GrEffectEdgeType getEdgeType() const { return fEdgeType; } |
+ |
+ SkScalar getRadius() const { return fRadius; } |
+ |
+ SkScalar getCenterX() const { return fCenterX; } |
+ |
+ SkScalar getIntervalLength() const { return fIntervalLength; } |
+ |
+ typedef GLDashingCircleEffect GLEffect; |
+ |
+ virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE; |
+ |
+ virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE; |
+ |
+private: |
+ DashingCircleEffect(GrEffectEdgeType edgeType, const DashInfo& info, SkScalar radius); |
+ |
+ virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE; |
+ |
+ GrEffectEdgeType fEdgeType; |
+ SkScalar fIntervalLength; |
+ SkScalar fRadius; |
+ SkScalar fCenterX; |
+ |
+ GR_DECLARE_EFFECT_TEST; |
+ |
+ typedef GrVertexEffect INHERITED; |
+}; |
+ |
+////////////////////////////////////////////////////////////////////////////// |
+ |
+class GLDashingCircleEffect : public GrGLVertexEffect { |
+public: |
+ GLDashingCircleEffect(const GrBackendEffectFactory&, const GrDrawEffect&); |
+ |
+ virtual void emitCode(GrGLFullShaderBuilder* 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 fParamUniform; |
+ SkScalar fPrevRadius; |
+ SkScalar fPrevCenterX; |
+ SkScalar fPrevIntervalLength; |
+ typedef GrGLVertexEffect INHERITED; |
+}; |
+ |
+GLDashingCircleEffect::GLDashingCircleEffect(const GrBackendEffectFactory& factory, |
+ const GrDrawEffect& drawEffect) |
+ : INHERITED (factory) { |
+ fPrevRadius = SK_ScalarMin; |
+ fPrevCenterX = SK_ScalarMin; |
+ fPrevIntervalLength = SK_ScalarMax; |
+} |
+ |
+void GLDashingCircleEffect::emitCode(GrGLFullShaderBuilder* builder, |
+ const GrDrawEffect& drawEffect, |
+ EffectKey key, |
+ const char* outputColor, |
+ const char* inputColor, |
+ const TransformedCoordsArray&, |
+ const TextureSamplerArray& samplers) { |
+ const DashingCircleEffect& dce = drawEffect.castEffect<DashingCircleEffect>(); |
+ const char *paramName; |
+ // The param uniforms, xyz, refer to circle radius - 0.5, cicles center x coord, and |
+ // the total interval length of the dash. |
+ fParamUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
+ kVec3f_GrSLType, |
+ "params", |
+ ¶mName); |
+ |
+ const char *vsCoordName, *fsCoordName; |
+ builder->addVarying(kVec2f_GrSLType, "Coord", &vsCoordName, &fsCoordName); |
+ const SkString* attr0Name = |
+ builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0]); |
+ builder->vsCodeAppendf("\t%s = %s;\n", vsCoordName, attr0Name->c_str()); |
+ |
+ // transforms all points so that we can compare them to our test circle |
+ builder->fsCodeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s.z) * %s.z;\n", |
+ fsCoordName, fsCoordName, paramName, paramName); |
+ builder->fsCodeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n", fsCoordName); |
+ builder->fsCodeAppendf("\t\tvec2 center = vec2(%s.y, 0.0);\n", paramName); |
+ builder->fsCodeAppend("\t\tfloat dist = length(center - fragPosShifted);\n"); |
+ if (GrEffectEdgeTypeIsAA(dce.getEdgeType())) { |
+ builder->fsCodeAppendf("\t\tfloat diff = dist - %s.x;\n", paramName); |
+ builder->fsCodeAppend("\t\tdiff = 1 - diff;\n"); |
+ builder->fsCodeAppend("\t\tfloat alpha = clamp(diff, 0.0, 1.0);\n"); |
+ } else { |
+ builder->fsCodeAppendf("\t\tfloat alpha = 1.0;\n"); |
+ builder->fsCodeAppendf("\t\talpha *= dist < %s.x + 0.5 ? 1.0 : 0.0;\n", paramName); |
+ } |
+ builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor, |
+ (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_str()); |
+} |
+ |
+void GLDashingCircleEffect::setData(const GrGLUniformManager& uman, const GrDrawEffect& drawEffect) { |
+ const DashingCircleEffect& dce = drawEffect.castEffect<DashingCircleEffect>(); |
+ SkScalar radius = dce.getRadius(); |
+ SkScalar centerX = dce.getCenterX(); |
+ SkScalar intervalLength = dce.getIntervalLength(); |
+ if (radius != fPrevRadius || centerX != fPrevCenterX || intervalLength != fPrevIntervalLength) { |
+ uman.set3f(fParamUniform, radius - 0.5f, centerX, intervalLength); |
+ fPrevRadius = radius; |
+ fPrevCenterX = centerX; |
+ fPrevIntervalLength = intervalLength; |
+ } |
+} |
+ |
+GrGLEffect::EffectKey GLDashingCircleEffect::GenKey(const GrDrawEffect& drawEffect, |
+ const GrGLCaps&) { |
+ const DashingCircleEffect& dce = drawEffect.castEffect<DashingCircleEffect>(); |
+ return dce.getEdgeType(); |
+} |
+ |
+////////////////////////////////////////////////////////////////////////////// |
+ |
+GrEffectRef* DashingCircleEffect::Create(GrEffectEdgeType edgeType, const DashInfo& info, |
+ SkScalar radius) { |
+ if (info.fCount != 2 || info.fIntervals[0] != 0) { |
+ return NULL; |
+ } |
+ |
+ return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(DashingCircleEffect, |
+ (edgeType, info, radius)))); |
+} |
+ |
+DashingCircleEffect::~DashingCircleEffect() {} |
+ |
+void DashingCircleEffect::getConstantColorComponents(GrColor* color, uint32_t* validFlags) const { |
+ *validFlags = 0; |
+} |
+ |
+const GrBackendEffectFactory& DashingCircleEffect::getFactory() const { |
+ return GrTBackendEffectFactory<DashingCircleEffect>::getInstance(); |
+} |
+ |
+DashingCircleEffect::DashingCircleEffect(GrEffectEdgeType edgeType, const DashInfo& info, |
+ SkScalar radius) |
+ : fEdgeType(edgeType) { |
+ SkScalar onLen = info.fIntervals[0]; |
+ SkScalar offLen = info.fIntervals[1]; |
+ fIntervalLength = onLen + offLen; |
+ fRadius = radius; |
+ fCenterX = SkScalarHalf(offLen); |
+ |
+ this->addVertexAttrib(kVec2f_GrSLType); |
+} |
+ |
+bool DashingCircleEffect::onIsEqual(const GrEffect& other) const { |
+ const DashingCircleEffect& dce = CastEffect<DashingCircleEffect>(other); |
+ return (fEdgeType == dce.fEdgeType && |
+ fIntervalLength == dce.fIntervalLength && |
+ fRadius == dce.fRadius && |
+ fCenterX == dce.fCenterX); |
+} |
+ |
+GR_DEFINE_EFFECT_TEST(DashingCircleEffect); |
+ |
+GrEffectRef* DashingCircleEffect::TestCreate(SkRandom* random, |
+ GrContext*, |
+ const GrDrawTargetCaps& caps, |
+ GrTexture*[]) { |
+ GrEffectRef* effect; |
+ GrEffectEdgeType edgeType = static_cast<GrEffectEdgeType>(random->nextULessThan( |
+ kGrEffectEdgeTypeCnt)); |
+ SkScalar strokeWidth = random->nextRangeScalar(0, 100.f); |
+ DashInfo info; |
+ info.fCount = 2; |
+ SkAutoTArray<SkScalar> intervals(info.fCount); |
+ info.fIntervals = intervals.get(); |
+ info.fIntervals[0] = 0; |
+ info.fIntervals[1] = random->nextRangeScalar(0, 10.f); |
+ info.fPhase = random->nextRangeScalar(0, info.fIntervals[1]); |
+ |
+ effect = DashingCircleEffect::Create(edgeType, info, strokeWidth); |
+ return effect; |
+} |
+ |
+////////////////////////////////////////////////////////////////////////////// |
+ |
class GLDashingLineEffect; |
+/* |
+ * This effect will draw a dashed line. The width of the dash is given by the strokeWidth and the |
+ * length and spacing by the DashInfo. Both of the previous two parameters are in device space. |
+ * This effect also requires the setting of a vec2 vertex attribute for the the four corners of the |
+ * bounding rect. This attribute is the "dash position" of each vertex. In other words it is the |
+ * vertex coords (in device space) if we transform the line to be horizontal, with the start of |
+ * line at the origin then shifted to the right by half the off interval. The line then goes in the |
+ * positive x direction. |
+ */ |
class DashingLineEffect : public GrVertexEffect { |
public: |
typedef SkPathEffect::DashInfo DashInfo; |
- /** |
- * The effect calculates the coverage for the case of a horizontal line in device space. |
- * The matrix that is passed in should be able to convert a line in source space to a |
- * horizontal line in device space. Additionally, the coord transform matrix should translate |
- * the the start of line to origin, and the shift it along the positive x-axis by the phase |
- * and half the off interval. |
- */ |
static GrEffectRef* Create(GrEffectEdgeType edgeType, const DashInfo& info, |
SkScalar strokeWidth); |
@@ -447,7 +666,7 @@ private: |
GR_DECLARE_EFFECT_TEST; |
- typedef GrEffect INHERITED; |
+ typedef GrVertexEffect INHERITED; |
}; |
////////////////////////////////////////////////////////////////////////////// |
@@ -481,7 +700,6 @@ GLDashingLineEffect::GLDashingLineEffect(const GrBackendEffectFactory& factory, |
: INHERITED (factory) { |
fPrevRect.fLeft = SK_ScalarNaN; |
fPrevIntervalLength = SK_ScalarMax; |
- |
} |
void GLDashingLineEffect::emitCode(GrGLFullShaderBuilder* builder, |
@@ -623,6 +841,14 @@ GrEffectRef* DashingLineEffect::TestCreate(SkRandom* random, |
////////////////////////////////////////////////////////////////////////////// |
GrEffectRef* GrDashingEffect::Create(GrEffectEdgeType edgeType, const SkPathEffect::DashInfo& info, |
- SkScalar strokeWidth) { |
- return DashingLineEffect::Create(edgeType, info, strokeWidth); |
+ SkScalar strokeWidth, GrDashingEffect::DashCap cap) { |
+ switch (cap) { |
+ case GrDashingEffect::kRound_DashCap: |
+ return DashingCircleEffect::Create(edgeType, info, SkScalarHalf(strokeWidth)); |
+ case GrDashingEffect::kNonRound_DashCap: |
+ return DashingLineEffect::Create(edgeType, info, strokeWidth); |
+ default: |
+ SkFAIL("Unexpected dashed cap."); |
+ } |
+ return NULL; |
} |