| Flutter Impeller |

Public Types | Public Member Functions | Static Public Attributes | List of all members
impeller::Tessellator Class Reference

A utility that generates triangles of the specified fill type given a polyline. This happens on the CPU. More...

`#include <tessellator.h>`

## Public Types
enum | Result { Result::kSuccess, Result::kInputError, Result::kTessellationError }
using | BuilderCallback = std::function< bool(const float *vertices, size_t vertices_count, const uint16_t *indices, size_t indices_count)>
| A callback that returns the results of the tessellation. More...

## Public Member Functions
| Tessellator ()
| ~Tessellator ()
Tessellator::Result | Tessellate (FillType fill_type, const Path::Polyline &polyline, const BuilderCallback &callback) const
| Generates filled triangles from the polyline. A callback is invoked once for the entire tessellation. More...

## Static Public Attributes
static constexpr size_t | kMultiContourThreshold = 30u
| An arbitrary value to determine when a multi-contour non-zero fill path should be split into multiple tessellations. More...

## Detailed Description

A utility that generates triangles of the specified fill type given a polyline. This happens on the CPU.

Definition at line 35 of file tessellator.h.

## Member Typedef Documentation

## ◆ BuilderCallback

using impeller::Tessellator::BuilderCallback = std::function<bool(const float* vertices, size_t vertices_count, const uint16_t* indices, size_t indices_count)>

A callback that returns the results of the tessellation.

       The index buffer may not be populated, in which case [indices] will
       be nullptr and indices_count will be 0.

Definition at line 58 of file tessellator.h.

## Member Enumeration Documentation

## ◆ Result

enum impeller::Tessellator::Result
| strong

Enumerator
kSuccess |
kInputError |
kTessellationError |

Definition at line 37 of file tessellator.h.

37 {
38 kSuccess,
39 kInputError,
40 kTessellationError,
41 };

## Constructor & Destructor Documentation

## ◆ Tessellator()

impeller::Tessellator::Tessellator | ( |  | ) |

Definition at line 34 of file tessellator.cc.

34 : c_tessellator_(nullptr, &DestroyTessellator) {
35 TESSalloc alloc = kAlloc;
36 {
37 // libTess2 copies the TESSalloc despite the non-const argument.
38 CTessellator tessellator(::tessNewTess(&alloc), &DestroyTessellator);
39 c_tessellator_ = std::move(tessellator);
40 }
41 }

References impeller::DestroyTessellator(), and impeller::kAlloc.

## ◆ ~Tessellator()

impeller::Tessellator::~Tessellator | ( |  | ) |
| default

## Member Function Documentation

## ◆ Tessellate()

Tessellator::Result impeller::Tessellator::Tessellate | ( | FillType | fill_type,
|  | const Path::Polyline & | polyline,
|  | const BuilderCallback & | callback
| ) |  | const

Generates filled triangles from the polyline. A callback is invoked once for the entire tessellation.

Parameters

  [in] | fill_type | The fill rule to use when filling.
  [in] | polyline | The polyline
  [in] | callback | The callback, return false to indicate failure.

Returns
  The result status of the tessellation.

Feed contour information to the tessellator.

Let's tessellate.

Feed contour information to the tessellator.

Let's tessellate.

Definition at line 61 of file tessellator.cc.

