Flutter Impeller
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

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_typeThe fill rule to use when filling.
[in]polylineThe polyline
[in]callbackThe 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) {
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) {
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) {
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
staticconstexpr

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::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