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