@@ -78,51 +78,141 @@ Tessellator::Result Tessellator::Tessellate(
78
78
constexpr int kVertexSize = 2 ;
79
79
constexpr int kPolygonSize = 3 ;
80
80
81
- // ----------------------------------------------------------------------------
82
- // / Feed contour information to the tessellator.
83
- // /
84
- static_assert (sizeof (Point ) == 2 * sizeof (float ));
85
- for (size_t contour_i = 0 ; contour_i < polyline.contours .size ();
86
- contour_i++) {
87
- size_t start_point_index, end_point_index;
88
- std::tie (start_point_index, end_point_index) =
89
- polyline.GetContourPointBounds (contour_i);
90
-
91
- ::tessAddContour (tessellator, // the C tessellator
92
- kVertexSize , //
93
- polyline.points.data() + start_point_index, //
94
- sizeof(Point ), //
95
- end_point_index - start_point_index //
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)
96
168
);
97
- }
98
-
99
- // ----------------------------------------------------------------------------
100
- // / Let's tessellate.
101
- // /
102
- auto result = ::tessTesselate (tessellator, // tessellator
103
- ToTessWindingRule (fill_type), // winding
104
- TESS_POLYGONS, // element type
105
- kPolygonSize , // polygon size
106
- kVertexSize , // vertex size
107
- nullptr // normal (null is automatic)
108
- );
109
-
110
- if (result != 1 ) {
111
- return Result::kTessellationError ;
112
- }
113
169
114
- int vertexItemCount = tessGetVertexCount (tessellator) * kVertexSize ;
115
- auto vertices = tessGetVertices (tessellator);
116
- int elementItemCount = tessGetElementCount (tessellator) * kPolygonSize ;
117
- auto elements = tessGetElements (tessellator);
118
- // libtess uses an int index internally due to usage of -1 as a sentinel
119
- // value.
120
- std::vector<uint16_t > indices (elementItemCount);
121
- for (int i = 0 ; i < elementItemCount; i++) {
122
- indices[i] = static_cast <uint16_t >(elements[i]);
123
- }
124
- if (!callback (vertices, vertexItemCount, indices.data (), elementItemCount)) {
125
- return Result::kInputError ;
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
+ }
126
216
}
127
217
128
218
return Result::kSuccess ;
0 commit comments