| Flutter Impeller |

tessellator_libtess.cc
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "impeller/tessellator/tessellator_libtess.h"
6
7 #include "third_party/libtess2/Include/tesselator.h"
8
9 namespace impeller {
10
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 TessellatorLibtess::TessellatorLibtess()
35 : c_tessellator_(nullptr, &DestroyTessellator) {
36 TESSalloc alloc = kAlloc;
37 {
38 // libTess2 copies the TESSalloc despite the non-const argument.
39 CTessellator tessellator(::tessNewTess(&alloc), &DestroyTessellator);
40 c_tessellator_ = std::move(tessellator);
41 }
42 }
43
44 TessellatorLibtess::~TessellatorLibtess() = default;
45
46 static int ToTessWindingRule(FillType fill_type) {
47 switch (fill_type) {
48 case FillType::kOdd:
49 return TESS_WINDING_ODD;
50 case FillType::kNonZero:
51 return TESS_WINDING_NONZERO;
52 }
53 return TESS_WINDING_ODD;
54 }
55
56 TessellatorLibtess::Result TessellatorLibtess::Tessellate(
57 const Path& path,
58 Scalar tolerance,
59 const BuilderCallback& callback) {
60 if (!callback) {
61 return TessellatorLibtess::Result::kInputError;
62 }
63
64 std::unique_ptr<std::vector<Point>> point_buffer =
65 std::make_unique<std::vector<Point>>();
66 auto polyline = path.CreatePolyline(tolerance, std::move(point_buffer));
67
68 auto fill_type = path.GetFillType();
69
70 if (polyline.points->empty()) {
71 return TessellatorLibtess::Result::kInputError;
72 }
73
74 auto tessellator = c_tessellator_.get();
75 if (!tessellator) {
76 return TessellatorLibtess::Result::kTessellationError;
77 }
78
79 constexpr int kVertexSize = 2;
80 constexpr int kPolygonSize = 3;
81
82 //----------------------------------------------------------------------------
83 /// Feed contour information to the tessellator.
84 ///
85 static_assert(sizeof(Point) == 2 * sizeof(float));
86 for (size_t contour_i = 0; contour_i < polyline.contours.size();
87 contour_i++) {
88 size_t start_point_index, end_point_index;
89 std::tie(start_point_index, end_point_index) =
90 polyline.GetContourPointBounds(contour_i);
91
92 ::tessAddContour(tessellator, // the C tessellator
93 kVertexSize, //
94 polyline.points->data() + start_point_index, //
95 sizeof(Point), //
96 end_point_index - start_point_index //
97 );
98 }
99
100 //----------------------------------------------------------------------------
101 /// Let's tessellate.
102 ///
103 auto result = ::tessTesselate(tessellator, // tessellator
104 ToTessWindingRule(fill_type), // winding
105 TESS_POLYGONS, // element type
106 kPolygonSize, // polygon size
107 kVertexSize, // vertex size
108 nullptr // normal (null is automatic)
109 );
110
111 if (result != 1) {
112 return TessellatorLibtess::Result::kTessellationError;
113 }
114
115 int element_item_count = tessGetElementCount(tessellator) * kPolygonSize;
116
117 // We default to using a 16bit index buffer, but in cases where we generate
118 // more tessellated data than this can contain we need to fall back to
119 // dropping the index buffer entirely. Instead code could instead switch to
120 // a uint32 index buffer, but this is done for simplicity with the other
121 // fast path above.
122 if (element_item_count < USHRT_MAX) {
123 int vertex_item_count = tessGetVertexCount(tessellator);
124 auto vertices = tessGetVertices(tessellator);
125 auto elements = tessGetElements(tessellator);
126
127 // libtess uses an int index internally due to usage of -1 as a sentinel
128 // value.
129 std::vector<uint16_t> indices(element_item_count);
130 for (int i = 0; i < element_item_count; i++) {
131 indices[i] = static_cast<uint16_t>(elements[i]);
132 }
133 if (!callback(vertices, vertex_item_count, indices.data(),
134 element_item_count)) {
135 return TessellatorLibtess::Result::kInputError;
136 }
137 } else {
138 std::vector<Point> points;
139 std::vector<float> data;
140
141 int vertex_item_count = tessGetVertexCount(tessellator) * kVertexSize;
142 auto vertices = tessGetVertices(tessellator);
143 points.reserve(vertex_item_count);
144 for (int i = 0; i < vertex_item_count; i += 2) {
145 points.emplace_back(vertices[i], vertices[i + 1]);
146 }
147
148 int element_item_count = tessGetElementCount(tessellator) * kPolygonSize;
149 auto elements = tessGetElements(tessellator);
150 data.reserve(element_item_count);
151 for (int i = 0; i < element_item_count; i++) {
152 data.emplace_back(points[elements[i]].x);
153 data.emplace_back(points[elements[i]].y);
154 }
155 if (!callback(data.data(), element_item_count, nullptr, 0u)) {
156 return TessellatorLibtess::Result::kInputError;
157 }
158 }
159
160 return TessellatorLibtess::Result::kSuccess;
161 }
162
163 void DestroyTessellator(TESStesselator* tessellator) {
164 if (tessellator != nullptr) {
165 ::tessDeleteTess(tessellator);
166 }
167 }
168
169 } // namespace impeller
impeller::kAlloc
static const TESSalloc kAlloc
Definition: tessellator_libtess.cc:24
impeller::TessellatorLibtess::Result
Result
Definition: tessellator_libtess.h:35
impeller::TessellatorLibtess::Result::kTessellationError
@ kTessellationError
polyline
const Path::Polyline & polyline
Definition: stroke_path_geometry.cc:296
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::FillType::kOdd
@ kOdd
impeller::TessellatorLibtess::Result::kInputError
@ kInputError
impeller::HeapRealloc
static void * HeapRealloc(void *userData, void *ptr, unsigned int size)
Definition: tessellator_libtess.cc:15
data
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63
impeller::HeapFree
static void HeapFree(void *userData, void *ptr)
Definition: tessellator_libtess.cc:19
tessellator_libtess.h
impeller::TessellatorLibtess::~TessellatorLibtess
~TessellatorLibtess()
impeller::TessellatorLibtess::Tessellate
TessellatorLibtess::Result Tessellate(const Path &path, Scalar tolerance, const BuilderCallback &callback)
Generates filled triangles from the path. A callback is invoked once for the entire tessellation.
Definition: tessellator_libtess.cc:56
impeller::Path
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
Definition: path.h:52
impeller::DestroyTessellator
void DestroyTessellator(TESStesselator *tessellator)
Definition: tessellator_libtess.cc:163
impeller::TessellatorLibtess::BuilderCallback
std::function< bool(const float *vertices, size_t vertices_count, const uint16_t *indices, size_t indices_count)> BuilderCallback
A callback that returns the results of the tessellation.
Definition: tessellator_libtess.h:48
impeller::FillType
FillType
Definition: path.h:30
impeller::FillType::kNonZero
@ kNonZero
impeller::HeapAlloc
static void * HeapAlloc(void *userData, unsigned int size)
Definition: tessellator_libtess.cc:11
impeller::TPoint< Scalar >
impeller::ToTessWindingRule
static int ToTessWindingRule(FillType fill_type)
Definition: tessellator_libtess.cc:46
impeller::TessellatorLibtess::TessellatorLibtess
TessellatorLibtess()
Definition: tessellator_libtess.cc:34
impeller
Definition: allocation.cc:12
impeller::TessellatorLibtess::Result::kSuccess
@ kSuccess
impeller::Path::CreatePolyline
Polyline CreatePolyline(Scalar scale, Polyline::PointBufferPtr point_buffer=std::make_unique< std::vector< Point >>(), Polyline::ReclaimPointBufferCallback reclaim=nullptr) const
Definition: path.cc:289
impeller::CTessellator
std::unique_ptr< TESStesselator, decltype(&DestroyTessellator)> CTessellator
Definition: tessellator_libtess.h:20
impeller::Path::GetFillType
FillType GetFillType() const
Definition: path.cc:47