OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2014 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
| 7 |
| 8 #include "GrDashingEffect.h" |
| 9 |
| 10 #include "gl/GrGLEffect.h" |
| 11 #include "gl/GrGLSL.h" |
| 12 #include "GrTBackendEffectFactory.h" |
| 13 |
| 14 #include "SkPath.h" |
| 15 |
| 16 ////////////////////////////////////////////////////////////////////////////// |
| 17 |
| 18 class GrGLDashingEffect : public GrGLEffect { |
| 19 public: |
| 20 GrGLDashingEffect(const GrBackendEffectFactory&, const GrDrawEffect&); |
| 21 |
| 22 virtual void emitCode(GrGLShaderBuilder* builder, |
| 23 const GrDrawEffect& drawEffect, |
| 24 EffectKey key, |
| 25 const char* outputColor, |
| 26 const char* inputColor, |
| 27 const TransformedCoordsArray&, |
| 28 const TextureSamplerArray&) SK_OVERRIDE; |
| 29 |
| 30 static inline EffectKey GenKey(const GrDrawEffect&, const GrGLCaps&); |
| 31 |
| 32 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVER
RIDE; |
| 33 |
| 34 private: |
| 35 GrGLUniformManager::UniformHandle fRectUniform; |
| 36 GrGLUniformManager::UniformHandle fIntervalUniform; |
| 37 SkRect fPrevRect; |
| 38 SkScalar fPrevIntervalLength; |
| 39 typedef GrGLEffect INHERITED; |
| 40 }; |
| 41 |
| 42 GrGLDashingEffect::GrGLDashingEffect(const GrBackendEffectFactory& factory, |
| 43 const GrDrawEffect& drawEffect) |
| 44 : INHERITED (factory) { |
| 45 fPrevRect.fLeft = SK_ScalarNaN; |
| 46 fPrevIntervalLength = SK_ScalarMax; |
| 47 |
| 48 } |
| 49 |
| 50 void GrGLDashingEffect::emitCode(GrGLShaderBuilder* builder, |
| 51 const GrDrawEffect& drawEffect, |
| 52 EffectKey key, |
| 53 const char* outputColor, |
| 54 const char* inputColor, |
| 55 const TransformedCoordsArray& coords, |
| 56 const TextureSamplerArray& samplers) { |
| 57 const GrDashingEffect& de = drawEffect.castEffect<GrDashingEffect>(); |
| 58 const char *rectName; |
| 59 // The rect uniform's xyzw refer to (left + 0.5, top + 0.5, right - 0.5, bot
tom - 0.5), |
| 60 // respectively. |
| 61 fRectUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, |
| 62 kVec4f_GrSLType, |
| 63 "rect", |
| 64 &rectName); |
| 65 const char *intervalName; |
| 66 // The interval uniform's refers to the total length of the interval (on + o
ff) |
| 67 fIntervalUniform = builder->addUniform(GrGLShaderBuilder::kFragment_Visibili
ty, |
| 68 kFloat_GrSLType, |
| 69 "interval", |
| 70 &intervalName); |
| 71 // transforms all points so that we can compare them to our test rect |
| 72 builder->fsCodeAppendf("\t\tfloat xShifted = %s.x - floor(%s.x / %s) * %s;\n
", |
| 73 coords[0].c_str(), coords[0].c_str(), intervalName, i
ntervalName); |
| 74 builder->fsCodeAppendf("\t\tvec2 fragPosShifted = vec2(xShifted, %s.y);\n",
coords[0].c_str()); |
| 75 if (GrEffectEdgeTypeIsAA(de.getEdgeType())) { |
| 76 // The amount of coverage removed in x and y by the edges is computed as
a pair of negative |
| 77 // numbers, xSub and ySub. |
| 78 builder->fsCodeAppend("\t\tfloat xSub, ySub;\n"); |
| 79 builder->fsCodeAppendf("\t\txSub = min(fragPosShifted.x - %s.x, 0.0);\n"
, rectName); |
| 80 builder->fsCodeAppendf("\t\txSub += min(%s.z - fragPosShifted.x, 0.0);\n
", rectName); |
| 81 builder->fsCodeAppendf("\t\tySub = min(fragPosShifted.y - %s.y, 0.0);\n"
, rectName); |
| 82 builder->fsCodeAppendf("\t\tySub += min(%s.w - fragPosShifted.y, 0.0);\n
", rectName); |
| 83 // Now compute coverage in x and y and multiply them to get the fraction
of the pixel |
| 84 // covered. |
| 85 builder->fsCodeAppendf("\t\tfloat alpha = (1.0 + max(xSub, -1.0)) * (1.0
+ max(ySub, -1.0));\n"); |
| 86 } else { |
| 87 // Assuming the bounding geometry is tight so no need to check y values |
| 88 builder->fsCodeAppendf("\t\tfloat alpha = 1.0;\n"); |
| 89 builder->fsCodeAppendf("\t\talpha *= (fragPosShifted.x - %s.x) > -0.5 ?
1.0 : 0.0;\n", rectName); |
| 90 builder->fsCodeAppendf("\t\talpha *= (%s.z - fragPosShifted.x) >= -0.5 ?
1.0 : 0.0;\n", rectName); |
| 91 } |
| 92 builder->fsCodeAppendf("\t\t%s = %s;\n", outputColor, |
| 93 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("alpha")).c_st
r()); |
| 94 } |
| 95 |
| 96 void GrGLDashingEffect::setData(const GrGLUniformManager& uman, const GrDrawEffe
ct& drawEffect) { |
| 97 const GrDashingEffect& de = drawEffect.castEffect<GrDashingEffect>(); |
| 98 const SkRect& rect = de.getRect(); |
| 99 SkScalar intervalLength = de.getIntervalLength(); |
| 100 if (rect != fPrevRect || intervalLength != fPrevIntervalLength) { |
| 101 uman.set4f(fRectUniform, rect.fLeft + 0.5f, rect.fTop + 0.5f, |
| 102 rect.fRight - 0.5f, rect.fBottom - 0.5f); |
| 103 uman.set1f(fIntervalUniform, intervalLength); |
| 104 fPrevRect = rect; |
| 105 fPrevIntervalLength = intervalLength; |
| 106 } |
| 107 } |
| 108 |
| 109 GrGLEffect::EffectKey GrGLDashingEffect::GenKey(const GrDrawEffect& drawEffect, |
| 110 const GrGLCaps&) { |
| 111 const GrDashingEffect& de = drawEffect.castEffect<GrDashingEffect>(); |
| 112 return de.getEdgeType(); |
| 113 } |
| 114 |
| 115 ////////////////////////////////////////////////////////////////////////////// |
| 116 |
| 117 GrEffectRef* GrDashingEffect::Create(GrEffectEdgeType edgeType, const DashInfo&
info, |
| 118 const SkMatrix& matrix, SkScalar strokeWidt
h) { |
| 119 if (info.fCount != 2) { |
| 120 return NULL; |
| 121 } |
| 122 |
| 123 return CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(GrDashingEffect, |
| 124 (edgeType, info, matrix, s
trokeWidth)))); |
| 125 } |
| 126 |
| 127 GrDashingEffect::~GrDashingEffect() {} |
| 128 |
| 129 void GrDashingEffect::getConstantColorComponents(GrColor* color, uint32_t* valid
Flags) const { |
| 130 *validFlags = 0; |
| 131 } |
| 132 |
| 133 const GrBackendEffectFactory& GrDashingEffect::getFactory() const { |
| 134 return GrTBackendEffectFactory<GrDashingEffect>::getInstance(); |
| 135 } |
| 136 |
| 137 GrDashingEffect::GrDashingEffect(GrEffectEdgeType edgeType, const DashInfo& info
, |
| 138 const SkMatrix& matrix, SkScalar strokeWidth) |
| 139 : fEdgeType(edgeType) |
| 140 , fCoordTransform(kLocal_GrCoordSet, matrix) { |
| 141 SkScalar onLen = info.fIntervals[0]; |
| 142 SkScalar offLen = info.fIntervals[1]; |
| 143 SkScalar halfOffLen = SkScalarHalf(offLen); |
| 144 SkScalar halfStroke = SkScalarHalf(strokeWidth); |
| 145 fIntervalLength = onLen + offLen; |
| 146 fRect.set(halfOffLen, -halfStroke, halfOffLen + onLen, halfStroke); |
| 147 |
| 148 addCoordTransform(&fCoordTransform); |
| 149 } |
| 150 |
| 151 bool GrDashingEffect::onIsEqual(const GrEffect& other) const { |
| 152 const GrDashingEffect& de = CastEffect<GrDashingEffect>(other); |
| 153 return (fEdgeType == de.fEdgeType && |
| 154 fCoordTransform == de.fCoordTransform && |
| 155 fRect == de.fRect && |
| 156 fIntervalLength == de.fIntervalLength); |
| 157 } |
| 158 |
| 159 GR_DEFINE_EFFECT_TEST(GrDashingEffect); |
| 160 |
| 161 GrEffectRef* GrDashingEffect::TestCreate(SkRandom* random, |
| 162 GrContext*, |
| 163 const GrDrawTargetCaps& caps, |
| 164 GrTexture*[]) { |
| 165 GrEffectRef* effect; |
| 166 SkMatrix m; |
| 167 m.reset(); |
| 168 GrEffectEdgeType edgeType = static_cast<GrEffectEdgeType>(random->nextULessT
han( |
| 169 kGrEffectEdgeTypeCnt)); |
| 170 SkScalar strokeWidth = random->nextRangeScalar(0, 100.f); |
| 171 DashInfo info; |
| 172 info.fCount = 2; |
| 173 SkAutoTArray<SkScalar> intervals(info.fCount); |
| 174 info.fIntervals = intervals.get(); |
| 175 info.fIntervals[0] = random->nextRangeScalar(0, 10.f); |
| 176 info.fIntervals[1] = random->nextRangeScalar(0, 10.f); |
| 177 info.fPhase = random->nextRangeScalar(0, info.fIntervals[0] + info.fInterval
s[1]); |
| 178 |
| 179 effect = GrDashingEffect::Create(edgeType, info, m, strokeWidth); |
| 180 return effect; |
| 181 } |
| 182 |
OLD | NEW |