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 "GrEffect.h" | 10 #include "GrEffect.h" |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 28 }; | 28 }; |
| 29 | 29 |
| 30 struct EllipseVertex { | 30 struct EllipseVertex { |
| 31 GrPoint fPos; | 31 GrPoint fPos; |
| 32 SkScalar fOuterXRadius; | 32 SkScalar fOuterXRadius; |
| 33 SkScalar fInnerXRadius; | 33 SkScalar fInnerXRadius; |
| 34 GrPoint fOuterOffset; | 34 GrPoint fOuterOffset; |
| 35 GrPoint fInnerOffset; | 35 GrPoint fInnerOffset; |
| 36 }; | 36 }; |
| 37 | 37 |
| 38 struct RRectVertex { | |
| 39 GrPoint fPos; | |
| 40 GrPoint fOffset; | |
| 41 GrPoint fOuterRadii; | |
| 42 GrPoint fInnerRadii; | |
| 43 }; | |
| 44 | |
| 38 inline bool circle_stays_circle(const SkMatrix& m) { | 45 inline bool circle_stays_circle(const SkMatrix& m) { |
| 39 return m.isSimilarity(); | 46 return m.isSimilarity(); |
| 40 } | 47 } |
| 41 | 48 |
| 42 } | 49 } |
| 43 | 50 |
| 44 /////////////////////////////////////////////////////////////////////////////// | 51 /////////////////////////////////////////////////////////////////////////////// |
| 45 | 52 |
| 46 /** | 53 /** |
| 47 * The output of this effect is a modulation of the input color and coverage for a circle, | 54 * The output of this effect is a modulation of the input color and coverage for a circle, |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 268 | 275 |
| 269 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random, | 276 GrEffectRef* EllipseEdgeEffect::TestCreate(SkMWCRandom* random, |
| 270 GrContext* context, | 277 GrContext* context, |
| 271 const GrDrawTargetCaps&, | 278 const GrDrawTargetCaps&, |
| 272 GrTexture* textures[]) { | 279 GrTexture* textures[]) { |
| 273 return EllipseEdgeEffect::Create(random->nextBool()); | 280 return EllipseEdgeEffect::Create(random->nextBool()); |
| 274 } | 281 } |
| 275 | 282 |
| 276 /////////////////////////////////////////////////////////////////////////////// | 283 /////////////////////////////////////////////////////////////////////////////// |
| 277 | 284 |
| 285 /** | |
| 286 * The output of this effect is a modulation of the input color and coverage for an axis-aligned | |
|
robertphillips
2013/04/24 15:13:30
ellipse -> RR?
jvanverth1
2013/04/24 19:02:27
Renamed this to AltEllipseEdgeEffect to reflect th
| |
| 287 * ellipse, specified as an offset vector from center and outer and inner radii in both x and y | |
| 288 * directions. | |
| 289 * | |
| 290 * This uses a slightly different algorithm than the EllipseEdgeEffect, above. R ather than | |
| 291 * scaling an ellipse to be a circle, it attempts to find the distance from the offset point to the | |
|
robertphillips
2013/04/24 15:13:30
ellipse -> RR?
| |
| 292 * ellipse by determining where the line through the origin and offset point wou ld cross the | |
| 293 * ellipse, and computing the distance to that. This is slower but works better for roundrects | |
| 294 * because the straight edges will be more accurate. | |
| 295 */ | |
| 296 | |
| 297 class RRectEdgeEffect : public GrEffect { | |
| 298 public: | |
| 299 static GrEffectRef* Create(bool stroke) { | |
| 300 // we go through this so we only have one copy of each effect (stroked/f illed) | |
| 301 GR_CREATE_STATIC_EFFECT(gRRectStrokeEdge, RRectEdgeEffect, (true)); | |
| 302 GR_CREATE_STATIC_EFFECT(gRRectFillEdge, RRectEdgeEffect, (false)); | |
| 303 | |
| 304 if (stroke) { | |
| 305 gRRectStrokeEdge->ref(); | |
| 306 return gRRectStrokeEdge; | |
| 307 } else { | |
| 308 gRRectFillEdge->ref(); | |
| 309 return gRRectFillEdge; | |
| 310 } | |
| 311 } | |
| 312 | |
| 313 virtual void getConstantColorComponents(GrColor* color, | |
| 314 uint32_t* validFlags) const SK_OVERR IDE { | |
| 315 *validFlags = 0; | |
| 316 } | |
| 317 | |
| 318 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { | |
| 319 return GrTBackendEffectFactory<RRectEdgeEffect>::getInstance(); | |
| 320 } | |
| 321 | |
| 322 virtual ~RRectEdgeEffect() {} | |
| 323 | |
| 324 static const char* Name() { return "RRectEdge"; } | |
| 325 | |
| 326 inline bool isStroked() const { return fStroke; } | |
| 327 | |
| 328 class GLEffect : public GrGLEffect { | |
| 329 public: | |
| 330 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) | |
|
robertphillips
2013/04/24 15:13:30
tab before the ':'
jvanverth1
2013/04/24 19:02:27
Done.
| |
| 331 : INHERITED (factory) {} | |
| 332 | |
| 333 virtual void emitCode(GrGLShaderBuilder* builder, | |
| 334 const GrDrawEffect& drawEffect, | |
| 335 EffectKey key, | |
| 336 const char* outputColor, | |
| 337 const char* inputColor, | |
| 338 const TextureSamplerArray& samplers) SK_OVERRIDE { | |
| 339 const RRectEdgeEffect& rrectEffect = drawEffect.castEffect<RRectEdge Effect>(); | |
| 340 | |
| 341 const char *vsOffsetName, *fsOffsetName; | |
| 342 const char *vsRadiiName, *fsRadiiName; | |
| 343 | |
| 344 builder->addVarying(kVec2f_GrSLType, "EllipseOffsets", &vsOffsetName , &fsOffsetName); | |
| 345 const SkString* attr0Name = | |
| 346 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[0]); | |
| 347 builder->vsCodeAppendf("\t%s = %s;\n", vsOffsetName, attr0Name->c_st r()); | |
| 348 | |
| 349 builder->addVarying(kVec4f_GrSLType, "EllipseRadii", &vsRadiiName, & fsRadiiName); | |
| 350 const SkString* attr1Name = | |
| 351 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice s()[1]); | |
| 352 builder->vsCodeAppendf("\t%s = %s;\n", vsRadiiName, attr1Name->c_str ()); | |
| 353 | |
|
robertphillips
2013/04/24 15:13:30
rm extra space?
jvanverth1
2013/04/24 19:02:27
Done.
| |
| 354 builder->fsCodeAppend("\tfloat edgeAlpha;\n"); | |
| 355 // get length of offset | |
| 356 builder->fsCodeAppendf("\tfloat len = length(%s.xy);\n", fsOffsetNam e); | |
|
robertphillips
2013/04/24 15:13:30
Couldn't offset be a vec2?
jvanverth1
2013/04/24 19:02:27
Done.
| |
| 357 builder->fsCodeAppend("\tvec4 offset;\n"); | |
| 358 | |
|
robertphillips
2013/04/24 15:13:30
ellipse -> RR?
jvanverth1
2013/04/24 19:02:27
Done.
| |
| 359 // for outer ellipse | |
| 360 builder->fsCodeAppendf("\toffset.xy = %s.xy*%s.yx;\n", | |
| 361 fsOffsetName, fsRadiiName); | |
| 362 builder->fsCodeAppendf("\tfloat tOuter = " | |
| 363 "%s.x*%s.y*inversesqrt(dot(offset.xy, offset. xy));\n", | |
| 364 fsRadiiName, fsRadiiName); | |
| 365 builder->fsCodeAppend("\tedgeAlpha = clamp(len*tOuter - len, 0.0, 1. 0);\n"); | |
| 366 | |
| 367 // for inner ellipse | |
| 368 if (rrectEffect.isStroked()) { | |
| 369 builder->fsCodeAppendf("\toffset.zw = %s.xy*%s.wz;\n", | |
| 370 fsOffsetName, fsRadiiName); | |
| 371 builder->fsCodeAppendf("\tfloat tInner = " | |
| 372 "%s.z*%s.w*inversesqrt(dot(offset.zw, off set.zw));\n", | |
| 373 fsRadiiName, fsRadiiName); | |
| 374 builder->fsCodeAppend("\tedgeAlpha *= clamp(len - len*tInner, 0. 0, 1.0);\n"); | |
| 375 } | |
| 376 | |
| 377 SkString modulate; | |
| 378 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); | |
| 379 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str() ); | |
| 380 } | |
| 381 | |
| 382 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG LCaps&) { | |
| 383 const RRectEdgeEffect& rrectEffect = drawEffect.castEffect<RRectEdge Effect>(); | |
| 384 | |
| 385 return rrectEffect.isStroked() ? 0x1 : 0x0; | |
| 386 } | |
| 387 | |
| 388 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_ OVERRIDE { | |
| 389 } | |
| 390 | |
| 391 private: | |
| 392 typedef GrGLEffect INHERITED; | |
| 393 }; | |
| 394 | |
| 395 private: | |
| 396 RRectEdgeEffect(bool stroke) : GrEffect() { | |
| 397 this->addVertexAttrib(kVec2f_GrSLType); | |
| 398 this->addVertexAttrib(kVec4f_GrSLType); | |
| 399 fStroke = stroke; | |
| 400 } | |
| 401 | |
| 402 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { | |
| 403 const RRectEdgeEffect& rree = CastEffect<RRectEdgeEffect>(other); | |
| 404 return rree.fStroke == fStroke; | |
| 405 } | |
| 406 | |
| 407 bool fStroke; | |
| 408 | |
| 409 GR_DECLARE_EFFECT_TEST; | |
| 410 | |
| 411 typedef GrEffect INHERITED; | |
| 412 }; | |
| 413 | |
| 414 GR_DEFINE_EFFECT_TEST(RRectEdgeEffect); | |
| 415 | |
| 416 GrEffectRef* RRectEdgeEffect::TestCreate(SkMWCRandom* random, | |
| 417 GrContext* context, | |
| 418 const GrDrawTargetCaps&, | |
| 419 GrTexture* textures[]) { | |
| 420 return RRectEdgeEffect::Create(random->nextBool()); | |
| 421 } | |
| 422 | |
| 423 /////////////////////////////////////////////////////////////////////////////// | |
| 424 | |
| 278 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, co nst GrPaint& paint, | 425 bool GrOvalRenderer::drawOval(GrDrawTarget* target, const GrContext* context, co nst GrPaint& paint, |
| 279 const GrRect& oval, const SkStrokeRec& stroke) | 426 const GrRect& oval, const SkStrokeRec& stroke) |
| 280 { | 427 { |
| 281 if (!paint.isAntiAlias()) { | 428 if (!paint.isAntiAlias()) { |
| 282 return false; | 429 return false; |
| 283 } | 430 } |
| 284 | 431 |
| 285 const SkMatrix& vm = context->getMatrix(); | 432 const SkMatrix& vm = context->getMatrix(); |
| 286 | 433 |
| 287 // we can draw circles | 434 // we can draw circles |
| 288 if (SkScalarNearlyEqual(oval.width(), oval.height()) | 435 if (SkScalarNearlyEqual(oval.width(), oval.height()) |
| 289 && circle_stays_circle(vm)) { | 436 && circle_stays_circle(vm)) { |
| 290 drawCircle(target, paint, oval, stroke); | 437 drawCircle(target, paint, oval, stroke); |
| 291 | 438 |
| 292 // and axis-aligned ellipses only | 439 // and axis-aligned ellipses only |
| 293 } else if (vm.rectStaysRect()) { | 440 } else if (vm.rectStaysRect()) { |
| 294 return drawEllipse(target, paint, oval, stroke); | 441 return drawEllipse(target, paint, oval, stroke); |
| 295 | 442 |
| 296 } else { | 443 } else { |
| 297 return false; | 444 return false; |
| 298 } | 445 } |
| 299 | 446 |
| 300 return true; | 447 return true; |
| 301 } | 448 } |
| 302 | 449 |
| 303 namespace { | 450 namespace { |
| 304 | 451 |
| 452 /////////////////////////////////////////////////////////////////////////////// | |
| 453 | |
| 305 // position + edge | 454 // position + edge |
| 306 extern const GrVertexAttrib gCircleVertexAttribs[] = { | 455 extern const GrVertexAttrib gCircleVertexAttribs[] = { |
| 307 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, | 456 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding }, |
| 308 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding} | 457 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding} |
| 309 }; | 458 }; |
| 310 | 459 |
| 311 }; | 460 }; |
| 312 | 461 |
| 313 void GrOvalRenderer::drawCircle(GrDrawTarget* target, | 462 void GrOvalRenderer::drawCircle(GrDrawTarget* target, |
| 314 const GrPaint& paint, | 463 const GrPaint& paint, |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 398 verts[2].fInnerRadius = innerRadius; | 547 verts[2].fInnerRadius = innerRadius; |
| 399 | 548 |
| 400 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); | 549 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); |
| 401 verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius); | 550 verts[3].fOffset = SkPoint::Make(outerRadius, outerRadius); |
| 402 verts[3].fOuterRadius = outerRadius; | 551 verts[3].fOuterRadius = outerRadius; |
| 403 verts[3].fInnerRadius = innerRadius; | 552 verts[3].fInnerRadius = innerRadius; |
| 404 | 553 |
| 405 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); | 554 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); |
| 406 } | 555 } |
| 407 | 556 |
| 557 /////////////////////////////////////////////////////////////////////////////// | |
| 558 | |
| 408 namespace { | 559 namespace { |
| 409 | 560 |
| 410 // position + edge | 561 // position + edge |
| 411 extern const GrVertexAttrib gEllipseVertexAttribs[] = { | 562 extern const GrVertexAttrib gEllipseVertexAttribs[] = { |
| 412 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBindi ng}, | 563 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBindi ng}, |
| 413 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding }, | 564 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding }, |
| 414 {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint), kEffect_GrVertexAttribBinding } | 565 {kVec4f_GrVertexAttribType, 2*sizeof(GrPoint), kEffect_GrVertexAttribBinding } |
| 415 }; | 566 }; |
| 416 | 567 |
| 417 }; | 568 }; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 478 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); | 629 GrEffectRef* effect = EllipseEdgeEffect::Create(isStroked); |
| 479 static const int kEllipseCenterAttrIndex = 1; | 630 static const int kEllipseCenterAttrIndex = 1; |
| 480 static const int kEllipseEdgeAttrIndex = 2; | 631 static const int kEllipseEdgeAttrIndex = 2; |
| 481 drawState->setEffect(kEdgeEffectStage, effect, | 632 drawState->setEffect(kEdgeEffectStage, effect, |
| 482 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( ); | 633 kEllipseCenterAttrIndex, kEllipseEdgeAttrIndex)->unref( ); |
| 483 | 634 |
| 484 SkScalar innerXRadius = 0.0f; | 635 SkScalar innerXRadius = 0.0f; |
| 485 SkScalar innerRatio = 1.0f; | 636 SkScalar innerRatio = 1.0f; |
| 486 | 637 |
| 487 if (SkStrokeRec::kFill_Style != style) { | 638 if (SkStrokeRec::kFill_Style != style) { |
| 488 | |
| 489 | |
| 490 if (SkScalarNearlyZero(scaledStroke.length())) { | 639 if (SkScalarNearlyZero(scaledStroke.length())) { |
| 491 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); | 640 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); |
| 492 } else { | 641 } else { |
| 493 scaledStroke.scale(0.5f); | 642 scaledStroke.scale(0.5f); |
| 494 } | 643 } |
| 495 | 644 |
| 496 // this is legit only if scale & translation (which should be the case a t the moment) | 645 // this is legit only if scale & translation (which should be the case a t the moment) |
| 497 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) { | 646 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_Style == style) { |
| 498 SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); | 647 SkScalar innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); |
| 499 if (innerYRadius > SK_ScalarNearlyZero) { | 648 if (innerYRadius > SK_ScalarNearlyZero) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 545 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); | 694 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); |
| 546 verts[3].fOuterXRadius = xRadius; | 695 verts[3].fOuterXRadius = xRadius; |
| 547 verts[3].fInnerXRadius = innerXRadius; | 696 verts[3].fInnerXRadius = innerXRadius; |
| 548 verts[3].fOuterOffset = SkPoint::Make(xRadius, outerRatio*yRadius); | 697 verts[3].fOuterOffset = SkPoint::Make(xRadius, outerRatio*yRadius); |
| 549 verts[3].fInnerOffset = SkPoint::Make(xRadius, innerRatio*yRadius); | 698 verts[3].fInnerOffset = SkPoint::Make(xRadius, innerRatio*yRadius); |
| 550 | 699 |
| 551 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); | 700 target->drawNonIndexed(kTriangleStrip_GrPrimitiveType, 0, 4, &bounds); |
| 552 | 701 |
| 553 return true; | 702 return true; |
| 554 } | 703 } |
| 704 | |
| 705 /////////////////////////////////////////////////////////////////////////////// | |
| 706 | |
| 707 bool GrOvalRenderer::drawSimpleRRect(GrDrawTarget* target, const GrContext* cont ext, | |
| 708 const GrPaint& paint, const GrRRect& rrect, | |
| 709 const SkStrokeRec& stroke) | |
| 710 { | |
| 711 const SkMatrix& vm = context->getMatrix(); | |
| 712 #ifdef SK_DEBUG | |
| 713 { | |
| 714 // we should have checked for this previously | |
| 715 SkASSERT(paint.isAntiAlias() && vm.rectStaysRect() && rrect.isSimple()); | |
| 716 } | |
| 717 #endif | |
| 718 | |
| 719 // do any matrix crunching before we reset the draw state for device coords | |
| 720 const SkRect& rrectBounds = rrect.getBounds(); | |
| 721 SkRect bounds; | |
| 722 vm.mapRect(&bounds, rrectBounds); | |
| 723 | |
| 724 SkVector radii = rrect.getSimpleRadii(); | |
| 725 SkScalar xRadius = SkScalarAbs(vm[SkMatrix::kMScaleX]*radii.fX + | |
| 726 vm[SkMatrix::kMSkewY]*radii.fY); | |
| 727 SkScalar yRadius = SkScalarAbs(vm[SkMatrix::kMSkewX]*radii.fX + | |
| 728 vm[SkMatrix::kMScaleY]*radii.fY); | |
| 729 // tall or wide quarter-ellipse corners aren't handled | |
| 730 if (SkScalarDiv(xRadius, yRadius) > 2 || SkScalarDiv(yRadius, xRadius) > 2) { | |
| 731 return false; | |
| 732 } | |
| 733 // if hairline stroke is greater than radius, we don't handle that right now | |
| 734 SkStrokeRec::Style style = stroke.getStyle(); | |
|
robertphillips
2013/04/24 15:13:30
SK_ScalarHalf?
jvanverth1
2013/04/24 19:02:27
Done.
| |
| 735 if (SkStrokeRec::kHairline_Style == style && (0.5f >= xRadius || 0.5f >= yRa dius)) { | |
| 736 return false; | |
| 737 } | |
| 738 | |
| 739 // do (potentially) anisotropic mapping of stroke | |
| 740 SkVector scaledStroke; | |
| 741 SkScalar strokeWidth = stroke.getWidth(); | |
| 742 scaledStroke.fX = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMScaleX] + vm[SkMat rix::kMSkewY])); | |
| 743 scaledStroke.fY = SkScalarAbs(strokeWidth*(vm[SkMatrix::kMSkewX] + vm[SkMatr ix::kMScaleY])); | |
| 744 | |
| 745 // if half of strokewidth is greater than radius, we don't handle that right now | |
| 746 if (SK_ScalarHalf*scaledStroke.fX >= xRadius || SK_ScalarHalf*scaledStroke.f Y >= yRadius) { | |
| 747 return false; | |
| 748 } | |
| 749 | |
| 750 // reset to device coordinates | |
| 751 GrDrawState* drawState = target->drawState(); | |
| 752 GrDrawState::AutoDeviceCoordDraw adcd(drawState); | |
| 753 if (!adcd.succeeded()) { | |
| 754 return false; | |
| 755 } | |
| 756 | |
|
robertphillips
2013/04/24 15:13:30
I agree with Brian that this should be long lived
bsalomon
2013/04/24 15:17:20
Also can see GrAAHairLinePathRenderer::Create().
| |
| 757 static const uint16_t kRRectIndices[] = { | |
| 758 // corners | |
| 759 0, 1, 5, 0, 5, 4, | |
| 760 2, 3, 7, 2, 7, 6, | |
| 761 8, 9, 13, 8, 13, 12, | |
| 762 10, 11, 15, 10, 15, 14, | |
| 763 | |
| 764 // edges | |
| 765 1, 2, 6, 1, 6, 5, | |
| 766 4, 5, 9, 4, 9, 8, | |
| 767 6, 7, 11, 6, 11, 10, | |
| 768 9, 10, 14, 9, 14, 13, | |
| 769 | |
|
robertphillips
2013/04/24 15:13:30
Maybe a comment here r.e. the magic positioning of
jvanverth1
2013/04/24 19:02:27
Done.
| |
| 770 // center | |
| 771 5, 6, 10, 5, 10, 9 | |
| 772 }; | |
| 773 | |
| 774 bool isStroked = (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairl ine_Style == style); | |
| 775 | |
| 776 enum { | |
| 777 // the edge effects share this stage with glyph rendering | |
| 778 // (kGlyphMaskStage in GrTextContext) && SW path rendering | |
| 779 // (kPathMaskStage in GrSWMaskHelper) | |
| 780 kEdgeEffectStage = GrPaint::kTotalStages, | |
| 781 }; | |
| 782 | |
| 783 // if the corners are circles, use the circle renderer | |
| 784 if ((!isStroked || scaledStroke.fX == scaledStroke.fY) && xRadius == yRadius ) { | |
| 785 drawState->setVertexAttribs<gCircleVertexAttribs>(SK_ARRAY_COUNT(gCircle VertexAttribs)); | |
| 786 GrAssert(sizeof(CircleVertex) == drawState->getVertexSize()); | |
| 787 | |
| 788 GrDrawTarget::AutoReleaseGeometry geo(target, 16, GR_ARRAY_COUNT(kRRectI ndices)); | |
| 789 if (!geo.succeeded()) { | |
| 790 GrPrintf("Failed to get space for vertices!\n"); | |
| 791 return false; | |
| 792 } | |
| 793 | |
| 794 CircleVertex* verts = reinterpret_cast<CircleVertex*>(geo.vertices()); | |
| 795 uint16_t* indices = reinterpret_cast<uint16_t*>(geo.indices()); | |
| 796 memcpy(indices, kRRectIndices, sizeof(kRRectIndices)); | |
|
bsalomon
2013/04/24 14:36:38
Should we use a long-lived index buffer? Could use
jvanverth1
2013/04/24 19:02:27
Done.
| |
| 797 | |
| 798 GrEffectRef* effect = CircleEdgeEffect::Create(isStroked); | |
| 799 static const int kCircleEdgeAttrIndex = 1; | |
| 800 drawState->setEffect(kEdgeEffectStage, effect, kCircleEdgeAttrIndex)->un ref(); | |
| 801 | |
| 802 SkScalar innerRadius = 0.0f; | |
| 803 SkScalar outerRadius = xRadius; | |
| 804 SkScalar halfWidth = 0; | |
| 805 if (style != SkStrokeRec::kFill_Style) { | |
| 806 if (SkScalarNearlyZero(scaledStroke.fX)) { | |
| 807 halfWidth = SK_ScalarHalf; | |
| 808 } else { | |
| 809 halfWidth = SkScalarHalf(scaledStroke.fX); | |
| 810 } | |
| 811 | |
| 812 if (isStroked) { | |
| 813 innerRadius = SkMaxScalar(0, xRadius - halfWidth); | |
| 814 } | |
| 815 outerRadius += halfWidth; | |
| 816 bounds.outset(halfWidth, halfWidth); | |
| 817 } | |
| 818 | |
| 819 // The radii are outset for two reasons. First, it allows the shader to simply perform | |
| 820 // clamp(distance-to-center - radius, 0, 1). Second, the outer radius is used to compute the | |
| 821 // verts of the bounding box that is rendered and the outset ensures the box will cover all | |
| 822 // pixels partially covered by the circle. | |
| 823 outerRadius += SK_ScalarHalf; | |
| 824 innerRadius -= SK_ScalarHalf; | |
| 825 | |
| 826 // Expand the rect so all the pixels will be captured. | |
| 827 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); | |
| 828 | |
| 829 SkScalar yCoords[4] = { | |
| 830 bounds.fTop, | |
| 831 bounds.fTop + outerRadius, | |
| 832 bounds.fBottom - outerRadius, | |
| 833 bounds.fBottom | |
| 834 }; | |
| 835 SkScalar yOuterRadii[4] = { | |
| 836 -outerRadius, | |
| 837 0, | |
| 838 0, | |
| 839 outerRadius | |
| 840 }; | |
| 841 for (int i = 0; i < 4; ++i) { | |
| 842 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); | |
| 843 verts->fOffset = SkPoint::Make(-outerRadius, yOuterRadii[i]); | |
| 844 verts->fOuterRadius = outerRadius; | |
| 845 verts->fInnerRadius = innerRadius; | |
| 846 verts++; | |
| 847 | |
| 848 verts->fPos = SkPoint::Make(bounds.fLeft + outerRadius, yCoords[i]); | |
| 849 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); | |
| 850 verts->fOuterRadius = outerRadius; | |
| 851 verts->fInnerRadius = innerRadius; | |
| 852 verts++; | |
| 853 | |
| 854 verts->fPos = SkPoint::Make(bounds.fRight - outerRadius, yCoords[i]) ; | |
| 855 verts->fOffset = SkPoint::Make(0, yOuterRadii[i]); | |
| 856 verts->fOuterRadius = outerRadius; | |
| 857 verts->fInnerRadius = innerRadius; | |
| 858 verts++; | |
| 859 | |
| 860 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); | |
| 861 verts->fOffset = SkPoint::Make(outerRadius, yOuterRadii[i]); | |
| 862 verts->fOuterRadius = outerRadius; | |
| 863 verts->fInnerRadius = innerRadius; | |
| 864 verts++; | |
| 865 } | |
| 866 | |
| 867 // drop out the middle quad if we're stroked | |
| 868 int indexCnt = isStroked ? GR_ARRAY_COUNT(kRRectIndices)-6 : GR_ARRAY_CO UNT(kRRectIndices); | |
| 869 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds); | |
| 870 | |
| 871 // otherwise we use the special ellipse renderer | |
| 872 } else { | |
| 873 | |
| 874 drawState->setVertexAttribs<gEllipseVertexAttribs>(SK_ARRAY_COUNT(gEllip seVertexAttribs)); | |
| 875 GrAssert(sizeof(RRectVertex) == drawState->getVertexSize()); | |
| 876 | |
| 877 GrDrawTarget::AutoReleaseGeometry geo(target, 16, GR_ARRAY_COUNT(kRRectI ndices)); | |
| 878 if (!geo.succeeded()) { | |
| 879 GrPrintf("Failed to get space for vertices!\n"); | |
| 880 return false; | |
| 881 } | |
| 882 | |
| 883 RRectVertex* verts = reinterpret_cast<RRectVertex*>(geo.vertices()); | |
| 884 uint16_t* indices = reinterpret_cast<uint16_t*>(geo.indices()); | |
| 885 memcpy(indices, kRRectIndices, sizeof(kRRectIndices)); | |
| 886 | |
| 887 GrEffectRef* effect = RRectEdgeEffect::Create(isStroked); | |
| 888 static const int kRRectCenterAttrIndex = 1; | |
| 889 static const int kRRectEdgeAttrIndex = 2; | |
| 890 drawState->setEffect(kEdgeEffectStage, effect, | |
| 891 kRRectCenterAttrIndex, kRRectEdgeAttrIndex)->unref( ); | |
| 892 | |
| 893 SkScalar innerXRadius = 0.0f; | |
| 894 SkScalar innerYRadius = 0.0f; | |
| 895 | |
| 896 if (SkStrokeRec::kFill_Style != style) { | |
| 897 if (SkScalarNearlyZero(scaledStroke.length())) { | |
| 898 scaledStroke.set(SK_ScalarHalf, SK_ScalarHalf); | |
| 899 } else { | |
| 900 scaledStroke.scale(0.5f); | |
| 901 } | |
| 902 | |
| 903 // this is legit only if scale & translation (which should be the ca se at the moment) | |
| 904 if (SkStrokeRec::kStroke_Style == style || SkStrokeRec::kHairline_St yle == style) { | |
| 905 innerXRadius = SkMaxScalar(0, xRadius - scaledStroke.fX); | |
| 906 innerYRadius = SkMaxScalar(0, yRadius - scaledStroke.fY); | |
| 907 } | |
| 908 xRadius += scaledStroke.fX; | |
| 909 yRadius += scaledStroke.fY; | |
| 910 bounds.outset(scaledStroke.fX, scaledStroke.fY); | |
| 911 } | |
| 912 | |
| 913 // Extend the radii out half a pixel to antialias. | |
| 914 SkScalar xOuterRadius = xRadius + SK_ScalarHalf; | |
| 915 SkScalar yOuterRadius = yRadius + SK_ScalarHalf; | |
| 916 SkScalar xInnerRadius = SkMaxScalar(innerXRadius - SK_ScalarHalf, 0); | |
| 917 SkScalar yInnerRadius = SkMaxScalar(innerYRadius - SK_ScalarHalf, 0); | |
| 918 | |
| 919 // Expand the rect so all the pixels will be captured. | |
| 920 bounds.outset(SK_ScalarHalf, SK_ScalarHalf); | |
| 921 | |
| 922 SkScalar yCoords[4] = { | |
| 923 bounds.fTop, | |
| 924 bounds.fTop + yOuterRadius, | |
| 925 bounds.fBottom - yOuterRadius, | |
| 926 bounds.fBottom | |
| 927 }; | |
| 928 SkScalar yOuterOffsets[4] = { | |
| 929 -yOuterRadius, | |
| 930 SK_ScalarNearlyZero, // we're using inversesqrt() in the shader, so can't be exactly 0 | |
| 931 SK_ScalarNearlyZero, | |
| 932 yOuterRadius | |
| 933 }; | |
| 934 | |
| 935 for (int i = 0; i < 4; ++i) { | |
| 936 verts->fPos = SkPoint::Make(bounds.fLeft, yCoords[i]); | |
| 937 verts->fOffset = SkPoint::Make(-xOuterRadius, yOuterOffsets[i]); | |
| 938 verts->fOuterRadii = SkPoint::Make(xOuterRadius, yOuterRadius); | |
| 939 verts->fInnerRadii = SkPoint::Make(xInnerRadius, yInnerRadius); | |
| 940 verts++; | |
| 941 | |
| 942 verts->fPos = SkPoint::Make(bounds.fLeft + xOuterRadius, yCoords[i]) ; | |
| 943 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] ); | |
| 944 verts->fOuterRadii = SkPoint::Make(xOuterRadius, yOuterRadius); | |
| 945 verts->fInnerRadii = SkPoint::Make(xInnerRadius, yInnerRadius); | |
| 946 verts++; | |
| 947 | |
| 948 verts->fPos = SkPoint::Make(bounds.fRight - xOuterRadius, yCoords[i] ); | |
| 949 verts->fOffset = SkPoint::Make(SK_ScalarNearlyZero, yOuterOffsets[i] ); | |
| 950 verts->fOuterRadii = SkPoint::Make(xOuterRadius, yOuterRadius); | |
| 951 verts->fInnerRadii = SkPoint::Make(xInnerRadius, yInnerRadius); | |
| 952 verts++; | |
| 953 | |
| 954 verts->fPos = SkPoint::Make(bounds.fRight, yCoords[i]); | |
| 955 verts->fOffset = SkPoint::Make(xOuterRadius, yOuterOffsets[i]); | |
| 956 verts->fOuterRadii = SkPoint::Make(xOuterRadius, yOuterRadius); | |
| 957 verts->fInnerRadii = SkPoint::Make(xInnerRadius, yInnerRadius); | |
| 958 verts++; | |
| 959 } | |
| 960 | |
| 961 // drop out the middle quad if we're stroked | |
| 962 int indexCnt = isStroked ? GR_ARRAY_COUNT(kRRectIndices)-6 : GR_ARRAY_CO UNT(kRRectIndices); | |
| 963 target->drawIndexed(kTriangles_GrPrimitiveType, 0, 0, 16, indexCnt, &bou nds); | |
| 964 } | |
| 965 | |
| 966 return true; | |
| 967 } | |
| 968 | |
| OLD | NEW |