64 {
65 if (!callback) {
66 return Result::kInputError;
67 }
68
69 if (polyline.points.empty()) {
70 return Result::kInputError;
71 }
72
73 auto tessellator = c_tessellator_.get();
74 if (!tessellator) {
75 return Result::kTessellationError;
76 }
77
78 constexpr int kVertexSize = 2;
79 constexpr int kPolygonSize = 3;
80
81 // If we have a larger polyline and the fill type is non-zero, we can split
82 // the tessellation up per contour. Since in general the complexity is at
83 // least nlog(n), this speeds up the processes substantially.
84 if (polyline.contours.size() > kMultiContourThreshold &&
85 fill_type == FillType::kNonZero) {
86 std::vector<Point> points;
87 std::vector<float> data;
88
89 //----------------------------------------------------------------------------
90 /// Feed contour information to the tessellator.
91 ///
92 size_t total = 0u;
93 static_assert(sizeof(Point) == 2 * sizeof(float));
94 for (size_t contour_i = 0; contour_i < polyline.contours.size();
95 contour_i++) {
96 size_t start_point_index, end_point_index;
97 std::tie(start_point_index, end_point_index) =
98 polyline.GetContourPointBounds(contour_i);
99
100 ::tessAddContour(tessellator, // the C tessellator
101 kVertexSize, //
102 polyline.points.data() + start_point_index, //
103 sizeof(Point), //
104 end_point_index - start_point_index //
105 );
106
107 //----------------------------------------------------------------------------
108 /// Let's tessellate.
109 ///
110 auto result = ::tessTesselate(tessellator, // tessellator
111 ToTessWindingRule(fill_type), // winding
112 TESS_POLYGONS, // element type
113 kPolygonSize, // polygon size
114 kVertexSize, // vertex size
115 nullptr // normal (null is automatic)
116 );
117
118 if (result != 1) {
119 return Result::kTessellationError;
120 }
121
122 int vertex_item_count = tessGetVertexCount(tessellator) * kVertexSize;
123 auto vertices = tessGetVertices(tessellator);
124 for (int i = 0; i < vertex_item_count; i += 2) {
125 points.emplace_back(vertices[i], vertices[i + 1]);
126 }
127
128 int element_item_count = tessGetElementCount(tessellator) * kPolygonSize;
129 auto elements = tessGetElements(tessellator);
130 total += element_item_count;
131 for (int i = 0; i < element_item_count; i++) {
132 data.emplace_back(points[elements[i]].x);
133 data.emplace_back(points[elements[i]].y);
134 }
135 points.clear();
136 }
137 if (!callback(data.data(), total, nullptr, 0u)) {
138 return Result::kInputError;
139 }
140 } else {
141 //----------------------------------------------------------------------------
142 /// Feed contour information to the tessellator.
143 ///
144 static_assert(sizeof(Point) == 2 * sizeof(float));
145 for (size_t contour_i = 0; contour_i < polyline.contours.size();
146 contour_i++) {
147 size_t start_point_index, end_point_index;
148 std::tie(start_point_index, end_point_index) =
149 polyline.GetContourPointBounds(contour_i);
150
151 ::tessAddContour(tessellator, // the C tessellator
152 kVertexSize, //
153 polyline.points.data() + start_point_index, //
154 sizeof(Point), //
155 end_point_index - start_point_index //
156 );
157 }
158
159 //----------------------------------------------------------------------------
160 /// Let's tessellate.
161 ///
162 auto result = ::tessTesselate(tessellator, // tessellator
163 ToTessWindingRule(fill_type), // winding
164 TESS_POLYGONS, // element type
165 kPolygonSize, // polygon size
166 kVertexSize, // vertex size
167 nullptr // normal (null is automatic)
168 );
169
170 if (result != 1) {
171 return Result::kTessellationError;
172 }
173
174 int element_item_count = tessGetElementCount(tessellator) * kPolygonSize;
175
176 // We default to using a 16bit index buffer, but in cases where we generate
177 // more tessellated data than this can contain we need to fall back to
178 // dropping the index buffer entirely. Instead code could instead switch to
179 // a uint32 index buffer, but this is done for simplicity with the other
180 // fast path above.
181 if (element_item_count < USHRT_MAX) {
182 int vertex_item_count = tessGetVertexCount(tessellator);
183 auto vertices = tessGetVertices(tessellator);
184 auto elements = tessGetElements(tessellator);
185
186 // libtess uses an int index internally due to usage of -1 as a sentinel
187 // value.
188 std::vector<uint16_t> indices(element_item_count);
189 for (int i = 0; i < element_item_count; i++) {
190 indices[i] = static_cast<uint16_t>(elements[i]);
191 }
192 if (!callback(vertices, vertex_item_count, indices.data(),
193 element_item_count)) {
194 return Result::kInputError;
195 }
196 } else {
197 std::vector<Point> points;
198 std::vector<float> data;
199
200 int vertex_item_count = tessGetVertexCount(tessellator) * kVertexSize;
201 auto vertices = tessGetVertices(tessellator);
202 for (int i = 0; i < vertex_item_count; i += 2) {
203 points.emplace_back(vertices[i], vertices[i + 1]);
204 }
205
206 int element_item_count = tessGetElementCount(tessellator) * kPolygonSize;
207 auto elements = tessGetElements(tessellator);
208 for (int i = 0; i < element_item_count; i++) {
209 data.emplace_back(points[elements[i]].x);
210 data.emplace_back(points[elements[i]].y);
211 }
212 if (!callback(data.data(), element_item_count, nullptr, 0u)) {
213 return Result::kInputError;
214 }
215 }
216 }
217
218 return Result::kSuccess;
219 }

References impeller::Path::Polyline::contours, impeller::Path::Polyline::GetContourPointBounds(), kInputError, kMultiContourThreshold, impeller::kNonZero, kSuccess, kTessellationError, impeller::Path::Polyline::points, and impeller::ToTessWindingRule().

Referenced by impeller::BM_Polyline(), impeller::Tessellate(), impeller::testing::TEST(), and impeller::testing::TEST_P().

## Member Data Documentation

## ◆ kMultiContourThreshold

constexpr size_t impeller::Tessellator::kMultiContourThreshold = 30u
| static constexpr

An arbitrary value to determine when a multi-contour non-zero fill path should be split into multiple tessellations.

Definition at line 49 of file tessellator.h.

Referenced by Tessellate(), and impeller::testing::TEST().

The documentation for this class was generated from the following files:

- impeller/tessellator/tessellator.h
- impeller/tessellator/tessellator.cc

impeller::kAlloc
static const TESSalloc kAlloc
Definition: tessellator.cc:24
impeller::Tessellator::Result::kInputError
@ kInputError
impeller::Point
TPoint< Scalar > Point
Definition: point.h:306
impeller::Tessellator::Result::kTessellationError
@ kTessellationError
impeller::Tessellator::kMultiContourThreshold
static constexpr size_t kMultiContourThreshold
An arbitrary value to determine when a multi-contour non-zero fill path should be split into multiple...
Definition: tessellator.h:49
impeller::DestroyTessellator
void DestroyTessellator(TESStesselator *tessellator)
Definition: tessellator.cc:221
impeller::Tessellator::Result::kSuccess
@ kSuccess
impeller::FillType::kNonZero
@ kNonZero
impeller::ToTessWindingRule
static int ToTessWindingRule(FillType fill_type)
Definition: tessellator.cc:45
impeller::CTessellator
std::unique_ptr< TESStesselator, decltype(&DestroyTessellator)> CTessellator
Definition: tessellator.h:22