1 /*
2 * Copyright 2021 Google LLC.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/tessellate/Tessellation.h"
9
10 #include "include/core/SkPath.h"
11 #include "src/core/SkGeometry.h"
12 #include "src/core/SkPathPriv.h"
13 #include "src/gpu/BufferWriter.h"
14 #include "src/gpu/tessellate/CullTest.h"
15 #include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
16 #include "src/gpu/tessellate/WangsFormula.h"
17
18 namespace skgpu {
19
20 namespace {
21
22 // Writes a new path, chopping as necessary so no verbs require more segments than
23 // kMaxTessellationSegmentsPerCurve. Curves completely outside the viewport are flattened into
24 // lines.
25 class PathChopper {
26 public:
PathChopper(const SkMatrix & matrix,const SkRect & viewport)27 PathChopper(const SkMatrix& matrix, const SkRect& viewport)
28 : fCullTest(viewport, matrix)
29 , fVectorXform(matrix) {
30 fPath.setIsVolatile(true);
31 }
32
path() const33 SkPath path() const { return fPath; }
34
moveTo(SkPoint p)35 void moveTo(SkPoint p) { fPath.moveTo(p); }
lineTo(SkPoint p1)36 void lineTo(SkPoint p1) { fPath.lineTo(p1); }
close()37 void close() { fPath.close(); }
38
quadTo(const SkPoint p[3])39 void quadTo(const SkPoint p[3]) {
40 if (!fCullTest.areVisible3(p)) {
41 this->lineTo(p[2]);
42 return;
43 }
44 float n = wangs_formula::quadratic_pow4(kTessellationPrecision, p, fVectorXform);
45 if (n > pow4(kMaxTessellationSegmentsPerCurve)) {
46 SkPoint chops[5];
47 SkChopQuadAtHalf(p, chops);
48 this->quadTo(chops);
49 this->quadTo(chops + 2);
50 return;
51 }
52 fPath.quadTo(p[1], p[2]);
53 }
54
conicTo(const SkPoint p[3],float w)55 void conicTo(const SkPoint p[3], float w) {
56 if (!fCullTest.areVisible3(p)) {
57 this->lineTo(p[2]);
58 return;
59 }
60 float n = wangs_formula::conic_pow2(kTessellationPrecision, p, w, fVectorXform);
61 if (n > pow2(kMaxTessellationSegmentsPerCurve)) {
62 SkConic chops[2];
63 if (!SkConic(p,w).chopAt(.5, chops)) {
64 this->lineTo(p[2]);
65 return;
66 }
67 this->conicTo(chops[0].fPts, chops[0].fW);
68 this->conicTo(chops[1].fPts, chops[1].fW);
69 return;
70 }
71 fPath.conicTo(p[1], p[2], w);
72 }
73
cubicTo(const SkPoint p[4])74 void cubicTo(const SkPoint p[4]) {
75 if (!fCullTest.areVisible4(p)) {
76 this->lineTo(p[3]);
77 return;
78 }
79 float n = wangs_formula::cubic_pow4(kTessellationPrecision, p, fVectorXform);
80 if (n > pow4(kMaxTessellationSegmentsPerCurve)) {
81 SkPoint chops[7];
82 SkChopCubicAtHalf(p, chops);
83 this->cubicTo(chops);
84 this->cubicTo(chops + 3);
85 return;
86 }
87 fPath.cubicTo(p[1], p[2], p[3]);
88 }
89
90 private:
91 const CullTest fCullTest;
92 const wangs_formula::VectorXform fVectorXform;
93 SkPath fPath;
94 };
95
96 } // namespace
97
PreChopPathCurves(const SkPath & path,const SkMatrix & matrix,const SkRect & viewport)98 SkPath PreChopPathCurves(const SkPath& path, const SkMatrix& matrix, const SkRect& viewport) {
99 PathChopper chopper(matrix, viewport);
100 for (auto [verb, p, w] : SkPathPriv::Iterate(path)) {
101 switch (verb) {
102 case SkPathVerb::kMove:
103 chopper.moveTo(p[0]);
104 break;
105 case SkPathVerb::kLine:
106 chopper.lineTo(p[1]);
107 break;
108 case SkPathVerb::kQuad:
109 chopper.quadTo(p);
110 break;
111 case SkPathVerb::kConic:
112 chopper.conicTo(p, *w);
113 break;
114 case SkPathVerb::kCubic:
115 chopper.cubicTo(p);
116 break;
117 case SkPathVerb::kClose:
118 chopper.close();
119 break;
120 }
121 }
122 return chopper.path();
123 }
124
125 } // namespace skgpu
126