|
4 | 4 |
|
5 | 5 | #include "impeller/tessellator/tessellator.h" |
6 | 6 |
|
7 | | -#include "third_party/libtess2/Include/tesselator.h" |
8 | | - |
9 | 7 | namespace impeller { |
10 | 8 |
|
11 | | -static void* HeapAlloc(void* userData, unsigned int size) { |
12 | | - return malloc(size); |
13 | | -} |
14 | | - |
15 | | -static void* HeapRealloc(void* userData, void* ptr, unsigned int size) { |
16 | | - return realloc(ptr, size); |
17 | | -} |
18 | | - |
19 | | -static void HeapFree(void* userData, void* ptr) { |
20 | | - free(ptr); |
21 | | -} |
22 | | - |
23 | | -// Note: these units are "number of entities" for bucket size and not in KB. |
24 | | -static const TESSalloc kAlloc = { |
25 | | - HeapAlloc, HeapRealloc, HeapFree, 0, /* =userData */ |
26 | | - 16, /* =meshEdgeBucketSize */ |
27 | | - 16, /* =meshVertexBucketSize */ |
28 | | - 16, /* =meshFaceBucketSize */ |
29 | | - 16, /* =dictNodeBucketSize */ |
30 | | - 16, /* =regionBucketSize */ |
31 | | - 0 /* =extraVertices */ |
32 | | -}; |
33 | | - |
34 | 9 | Tessellator::Tessellator() |
35 | | - : point_buffer_(std::make_unique<std::vector<Point>>()), |
36 | | - c_tessellator_(nullptr, &DestroyTessellator) { |
| 10 | + : point_buffer_(std::make_unique<std::vector<Point>>()) { |
37 | 11 | point_buffer_->reserve(2048); |
38 | | - TESSalloc alloc = kAlloc; |
39 | | - { |
40 | | - // libTess2 copies the TESSalloc despite the non-const argument. |
41 | | - CTessellator tessellator(::tessNewTess(&alloc), &DestroyTessellator); |
42 | | - c_tessellator_ = std::move(tessellator); |
43 | | - } |
44 | 12 | } |
45 | 13 |
|
46 | 14 | Tessellator::~Tessellator() = default; |
47 | 15 |
|
48 | | -static int ToTessWindingRule(FillType fill_type) { |
49 | | - switch (fill_type) { |
50 | | - case FillType::kOdd: |
51 | | - return TESS_WINDING_ODD; |
52 | | - case FillType::kNonZero: |
53 | | - return TESS_WINDING_NONZERO; |
54 | | - } |
55 | | - return TESS_WINDING_ODD; |
56 | | -} |
57 | | - |
58 | | -Tessellator::Result Tessellator::Tessellate(const Path& path, |
59 | | - Scalar tolerance, |
60 | | - const BuilderCallback& callback) { |
61 | | - if (!callback) { |
62 | | - return Result::kInputError; |
63 | | - } |
64 | | - |
65 | | - point_buffer_->clear(); |
66 | | - auto polyline = |
67 | | - path.CreatePolyline(tolerance, std::move(point_buffer_), |
68 | | - [this](Path::Polyline::PointBufferPtr point_buffer) { |
69 | | - point_buffer_ = std::move(point_buffer); |
70 | | - }); |
71 | | - |
72 | | - auto fill_type = path.GetFillType(); |
73 | | - |
74 | | - if (polyline.points->empty()) { |
75 | | - return Result::kInputError; |
76 | | - } |
77 | | - |
78 | | - auto tessellator = c_tessellator_.get(); |
79 | | - if (!tessellator) { |
80 | | - return Result::kTessellationError; |
81 | | - } |
82 | | - |
83 | | - constexpr int kVertexSize = 2; |
84 | | - constexpr int kPolygonSize = 3; |
85 | | - |
86 | | - //---------------------------------------------------------------------------- |
87 | | - /// Feed contour information to the tessellator. |
88 | | - /// |
89 | | - static_assert(sizeof(Point) == 2 * sizeof(float)); |
90 | | - for (size_t contour_i = 0; contour_i < polyline.contours.size(); |
91 | | - contour_i++) { |
92 | | - size_t start_point_index, end_point_index; |
93 | | - std::tie(start_point_index, end_point_index) = |
94 | | - polyline.GetContourPointBounds(contour_i); |
95 | | - |
96 | | - ::tessAddContour(tessellator, // the C tessellator |
97 | | - kVertexSize, // |
98 | | - polyline.points->data() + start_point_index, // |
99 | | - sizeof(Point), // |
100 | | - end_point_index - start_point_index // |
101 | | - ); |
102 | | - } |
103 | | - |
104 | | - //---------------------------------------------------------------------------- |
105 | | - /// Let's tessellate. |
106 | | - /// |
107 | | - auto result = ::tessTesselate(tessellator, // tessellator |
108 | | - ToTessWindingRule(fill_type), // winding |
109 | | - TESS_POLYGONS, // element type |
110 | | - kPolygonSize, // polygon size |
111 | | - kVertexSize, // vertex size |
112 | | - nullptr // normal (null is automatic) |
113 | | - ); |
114 | | - |
115 | | - if (result != 1) { |
116 | | - return Result::kTessellationError; |
117 | | - } |
118 | | - |
119 | | - int element_item_count = tessGetElementCount(tessellator) * kPolygonSize; |
120 | | - |
121 | | - // We default to using a 16bit index buffer, but in cases where we generate |
122 | | - // more tessellated data than this can contain we need to fall back to |
123 | | - // dropping the index buffer entirely. Instead code could instead switch to |
124 | | - // a uint32 index buffer, but this is done for simplicity with the other |
125 | | - // fast path above. |
126 | | - if (element_item_count < USHRT_MAX) { |
127 | | - int vertex_item_count = tessGetVertexCount(tessellator); |
128 | | - auto vertices = tessGetVertices(tessellator); |
129 | | - auto elements = tessGetElements(tessellator); |
130 | | - |
131 | | - // libtess uses an int index internally due to usage of -1 as a sentinel |
132 | | - // value. |
133 | | - std::vector<uint16_t> indices(element_item_count); |
134 | | - for (int i = 0; i < element_item_count; i++) { |
135 | | - indices[i] = static_cast<uint16_t>(elements[i]); |
136 | | - } |
137 | | - if (!callback(vertices, vertex_item_count, indices.data(), |
138 | | - element_item_count)) { |
139 | | - return Result::kInputError; |
140 | | - } |
141 | | - } else { |
142 | | - std::vector<Point> points; |
143 | | - std::vector<float> data; |
144 | | - |
145 | | - int vertex_item_count = tessGetVertexCount(tessellator) * kVertexSize; |
146 | | - auto vertices = tessGetVertices(tessellator); |
147 | | - points.reserve(vertex_item_count); |
148 | | - for (int i = 0; i < vertex_item_count; i += 2) { |
149 | | - points.emplace_back(vertices[i], vertices[i + 1]); |
150 | | - } |
151 | | - |
152 | | - int element_item_count = tessGetElementCount(tessellator) * kPolygonSize; |
153 | | - auto elements = tessGetElements(tessellator); |
154 | | - data.reserve(element_item_count); |
155 | | - for (int i = 0; i < element_item_count; i++) { |
156 | | - data.emplace_back(points[elements[i]].x); |
157 | | - data.emplace_back(points[elements[i]].y); |
158 | | - } |
159 | | - if (!callback(data.data(), element_item_count, nullptr, 0u)) { |
160 | | - return Result::kInputError; |
161 | | - } |
162 | | - } |
163 | | - |
164 | | - return Result::kSuccess; |
165 | | -} |
166 | | - |
167 | 16 | Path::Polyline Tessellator::CreateTempPolyline(const Path& path, |
168 | 17 | Scalar tolerance) { |
169 | 18 | FML_DCHECK(point_buffer_); |
@@ -239,12 +88,6 @@ std::vector<Point> Tessellator::TessellateConvex(const Path& path, |
239 | 88 | return output; |
240 | 89 | } |
241 | 90 |
|
242 | | -void DestroyTessellator(TESStesselator* tessellator) { |
243 | | - if (tessellator != nullptr) { |
244 | | - ::tessDeleteTess(tessellator); |
245 | | - } |
246 | | -} |
247 | | - |
248 | 91 | static constexpr int kPrecomputedDivisionCount = 1024; |
249 | 92 | static int kPrecomputedDivisions[kPrecomputedDivisionCount] = { |
250 | 93 | // clang-format off |
|
0 commit comments