| Flutter Impeller |

tessellator_unittests.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 "flutter/testing/testing.h"
6 #include "gtest/gtest.h"
7
8 #include "impeller/geometry/geometry_asserts.h"
9 #include "impeller/geometry/path.h"
10 #include "impeller/geometry/path_builder.h"
11 #include "impeller/tessellator/tessellator.h"
12 #include "impeller/tessellator/tessellator_libtess.h"
13
14 namespace impeller {
15 namespace testing {
16
17 TEST(TessellatorTest, TessellatorBuilderReturnsCorrectResultStatus) {
18 // Zero points.
19 {
20 TessellatorLibtess t;
21 auto path = PathBuilder{}.TakePath(FillType::kOdd);
22 TessellatorLibtess::Result result = t.Tessellate(
23 path, 1.0f,
24 [](const float* vertices, size_t vertices_count,
25 const uint16_t* indices, size_t indices_count) { return true; });
26
27 ASSERT_EQ(result, TessellatorLibtess::Result::kInputError);
28 }
29
30 // One point.
31 {
32 TessellatorLibtess t;
33 auto path = PathBuilder{}.LineTo({0, 0}).TakePath(FillType::kOdd);
34 TessellatorLibtess::Result result = t.Tessellate(
35 path, 1.0f,
36 [](const float* vertices, size_t vertices_count,
37 const uint16_t* indices, size_t indices_count) { return true; });
38
39 ASSERT_EQ(result, TessellatorLibtess::Result::kSuccess);
40 }
41
42 // Two points.
43 {
44 TessellatorLibtess t;
45 auto path = PathBuilder{}.AddLine({0, 0}, {0, 1}).TakePath(FillType::kOdd);
46 TessellatorLibtess::Result result = t.Tessellate(
47 path, 1.0f,
48 [](const float* vertices, size_t vertices_count,
49 const uint16_t* indices, size_t indices_count) { return true; });
50
51 ASSERT_EQ(result, TessellatorLibtess::Result::kSuccess);
52 }
53
54 // Many points.
55 {
56 TessellatorLibtess t;
57 PathBuilder builder;
58 for (int i = 0; i < 1000; i++) {
59 auto coord = i * 1.0f;
60 builder.AddLine({coord, coord}, {coord + 1, coord + 1});
61 }
62 auto path = builder.TakePath(FillType::kOdd);
63 TessellatorLibtess::Result result = t.Tessellate(
64 path, 1.0f,
65 [](const float* vertices, size_t vertices_count,
66 const uint16_t* indices, size_t indices_count) { return true; });
67
68 ASSERT_EQ(result, TessellatorLibtess::Result::kSuccess);
69 }
70
71 // Closure fails.
72 {
73 TessellatorLibtess t;
74 auto path = PathBuilder{}.AddLine({0, 0}, {0, 1}).TakePath(FillType::kOdd);
75 TessellatorLibtess::Result result = t.Tessellate(
76 path, 1.0f,
77 [](const float* vertices, size_t vertices_count,
78 const uint16_t* indices, size_t indices_count) { return false; });
79
80 ASSERT_EQ(result, TessellatorLibtess::Result::kInputError);
81 }
82 }
83
84 TEST(TessellatorTest, TessellateConvex) {
85 {
86 std::vector<Point> points;
87 std::vector<uint16_t> indices;
88 // Sanity check simple rectangle.
89 Tessellator::TessellateConvexInternal(
90 PathBuilder{}.AddRect(Rect::MakeLTRB(0, 0, 10, 10)).TakePath(), points,
91 indices, 1.0);
92
93 // Note: the origin point is repeated but not referenced in the indices
94 // below
95 std::vector<Point> expected = {{0, 0}, {10, 0}, {10, 10}, {0, 10}, {0, 0}};
96 std::vector<uint16_t> expected_indices = {0, 1, 3, 2};
97 EXPECT_EQ(points, expected);
98 EXPECT_EQ(indices, expected_indices);
99 }
100
101 {
102 std::vector<Point> points;
103 std::vector<uint16_t> indices;
104 Tessellator::TessellateConvexInternal(
105 PathBuilder{}
106 .AddRect(Rect::MakeLTRB(0, 0, 10, 10))
107 .AddRect(Rect::MakeLTRB(20, 20, 30, 30))
108 .TakePath(),
109 points, indices, 1.0);
110
111 std::vector<Point> expected = {{0, 0}, {10, 0}, {10, 10}, {0, 10},
112 {0, 0}, {20, 20}, {30, 20}, {30, 30},
113 {20, 30}, {20, 20}};
114 std::vector<uint16_t> expected_indices = {0, 1, 3, 2, 2, 5, 5, 6, 8, 7};
115 EXPECT_EQ(points, expected);
116 EXPECT_EQ(indices, expected_indices);
117 }
118 }
119
120 // Filled Paths without an explicit close should still be closed
121 TEST(TessellatorTest, TessellateConvexUnclosedPath) {
122 std::vector<Point> points;
123 std::vector<uint16_t> indices;
124
125 // Create a rectangle that lacks an explicit close.
126 Path path = PathBuilder{}
127 .LineTo({100, 0})
128 .LineTo({100, 100})
129 .LineTo({0, 100})
130 .TakePath();
131 Tessellator::TessellateConvexInternal(path, points, indices, 1.0);
132
133 std::vector<Point> expected = {{0, 0}, {100, 0}, {100, 100}, {0, 100}};
134 std::vector<uint16_t> expected_indices = {0, 1, 3, 2};
135 EXPECT_EQ(points, expected);
136 EXPECT_EQ(indices, expected_indices);
137 }
138
139 TEST(TessellatorTest, CircleVertexCounts) {
140 auto tessellator = std::make_shared<Tessellator>();
141
142 auto test = [&tessellator](const Matrix& transform, Scalar radius) {
143 auto generator = tessellator->FilledCircle(transform, {}, radius);
144 size_t quadrant_divisions = generator.GetVertexCount() / 4;
145
146 // Confirm the approximation error is within the currently accepted
147 // |kCircleTolerance| value advertised by |CircleTessellator|.
148 // (With an additional 1% tolerance for floating point rounding.)
149 double angle = kPiOver2 / quadrant_divisions;
150 Point first = {radius, 0};
151 Point next = {static_cast<Scalar>(cos(angle) * radius),
152 static_cast<Scalar>(sin(angle) * radius)};
153 Point midpoint = (first + next) * 0.5;
154 EXPECT_GE(midpoint.GetLength(),
155 radius - Tessellator::kCircleTolerance * 1.01)
156 << ", transform = " << transform << ", radius = " << radius
157 << ", divisions = " << quadrant_divisions;
158 };
159
160 test({}, 0.0);
161 test({}, 0.9);
162 test({}, 1.0);
163 test({}, 1.9);
164 test(Matrix::MakeScale(Vector2(2.0, 2.0)), 0.95);
165 test({}, 2.0);
166 test(Matrix::MakeScale(Vector2(2.0, 2.0)), 1.0);
167 test({}, 11.9);
168 test({}, 12.0);
169 test({}, 35.9);
170 for (int i = 36; i < 10000; i += 4) {
171 test({}, i);
172 }
173 }
174
175 TEST(TessellatorTest, FilledCircleTessellationVertices) {
176 auto tessellator = std::make_shared<Tessellator>();
177
178 auto test = [&tessellator](const Matrix& transform, const Point& center,
179 Scalar radius) {
180 auto generator = tessellator->FilledCircle(transform, center, radius);
181 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
182
183 auto vertex_count = generator.GetVertexCount();
184 auto vertices = std::vector<Point>();
185 generator.GenerateVertices([&vertices](const Point& p) { //
186 vertices.push_back(p);
187 });
188 EXPECT_EQ(vertices.size(), vertex_count);
189 ASSERT_EQ(vertex_count % 4, 0u);
190
191 auto quadrant_count = vertex_count / 4;
192 for (size_t i = 0; i < quadrant_count; i++) {
193 double angle = kPiOver2 * i / (quadrant_count - 1);
194 double degrees = angle * 180.0 / kPi;
195 double rsin = sin(angle) * radius;
196 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
197 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radius;
198 EXPECT_POINT_NEAR(vertices[i * 2],
199 Point(center.x - rcos, center.y + rsin))
200 << "vertex " << i << ", angle = " << degrees << std::endl;
201 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
202 Point(center.x - rcos, center.y - rsin))
203 << "vertex " << i << ", angle = " << degrees << std::endl;
204 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1],
205 Point(center.x + rcos, center.y - rsin))
206 << "vertex " << i << ", angle = " << degrees << std::endl;
207 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2],
208 Point(center.x + rcos, center.y + rsin))
209 << "vertex " << i << ", angle = " << degrees << std::endl;
210 }
211 };
212
213 test({}, {}, 2.0);
214 test({}, {10, 10}, 2.0);
215 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {}, 2.0);
216 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {}, 1000.0);
217 }
218
219 TEST(TessellatorTest, StrokedCircleTessellationVertices) {
220 auto tessellator = std::make_shared<Tessellator>();
221
222 auto test = [&tessellator](const Matrix& transform, const Point& center,
223 Scalar radius, Scalar half_width) {
224 ASSERT_GT(radius, half_width);
225 auto generator =
226 tessellator->StrokedCircle(transform, center, radius, half_width);
227 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
228
229 auto vertex_count = generator.GetVertexCount();
230 auto vertices = std::vector<Point>();
231 generator.GenerateVertices([&vertices](const Point& p) { //
232 vertices.push_back(p);
233 });
234 EXPECT_EQ(vertices.size(), vertex_count);
235 ASSERT_EQ(vertex_count % 4, 0u);
236
237 auto quadrant_count = vertex_count / 8;
238
239 // Test outer points first
240 for (size_t i = 0; i < quadrant_count; i++) {
241 double angle = kPiOver2 * i / (quadrant_count - 1);
242 double degrees = angle * 180.0 / kPi;
243 double rsin = sin(angle) * (radius + half_width);
244 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
245 double rcos =
246 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius + half_width);
247 EXPECT_POINT_NEAR(vertices[i * 2],
248 Point(center.x - rcos, center.y - rsin))
249 << "vertex " << i << ", angle = " << degrees << std::endl;
250 EXPECT_POINT_NEAR(vertices[quadrant_count * 2 + i * 2],
251 Point(center.x + rsin, center.y - rcos))
252 << "vertex " << i << ", angle = " << degrees << std::endl;
253 EXPECT_POINT_NEAR(vertices[quadrant_count * 4 + i * 2],
254 Point(center.x + rcos, center.y + rsin))
255 << "vertex " << i << ", angle = " << degrees << std::endl;
256 EXPECT_POINT_NEAR(vertices[quadrant_count * 6 + i * 2],
257 Point(center.x - rsin, center.y + rcos))
258 << "vertex " << i << ", angle = " << degrees << std::endl;
259 }
260
261 // Then test innerer points
262 for (size_t i = 0; i < quadrant_count; i++) {
263 double angle = kPiOver2 * i / (quadrant_count - 1);
264 double degrees = angle * 180.0 / kPi;
265 double rsin = sin(angle) * (radius - half_width);
266 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
267 double rcos =
268 (i == quadrant_count - 1) ? 0.0f : cos(angle) * (radius - half_width);
269 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
270 Point(center.x - rcos, center.y - rsin))
271 << "vertex " << i << ", angle = " << degrees << std::endl;
272 EXPECT_POINT_NEAR(vertices[quadrant_count * 2 + i * 2 + 1],
273 Point(center.x + rsin, center.y - rcos))
274 << "vertex " << i << ", angle = " << degrees << std::endl;
275 EXPECT_POINT_NEAR(vertices[quadrant_count * 4 + i * 2 + 1],
276 Point(center.x + rcos, center.y + rsin))
277 << "vertex " << i << ", angle = " << degrees << std::endl;
278 EXPECT_POINT_NEAR(vertices[quadrant_count * 6 + i * 2 + 1],
279 Point(center.x - rsin, center.y + rcos))
280 << "vertex " << i << ", angle = " << degrees << std::endl;
281 }
282 };
283
284 test({}, {}, 2.0, 1.0);
285 test({}, {}, 2.0, 0.5);
286 test({}, {10, 10}, 2.0, 1.0);
287 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {}, 2.0, 1.0);
288 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {}, 1000.0, 10.0);
289 }
290
291 TEST(TessellatorTest, RoundCapLineTessellationVertices) {
292 auto tessellator = std::make_shared<Tessellator>();
293
294 auto test = [&tessellator](const Matrix& transform, const Point& p0,
295 const Point& p1, Scalar radius) {
296 auto generator = tessellator->RoundCapLine(transform, p0, p1, radius);
297 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
298
299 auto vertex_count = generator.GetVertexCount();
300 auto vertices = std::vector<Point>();
301 generator.GenerateVertices([&vertices](const Point& p) { //
302 vertices.push_back(p);
303 });
304 EXPECT_EQ(vertices.size(), vertex_count);
305 ASSERT_EQ(vertex_count % 4, 0u);
306
307 Point along = p1 - p0;
308 Scalar length = along.GetLength();
309 if (length > 0) {
310 along *= radius / length;
311 } else {
312 along = {radius, 0};
313 }
314 Point across = {-along.y, along.x};
315
316 auto quadrant_count = vertex_count / 4;
317 for (size_t i = 0; i < quadrant_count; i++) {
318 double angle = kPiOver2 * i / (quadrant_count - 1);
319 double degrees = angle * 180.0 / kPi;
320 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
321 Point relative_along =
322 along * ((i == quadrant_count - 1) ? 0.0f : cos(angle));
323 Point relative_across = across * sin(angle);
324 EXPECT_POINT_NEAR(vertices[i * 2], //
325 p0 - relative_along + relative_across)
326 << "vertex " << i << ", angle = " << degrees << ", " //
327 << "line = " << p0 << " => " << p1 << ", " //
328 << "radius = " << radius << std::endl;
329 EXPECT_POINT_NEAR(vertices[i * 2 + 1], //
330 p0 - relative_along - relative_across)
331 << "vertex " << i << ", angle = " << degrees << ", " //
332 << "line = " << p0 << " => " << p1 << ", " //
333 << "radius = " << radius << std::endl;
334 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1], //
335 p1 + relative_along - relative_across)
336 << "vertex " << i << ", angle = " << degrees << ", " //
337 << "line = " << p0 << " => " << p1 << ", " //
338 << "radius = " << radius << std::endl;
339 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2], //
340 p1 + relative_along + relative_across)
341 << "vertex " << i << ", angle = " << degrees << ", " //
342 << "line = " << p0 << " => " << p1 << ", " //
343 << "radius = " << radius << std::endl;
344 }
345 };
346
347 // Empty line should actually use the circle generator, but its
348 // results should match the same math as the round cap generator.
349 test({}, {0, 0}, {0, 0}, 10);
350
351 test({}, {0, 0}, {10, 0}, 2);
352 test({}, {10, 0}, {0, 0}, 2);
353 test({}, {0, 0}, {10, 10}, 2);
354
355 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {0, 0}, {10, 0}, 2);
356 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {10, 0}, {0, 0}, 2);
357 test(Matrix::MakeScale({500.0, 500.0, 0.0}), {0, 0}, {10, 10}, 2);
358
359 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {0, 0}, {10, 0}, 2);
360 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {10, 0}, {0, 0}, 2);
361 test(Matrix::MakeScale({0.002, 0.002, 0.0}), {0, 0}, {10, 10}, 2);
362 }
363
364 TEST(TessellatorTest, FilledEllipseTessellationVertices) {
365 auto tessellator = std::make_shared<Tessellator>();
366
367 auto test = [&tessellator](const Matrix& transform, const Rect& bounds) {
368 auto center = bounds.GetCenter();
369 auto half_size = bounds.GetSize() * 0.5f;
370
371 auto generator = tessellator->FilledEllipse(transform, bounds);
372 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
373
374 auto vertex_count = generator.GetVertexCount();
375 auto vertices = std::vector<Point>();
376 generator.GenerateVertices([&vertices](const Point& p) { //
377 vertices.push_back(p);
378 });
379 EXPECT_EQ(vertices.size(), vertex_count);
380 ASSERT_EQ(vertex_count % 4, 0u);
381
382 auto quadrant_count = vertex_count / 4;
383 for (size_t i = 0; i < quadrant_count; i++) {
384 double angle = kPiOver2 * i / (quadrant_count - 1);
385 double degrees = angle * 180.0 / kPi;
386 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
387 double rcos =
388 (i == quadrant_count - 1) ? 0.0f : cos(angle) * half_size.width;
389 double rsin = sin(angle) * half_size.height;
390 EXPECT_POINT_NEAR(vertices[i * 2],
391 Point(center.x - rcos, center.y + rsin))
392 << "vertex " << i << ", angle = " << degrees << ", " //
393 << "bounds = " << bounds << std::endl;
394 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
395 Point(center.x - rcos, center.y - rsin))
396 << "vertex " << i << ", angle = " << degrees << ", " //
397 << "bounds = " << bounds << std::endl;
398 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1],
399 Point(center.x + rcos, center.y - rsin))
400 << "vertex " << i << ", angle = " << degrees << ", " //
401 << "bounds = " << bounds << std::endl;
402 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2],
403 Point(center.x + rcos, center.y + rsin))
404 << "vertex " << i << ", angle = " << degrees << ", " //
405 << "bounds = " << bounds << std::endl;
406 }
407 };
408
409 // Square bounds should actually use the circle generator, but its
410 // results should match the same math as the ellipse generator.
411 test({}, Rect::MakeXYWH(0, 0, 2, 2));
412
413 test({}, Rect::MakeXYWH(0, 0, 2, 3));
414 test({}, Rect::MakeXYWH(0, 0, 3, 2));
415 test({}, Rect::MakeXYWH(5, 10, 2, 3));
416 test({}, Rect::MakeXYWH(16, 7, 3, 2));
417 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 3, 2));
418 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 2, 3));
419 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
420 Rect::MakeXYWH(5000, 10000, 3000, 2000));
421 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
422 Rect::MakeXYWH(5000, 10000, 2000, 3000));
423 }
424
425 TEST(TessellatorTest, FilledRoundRectTessellationVertices) {
426 auto tessellator = std::make_shared<Tessellator>();
427
428 auto test = [&tessellator](const Matrix& transform, const Rect& bounds,
429 const Size& radii) {
430 FML_DCHECK(radii.width * 2 <= bounds.GetWidth()) << radii << bounds;
431 FML_DCHECK(radii.height * 2 <= bounds.GetHeight()) << radii << bounds;
432
433 Scalar middle_left = bounds.GetX() + radii.width;
434 Scalar middle_top = bounds.GetY() + radii.height;
435 Scalar middle_right = bounds.GetX() + bounds.GetWidth() - radii.width;
436 Scalar middle_bottom = bounds.GetY() + bounds.GetHeight() - radii.height;
437
438 auto generator = tessellator->FilledRoundRect(transform, bounds, radii);
439 EXPECT_EQ(generator.GetTriangleType(), PrimitiveType::kTriangleStrip);
440
441 auto vertex_count = generator.GetVertexCount();
442 auto vertices = std::vector<Point>();
443 generator.GenerateVertices([&vertices](const Point& p) { //
444 vertices.push_back(p);
445 });
446 EXPECT_EQ(vertices.size(), vertex_count);
447 ASSERT_EQ(vertex_count % 4, 0u);
448
449 auto quadrant_count = vertex_count / 4;
450 for (size_t i = 0; i < quadrant_count; i++) {
451 double angle = kPiOver2 * i / (quadrant_count - 1);
452 double degrees = angle * 180.0 / kPi;
453 // Note that cos(radians(90 degrees)) isn't exactly 0.0 like it should be
454 double rcos = (i == quadrant_count - 1) ? 0.0f : cos(angle) * radii.width;
455 double rsin = sin(angle) * radii.height;
456 EXPECT_POINT_NEAR(vertices[i * 2],
457 Point(middle_left - rcos, middle_bottom + rsin))
458 << "vertex " << i << ", angle = " << degrees << ", " //
459 << "bounds = " << bounds << std::endl;
460 EXPECT_POINT_NEAR(vertices[i * 2 + 1],
461 Point(middle_left - rcos, middle_top - rsin))
462 << "vertex " << i << ", angle = " << degrees << ", " //
463 << "bounds = " << bounds << std::endl;
464 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 1],
465 Point(middle_right + rcos, middle_top - rsin))
466 << "vertex " << i << ", angle = " << degrees << ", " //
467 << "bounds = " << bounds << std::endl;
468 EXPECT_POINT_NEAR(vertices[vertex_count - i * 2 - 2],
469 Point(middle_right + rcos, middle_bottom + rsin))
470 << "vertex " << i << ", angle = " << degrees << ", " //
471 << "bounds = " << bounds << std::endl;
472 }
473 };
474
475 // Both radii spanning the bounds should actually use the circle/ellipse
476 // generator, but their results should match the same math as the round
477 // rect generator.
478 test({}, Rect::MakeXYWH(0, 0, 20, 20), {10, 10});
479
480 // One radius spanning the bounds, but not the other will not match the
481 // round rect math if the generator transfers to circle/ellipse
482 test({}, Rect::MakeXYWH(0, 0, 20, 20), {10, 5});
483 test({}, Rect::MakeXYWH(0, 0, 20, 20), {5, 10});
484
485 test({}, Rect::MakeXYWH(0, 0, 20, 30), {2, 2});
486 test({}, Rect::MakeXYWH(0, 0, 30, 20), {2, 2});
487 test({}, Rect::MakeXYWH(5, 10, 20, 30), {2, 3});
488 test({}, Rect::MakeXYWH(16, 7, 30, 20), {2, 3});
489 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 30, 20),
490 {2, 3});
491 test(Matrix::MakeScale({500.0, 500.0, 0.0}), Rect::MakeXYWH(5, 10, 20, 30),
492 {2, 3});
493 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
494 Rect::MakeXYWH(5000, 10000, 3000, 2000), {50, 70});
495 test(Matrix::MakeScale({0.002, 0.002, 0.0}),
496 Rect::MakeXYWH(5000, 10000, 2000, 3000), {50, 70});
497 }
498
499 TEST(TessellatorTest, EarlyReturnEmptyConvexShape) {
500 // This path is not technically empty (it has a size in one dimension),
501 // but is otherwise completely flat.
502 PathBuilder builder;
503 builder.MoveTo({0, 0});
504 builder.MoveTo({10, 10}, /*relative=*/true);
505
506 std::vector<Point> points;
507 std::vector<uint16_t> indices;
508 Tessellator::TessellateConvexInternal(builder.TakePath(), points, indices,
509 3.0);
510
511 EXPECT_TRUE(points.empty());
512 }
513
514 #if !NDEBUG
515 TEST(TessellatorTest, ChecksConcurrentPolylineUsage) {
516 auto tessellator = std::make_shared<Tessellator>();
517 PathBuilder builder;
518 builder.AddLine({0, 0}, {100, 100});
519 auto path = builder.TakePath();
520
521 auto polyline = tessellator->CreateTempPolyline(path, 0.1);
522 EXPECT_DEBUG_DEATH(tessellator->CreateTempPolyline(path, 0.1),
523 "point_buffer_");
524 }
525 #endif // NDEBUG
526
527 } // namespace testing
528 } // namespace impeller
impeller::PathBuilder
Definition: path_builder.h:15
impeller::PathBuilder::AddRect
PathBuilder & AddRect(Rect rect)
Definition: path_builder.cc:129
impeller::PathBuilder::TakePath
Path TakePath(FillType fill=FillType::kNonZero)
Definition: path_builder.cc:28
impeller::PathBuilder::LineTo
PathBuilder & LineTo(Point point, bool relative=false)
Insert a line from the current position to point.
Definition: path_builder.cc:64
impeller::PathBuilder::MoveTo
PathBuilder & MoveTo(Point point, bool relative=false)
Definition: path_builder.cc:45
impeller::PathBuilder::AddLine
PathBuilder & AddLine(const Point &p1, const Point &p2)
Move to point p1, then insert a line from p1 to p2.
Definition: path_builder.cc:444
impeller::Path
Paths are lightweight objects that describe a collection of linear, quadratic, or cubic segments....
Definition: path.h:53
impeller::Tessellator::kCircleTolerance
static constexpr Scalar kCircleTolerance
The pixel tolerance used by the algorighm to determine how many divisions to create for a circle.
Definition: tessellator.h:238
impeller::Tessellator::TessellateConvexInternal
static void TessellateConvexInternal(const Path &path, std::vector< Point > &point_buffer, std::vector< uint16_t > &index_buffer, Scalar tolerance)
Definition: tessellator.cc:164
impeller::TessellatorLibtess
An extended tessellator that offers arbitrary/concave tessellation via the libtess2 library.
Definition: tessellator_libtess.h:29
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::TessellatorLibtess::Result
Result
Definition: tessellator_libtess.h:35
impeller::TessellatorLibtess::Result::kSuccess
@ kSuccess
impeller::TessellatorLibtess::Result::kInputError
@ kInputError
transform
Matrix transform
Definition: gaussian_blur_filter_contents.cc:214
path.h
path_builder.h
geometry_asserts.h
EXPECT_POINT_NEAR
#define EXPECT_POINT_NEAR(a, b)
Definition: geometry_asserts.h:205
impeller::testing::TEST
TEST(AllocationSizeTest, CanCreateTypedAllocations)
Definition: allocation_size_unittests.cc:10
impeller
Definition: allocation.cc:12
impeller::PrimitiveType::kTriangleStrip
@ kTriangleStrip
impeller::Vector2
Point Vector2
Definition: point.h:331
impeller::kPi
constexpr float kPi
Definition: constants.h:26
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::FillType::kOdd
@ kOdd
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::kPiOver2
constexpr float kPiOver2
Definition: constants.h:32
impeller::LineTo
void LineTo(PathBuilder *builder, Scalar x, Scalar y)
Definition: tessellator.cc:24
polyline
const Path::Polyline & polyline
Definition: stroke_path_geometry.cc:311
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::TPoint< Scalar >
impeller::TPoint::GetLength
constexpr Type GetLength() const
Definition: point.h:206
impeller::TPoint::y
Type y
Definition: point.h:31
impeller::TPoint::x
Type x
Definition: point.h:30
impeller::TRect< Scalar >
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::TSize< Scalar >
tessellator.h
tessellator_libtess.h