OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrOvalRenderer.h" | 8 #include "GrOvalRenderer.h" |
9 | 9 |
10 #include "effects/GrCircleEdgeEffect.h" | 10 #include "GrEffect.h" |
11 #include "effects/GrEllipseEdgeEffect.h" | 11 #include "gl/GrGLEffect.h" |
| 12 #include "gl/GrGLSL.h" |
| 13 #include "GrTBackendEffectFactory.h" |
12 | 14 |
13 #include "GrDrawState.h" | 15 #include "GrDrawState.h" |
14 #include "GrDrawTarget.h" | 16 #include "GrDrawTarget.h" |
15 #include "SkStrokeRec.h" | 17 #include "SkStrokeRec.h" |
16 | 18 |
17 SK_DEFINE_INST_COUNT(GrOvalRenderer) | 19 SK_DEFINE_INST_COUNT(GrOvalRenderer) |
18 | 20 |
19 namespace { | 21 namespace { |
20 | 22 |
21 struct CircleVertex { | 23 struct CircleVertex { |
(...skipping 11 matching lines...) Expand all Loading... |
33 SkScalar fInnerXRadius; | 35 SkScalar fInnerXRadius; |
34 SkScalar fInnerXYRatio; | 36 SkScalar fInnerXYRatio; |
35 }; | 37 }; |
36 | 38 |
37 inline bool circle_stays_circle(const SkMatrix& m) { | 39 inline bool circle_stays_circle(const SkMatrix& m) { |
38 return m.isSimilarity(); | 40 return m.isSimilarity(); |
39 } | 41 } |
40 | 42 |
41 } | 43 } |
42 | 44 |
| 45 /////////////////////////////////////////////////////////////////////////////// |
| 46 |
| 47 /** |
| 48 * The output of this effect is a modulation of the input color and coverage for
a circle, |
| 49 * specified as center_x, center_y, x_radius, inner radius and outer radius in w
indow space |
| 50 * (y-down). |
| 51 */ |
| 52 |
| 53 class CircleEdgeEffect : public GrEffect { |
| 54 public: |
| 55 static GrEffectRef* Create(bool stroke) { |
| 56 // we go through this so we only have one copy of each effect (stroked/f
illed) |
| 57 static SkAutoTUnref<GrEffectRef> gCircleStrokeEdgeEffectRef( |
| 58 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEff
ect, (true))))); |
| 59 static SkAutoTUnref<GrEffectRef> gCircleFillEdgeEffectRef( |
| 60 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(CircleEdgeEff
ect, (false))))); |
| 61 |
| 62 if (stroke) { |
| 63 gCircleStrokeEdgeEffectRef.get()->ref(); |
| 64 return gCircleStrokeEdgeEffectRef; |
| 65 } else { |
| 66 gCircleFillEdgeEffectRef.get()->ref(); |
| 67 return gCircleFillEdgeEffectRef; |
| 68 } |
| 69 } |
| 70 |
| 71 virtual void getConstantColorComponents(GrColor* color, |
| 72 uint32_t* validFlags) const SK_OVERR
IDE { |
| 73 *validFlags = 0; |
| 74 } |
| 75 |
| 76 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
| 77 return GrTBackendEffectFactory<CircleEdgeEffect>::getInstance(); |
| 78 } |
| 79 |
| 80 virtual ~CircleEdgeEffect() {} |
| 81 |
| 82 static const char* Name() { return "CircleEdge"; } |
| 83 |
| 84 inline bool isStroked() const { return fStroke; } |
| 85 |
| 86 class GLEffect : public GrGLEffect { |
| 87 public: |
| 88 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
| 89 : INHERITED (factory) {} |
| 90 |
| 91 virtual void emitCode(GrGLShaderBuilder* builder, |
| 92 const GrDrawEffect& drawEffect, |
| 93 EffectKey key, |
| 94 const char* outputColor, |
| 95 const char* inputColor, |
| 96 const TextureSamplerArray& samplers) SK_OVERRIDE { |
| 97 const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleE
dgeEffect>(); |
| 98 const char *vsName, *fsName; |
| 99 builder->addVarying(kVec4f_GrSLType, "CircleEdge", &vsName, &fsName)
; |
| 100 |
| 101 const SkString* attrName = |
| 102 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); |
| 103 builder->vsCodeAppendf("\t%s = %s;\n", vsName, attrName->c_str()); |
| 104 |
| 105 builder->fsCodeAppendf("\tfloat d = distance(%s.xy, %s.xy);\n", |
| 106 builder->fragmentPosition(), fsName); |
| 107 builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.z - d, 0.0, 1.0
);\n", fsName); |
| 108 if (circleEffect.isStroked()) { |
| 109 builder->fsCodeAppendf("\tfloat innerAlpha = clamp(d - %s.w, 0.0
, 1.0);\n", fsName); |
| 110 builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n"); |
| 111 } |
| 112 SkString modulate; |
| 113 GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha"); |
| 114 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()
); |
| 115 } |
| 116 |
| 117 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG
LCaps&) { |
| 118 const CircleEdgeEffect& circleEffect = drawEffect.castEffect<CircleE
dgeEffect>(); |
| 119 |
| 120 return circleEffect.isStroked() ? 0x1 : 0x0; |
| 121 } |
| 122 |
| 123 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_
OVERRIDE {} |
| 124 |
| 125 private: |
| 126 typedef GrGLEffect INHERITED; |
| 127 }; |
| 128 |
| 129 |
| 130 private: |
| 131 CircleEdgeEffect(bool stroke) : GrEffect() { |
| 132 this->addVertexAttrib(kVec4f_GrSLType); |
| 133 fStroke = stroke; |
| 134 } |
| 135 |
| 136 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { |
| 137 const CircleEdgeEffect& cee = CastEffect<CircleEdgeEffect>(other); |
| 138 return cee.fStroke == fStroke; |
| 139 } |
| 140 |
| 141 bool fStroke; |
| 142 |
| 143 GR_DECLARE_EFFECT_TEST; |
| 144 |
| 145 typedef GrEffect INHERITED; |
| 146 }; |
| 147 |
| 148 GR_DEFINE_EFFECT_TEST(CircleEdgeEffect); |
| 149 |
| 150 GrEffectRef* CircleEdgeEffect::TestCreate(SkMWCRandom* random, |
| 151 GrContext* context, |
| 152 const GrDrawTargetCaps&, |
| 153 GrTexture* textures[]) { |
| 154 return CircleEdgeEffect::Create(random->nextBool()); |
| 155 } |
| 156 |
| 157 /////////////////////////////////////////////////////////////////////////////// |
| 158 |
| 159 /** |
| 160 * The output of this effect is a modulation of the input color and coverage for
an axis-aligned |
| 161 * ellipse, specified as center_x, center_y, x_radius, x_radius/y_radius in wind
ow space (y-down). |
| 162 */ |
| 163 |
| 164 class EllipseEdgeEffect : public GrEffect { |
| 165 public: |
| 166 static GrEffectRef* Create(bool stroke) { |
| 167 // we go through this so we only have one copy of each effect (stroked/f
illed) |
| 168 static SkAutoTUnref<GrEffectRef> gEllipseStrokeEdgeEffectRef( |
| 169 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEf
fect, (true))))); |
| 170 static SkAutoTUnref<GrEffectRef> gEllipseFillEdgeEffectRef( |
| 171 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEf
fect, (false))))); |
| 172 |
| 173 if (stroke) { |
| 174 gEllipseStrokeEdgeEffectRef.get()->ref(); |
| 175 return gEllipseStrokeEdgeEffectRef; |
| 176 } else { |
| 177 gEllipseFillEdgeEffectRef.get()->ref(); |
| 178 return gEllipseFillEdgeEffectRef; |
| 179 } |
| 180 } |
| 181 |
| 182 virtual void getConstantColorComponents(GrColor* color, |
| 183 uint32_t* validFlags) const SK_OVERR
IDE { |
| 184 *validFlags = 0; |
| 185 } |
| 186 |
| 187 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
| 188 return GrTBackendEffectFactory<EllipseEdgeEffect>::getInstance(); |
| 189 } |
| 190 |
| 191 virtual ~EllipseEdgeEffect() {} |
| 192 |
| 193 static const char* Name() { return "EllipseEdge"; } |
| 194 |
| 195 inline bool isStroked() const { return fStroke; } |
| 196 |
| 197 class GLEffect : public GrGLEffect { |
| 198 public: |
| 199 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
| 200 : INHERITED (factory) {} |
| 201 |
| 202 virtual void emitCode(GrGLShaderBuilder* builder, |
| 203 const GrDrawEffect& drawEffect, |
| 204 EffectKey key, |
| 205 const char* outputColor, |
| 206 const char* inputColor, |
| 207 const TextureSamplerArray& samplers) SK_OVERRIDE { |
| 208 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip
seEdgeEffect>(); |
| 209 |
| 210 const char *vsCenterName, *fsCenterName; |
| 211 const char *vsEdgeName, *fsEdgeName; |
| 212 |
| 213 builder->addVarying(kVec2f_GrSLType, "EllipseCenter", &vsCenterName,
&fsCenterName); |
| 214 const SkString* attr0Name = |
| 215 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); |
| 216 builder->vsCodeAppendf("\t%s = %s;\n", vsCenterName, attr0Name->c_st
r()); |
| 217 |
| 218 builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsEdgeName, &fs
EdgeName); |
| 219 const SkString* attr1Name = |
| 220 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[1]); |
| 221 builder->vsCodeAppendf("\t%s = %s;\n", vsEdgeName, attr1Name->c_str(
)); |
| 222 |
| 223 // translate to origin |
| 224 builder->fsCodeAppendf("\tvec2 outerOffset = (%s.xy - %s.xy);\n", |
| 225 builder->fragmentPosition(), fsCenterName); |
| 226 builder->fsCodeAppend("\tvec2 innerOffset = outerOffset;\n"); |
| 227 // scale y by xRadius/yRadius |
| 228 builder->fsCodeAppendf("\touterOffset.y *= %s.y;\n", fsEdgeName); |
| 229 builder->fsCodeAppend("\tfloat dOuter = length(outerOffset);\n"); |
| 230 // compare outer lengths against xOuterRadius |
| 231 builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0,
1.0);\n", |
| 232 fsEdgeName); |
| 233 |
| 234 if (ellipseEffect.isStroked()) { |
| 235 builder->fsCodeAppendf("\tinnerOffset.y *= %s.w;\n", fsEdgeName)
; |
| 236 builder->fsCodeAppend("\tfloat dInner = length(innerOffset);\n")
; |
| 237 |
| 238 // compare inner lengths against xInnerRadius |
| 239 builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.z,
0.0, 1.0);\n", |
| 240 fsEdgeName); |
| 241 builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n"); |
| 242 } |
| 243 |
| 244 SkString modulate; |
| 245 GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha"); |
| 246 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()
); |
| 247 } |
| 248 |
| 249 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG
LCaps&) { |
| 250 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip
seEdgeEffect>(); |
| 251 |
| 252 return ellipseEffect.isStroked() ? 0x1 : 0x0; |
| 253 } |
| 254 |
| 255 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_
OVERRIDE { |
| 256 } |
| 257 |
| 258 private: |
| 259 typedef GrGLEffect INHERITED; |
| 260 }; |
| 261 |
| 262 private: |
| 263 EllipseEdgeEffect(bool stroke) : GrEffect() { |
| 264 this->addVertexAttrib(kVec2f_GrSLType); |
| 265 this->addVertexAttrib(kVec4f_GrSLType); |
| 266 fStroke = stroke; |
| 267 } |
| 268 |
| 269 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { |
| 270 const EllipseEdgeEffect& eee = CastEffect<EllipseEdgeEffect>(other); |
| 271 return eee.fStroke == fStroke; |
| 272 } |
| 273 |
| 274 bool fStroke; |
| 275 |
| 276 GR_DECLARE_EFFECT_TEST; |
| 277 |
| 278 typedef GrEffect INHERITED; |
| 279 }; |
| 280 |
| 281 GR_DEFINE_EFFECT_TEST(EllipseEdgeEffect); |
| 282 |
| 283 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random, |
| 284 GrContext* context, |
| 285 const GrDrawTargetCaps&, |
| 286 GrTexture* textures[]) { |
| 287 return EllipseEdgeEffect::Create(random->nextBool()); |
| 288 } |
| 289 |
| 290 /////////////////////////////////////////////////////////////////////////////// |
| 291 |
43 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, co
nst GrPaint& paint, | 292 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, co
nst GrPaint& paint, |
44 const GrRect& oval, const SkStrokeRec& stroke) | 293 const GrRect& oval, const SkStrokeRec& stroke) |
45 { | 294 { |
46 if (!paint.isAntiAlias()) { | 295 if (!paint.isAntiAlias()) { |
47 return false; | 296 return false; |
48 } | 297 } |
49 | 298 |
50 const SkMatrix& vm = context->getMatrix(); | 299 const SkMatrix& vm = context->getMatrix(); |
51 | 300 |
52 // we can draw circles | 301 // we can draw circles |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 | 350 |
102 SkStrokeRec::Style style = stroke.getStyle(); | 351 SkStrokeRec::Style style = stroke.getStyle(); |
103 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl
ine_Style == style); | 352 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl
ine_Style == style); |
104 enum { | 353 enum { |
105 // the edge effects share this stage with glyph rendering | 354 // the edge effects share this stage with glyph rendering |
106 // (kGlyphMaskStage in GrTextContext) && SW path rendering | 355 // (kGlyphMaskStage in GrTextContext) && SW path rendering |
107 // (kPathMaskStage in GrSWMaskHelper) | 356 // (kPathMaskStage in GrSWMaskHelper) |
108 kEdgeEffectStage = GrPaint::kTotalStages, | 357 kEdgeEffectStage = GrPaint::kTotalStages, |
109 }; | 358 }; |
110 | 359 |
111 GrEffectRef* effect = GrCircleEdgeEffect::Create(isStroked); | 360 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked); |
112 static const int kCircleEdgeAttrIndex = 1; | 361 static const int kCircleEdgeAttrIndex = 1; |
113 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref(
); | 362 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref(
); |
114 | 363 |
115 SkScalar innerRadius = 0.0f; | 364 SkScalar innerRadius = 0.0f; |
116 SkScalar outerRadius = radius; | 365 SkScalar outerRadius = radius; |
117 SkScalar halfWidth = 0; | 366 SkScalar halfWidth = 0; |
118 if (style != SkStrokeRec::kFill_Style) { | 367 if (style != SkStrokeRec::kFill_Style) { |
119 if (SkScalarNearlyZero(strokeWidth)) { | 368 if (SkScalarNearlyZero(strokeWidth)) { |
120 halfWidth = SK_ScalarHalf; | 369 halfWidth = SK_ScalarHalf; |
121 } else { | 370 } else { |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 | 449 |
201 SkStrokeRec::Style style = stroke.getStyle(); | 450 SkStrokeRec::Style style = stroke.getStyle(); |
202 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl
ine_Style == style); | 451 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl
ine_Style == style); |
203 enum { | 452 enum { |
204 // the edge effects share this stage with glyph rendering | 453 // the edge effects share this stage with glyph rendering |
205 // (kGlyphMaskStage in GrTextContext) && SW path rendering | 454 // (kGlyphMaskStage in GrTextContext) && SW path rendering |
206 // (kPathMaskStage in GrSWMaskHelper) | 455 // (kPathMaskStage in GrSWMaskHelper) |
207 kEdgeEffectStage = GrPaint::kTotalStages, | 456 kEdgeEffectStage = GrPaint::kTotalStages, |
208 }; | 457 }; |
209 | 458 |
210 GrEffectRef* effect = GrEllipseEdgeEffect::Create(isStroked); | 459 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); |
211 static const int kEllipseCenterAttrIndex = 1; | 460 static const int kEllipseCenterAttrIndex = 1; |
212 static const int kEllipseEdgeAttrIndex = 2; | 461 static const int kEllipseEdgeAttrIndex = 2; |
213 drawState->setEffect(kEdgeEffectStage, effect, | 462 drawState->setEffect(kEdgeEffectStage, effect, |
214 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref(
); | 463 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref(
); |
215 | 464 |
216 SkScalar xRadius = SkScalarHalf(xformedRect.width()); | 465 SkScalar xRadius = SkScalarHalf(xformedRect.width()); |
217 SkScalar yRadius = SkScalarHalf(xformedRect.height()); | 466 SkScalar yRadius = SkScalarHalf(xformedRect.height()); |
218 SkScalar innerXRadius = 0.0f; | 467 SkScalar innerXRadius = 0.0f; |
219 SkScalar innerRatio = 1.0f; | 468 SkScalar innerRatio = 1.0f; |
220 | 469 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 T += center.fY - SK_ScalarHalf; | 515 T += center.fY - SK_ScalarHalf; |
267 B += center.fY + SK_ScalarHalf; | 516 B += center.fY + SK_ScalarHalf; |
268 | 517 |
269 verts[0].fPos = SkPoint::Make(L, T); | 518 verts[0].fPos = SkPoint::Make(L, T); |
270 verts[1].fPos = SkPoint::Make(R, T); | 519 verts[1].fPos = SkPoint::Make(R, T); |
271 verts[2].fPos = SkPoint::Make(L, B); | 520 verts[2].fPos = SkPoint::Make(L, B); |
272 verts[3].fPos = SkPoint::Make(R, B); | 521 verts[3].fPos = SkPoint::Make(R, B); |
273 | 522 |
274 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); | 523 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); |
275 } | 524 } |
OLD | NEW |