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