diff options
author | Chris Dalton <csmartdalton@google.com> | 2018-04-23 21:14:42 -0600 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-04-24 15:23:06 +0000 |
commit | 6f5e77a08faf9d967eba8194811cbf2391092c23 (patch) | |
tree | 577ea1030e16bd68c47eaa5cd3c494785c7204e6 /gm | |
parent | b97f28b90399c2571712401a30b0299d37b4b52e (diff) |
ccpr: Cull extremely thin triangles
When triangles get too thin it's possible for FP round-off error to
actually give us the wrong winding direction, causing rendering
artifacts. This change also allows us to unblacklist ANGLE.
Bug: skia:7805
Bug: skia:7820
Change-Id: Ibaa0f033eba625d720e3a594c4515d8264cc413d
Reviewed-on: https://skia-review.googlesource.com/123262
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
Diffstat (limited to 'gm')
-rw-r--r-- | gm/mandoline.cpp | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/gm/mandoline.cpp b/gm/mandoline.cpp new file mode 100644 index 0000000000..17dd02f7e0 --- /dev/null +++ b/gm/mandoline.cpp @@ -0,0 +1,202 @@ +/* + * Copyright 2018 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "gm.h" +#include "sk_tool_utils.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkPoint.h" +#include "SkGeometry.h" +#include <math.h> + +namespace skiagm { + +// Slices paths into sliver-size contours shaped like ice cream cones. +class MandolineSlicer { +public: + static constexpr int kDefaultSubdivisions = 10; + + MandolineSlicer(SkPoint anchorPt) { + fPath.setFillType(SkPath::kEvenOdd_FillType); + fPath.setIsVolatile(true); + this->reset(anchorPt); + } + + void reset(SkPoint anchorPt) { + fPath.reset(); + fLastPt = fAnchorPt = anchorPt; + } + + void sliceLine(SkPoint pt, int numSubdivisions = kDefaultSubdivisions) { + if (numSubdivisions <= 0) { + fPath.moveTo(fAnchorPt); + fPath.lineTo(fLastPt); + fPath.lineTo(pt); + fPath.close(); + fLastPt = pt; + return; + } + float T = this->chooseChopT(numSubdivisions); + if (0 == T) { + fPath.lineTo(fLastPt); + this->sliceLine(pt, numSubdivisions - 1); + return; + } + SkPoint midpt = fLastPt * (1 - T) + pt * T; + this->sliceLine(midpt, numSubdivisions - 1); + this->sliceLine(pt, numSubdivisions - 1); + } + + void sliceQuadratic(SkPoint p1, SkPoint p2, int numSubdivisions = kDefaultSubdivisions) { + if (numSubdivisions <= 0) { + fPath.moveTo(fAnchorPt); + fPath.lineTo(fLastPt); + fPath.quadTo(p1, p2); + fPath.close(); + fLastPt = p2; + return; + } + float T = this->chooseChopT(numSubdivisions); + if (0 == T) { + fPath.quadTo(fLastPt, fLastPt); + this->sliceQuadratic(p1, p2, numSubdivisions - 1); + return; + } + SkPoint P[3] = {fLastPt, p1, p2}, PP[5]; + SkChopQuadAt(P, PP, T); + this->sliceQuadratic(PP[1], PP[2], numSubdivisions - 1); + this->sliceQuadratic(PP[3], PP[4], numSubdivisions - 1); + } + + void sliceCubic(SkPoint p1, SkPoint p2, SkPoint p3, + int numSubdivisions = kDefaultSubdivisions) { + if (numSubdivisions <= 0) { + fPath.moveTo(fAnchorPt); + fPath.lineTo(fLastPt); + fPath.cubicTo(p1, p2, p3); + fPath.close(); + fLastPt = p3; + return; + } + float T = this->chooseChopT(numSubdivisions); + if (0 == T) { + fPath.cubicTo(fLastPt, fLastPt, fLastPt); + this->sliceCubic(p1, p2, p3, numSubdivisions - 1); + return; + } + SkPoint P[4] = {fLastPt, p1, p2, p3}, PP[7]; + SkChopCubicAt(P, PP, T); + this->sliceCubic(PP[1], PP[2], PP[3], numSubdivisions - 1); + this->sliceCubic(PP[4], PP[5], PP[6], numSubdivisions - 1); + } + + void sliceConic(SkPoint p1, SkPoint p2, float w, int numSubdivisions = kDefaultSubdivisions) { + if (numSubdivisions <= 0) { + fPath.moveTo(fAnchorPt); + fPath.lineTo(fLastPt); + fPath.conicTo(p1, p2, w); + fPath.close(); + fLastPt = p2; + return; + } + float T = this->chooseChopT(numSubdivisions); + if (0 == T) { + fPath.conicTo(fLastPt, fLastPt, w); + this->sliceConic(p1, p2, w, numSubdivisions - 1); + return; + } + SkConic conic(fLastPt, p1, p2, w), halves[2]; + if (!conic.chopAt(T, halves)) { + SK_ABORT("SkConic::chopAt failed"); + } + this->sliceConic(halves[0].fPts[1], halves[0].fPts[2], halves[0].fW, numSubdivisions - 1); + this->sliceConic(halves[1].fPts[1], halves[1].fPts[2], halves[1].fW, numSubdivisions - 1); + } + + const SkPath& path() const { return fPath; } + +private: + float chooseChopT(int numSubdivisions) { + SkASSERT(numSubdivisions > 0); + if (numSubdivisions > 1) { + return .5f; + } + float T = (0 == fRand.nextU() % 10) ? 0 : scalbnf(1, -(int)fRand.nextRangeU(10, 149)); + SkASSERT(T >= 0 && T < 1); + return T; + } + + SkRandom fRand; + SkPath fPath; + SkPoint fAnchorPt; + SkPoint fLastPt; +}; + +class SliverPathsGM : public GM { +public: + SliverPathsGM() { + this->setBGColor(sk_tool_utils::color_to_565(SK_ColorBLACK)); + } + +protected: + SkString onShortName() override { + return SkString("mandoline"); + } + + SkISize onISize() override { + return SkISize::Make(560, 475); + } + + void onDraw(SkCanvas* canvas) override { + SkPaint paint; + paint.setColor(SK_ColorWHITE); + paint.setAntiAlias(true); + + MandolineSlicer mandoline({41, 43}); + mandoline.sliceCubic({5, 277}, {381, -74}, {243, 162}); + mandoline.sliceLine({41, 43}); + canvas->drawPath(mandoline.path(), paint); + + mandoline.reset({357.049988f, 446.049988f}); + mandoline.sliceCubic({472.750000f, -71.950012f}, {639.750000f, 531.950012f}, + {309.049988f, 347.950012f}); + mandoline.sliceLine({309.049988f, 419}); + mandoline.sliceLine({357.049988f, 446.049988f}); + canvas->drawPath(mandoline.path(), paint); + + canvas->save(); + canvas->translate(421, 105); + canvas->scale(100, 81); + mandoline.reset({-cosf(SkDegreesToRadians(-60)), sinf(SkDegreesToRadians(-60))}); + mandoline.sliceConic({-2, 0}, + {-cosf(SkDegreesToRadians(60)), sinf(SkDegreesToRadians(60))}, .5f); + mandoline.sliceConic({-cosf(SkDegreesToRadians(120))*2, sinf(SkDegreesToRadians(120))*2}, + {1, 0}, .5f); + mandoline.sliceLine({0, 0}); + mandoline.sliceLine({-cosf(SkDegreesToRadians(-60)), sinf(SkDegreesToRadians(-60))}); + canvas->drawPath(mandoline.path(), paint); + canvas->restore(); + + canvas->save(); + canvas->translate(150, 300); + canvas->scale(75, 75); + mandoline.reset({1, 0}); + constexpr int nquads = 5; + for (int i = 0; i < nquads; ++i) { + float theta1 = 2*SK_ScalarPI/nquads * (i + .5f); + float theta2 = 2*SK_ScalarPI/nquads * (i + 1); + mandoline.sliceQuadratic({cosf(theta1)*2, sinf(theta1)*2}, + {cosf(theta2), sinf(theta2)}); + } + canvas->drawPath(mandoline.path(), paint); + canvas->restore(); + } +}; + +DEF_GM(return new SliverPathsGM;) + +} |