Chromium Code Reviews| 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 { | |
|
robertphillips
2013/03/31 22:59:08
put this '}' on prior line?
| |
| 124 } | |
| 125 | |
| 126 private: | |
| 127 typedef GrGLEffect INHERITED; | |
| 128 }; | |
| 129 | |
| 130 | |
| 131 private: | |
| 132 CircleEdgeEffect(bool stroke) : GrEffect() { | |
| 133 this->addVertexAttrib(kVec4f_GrSLType); | |
| 134 fStroke = stroke; | |
| 135 } | |
| 136 | |
| 137 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { | |
| 138 const CircleEdgeEffect& cee = CastEffect<CircleEdgeEffect>(other); | |
| 139 return cee.fStroke == fStroke; | |
| 140 } | |
| 141 | |
| 142 bool fStroke; | |
| 143 | |
| 144 GR_DECLARE_EFFECT_TEST; | |
| 145 | |
| 146 typedef GrEffect INHERITED; | |
| 147 }; | |
| 148 | |
| 149 GR_DEFINE_EFFECT_TEST(CircleEdgeEffect); | |
| 150 | |
| 151 GrEffectRef* CircleEdgeEffect::TestCreate(SkMWCRandom* random, | |
| 152 GrContext* context, | |
| 153 const GrDrawTargetCaps&, | |
| 154 GrTexture* textures[]) { | |
| 155 return CircleEdgeEffect::Create(random->nextBool()); | |
| 156 } | |
| 157 | |
| 158 /////////////////////////////////////////////////////////////////////////////// | |
| 159 | |
| 160 /** | |
| 161 * The output of this effect is a modulation of the input color and coverage for an axis-aligned | |
| 162 * ellipse, specified as center_x, center_y, x_radius, x_radius/y_radius in wind ow space (y-down). | |
| 163 */ | |
| 164 | |
| 165 class EllipseEdgeEffect : public GrEffect { | |
| 166 public: | |
| 167 static GrEffectRef* Create(bool stroke) { | |
| 168 // we go through this so we only have one copy of each effect (stroked/f illed) | |
| 169 static SkAutoTUnref<GrEffectRef> gEllipseStrokeEdgeEffectRef( | |
| 170 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEf fect, (true))))); | |
| 171 static SkAutoTUnref<GrEffectRef> gEllipseFillEdgeEffectRef( | |
| 172 CreateEffectRef(AutoEffectUnref(SkNEW_ARGS(EllipseEdgeEf fect, (false))))); | |
| 173 | |
| 174 if (stroke) { | |
| 175 gEllipseStrokeEdgeEffectRef.get()->ref(); | |
| 176 return gEllipseStrokeEdgeEffectRef; | |
| 177 } else { | |
| 178 gEllipseFillEdgeEffectRef.get()->ref(); | |
| 179 return gEllipseFillEdgeEffectRef; | |
| 180 } | |
| 181 } | |
| 182 | |
| 183 virtual void getConstantColorComponents(GrColor* color, | |
| 184 uint32_t* validFlags) const SK_OVERR IDE { | |
| 185 *validFlags = 0; | |
| 186 } | |
| 187 | |
| 188 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | |
| 189 return GrTBackendEffectFactory<EllipseEdgeEffect>::getInstance(); | |
| 190 } | |
| 191 | |
| 192 virtual ~EllipseEdgeEffect() {} | |
| 193 | |
| 194 static const char* Name() { return "EllipseEdge"; } | |
| 195 | |
| 196 inline bool isStroked() const { return fStroke; } | |
| 197 | |
| 198 class GLEffect : public GrGLEffect { | |
| 199 public: | |
| 200 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) | |
| 201 : INHERITED (factory) {} | |
| 202 | |
| 203 virtual void emitCode(GrGLShaderBuilder* builder, | |
| 204 const GrDrawEffect& drawEffect, | |
| 205 EffectKey key, | |
| 206 const char* outputColor, | |
| 207 const char* inputColor, | |
| 208 const TextureSamplerArray& samplers) SK_OVERRIDE { | |
| 209 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip seEdgeEffect>(); | |
| 210 | |
| 211 const char *vsCenterName, *fsCenterName; | |
| 212 const char *vsEdgeName, *fsEdgeName; | |
| 213 | |
| 214 builder->addVarying(kVec2f_GrSLType, "EllipseCenter", &vsCenterName, &fsCenterName); | |
| 215 const SkString* attr0Name = | |
| 216 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); | |
| 217 builder->vsCodeAppendf("\t%s = %s;\n", vsCenterName, attr0Name->c_st r()); | |
| 218 | |
| 219 builder->addVarying(kVec4f_GrSLType, "EllipseEdge", &vsEdgeName, &fs EdgeName); | |
| 220 const SkString* attr1Name = | |
| 221 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]); | |
| 222 builder->vsCodeAppendf("\t%s = %s;\n", vsEdgeName, attr1Name->c_str( )); | |
| 223 | |
| 224 // translate to origin | |
| 225 builder->fsCodeAppendf("\tvec2 outerOffset = (%s.xy - %s.xy);\n", | |
| 226 builder->fragmentPosition(), fsCenterName); | |
| 227 builder->fsCodeAppend("\tvec2 innerOffset = outerOffset;\n"); | |
| 228 // scale y by xRadius/yRadius | |
| 229 builder->fsCodeAppendf("\touterOffset.y *= %s.y;\n", fsEdgeName); | |
| 230 builder->fsCodeAppend("\tfloat dOuter = length(outerOffset);\n"); | |
| 231 // compare outer lengths against xOuterRadius | |
| 232 builder->fsCodeAppendf("\tfloat edgeAlpha = clamp(%s.x-dOuter, 0.0, 1.0);\n", 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 | |
|
robertphillips
2013/03/31 22:59:08
overlength
| |
| 239 builder->fsCodeAppendf("\tfloat innerAlpha = clamp(dInner-%s.z, 0.0, 1.0);\n", fsEdgeName); | |
| 240 builder->fsCodeAppend("\tedgeAlpha *= innerAlpha;\n"); | |
| 241 } | |
| 242 | |
| 243 SkString modulate; | |
| 244 GrGLSLModulate4f(&modulate, inputColor, "edgeAlpha"); | |
| 245 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); | |
| 246 } | |
| 247 | |
| 248 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { | |
| 249 const EllipseEdgeEffect& ellipseEffect = drawEffect.castEffect<Ellip seEdgeEffect>(); | |
| 250 | |
| 251 return ellipseEffect.isStroked() ? 0x1 : 0x0; | |
| 252 } | |
| 253 | |
| 254 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_ OVERRIDE { | |
| 255 } | |
| 256 | |
| 257 private: | |
| 258 typedef GrGLEffect INHERITED; | |
| 259 }; | |
| 260 | |
| 261 private: | |
| 262 EllipseEdgeEffect(bool stroke) : GrEffect() { | |
| 263 this->addVertexAttrib(kVec2f_GrSLType); | |
| 264 this->addVertexAttrib(kVec4f_GrSLType); | |
| 265 fStroke = stroke; | |
| 266 } | |
| 267 | |
| 268 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { | |
| 269 const EllipseEdgeEffect& eee = CastEffect<EllipseEdgeEffect>(other); | |
| 270 return eee.fStroke == fStroke; | |
| 271 } | |
| 272 | |
| 273 bool fStroke; | |
| 274 | |
| 275 GR_DECLARE_EFFECT_TEST; | |
| 276 | |
| 277 typedef GrEffect INHERITED; | |
| 278 }; | |
| 279 | |
| 280 GR_DEFINE_EFFECT_TEST(EllipseEdgeEffect); | |
| 281 | |
| 282 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random, | |
| 283 GrContext* context, | |
| 284 const GrDrawTargetCaps&, | |
| 285 GrTexture* textures[]) { | |
| 286 return EllipseEdgeEffect::Create(random->nextBool()); | |
| 287 } | |
| 288 | |
| 289 /////////////////////////////////////////////////////////////////////////////// | |
| 290 | |
| 43 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, co nst GrPaint& paint, | 291 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, co nst GrPaint& paint, |
| 44 const GrRect& oval, const SkStrokeRec& stroke) | 292 const GrRect& oval, const SkStrokeRec& stroke) |
| 45 { | 293 { |
| 46 if (!paint.isAntiAlias()) { | 294 if (!paint.isAntiAlias()) { |
| 47 return false; | 295 return false; |
| 48 } | 296 } |
| 49 | 297 |
| 50 const SkMatrix& vm = context->getMatrix(); | 298 const SkMatrix& vm = context->getMatrix(); |
| 51 | 299 |
| 52 // we can draw circles | 300 // we can draw circles |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 103 SkStrokeRec::Style style = stroke.getStyle(); | 351 SkStrokeRec::Style style = stroke.getStyle(); |
| 104 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); | 352 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); |
| 105 enum { | 353 enum { |
| 106 // the edge effects share this stage with glyph rendering | 354 // the edge effects share this stage with glyph rendering |
| 107 // (kGlyphMaskStage in GrTextContext) && SW path rendering | 355 // (kGlyphMaskStage in GrTextContext) && SW path rendering |
| 108 // (kPathMaskStage in GrSWMaskHelper) | 356 // (kPathMaskStage in GrSWMaskHelper) |
| 109 kEdgeEffectStage = GrPaint::kTotalStages, | 357 kEdgeEffectStage = GrPaint::kTotalStages, |
| 110 }; | 358 }; |
| 111 drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); | 359 drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); |
| 112 | 360 |
| 113 GrEffectRef* effect = GrCircleEdgeEffect::Create(isStroked); | 361 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked); |
| 114 static const int kCircleEdgeAttrIndex = 1; | 362 static const int kCircleEdgeAttrIndex = 1; |
| 115 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref( ); | 363 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->unref( ); |
| 116 | 364 |
| 117 SkScalar innerRadius = 0.0f; | 365 SkScalar innerRadius = 0.0f; |
| 118 SkScalar outerRadius = radius; | 366 SkScalar outerRadius = radius; |
| 119 SkScalar halfWidth = 0; | 367 SkScalar halfWidth = 0; |
| 120 if (style != SkStrokeRec::kFill_Style) { | 368 if (style != SkStrokeRec::kFill_Style) { |
| 121 if (SkScalarNearlyZero(strokeWidth)) { | 369 if (SkScalarNearlyZero(strokeWidth)) { |
| 122 halfWidth = SK_ScalarHalf; | 370 halfWidth = SK_ScalarHalf; |
| 123 } else { | 371 } else { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 202 SkStrokeRec::Style style = stroke.getStyle(); | 450 SkStrokeRec::Style style = stroke.getStyle(); |
| 203 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); | 451 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); |
| 204 enum { | 452 enum { |
| 205 // the edge effects share this stage with glyph rendering | 453 // the edge effects share this stage with glyph rendering |
| 206 // (kGlyphMaskStage in GrTextContext) && SW path rendering | 454 // (kGlyphMaskStage in GrTextContext) && SW path rendering |
| 207 // (kPathMaskStage in GrSWMaskHelper) | 455 // (kPathMaskStage in GrSWMaskHelper) |
| 208 kEdgeEffectStage = GrPaint::kTotalStages, | 456 kEdgeEffectStage = GrPaint::kTotalStages, |
| 209 }; | 457 }; |
| 210 drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); | 458 drawState->setAttribBindings(GrDrawState::kDefault_AttribBindings); |
| 211 | 459 |
| 212 GrEffectRef* effect = GrEllipseEdgeEffect::Create(isStroked); | 460 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); |
| 213 static const int kEllipseCenterAttrIndex = 1; | 461 static const int kEllipseCenterAttrIndex = 1; |
| 214 static const int kEllipseEdgeAttrIndex = 2; | 462 static const int kEllipseEdgeAttrIndex = 2; |
| 215 drawState->setEffect(kEdgeEffectStage, effect, | 463 drawState->setEffect(kEdgeEffectStage, effect, |
| 216 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( ); | 464 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( ); |
| 217 | 465 |
| 218 SkScalar xRadius = SkScalarHalf(xformedRect.width()); | 466 SkScalar xRadius = SkScalarHalf(xformedRect.width()); |
| 219 SkScalar yRadius = SkScalarHalf(xformedRect.height()); | 467 SkScalar yRadius = SkScalarHalf(xformedRect.height()); |
| 220 SkScalar innerXRadius = 0.0f; | 468 SkScalar innerXRadius = 0.0f; |
| 221 SkScalar innerRatio = 1.0f; | 469 SkScalar innerRatio = 1.0f; |
| 222 | 470 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 268 T += center.fY - SK_ScalarHalf; | 516 T += center.fY - SK_ScalarHalf; |
| 269 B += center.fY + SK_ScalarHalf; | 517 B += center.fY + SK_ScalarHalf; |
| 270 | 518 |
| 271 verts[0].fPos = SkPoint::Make(L, T); | 519 verts[0].fPos = SkPoint::Make(L, T); |
| 272 verts[1].fPos = SkPoint::Make(R, T); | 520 verts[1].fPos = SkPoint::Make(R, T); |
| 273 verts[2].fPos = SkPoint::Make(L, B); | 521 verts[2].fPos = SkPoint::Make(L, B); |
| 274 verts[3].fPos = SkPoint::Make(R, B); | 522 verts[3].fPos = SkPoint::Make(R, B); |
| 275 | 523 |
| 276 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); | 524 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4); |
| 277 } | 525 } |
| OLD | NEW |