@@ -78,51 +78,141 @@ Tessellator::Result Tessellator::Tessellate(
7878 constexpr int kVertexSize = 2 ;
7979 constexpr int kPolygonSize = 3 ;
8080
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)
96168 );
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- }
113169
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+ }
126216 }
127217
128218 return Result::kSuccess ;
0 commit comments