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 |