| Flutter Impeller |

geometry_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 "gtest/gtest.h"
6 #include "impeller/geometry/geometry_asserts.h"
7
8 #include <limits>
9 #include <sstream>
10 #include <type_traits>
11
12 #include "flutter/fml/build_config.h"
13 #include "flutter/testing/testing.h"
14 #include "impeller/geometry/color.h"
15 #include "impeller/geometry/constants.h"
16 #include "impeller/geometry/gradient.h"
17 #include "impeller/geometry/half.h"
18 #include "impeller/geometry/point.h"
19 #include "impeller/geometry/rect.h"
20 #include "impeller/geometry/scalar.h"
21 #include "impeller/geometry/size.h"
22
23 // TODO(zanderso): https://github.com/flutter/flutter/issues/127701
24 // NOLINTBEGIN(bugprone-unchecked-optional-access)
25
26 namespace impeller {
27 namespace testing {
28
29 TEST(GeometryTest, ScalarNearlyEqual) {
30 ASSERT_FALSE(ScalarNearlyEqual(0.0021f, 0.001f));
31 ASSERT_TRUE(ScalarNearlyEqual(0.0019f, 0.001f));
32 ASSERT_TRUE(ScalarNearlyEqual(0.002f, 0.001f, 0.0011f));
33 ASSERT_FALSE(ScalarNearlyEqual(0.002f, 0.001f, 0.0009f));
34 ASSERT_TRUE(ScalarNearlyEqual(
35 1.0f, 1.0f + std::numeric_limits<float>::epsilon() * 4));
36 }
37
38 TEST(GeometryTest, MakeColumn) {
39 auto matrix = Matrix::MakeColumn(1, 2, 3, 4, //
40 5, 6, 7, 8, //
41 9, 10, 11, 12, //
42 13, 14, 15, 16);
43
44 auto expect = Matrix{1, 2, 3, 4, //
45 5, 6, 7, 8, //
46 9, 10, 11, 12, //
47 13, 14, 15, 16};
48
49 ASSERT_TRUE(matrix == expect);
50 }
51
52 TEST(GeometryTest, MakeRow) {
53 auto matrix = Matrix::MakeRow(1, 2, 3, 4, //
54 5, 6, 7, 8, //
55 9, 10, 11, 12, //
56 13, 14, 15, 16);
57
58 auto expect = Matrix{1, 5, 9, 13, //
59 2, 6, 10, 14, //
60 3, 7, 11, 15, //
61 4, 8, 12, 16};
62
63 ASSERT_TRUE(matrix == expect);
64 }
65
66 TEST(GeometryTest, RotationMatrix) {
67 auto rotation = Matrix::MakeRotationZ(Radians{kPiOver4});
68 auto expect = Matrix{0.707, 0.707, 0, 0, //
69 -0.707, 0.707, 0, 0, //
70 0, 0, 1, 0, //
71 0, 0, 0, 1};
72 ASSERT_MATRIX_NEAR(rotation, expect);
73 }
74
75 TEST(GeometryTest, InvertMultMatrix) {
76 {
77 auto rotation = Matrix::MakeRotationZ(Radians{kPiOver4});
78 auto invert = rotation.Invert();
79 auto expect = Matrix{0.707, -0.707, 0, 0, //
80 0.707, 0.707, 0, 0, //
81 0, 0, 1, 0, //
82 0, 0, 0, 1};
83 ASSERT_MATRIX_NEAR(invert, expect);
84 }
85 {
86 auto scale = Matrix::MakeScale(Vector2{2, 4});
87 auto invert = scale.Invert();
88 auto expect = Matrix{0.5, 0, 0, 0, //
89 0, 0.25, 0, 0, //
90 0, 0, 1, 0, //
91 0, 0, 0, 1};
92 ASSERT_MATRIX_NEAR(invert, expect);
93 }
94 }
95
96 TEST(GeometryTest, MatrixBasis) {
97 auto matrix = Matrix{1, 2, 3, 4, //
98 5, 6, 7, 8, //
99 9, 10, 11, 12, //
100 13, 14, 15, 16};
101 auto basis = matrix.Basis();
102 auto expect = Matrix{1, 2, 3, 0, //
103 5, 6, 7, 0, //
104 9, 10, 11, 0, //
105 0, 0, 0, 1};
106 ASSERT_MATRIX_NEAR(basis, expect);
107 }
108
109 TEST(GeometryTest, MutliplicationMatrix) {
110 auto rotation = Matrix::MakeRotationZ(Radians{kPiOver4});
111 auto invert = rotation.Invert();
112 ASSERT_MATRIX_NEAR(rotation * invert, Matrix{});
113 }
114
115 TEST(GeometryTest, DeterminantTest) {
116 auto matrix = Matrix{3, 4, 14, 155, 2, 1, 3, 4, 2, 3, 2, 1, 1, 2, 4, 2};
117 ASSERT_EQ(matrix.GetDeterminant(), -1889);
118 }
119
120 TEST(GeometryTest, InvertMatrix) {
121 auto inverted = Matrix{10, -9, -12, 8, //
122 7, -12, 11, 22, //
123 -10, 10, 3, 6, //
124 -2, 22, 2, 1}
125 .Invert();
126
127 auto result = Matrix{
128 438.0 / 85123.0, 1751.0 / 85123.0, -7783.0 / 85123.0, 4672.0 / 85123.0,
129 393.0 / 85123.0, -178.0 / 85123.0, -570.0 / 85123.0, 4192 / 85123.0,
130 -5230.0 / 85123.0, 2802.0 / 85123.0, -3461.0 / 85123.0, 962.0 / 85123.0,
131 2690.0 / 85123.0, 1814.0 / 85123.0, 3896.0 / 85123.0, 319.0 / 85123.0};
132
133 ASSERT_MATRIX_NEAR(inverted, result);
134 }
135
136 TEST(GeometryTest, TestDecomposition) {
137 auto rotated = Matrix::MakeRotationZ(Radians{kPiOver4});
138
139 auto result = rotated.Decompose();
140
141 ASSERT_TRUE(result.has_value());
142
143 MatrixDecomposition res = result.value();
144
145 auto quaternion = Quaternion{{0.0, 0.0, 1.0}, kPiOver4};
146 ASSERT_QUATERNION_NEAR(res.rotation, quaternion);
147 }
148
149 TEST(GeometryTest, TestDecomposition2) {
150 auto rotated = Matrix::MakeRotationZ(Radians{kPiOver4});
151 auto scaled = Matrix::MakeScale({2.0, 3.0, 1.0});
152 auto translated = Matrix::MakeTranslation({-200, 750, 20});
153
154 auto result = (translated * rotated * scaled).Decompose();
155
156 ASSERT_TRUE(result.has_value());
157
158 MatrixDecomposition res = result.value();
159
160 auto quaternion = Quaternion{{0.0, 0.0, 1.0}, kPiOver4};
161
162 ASSERT_QUATERNION_NEAR(res.rotation, quaternion);
163
164 ASSERT_FLOAT_EQ(res.translation.x, -200);
165 ASSERT_FLOAT_EQ(res.translation.y, 750);
166 ASSERT_FLOAT_EQ(res.translation.z, 20);
167
168 ASSERT_FLOAT_EQ(res.scale.x, 2);
169 ASSERT_FLOAT_EQ(res.scale.y, 3);
170 ASSERT_FLOAT_EQ(res.scale.z, 1);
171 }
172
173 TEST(GeometryTest, TestRecomposition) {
174 /*
175 * Decomposition.
176 */
177 auto rotated = Matrix::MakeRotationZ(Radians{kPiOver4});
178
179 auto result = rotated.Decompose();
180
181 ASSERT_TRUE(result.has_value());
182
183 MatrixDecomposition res = result.value();
184
185 auto quaternion = Quaternion{{0.0, 0.0, 1.0}, kPiOver4};
186
187 ASSERT_QUATERNION_NEAR(res.rotation, quaternion);
188
189 /*
190 * Recomposition.
191 */
192 ASSERT_MATRIX_NEAR(rotated, Matrix{res});
193 }
194
195 TEST(GeometryTest, TestRecomposition2) {
196 auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
197 Matrix::MakeRotationZ(Radians{kPiOver4}) *
198 Matrix::MakeScale({2.0, 2.0, 2.0});
199
200 auto result = matrix.Decompose();
201
202 ASSERT_TRUE(result.has_value());
203
204 ASSERT_MATRIX_NEAR(matrix, Matrix{result.value()});
205 }
206
207 TEST(GeometryTest, MatrixVectorMultiplication) {
208 {
209 auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
210 Matrix::MakeRotationZ(Radians{kPiOver2}) *
211 Matrix::MakeScale({2.0, 2.0, 2.0});
212 auto vector = Vector4(10, 20, 30, 2);
213
214 Vector4 result = matrix * vector;
215 auto expected = Vector4(160, 220, 260, 2);
216 ASSERT_VECTOR4_NEAR(result, expected);
217 }
218
219 {
220 auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
221 Matrix::MakeRotationZ(Radians{kPiOver2}) *
222 Matrix::MakeScale({2.0, 2.0, 2.0});
223 auto vector = Vector3(10, 20, 30);
224
225 Vector3 result = matrix * vector;
226 auto expected = Vector3(60, 120, 160);
227 ASSERT_VECTOR3_NEAR(result, expected);
228 }
229
230 {
231 auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
232 Matrix::MakeRotationZ(Radians{kPiOver2}) *
233 Matrix::MakeScale({2.0, 2.0, 2.0});
234 auto vector = Point(10, 20);
235
236 Point result = matrix * vector;
237 auto expected = Point(60, 120);
238 ASSERT_POINT_NEAR(result, expected);
239 }
240
241 // Matrix Vector ops should respect perspective transforms.
242 {
243 auto matrix = Matrix::MakePerspective(Radians(kPiOver2), 1, 1, 100);
244 auto vector = Vector3(3, 3, -3);
245
246 Vector3 result = matrix * vector;
247 auto expected = Vector3(-1, -1, 1.3468);
248 ASSERT_VECTOR3_NEAR(result, expected);
249 }
250
251 {
252 auto matrix = Matrix::MakePerspective(Radians(kPiOver2), 1, 1, 100) *
253 Matrix::MakeTranslation(Vector3(0, 0, -3));
254 auto point = Point(3, 3);
255
256 Point result = matrix * point;
257 auto expected = Point(-1, -1);
258 ASSERT_POINT_NEAR(result, expected);
259 }
260
261 // Resolves to 0 on perspective singularity.
262 {
263 auto matrix = Matrix::MakePerspective(Radians(kPiOver2), 1, 1, 100);
264 auto point = Point(3, 3);
265
266 Point result = matrix * point;
267 auto expected = Point(0, 0);
268 ASSERT_POINT_NEAR(result, expected);
269 }
270 }
271
272 TEST(GeometryTest, MatrixMakeRotationFromQuaternion) {
273 {
274 auto matrix = Matrix::MakeRotation(Quaternion({1, 0, 0}, kPiOver2));
275 auto expected = Matrix::MakeRotationX(Radians(kPiOver2));
276 ASSERT_MATRIX_NEAR(matrix, expected);
277 }
278
279 {
280 auto matrix = Matrix::MakeRotation(Quaternion({0, 1, 0}, kPiOver2));
281 auto expected = Matrix::MakeRotationY(Radians(kPiOver2));
282 ASSERT_MATRIX_NEAR(matrix, expected);
283 }
284
285 {
286 auto matrix = Matrix::MakeRotation(Quaternion({0, 0, 1}, kPiOver2));
287 auto expected = Matrix::MakeRotationZ(Radians(kPiOver2));
288 ASSERT_MATRIX_NEAR(matrix, expected);
289 }
290 }
291
292 TEST(GeometryTest, MatrixTransformDirection) {
293 {
294 auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
295 Matrix::MakeRotationZ(Radians{kPiOver2}) *
296 Matrix::MakeScale({2.0, 2.0, 2.0});
297 auto vector = Vector4(10, 20, 30, 2);
298
299 Vector4 result = matrix.TransformDirection(vector);
300 auto expected = Vector4(-40, 20, 60, 2);
301 ASSERT_VECTOR4_NEAR(result, expected);
302 }
303
304 {
305 auto matrix = Matrix::MakeTranslation({100, 100, 100}) *
306 Matrix::MakeRotationZ(Radians{kPiOver2}) *
307 Matrix::MakeScale({2.0, 2.0, 2.0});
308 auto vector = Vector3(10, 20, 30);
309
310 Vector3 result = matrix.TransformDirection(vector);
311 auto expected = Vector3(-40, 20, 60);
312 ASSERT_VECTOR3_NEAR(result, expected);
313 }
314
315 {
316 auto matrix = Matrix::MakeTranslation({0, -0.4, 100}) *
317 Matrix::MakeRotationZ(Radians{kPiOver2}) *
318 Matrix::MakeScale({2.0, 2.0, 2.0});
319 auto vector = Point(10, 20);
320
321 Point result = matrix.TransformDirection(vector);
322 auto expected = Point(-40, 20);
323 ASSERT_POINT_NEAR(result, expected);
324 }
325 }
326
327 TEST(GeometryTest, MatrixGetMaxBasisLength) {
328 {
329 auto m = Matrix::MakeScale({3, 1, 1});
330 ASSERT_EQ(m.GetMaxBasisLength(), 3);
331
332 m = m * Matrix::MakeSkew(0, 4);
333 ASSERT_EQ(m.GetMaxBasisLength(), 5);
334 }
335
336 {
337 auto m = Matrix::MakeScale({-3, 4, 2});
338 ASSERT_EQ(m.GetMaxBasisLength(), 4);
339 }
340 }
341
342 TEST(GeometryTest, MatrixGetMaxBasisLengthXY) {
343 {
344 auto m = Matrix::MakeScale({3, 1, 1});
345 ASSERT_EQ(m.GetMaxBasisLengthXY(), 3);
346
347 m = m * Matrix::MakeSkew(0, 4);
348 ASSERT_EQ(m.GetMaxBasisLengthXY(), 5);
349 }
350
351 {
352 auto m = Matrix::MakeScale({-3, 4, 7});
353 ASSERT_EQ(m.GetMaxBasisLengthXY(), 4);
354 }
355 }
356
357 TEST(GeometryTest, MatrixMakeOrthographic) {
358 {
359 auto m = Matrix::MakeOrthographic(Size(100, 200));
360 auto expect = Matrix{
361 0.02, 0, 0, 0, //
362 0, -0.01, 0, 0, //
363 0, 0, 0, 0, //
364 -1, 1, 0.5, 1, //
365 };
366 ASSERT_MATRIX_NEAR(m, expect);
367 }
368
369 {
370 auto m = Matrix::MakeOrthographic(Size(400, 100));
371 auto expect = Matrix{
372 0.005, 0, 0, 0, //
373 0, -0.02, 0, 0, //
374 0, 0, 0, 0, //
375 -1, 1, 0.5, 1, //
376 };
377 ASSERT_MATRIX_NEAR(m, expect);
378 }
379 }
380
381 TEST(GeometryTest, MatrixMakePerspective) {
382 {
383 auto m = Matrix::MakePerspective(Degrees(60), Size(100, 200), 1, 10);
384 auto expect = Matrix{
385 3.4641, 0, 0, 0, //
386 0, 1.73205, 0, 0, //
387 0, 0, 1.11111, 1, //
388 0, 0, -1.11111, 0, //
389 };
390 ASSERT_MATRIX_NEAR(m, expect);
391 }
392
393 {
394 auto m = Matrix::MakePerspective(Radians(1), 2, 10, 20);
395 auto expect = Matrix{
396 0.915244, 0, 0, 0, //
397 0, 1.83049, 0, 0, //
398 0, 0, 2, 1, //
399 0, 0, -20, 0, //
400 };
401 ASSERT_MATRIX_NEAR(m, expect);
402 }
403 }
404
405 TEST(GeometryTest, MatrixGetBasisVectors) {
406 {
407 auto m = Matrix();
408 Vector3 x = m.GetBasisX();
409 Vector3 y = m.GetBasisY();
410 Vector3 z = m.GetBasisZ();
411 ASSERT_VECTOR3_NEAR(x, Vector3(1, 0, 0));
412 ASSERT_VECTOR3_NEAR(y, Vector3(0, 1, 0));
413 ASSERT_VECTOR3_NEAR(z, Vector3(0, 0, 1));
414 }
415
416 {
417 auto m = Matrix::MakeRotationZ(Radians{kPiOver2}) *
418 Matrix::MakeRotationX(Radians{kPiOver2}) *
419 Matrix::MakeScale(Vector3(2, 3, 4));
420 Vector3 x = m.GetBasisX();
421 Vector3 y = m.GetBasisY();
422 Vector3 z = m.GetBasisZ();
423 ASSERT_VECTOR3_NEAR(x, Vector3(0, 2, 0));
424 ASSERT_VECTOR3_NEAR(y, Vector3(0, 0, 3));
425 ASSERT_VECTOR3_NEAR(z, Vector3(4, 0, 0));
426 }
427 }
428
429 TEST(GeometryTest, MatrixGetDirectionScale) {
430 {
431 auto m = Matrix();
432 Scalar result = m.GetDirectionScale(Vector3{1, 0, 0});
433 ASSERT_FLOAT_EQ(result, 1);
434 }
435
436 {
437 auto m = Matrix::MakeRotationX(Degrees{10}) *
438 Matrix::MakeRotationY(Degrees{83}) *
439 Matrix::MakeRotationZ(Degrees{172});
440 Scalar result = m.GetDirectionScale(Vector3{0, 1, 0});
441 ASSERT_FLOAT_EQ(result, 1);
442 }
443
444 {
445 auto m = Matrix::MakeRotationZ(Radians{kPiOver2}) *
446 Matrix::MakeScale(Vector3(3, 4, 5));
447 Scalar result = m.GetDirectionScale(Vector3{2, 0, 0});
448 ASSERT_FLOAT_EQ(result, 8);
449 }
450 }
451
452 TEST(GeometryTest, MatrixIsAligned) {
453 {
454 auto m = Matrix::MakeTranslation({1, 2, 3});
455 bool result = m.IsAligned();
456 ASSERT_TRUE(result);
457 }
458
459 {
460 auto m = Matrix::MakeRotationZ(Degrees{123});
461 bool result = m.IsAligned();
462 ASSERT_FALSE(result);
463 }
464 }
465
466 TEST(GeometryTest, MatrixTranslationScaleOnly) {
467 {
468 auto m = Matrix();
469 bool result = m.IsTranslationScaleOnly();
470 ASSERT_TRUE(result);
471 }
472
473 {
474 auto m = Matrix::MakeScale(Vector3(2, 3, 4));
475 bool result = m.IsTranslationScaleOnly();
476 ASSERT_TRUE(result);
477 }
478
479 {
480 auto m = Matrix::MakeTranslation(Vector3(2, 3, 4));
481 bool result = m.IsTranslationScaleOnly();
482 ASSERT_TRUE(result);
483 }
484
485 {
486 auto m = Matrix::MakeRotationZ(Degrees(10));
487 bool result = m.IsTranslationScaleOnly();
488 ASSERT_FALSE(result);
489 }
490 }
491
492 TEST(GeometryTest, MatrixLookAt) {
493 {
494 auto m = Matrix::MakeLookAt(Vector3(0, 0, -1), Vector3(0, 0, 1),
495 Vector3(0, 1, 0));
496 auto expected = Matrix{
497 1, 0, 0, 0, //
498 0, 1, 0, 0, //
499 0, 0, 1, 0, //
500 0, 0, 1, 1, //
501 };
502 ASSERT_MATRIX_NEAR(m, expected);
503 }
504
505 // Sideways tilt.
506 {
507 auto m = Matrix::MakeLookAt(Vector3(0, 0, -1), Vector3(0, 0, 1),
508 Vector3(1, 1, 0).Normalize());
509
510 // clang-format off
511 auto expected = Matrix{
512 k1OverSqrt2, k1OverSqrt2, 0, 0,
513 -k1OverSqrt2, k1OverSqrt2, 0, 0,
514 0, 0, 1, 0,
515 0, 0, 1, 1,
516 };
517 // clang-format on
518 ASSERT_MATRIX_NEAR(m, expected);
519 }
520
521 // Half way between +x and -y, yaw 90
522 {
523 auto m =
524 Matrix::MakeLookAt(Vector3(), Vector3(10, -10, 0), Vector3(0, 0, -1));
525
526 // clang-format off
527 auto expected = Matrix{
528 -k1OverSqrt2, 0, k1OverSqrt2, 0,
529 -k1OverSqrt2, 0, -k1OverSqrt2, 0,
530 0, -1, 0, 0,
531 0, 0, 0, 1,
532 };
533 // clang-format on
534 ASSERT_MATRIX_NEAR(m, expected);
535 }
536 }
537
538 TEST(GeometryTest, QuaternionLerp) {
539 auto q1 = Quaternion{{0.0, 0.0, 1.0}, 0.0};
540 auto q2 = Quaternion{{0.0, 0.0, 1.0}, kPiOver4};
541
542 auto q3 = q1.Slerp(q2, 0.5);
543
544 auto expected = Quaternion{{0.0, 0.0, 1.0}, kPiOver4 / 2.0};
545
546 ASSERT_QUATERNION_NEAR(q3, expected);
547 }
548
549 TEST(GeometryTest, QuaternionVectorMultiply) {
550 {
551 Quaternion q({0, 0, 1}, 0);
552 Vector3 v(0, 1, 0);
553
554 Vector3 result = q * v;
555 Vector3 expected(0, 1, 0);
556
557 ASSERT_VECTOR3_NEAR(result, expected);
558 }
559
560 {
561 Quaternion q({0, 0, 1}, k2Pi);
562 Vector3 v(1, 0, 0);
563
564 Vector3 result = q * v;
565 Vector3 expected(1, 0, 0);
566
567 ASSERT_VECTOR3_NEAR(result, expected);
568 }
569
570 {
571 Quaternion q({0, 0, 1}, kPiOver4);
572 Vector3 v(0, 1, 0);
573
574 Vector3 result = q * v;
575 Vector3 expected(-k1OverSqrt2, k1OverSqrt2, 0);
576
577 ASSERT_VECTOR3_NEAR(result, expected);
578 }
579
580 {
581 Quaternion q(Vector3(1, 0, 1).Normalize(), kPi);
582 Vector3 v(0, 0, -1);
583
584 Vector3 result = q * v;
585 Vector3 expected(-1, 0, 0);
586
587 ASSERT_VECTOR3_NEAR(result, expected);
588 }
589 }
590
591 TEST(GeometryTest, CanGenerateMipCounts) {
592 ASSERT_EQ((Size{128, 128}.MipCount()), 7u);
593 ASSERT_EQ((Size{128, 256}.MipCount()), 8u);
594 ASSERT_EQ((Size{128, 130}.MipCount()), 8u);
595 ASSERT_EQ((Size{128, 257}.MipCount()), 9u);
596 ASSERT_EQ((Size{257, 128}.MipCount()), 9u);
597 ASSERT_EQ((Size{128, 0}.MipCount()), 1u);
598 ASSERT_EQ((Size{128, -25}.MipCount()), 1u);
599 ASSERT_EQ((Size{-128, 25}.MipCount()), 1u);
600 ASSERT_EQ((Size{1, 1}.MipCount()), 1u);
601 ASSERT_EQ((Size{0, 0}.MipCount()), 1u);
602 }
603
604 TEST(GeometryTest, CanConvertTTypesExplicitly) {
605 {
606 Point p1(1.0, 2.0);
607 IPoint p2 = static_cast<IPoint>(p1);
608 ASSERT_EQ(p2.x, 1u);
609 ASSERT_EQ(p2.y, 2u);
610 }
611
612 {
613 Size s1(1.0, 2.0);
614 ISize s2 = static_cast<ISize>(s1);
615 ASSERT_EQ(s2.width, 1u);
616 ASSERT_EQ(s2.height, 2u);
617 }
618
619 {
620 Size s1(1.0, 2.0);
621 Point p1 = static_cast<Point>(s1);
622 ASSERT_EQ(p1.x, 1u);
623 ASSERT_EQ(p1.y, 2u);
624 }
625
626 {
627 Rect r1 = Rect::MakeXYWH(1.0, 2.0, 3.0, 4.0);
628 IRect r2 = static_cast<IRect>(r1);
629 ASSERT_EQ(r2.GetOrigin().x, 1u);
630 ASSERT_EQ(r2.GetOrigin().y, 2u);
631 ASSERT_EQ(r2.GetSize().width, 3u);
632 ASSERT_EQ(r2.GetSize().height, 4u);
633 ASSERT_EQ(r2.GetX(), 1u);
634 ASSERT_EQ(r2.GetY(), 2u);
635 ASSERT_EQ(r2.GetWidth(), 3u);
636 ASSERT_EQ(r2.GetHeight(), 4u);
637 }
638 }
639
640 TEST(GeometryTest, CanPerformAlgebraicPointOps) {
641 {
642 IPoint p1(1, 2);
643 IPoint p2 = p1 + IPoint(1, 2);
644 ASSERT_EQ(p2.x, 2u);
645 ASSERT_EQ(p2.y, 4u);
646 }
647
648 {
649 IPoint p1(3, 6);
650 IPoint p2 = p1 - IPoint(1, 2);
651 ASSERT_EQ(p2.x, 2u);
652 ASSERT_EQ(p2.y, 4u);
653 }
654
655 {
656 IPoint p1(1, 2);
657 IPoint p2 = p1 * IPoint(2, 3);
658 ASSERT_EQ(p2.x, 2u);
659 ASSERT_EQ(p2.y, 6u);
660 }
661
662 {
663 IPoint p1(2, 6);
664 IPoint p2 = p1 / IPoint(2, 3);
665 ASSERT_EQ(p2.x, 1u);
666 ASSERT_EQ(p2.y, 2u);
667 }
668 }
669
670 TEST(GeometryTest, CanPerformAlgebraicPointOpsWithArithmeticTypes) {
671 // LHS
672 {
673 IPoint p1(1, 2);
674 IPoint p2 = p1 * 2.0f;
675 ASSERT_EQ(p2.x, 2u);
676 ASSERT_EQ(p2.y, 4u);
677 }
678
679 {
680 IPoint p1(2, 6);
681 IPoint p2 = p1 / 2.0f;
682 ASSERT_EQ(p2.x, 1u);
683 ASSERT_EQ(p2.y, 3u);
684 }
685
686 // RHS
687 {
688 IPoint p1(1, 2);
689 IPoint p2 = 2.0f * p1;
690 ASSERT_EQ(p2.x, 2u);
691 ASSERT_EQ(p2.y, 4u);
692 }
693
694 {
695 IPoint p1(2, 6);
696 IPoint p2 = 12.0f / p1;
697 ASSERT_EQ(p2.x, 6u);
698 ASSERT_EQ(p2.y, 2u);
699 }
700 }
701
702 TEST(GeometryTest, PointIntegerCoercesToFloat) {
703 // Integer on LHS, float on RHS
704 {
705 IPoint p1(1, 2);
706 Point p2 = p1 + Point(1, 2);
707 ASSERT_FLOAT_EQ(p2.x, 2u);
708 ASSERT_FLOAT_EQ(p2.y, 4u);
709 }
710
711 {
712 IPoint p1(3, 6);
713 Point p2 = p1 - Point(1, 2);
714 ASSERT_FLOAT_EQ(p2.x, 2u);
715 ASSERT_FLOAT_EQ(p2.y, 4u);
716 }
717
718 {
719 IPoint p1(1, 2);
720 Point p2 = p1 * Point(2, 3);
721 ASSERT_FLOAT_EQ(p2.x, 2u);
722 ASSERT_FLOAT_EQ(p2.y, 6u);
723 }
724
725 {
726 IPoint p1(2, 6);
727 Point p2 = p1 / Point(2, 3);
728 ASSERT_FLOAT_EQ(p2.x, 1u);
729 ASSERT_FLOAT_EQ(p2.y, 2u);
730 }
731
732 // Float on LHS, integer on RHS
733 {
734 Point p1(1, 2);
735 Point p2 = p1 + IPoint(1, 2);
736 ASSERT_FLOAT_EQ(p2.x, 2u);
737 ASSERT_FLOAT_EQ(p2.y, 4u);
738 }
739
740 {
741 Point p1(3, 6);
742 Point p2 = p1 - IPoint(1, 2);
743 ASSERT_FLOAT_EQ(p2.x, 2u);
744 ASSERT_FLOAT_EQ(p2.y, 4u);
745 }
746
747 {
748 Point p1(1, 2);
749 Point p2 = p1 * IPoint(2, 3);
750 ASSERT_FLOAT_EQ(p2.x, 2u);
751 ASSERT_FLOAT_EQ(p2.y, 6u);
752 }
753
754 {
755 Point p1(2, 6);
756 Point p2 = p1 / IPoint(2, 3);
757 ASSERT_FLOAT_EQ(p2.x, 1u);
758 ASSERT_FLOAT_EQ(p2.y, 2u);
759 }
760 }
761
762 TEST(GeometryTest, SizeCoercesToPoint) {
763 // Point on LHS, Size on RHS
764 {
765 IPoint p1(1, 2);
766 IPoint p2 = p1 + ISize(1, 2);
767 ASSERT_EQ(p2.x, 2u);
768 ASSERT_EQ(p2.y, 4u);
769 }
770
771 {
772 IPoint p1(3, 6);
773 IPoint p2 = p1 - ISize(1, 2);
774 ASSERT_EQ(p2.x, 2u);
775 ASSERT_EQ(p2.y, 4u);
776 }
777
778 {
779 IPoint p1(1, 2);
780 IPoint p2 = p1 * ISize(2, 3);
781 ASSERT_EQ(p2.x, 2u);
782 ASSERT_EQ(p2.y, 6u);
783 }
784
785 {
786 IPoint p1(2, 6);
787 IPoint p2 = p1 / ISize(2, 3);
788 ASSERT_EQ(p2.x, 1u);
789 ASSERT_EQ(p2.y, 2u);
790 }
791
792 // Size on LHS, Point on RHS
793 {
794 ISize p1(1, 2);
795 IPoint p2 = p1 + IPoint(1, 2);
796 ASSERT_EQ(p2.x, 2u);
797 ASSERT_EQ(p2.y, 4u);
798 }
799
800 {
801 ISize p1(3, 6);
802 IPoint p2 = p1 - IPoint(1, 2);
803 ASSERT_EQ(p2.x, 2u);
804 ASSERT_EQ(p2.y, 4u);
805 }
806
807 {
808 ISize p1(1, 2);
809 IPoint p2 = p1 * IPoint(2, 3);
810 ASSERT_EQ(p2.x, 2u);
811 ASSERT_EQ(p2.y, 6u);
812 }
813
814 {
815 ISize p1(2, 6);
816 IPoint p2 = p1 / IPoint(2, 3);
817 ASSERT_EQ(p2.x, 1u);
818 ASSERT_EQ(p2.y, 2u);
819 }
820 }
821
822 TEST(GeometryTest, CanUsePointAssignmentOperators) {
823 // Point on RHS
824 {
825 IPoint p(1, 2);
826 p += IPoint(1, 2);
827 ASSERT_EQ(p.x, 2u);
828 ASSERT_EQ(p.y, 4u);
829 }
830
831 {
832 IPoint p(3, 6);
833 p -= IPoint(1, 2);
834 ASSERT_EQ(p.x, 2u);
835 ASSERT_EQ(p.y, 4u);
836 }
837
838 {
839 IPoint p(1, 2);
840 p *= IPoint(2, 3);
841 ASSERT_EQ(p.x, 2u);
842 ASSERT_EQ(p.y, 6u);
843 }
844
845 {
846 IPoint p(2, 6);
847 p /= IPoint(2, 3);
848 ASSERT_EQ(p.x, 1u);
849 ASSERT_EQ(p.y, 2u);
850 }
851
852 // Size on RHS
853 {
854 IPoint p(1, 2);
855 p += ISize(1, 2);
856 ASSERT_EQ(p.x, 2u);
857 ASSERT_EQ(p.y, 4u);
858 }
859
860 {
861 IPoint p(3, 6);
862 p -= ISize(1, 2);
863 ASSERT_EQ(p.x, 2u);
864 ASSERT_EQ(p.y, 4u);
865 }
866
867 {
868 IPoint p(1, 2);
869 p *= ISize(2, 3);
870 ASSERT_EQ(p.x, 2u);
871 ASSERT_EQ(p.y, 6u);
872 }
873
874 {
875 IPoint p(2, 6);
876 p /= ISize(2, 3);
877 ASSERT_EQ(p.x, 1u);
878 ASSERT_EQ(p.y, 2u);
879 }
880
881 // Arithmetic type on RHS
882 {
883 IPoint p(1, 2);
884 p *= 3;
885 ASSERT_EQ(p.x, 3u);
886 ASSERT_EQ(p.y, 6u);
887 }
888
889 {
890 IPoint p(3, 6);
891 p /= 3;
892 ASSERT_EQ(p.x, 1u);
893 ASSERT_EQ(p.y, 2u);
894 }
895 }
896
897 TEST(GeometryTest, PointDotProduct) {
898 {
899 Point p(1, 0);
900 Scalar s = p.Dot(Point(-1, 0));
901 ASSERT_FLOAT_EQ(s, -1);
902 }
903
904 {
905 Point p(0, -1);
906 Scalar s = p.Dot(Point(-1, 0));
907 ASSERT_FLOAT_EQ(s, 0);
908 }
909
910 {
911 Point p(1, 2);
912 Scalar s = p.Dot(Point(3, -4));
913 ASSERT_FLOAT_EQ(s, -5);
914 }
915 }
916
917 TEST(GeometryTest, PointCrossProduct) {
918 {
919 Point p(1, 0);
920 Scalar s = p.Cross(Point(-1, 0));
921 ASSERT_FLOAT_EQ(s, 0);
922 }
923
924 {
925 Point p(0, -1);
926 Scalar s = p.Cross(Point(-1, 0));
927 ASSERT_FLOAT_EQ(s, -1);
928 }
929
930 {
931 Point p(1, 2);
932 Scalar s = p.Cross(Point(3, -4));
933 ASSERT_FLOAT_EQ(s, -10);
934 }
935 }
936
937 TEST(GeometryTest, PointReflect) {
938 {
939 Point axis = Point(0, 1);
940 Point a(2, 3);
941 auto reflected = a.Reflect(axis);
942 auto expected = Point(2, -3);
943 ASSERT_POINT_NEAR(reflected, expected);
944 }
945
946 {
947 Point axis = Point(1, 1).Normalize();
948 Point a(1, 0);
949 auto reflected = a.Reflect(axis);
950 auto expected = Point(0, -1);
951 ASSERT_POINT_NEAR(reflected, expected);
952 }
953
954 {
955 Point axis = Point(1, 1).Normalize();
956 Point a(-1, -1);
957 auto reflected = a.Reflect(axis);
958 ASSERT_POINT_NEAR(reflected, -a);
959 }
960 }
961
962 TEST(GeometryTest, PointAbs) {
963 Point a(-1, -2);
964 auto a_abs = a.Abs();
965 auto expected = Point(1, 2);
966 ASSERT_POINT_NEAR(a_abs, expected);
967 }
968
969 TEST(GeometryTest, PointAngleTo) {
970 // Negative result in the CCW (with up = -Y) direction.
971 {
972 Point a(1, 1);
973 Point b(1, -1);
974 Radians actual = a.AngleTo(b);
975 Radians expected = Radians{-kPi / 2};
976 ASSERT_FLOAT_EQ(actual.radians, expected.radians);
977 }
978
979 // Check the other direction to ensure the result is signed correctly.
980 {
981 Point a(1, -1);
982 Point b(1, 1);
983 Radians actual = a.AngleTo(b);
984 Radians expected = Radians{kPi / 2};
985 ASSERT_FLOAT_EQ(actual.radians, expected.radians);
986 }
987
988 // Differences in magnitude should have no impact on the result.
989 {
990 Point a(100, -100);
991 Point b(0.01, 0.01);
992 Radians actual = a.AngleTo(b);
993 Radians expected = Radians{kPi / 2};
994 ASSERT_FLOAT_EQ(actual.radians, expected.radians);
995 }
996 }
997
998 TEST(GeometryTest, PointMin) {
999 Point p(1, 2);
1000 Point result = p.Min({0, 10});
1001 Point expected(0, 2);
1002 ASSERT_POINT_NEAR(result, expected);
1003 }
1004
1005 TEST(GeometryTest, Vector3Min) {
1006 Vector3 p(1, 2, 3);
1007 Vector3 result = p.Min({0, 10, 2});
1008 Vector3 expected(0, 2, 2);
1009 ASSERT_VECTOR3_NEAR(result, expected);
1010 }
1011
1012 TEST(GeometryTest, Vector4Min) {
1013 Vector4 p(1, 2, 3, 4);
1014 Vector4 result = p.Min({0, 10, 2, 1});
1015 Vector4 expected(0, 2, 2, 1);
1016 ASSERT_VECTOR4_NEAR(result, expected);
1017 }
1018
1019 TEST(GeometryTest, PointMax) {
1020 Point p(1, 2);
1021 Point result = p.Max({0, 10});
1022 Point expected(1, 10);
1023 ASSERT_POINT_NEAR(result, expected);
1024 }
1025
1026 TEST(GeometryTest, Vector3Max) {
1027 Vector3 p(1, 2, 3);
1028 Vector3 result = p.Max({0, 10, 2});
1029 Vector3 expected(1, 10, 3);
1030 ASSERT_VECTOR3_NEAR(result, expected);
1031 }
1032
1033 TEST(GeometryTest, Vector4Max) {
1034 Vector4 p(1, 2, 3, 4);
1035 Vector4 result = p.Max({0, 10, 2, 1});
1036 Vector4 expected(1, 10, 3, 4);
1037 ASSERT_VECTOR4_NEAR(result, expected);
1038 }
1039
1040 TEST(GeometryTest, PointFloor) {
1041 Point p(1.5, 2.3);
1042 Point result = p.Floor();
1043 Point expected(1, 2);
1044 ASSERT_POINT_NEAR(result, expected);
1045 }
1046
1047 TEST(GeometryTest, Vector3Floor) {
1048 Vector3 p(1.5, 2.3, 3.9);
1049 Vector3 result = p.Floor();
1050 Vector3 expected(1, 2, 3);
1051 ASSERT_VECTOR3_NEAR(result, expected);
1052 }
1053
1054 TEST(GeometryTest, Vector4Floor) {
1055 Vector4 p(1.5, 2.3, 3.9, 4.0);
1056 Vector4 result = p.Floor();
1057 Vector4 expected(1, 2, 3, 4);
1058 ASSERT_VECTOR4_NEAR(result, expected);
1059 }
1060
1061 TEST(GeometryTest, PointCeil) {
1062 Point p(1.5, 2.3);
1063 Point result = p.Ceil();
1064 Point expected(2, 3);
1065 ASSERT_POINT_NEAR(result, expected);
1066 }
1067
1068 TEST(GeometryTest, Vector3Ceil) {
1069 Vector3 p(1.5, 2.3, 3.9);
1070 Vector3 result = p.Ceil();
1071 Vector3 expected(2, 3, 4);
1072 ASSERT_VECTOR3_NEAR(result, expected);
1073 }
1074
1075 TEST(GeometryTest, Vector4Ceil) {
1076 Vector4 p(1.5, 2.3, 3.9, 4.0);
1077 Vector4 result = p.Ceil();
1078 Vector4 expected(2, 3, 4, 4);
1079 ASSERT_VECTOR4_NEAR(result, expected);
1080 }
1081
1082 TEST(GeometryTest, PointRound) {
1083 Point p(1.5, 2.3);
1084 Point result = p.Round();
1085 Point expected(2, 2);
1086 ASSERT_POINT_NEAR(result, expected);
1087 }
1088
1089 TEST(GeometryTest, Vector3Round) {
1090 Vector3 p(1.5, 2.3, 3.9);
1091 Vector3 result = p.Round();
1092 Vector3 expected(2, 2, 4);
1093 ASSERT_VECTOR3_NEAR(result, expected);
1094 }
1095
1096 TEST(GeometryTest, Vector4Round) {
1097 Vector4 p(1.5, 2.3, 3.9, 4.0);
1098 Vector4 result = p.Round();
1099 Vector4 expected(2, 2, 4, 4);
1100 ASSERT_VECTOR4_NEAR(result, expected);
1101 }
1102
1103 TEST(GeometryTest, PointLerp) {
1104 Point p(1, 2);
1105 Point result = p.Lerp({5, 10}, 0.75);
1106 Point expected(4, 8);
1107 ASSERT_POINT_NEAR(result, expected);
1108 }
1109
1110 TEST(GeometryTest, Vector3Lerp) {
1111 Vector3 p(1, 2, 3);
1112 Vector3 result = p.Lerp({5, 10, 15}, 0.75);
1113 Vector3 expected(4, 8, 12);
1114 ASSERT_VECTOR3_NEAR(result, expected);
1115 }
1116
1117 TEST(GeometryTest, Vector4Lerp) {
1118 Vector4 p(1, 2, 3, 4);
1119 Vector4 result = p.Lerp({5, 10, 15, 20}, 0.75);
1120 Vector4 expected(4, 8, 12, 16);
1121 ASSERT_VECTOR4_NEAR(result, expected);
1122 }
1123
1124 TEST(GeometryTest, CanUseVector3AssignmentOperators) {
1125 {
1126 Vector3 p(1, 2, 4);
1127 p += Vector3(1, 2, 4);
1128 ASSERT_EQ(p.x, 2u);
1129 ASSERT_EQ(p.y, 4u);
1130 ASSERT_EQ(p.z, 8u);
1131 }
1132
1133 {
1134 Vector3 p(3, 6, 8);
1135 p -= Vector3(1, 2, 3);
1136 ASSERT_EQ(p.x, 2u);
1137 ASSERT_EQ(p.y, 4u);
1138 ASSERT_EQ(p.z, 5u);
1139 }
1140
1141 {
1142 Vector3 p(1, 2, 3);
1143 p *= Vector3(2, 3, 4);
1144 ASSERT_EQ(p.x, 2u);
1145 ASSERT_EQ(p.y, 6u);
1146 ASSERT_EQ(p.z, 12u);
1147 }
1148
1149 {
1150 Vector3 p(1, 2, 3);
1151 p *= 2;
1152 ASSERT_EQ(p.x, 2u);
1153 ASSERT_EQ(p.y, 4u);
1154 ASSERT_EQ(p.z, 6u);
1155 }
1156
1157 {
1158 Vector3 p(2, 6, 12);
1159 p /= Vector3(2, 3, 4);
1160 ASSERT_EQ(p.x, 1u);
1161 ASSERT_EQ(p.y, 2u);
1162 ASSERT_EQ(p.z, 3u);
1163 }
1164
1165 {
1166 Vector3 p(2, 6, 12);
1167 p /= 2;
1168 ASSERT_EQ(p.x, 1u);
1169 ASSERT_EQ(p.y, 3u);
1170 ASSERT_EQ(p.z, 6u);
1171 }
1172 }
1173
1174 TEST(GeometryTest, CanPerformAlgebraicVector3Ops) {
1175 {
1176 Vector3 p1(1, 2, 3);
1177 Vector3 p2 = p1 + Vector3(1, 2, 3);
1178 ASSERT_EQ(p2.x, 2u);
1179 ASSERT_EQ(p2.y, 4u);
1180 ASSERT_EQ(p2.z, 6u);
1181 }
1182
1183 {
1184 Vector3 p1(3, 6, 9);
1185 Vector3 p2 = p1 - Vector3(1, 2, 3);
1186 ASSERT_EQ(p2.x, 2u);
1187 ASSERT_EQ(p2.y, 4u);
1188 ASSERT_EQ(p2.z, 6u);
1189 }
1190
1191 {
1192 Vector3 p1(1, 2, 3);
1193 Vector3 p2 = p1 * Vector3(2, 3, 4);
1194 ASSERT_EQ(p2.x, 2u);
1195 ASSERT_EQ(p2.y, 6u);
1196 ASSERT_EQ(p2.z, 12u);
1197 }
1198
1199 {
1200 Vector3 p1(2, 6, 12);
1201 Vector3 p2 = p1 / Vector3(2, 3, 4);
1202 ASSERT_EQ(p2.x, 1u);
1203 ASSERT_EQ(p2.y, 2u);
1204 ASSERT_EQ(p2.z, 3u);
1205 }
1206 }
1207
1208 TEST(GeometryTest, CanPerformAlgebraicVector3OpsWithArithmeticTypes) {
1209 // LHS
1210 {
1211 Vector3 p1(1, 2, 3);
1212 Vector3 p2 = p1 + 2.0f;
1213 ASSERT_EQ(p2.x, 3);
1214 ASSERT_EQ(p2.y, 4);
1215 ASSERT_EQ(p2.z, 5);
1216 }
1217
1218 {
1219 Vector3 p1(1, 2, 3);
1220 Vector3 p2 = p1 - 2.0f;
1221 ASSERT_EQ(p2.x, -1);
1222 ASSERT_EQ(p2.y, 0);
1223 ASSERT_EQ(p2.z, 1);
1224 }
1225
1226 {
1227 Vector3 p1(1, 2, 3);
1228 Vector3 p2 = p1 * 2.0f;
1229 ASSERT_EQ(p2.x, 2);
1230 ASSERT_EQ(p2.y, 4);
1231 ASSERT_EQ(p2.z, 6);
1232 }
1233
1234 {
1235 Vector3 p1(2, 6, 12);
1236 Vector3 p2 = p1 / 2.0f;
1237 ASSERT_EQ(p2.x, 1);
1238 ASSERT_EQ(p2.y, 3);
1239 ASSERT_EQ(p2.z, 6);
1240 }
1241
1242 // RHS
1243 {
1244 Vector3 p1(1, 2, 3);
1245 Vector3 p2 = 2.0f + p1;
1246 ASSERT_EQ(p2.x, 3);
1247 ASSERT_EQ(p2.y, 4);
1248 ASSERT_EQ(p2.z, 5);
1249 }
1250
1251 {
1252 Vector3 p1(1, 2, 3);
1253 Vector3 p2 = 2.0f - p1;
1254 ASSERT_EQ(p2.x, 1);
1255 ASSERT_EQ(p2.y, 0);
1256 ASSERT_EQ(p2.z, -1);
1257 }
1258
1259 {
1260 Vector3 p1(1, 2, 3);
1261 Vector3 p2 = 2.0f * p1;
1262 ASSERT_EQ(p2.x, 2);
1263 ASSERT_EQ(p2.y, 4);
1264 ASSERT_EQ(p2.z, 6);
1265 }
1266
1267 {
1268 Vector3 p1(2, 6, 12);
1269 Vector3 p2 = 12.0f / p1;
1270 ASSERT_EQ(p2.x, 6);
1271 ASSERT_EQ(p2.y, 2);
1272 ASSERT_EQ(p2.z, 1);
1273 }
1274 }
1275
1276 TEST(GeometryTest, ColorPremultiply) {
1277 {
1278 Color a(1.0, 0.5, 0.2, 0.5);
1279 Color premultiplied = a.Premultiply();
1280 Color expected = Color(0.5, 0.25, 0.1, 0.5);
1281 ASSERT_COLOR_NEAR(premultiplied, expected);
1282 }
1283
1284 {
1285 Color a(0.5, 0.25, 0.1, 0.5);
1286 Color unpremultiplied = a.Unpremultiply();
1287 Color expected = Color(1.0, 0.5, 0.2, 0.5);
1288 ASSERT_COLOR_NEAR(unpremultiplied, expected);
1289 }
1290
1291 {
1292 Color a(0.5, 0.25, 0.1, 0.0);
1293 Color unpremultiplied = a.Unpremultiply();
1294 Color expected = Color(0.0, 0.0, 0.0, 0.0);
1295 ASSERT_COLOR_NEAR(unpremultiplied, expected);
1296 }
1297 }
1298
1299 TEST(GeometryTest, ColorR8G8B8A8) {
1300 {
1301 Color a(1.0, 0.5, 0.2, 0.5);
1302 std::array<uint8_t, 4> expected = {255, 128, 51, 128};
1303 ASSERT_ARRAY_4_NEAR(a.ToR8G8B8A8(), expected);
1304 }
1305
1306 {
1307 Color a(0.0, 0.0, 0.0, 0.0);
1308 std::array<uint8_t, 4> expected = {0, 0, 0, 0};
1309 ASSERT_ARRAY_4_NEAR(a.ToR8G8B8A8(), expected);
1310 }
1311
1312 {
1313 Color a(1.0, 1.0, 1.0, 1.0);
1314 std::array<uint8_t, 4> expected = {255, 255, 255, 255};
1315 ASSERT_ARRAY_4_NEAR(a.ToR8G8B8A8(), expected);
1316 }
1317 }
1318
1319 TEST(GeometryTest, ColorLerp) {
1320 {
1321 Color a(0.0, 0.0, 0.0, 0.0);
1322 Color b(1.0, 1.0, 1.0, 1.0);
1323
1324 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.5), Color(0.5, 0.5, 0.5, 0.5));
1325 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.0), a);
1326 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 1.0), b);
1327 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.2), Color(0.2, 0.2, 0.2, 0.2));
1328 }
1329
1330 {
1331 Color a(0.2, 0.4, 1.0, 0.5);
1332 Color b(0.4, 1.0, 0.2, 0.3);
1333
1334 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.5), Color(0.3, 0.7, 0.6, 0.4));
1335 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.0), a);
1336 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 1.0), b);
1337 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.2), Color(0.24, 0.52, 0.84, 0.46));
1338 }
1339 }
1340
1341 TEST(GeometryTest, ColorClamp01) {
1342 {
1343 Color result = Color(0.5, 0.5, 0.5, 0.5).Clamp01();
1344 Color expected = Color(0.5, 0.5, 0.5, 0.5);
1345 ASSERT_COLOR_NEAR(result, expected);
1346 }
1347
1348 {
1349 Color result = Color(-1, -1, -1, -1).Clamp01();
1350 Color expected = Color(0, 0, 0, 0);
1351 ASSERT_COLOR_NEAR(result, expected);
1352 }
1353
1354 {
1355 Color result = Color(2, 2, 2, 2).Clamp01();
1356 Color expected = Color(1, 1, 1, 1);
1357 ASSERT_COLOR_NEAR(result, expected);
1358 }
1359 }
1360
1361 TEST(GeometryTest, ColorMakeRGBA8) {
1362 {
1363 Color a = Color::MakeRGBA8(0, 0, 0, 0);
1364 Color b = Color::BlackTransparent();
1365 ASSERT_COLOR_NEAR(a, b);
1366 }
1367
1368 {
1369 Color a = Color::MakeRGBA8(255, 255, 255, 255);
1370 Color b = Color::White();
1371 ASSERT_COLOR_NEAR(a, b);
1372 }
1373
1374 {
1375 Color a = Color::MakeRGBA8(63, 127, 191, 127);
1376 Color b(0.247059, 0.498039, 0.74902, 0.498039);
1377 ASSERT_COLOR_NEAR(a, b);
1378 }
1379 }
1380
1381 TEST(GeometryTest, ColorApplyColorMatrix) {
1382 {
1383 ColorMatrix color_matrix = {
1384 1, 1, 1, 1, 1, //
1385 1, 1, 1, 1, 1, //
1386 1, 1, 1, 1, 1, //
1387 1, 1, 1, 1, 1, //
1388 };
1389 auto result = Color::White().ApplyColorMatrix(color_matrix);
1390 auto expected = Color(1, 1, 1, 1);
1391 ASSERT_COLOR_NEAR(result, expected);
1392 }
1393
1394 {
1395 ColorMatrix color_matrix = {
1396 0.1, 0, 0, 0, 0.01, //
1397 0, 0.2, 0, 0, 0.02, //
1398 0, 0, 0.3, 0, 0.03, //
1399 0, 0, 0, 0.4, 0.04, //
1400 };
1401 auto result = Color::White().ApplyColorMatrix(color_matrix);
1402 auto expected = Color(0.11, 0.22, 0.33, 0.44);
1403 ASSERT_COLOR_NEAR(result, expected);
1404 }
1405 }
1406
1407 TEST(GeometryTest, ColorLinearToSRGB) {
1408 {
1409 auto result = Color::White().LinearToSRGB();
1410 auto expected = Color(1, 1, 1, 1);
1411 ASSERT_COLOR_NEAR(result, expected);
1412 }
1413
1414 {
1415 auto result = Color::BlackTransparent().LinearToSRGB();
1416 auto expected = Color(0, 0, 0, 0);
1417 ASSERT_COLOR_NEAR(result, expected);
1418 }
1419
1420 {
1421 auto result = Color(0.2, 0.4, 0.6, 0.8).LinearToSRGB();
1422 auto expected = Color(0.484529, 0.665185, 0.797738, 0.8);
1423 ASSERT_COLOR_NEAR(result, expected);
1424 }
1425 }
1426
1427 TEST(GeometryTest, ColorSRGBToLinear) {
1428 {
1429 auto result = Color::White().SRGBToLinear();
1430 auto expected = Color(1, 1, 1, 1);
1431 ASSERT_COLOR_NEAR(result, expected);
1432 }
1433
1434 {
1435 auto result = Color::BlackTransparent().SRGBToLinear();
1436 auto expected = Color(0, 0, 0, 0);
1437 ASSERT_COLOR_NEAR(result, expected);
1438 }
1439
1440 {
1441 auto result = Color(0.2, 0.4, 0.6, 0.8).SRGBToLinear();
1442 auto expected = Color(0.0331048, 0.132868, 0.318547, 0.8);
1443 ASSERT_COLOR_NEAR(result, expected);
1444 }
1445 }
1446
1447 #define _BLEND_MODE_NAME_CHECK(blend_mode) \
1448 case BlendMode::k##blend_mode: \
1449 ASSERT_STREQ(result, #blend_mode); \
1450 break;
1451
1452 TEST(GeometryTest, BlendModeToString) {
1453 using BlendT = std::underlying_type_t<BlendMode>;
1454 for (BlendT i = 0; i <= static_cast<BlendT>(BlendMode::kLast); i++) {
1455 auto mode = static_cast<BlendMode>(i);
1456 auto result = BlendModeToString(mode);
1457 switch (mode) { IMPELLER_FOR_EACH_BLEND_MODE(_BLEND_MODE_NAME_CHECK) }
1458 }
1459 }
1460
1461 TEST(GeometryTest, CanConvertBetweenDegressAndRadians) {
1462 {
1463 auto deg = Degrees{90.0};
1464 Radians rad = deg;
1465 ASSERT_FLOAT_EQ(rad.radians, kPiOver2);
1466 }
1467 }
1468
1469 TEST(GeometryTest, RectUnion) {
1470 {
1471 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1472 Rect b = Rect::MakeXYWH(0, 0, 0, 0);
1473 auto u = a.Union(b);
1474 auto expected = Rect::MakeXYWH(0, 0, 200, 200);
1475 ASSERT_RECT_NEAR(u, expected);
1476 }
1477
1478 {
1479 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1480 Rect b = Rect::MakeXYWH(10, 10, 0, 0);
1481 auto u = a.Union(b);
1482 auto expected = Rect::MakeXYWH(10, 10, 190, 190);
1483 ASSERT_RECT_NEAR(u, expected);
1484 }
1485
1486 {
1487 Rect a = Rect::MakeXYWH(0, 0, 100, 100);
1488 Rect b = Rect::MakeXYWH(10, 10, 100, 100);
1489 auto u = a.Union(b);
1490 auto expected = Rect::MakeXYWH(0, 0, 110, 110);
1491 ASSERT_RECT_NEAR(u, expected);
1492 }
1493
1494 {
1495 Rect a = Rect::MakeXYWH(0, 0, 100, 100);
1496 Rect b = Rect::MakeXYWH(100, 100, 100, 100);
1497 auto u = a.Union(b);
1498 auto expected = Rect::MakeXYWH(0, 0, 200, 200);
1499 ASSERT_RECT_NEAR(u, expected);
1500 }
1501 }
1502
1503 TEST(GeometryTest, OptRectUnion) {
1504 Rect a = Rect::MakeLTRB(0, 0, 100, 100);
1505 Rect b = Rect::MakeLTRB(100, 100, 200, 200);
1506 Rect c = Rect::MakeLTRB(100, 0, 200, 100);
1507
1508 // NullOpt, NullOpt
1509 EXPECT_FALSE(Rect::Union(std::nullopt, std::nullopt).has_value());
1510 EXPECT_EQ(Rect::Union(std::nullopt, std::nullopt), std::nullopt);
1511
1512 auto test1 = [](const Rect& r) {
1513 // Rect, NullOpt
1514 EXPECT_TRUE(Rect::Union(r, std::nullopt).has_value());
1515 EXPECT_EQ(Rect::Union(r, std::nullopt).value(), r);
1516
1517 // OptRect, NullOpt
1518 EXPECT_TRUE(Rect::Union(std::optional(r), std::nullopt).has_value());
1519 EXPECT_EQ(Rect::Union(std::optional(r), std::nullopt).value(), r);
1520
1521 // NullOpt, Rect
1522 EXPECT_TRUE(Rect::Union(std::nullopt, r).has_value());
1523 EXPECT_EQ(Rect::Union(std::nullopt, r).value(), r);
1524
1525 // NullOpt, OptRect
1526 EXPECT_TRUE(Rect::Union(std::nullopt, std::optional(r)).has_value());
1527 EXPECT_EQ(Rect::Union(std::nullopt, std::optional(r)).value(), r);
1528 };
1529
1530 test1(a);
1531 test1(b);
1532 test1(c);
1533
1534 auto test2 = [](const Rect& a, const Rect& b, const Rect& u) {
1535 ASSERT_EQ(a.Union(b), u);
1536
1537 // Rect, OptRect
1538 EXPECT_TRUE(Rect::Union(a, std::optional(b)).has_value());
1539 EXPECT_EQ(Rect::Union(a, std::optional(b)).value(), u);
1540
1541 // OptRect, Rect
1542 EXPECT_TRUE(Rect::Union(std::optional(a), b).has_value());
1543 EXPECT_EQ(Rect::Union(std::optional(a), b).value(), u);
1544
1545 // OptRect, OptRect
1546 EXPECT_TRUE(Rect::Union(std::optional(a), std::optional(b)).has_value());
1547 EXPECT_EQ(Rect::Union(std::optional(a), std::optional(b)).value(), u);
1548 };
1549
1550 test2(a, b, Rect::MakeLTRB(0, 0, 200, 200));
1551 test2(a, c, Rect::MakeLTRB(0, 0, 200, 100));
1552 test2(b, c, Rect::MakeLTRB(100, 0, 200, 200));
1553 }
1554
1555 TEST(GeometryTest, RectIntersection) {
1556 {
1557 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1558 Rect b = Rect::MakeXYWH(0, 0, 0, 0);
1559
1560 auto u = a.Intersection(b);
1561 ASSERT_FALSE(u.has_value());
1562 }
1563
1564 {
1565 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1566 Rect b = Rect::MakeXYWH(10, 10, 0, 0);
1567 auto u = a.Intersection(b);
1568 ASSERT_FALSE(u.has_value());
1569 }
1570
1571 {
1572 Rect a = Rect::MakeXYWH(0, 0, 100, 100);
1573 Rect b = Rect::MakeXYWH(10, 10, 100, 100);
1574 auto u = a.Intersection(b);
1575 ASSERT_TRUE(u.has_value());
1576 auto expected = Rect::MakeXYWH(10, 10, 90, 90);
1577 ASSERT_RECT_NEAR(u.value(), expected);
1578 }
1579
1580 {
1581 Rect a = Rect::MakeXYWH(0, 0, 100, 100);
1582 Rect b = Rect::MakeXYWH(100, 100, 100, 100);
1583 auto u = a.Intersection(b);
1584 ASSERT_FALSE(u.has_value());
1585 }
1586
1587 {
1588 Rect a = Rect::MakeMaximum();
1589 Rect b = Rect::MakeXYWH(10, 10, 300, 300);
1590 auto u = a.Intersection(b);
1591 ASSERT_TRUE(u);
1592 ASSERT_RECT_NEAR(u.value(), b);
1593 }
1594
1595 {
1596 Rect a = Rect::MakeMaximum();
1597 Rect b = Rect::MakeMaximum();
1598 auto u = a.Intersection(b);
1599 ASSERT_TRUE(u);
1600 ASSERT_EQ(u, Rect::MakeMaximum());
1601 }
1602 }
1603
1604 TEST(GeometryTest, OptRectIntersection) {
1605 Rect a = Rect::MakeLTRB(0, 0, 110, 110);
1606 Rect b = Rect::MakeLTRB(100, 100, 200, 200);
1607 Rect c = Rect::MakeLTRB(100, 0, 200, 110);
1608
1609 // NullOpt, NullOpt
1610 EXPECT_FALSE(Rect::Intersection(std::nullopt, std::nullopt).has_value());
1611 EXPECT_EQ(Rect::Intersection(std::nullopt, std::nullopt), std::nullopt);
1612
1613 auto test1 = [](const Rect& r) {
1614 // Rect, NullOpt
1615 EXPECT_TRUE(Rect::Intersection(r, std::nullopt).has_value());
1616 EXPECT_EQ(Rect::Intersection(r, std::nullopt).value(), r);
1617
1618 // OptRect, NullOpt
1619 EXPECT_TRUE(Rect::Intersection(std::optional(r), std::nullopt).has_value());
1620 EXPECT_EQ(Rect::Intersection(std::optional(r), std::nullopt).value(), r);
1621
1622 // NullOpt, Rect
1623 EXPECT_TRUE(Rect::Intersection(std::nullopt, r).has_value());
1624 EXPECT_EQ(Rect::Intersection(std::nullopt, r).value(), r);
1625
1626 // NullOpt, OptRect
1627 EXPECT_TRUE(Rect::Intersection(std::nullopt, std::optional(r)).has_value());
1628 EXPECT_EQ(Rect::Intersection(std::nullopt, std::optional(r)).value(), r);
1629 };
1630
1631 test1(a);
1632 test1(b);
1633 test1(c);
1634
1635 auto test2 = [](const Rect& a, const Rect& b, const Rect& i) {
1636 ASSERT_EQ(a.Intersection(b), i);
1637
1638 // Rect, OptRect
1639 EXPECT_TRUE(Rect::Intersection(a, std::optional(b)).has_value());
1640 EXPECT_EQ(Rect::Intersection(a, std::optional(b)).value(), i);
1641
1642 // OptRect, Rect
1643 EXPECT_TRUE(Rect::Intersection(std::optional(a), b).has_value());
1644 EXPECT_EQ(Rect::Intersection(std::optional(a), b).value(), i);
1645
1646 // OptRect, OptRect
1647 EXPECT_TRUE(
1648 Rect::Intersection(std::optional(a), std::optional(b)).has_value());
1649 EXPECT_EQ(Rect::Intersection(std::optional(a), std::optional(b)).value(),
1650 i);
1651 };
1652
1653 test2(a, b, Rect::MakeLTRB(100, 100, 110, 110));
1654 test2(a, c, Rect::MakeLTRB(100, 0, 110, 110));
1655 test2(b, c, Rect::MakeLTRB(100, 100, 200, 110));
1656 }
1657
1658 TEST(GeometryTest, RectIntersectsWithRect) {
1659 {
1660 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1661 Rect b = Rect::MakeXYWH(0, 0, 0, 0);
1662 ASSERT_FALSE(a.IntersectsWithRect(b));
1663 }
1664
1665 {
1666 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1667 Rect b = Rect::MakeXYWH(10, 10, 0, 0);
1668 ASSERT_FALSE(a.IntersectsWithRect(b));
1669 }
1670
1671 {
1672 Rect a = Rect::MakeXYWH(0, 0, 100, 100);
1673 Rect b = Rect::MakeXYWH(10, 10, 100, 100);
1674 ASSERT_TRUE(a.IntersectsWithRect(b));
1675 }
1676
1677 {
1678 Rect a = Rect::MakeXYWH(0, 0, 100, 100);
1679 Rect b = Rect::MakeXYWH(100, 100, 100, 100);
1680 ASSERT_FALSE(a.IntersectsWithRect(b));
1681 }
1682
1683 {
1684 Rect a = Rect::MakeMaximum();
1685 Rect b = Rect::MakeXYWH(10, 10, 100, 100);
1686 ASSERT_TRUE(a.IntersectsWithRect(b));
1687 }
1688
1689 {
1690 Rect a = Rect::MakeMaximum();
1691 Rect b = Rect::MakeMaximum();
1692 ASSERT_TRUE(a.IntersectsWithRect(b));
1693 }
1694 }
1695
1696 TEST(GeometryTest, RectCutout) {
1697 // No cutout.
1698 {
1699 Rect a = Rect::MakeXYWH(0, 0, 100, 100);
1700 Rect b = Rect::MakeXYWH(0, 0, 50, 50);
1701 auto u = a.Cutout(b);
1702 ASSERT_TRUE(u.has_value());
1703 ASSERT_RECT_NEAR(u.value(), a);
1704 }
1705
1706 // Full cutout.
1707 {
1708 Rect a = Rect::MakeXYWH(0, 0, 100, 100);
1709 Rect b = Rect::MakeXYWH(-10, -10, 120, 120);
1710 auto u = a.Cutout(b);
1711 ASSERT_FALSE(u.has_value());
1712 }
1713
1714 // Cutout from top.
1715 {
1716 auto a = Rect::MakeLTRB(0, 0, 100, 100);
1717 auto b = Rect::MakeLTRB(-10, -10, 110, 90);
1718 auto u = a.Cutout(b);
1719 auto expected = Rect::MakeLTRB(0, 90, 100, 100);
1720 ASSERT_TRUE(u.has_value());
1721 ASSERT_RECT_NEAR(u.value(), expected);
1722 }
1723
1724 // Cutout from bottom.
1725 {
1726 auto a = Rect::MakeLTRB(0, 0, 100, 100);
1727 auto b = Rect::MakeLTRB(-10, 10, 110, 110);
1728 auto u = a.Cutout(b);
1729 auto expected = Rect::MakeLTRB(0, 0, 100, 10);
1730 ASSERT_TRUE(u.has_value());
1731 ASSERT_RECT_NEAR(u.value(), expected);
1732 }
1733
1734 // Cutout from left.
1735 {
1736 auto a = Rect::MakeLTRB(0, 0, 100, 100);
1737 auto b = Rect::MakeLTRB(-10, -10, 90, 110);
1738 auto u = a.Cutout(b);
1739 auto expected = Rect::MakeLTRB(90, 0, 100, 100);
1740 ASSERT_TRUE(u.has_value());
1741 ASSERT_RECT_NEAR(u.value(), expected);
1742 }
1743
1744 // Cutout from right.
1745 {
1746 auto a = Rect::MakeLTRB(0, 0, 100, 100);
1747 auto b = Rect::MakeLTRB(10, -10, 110, 110);
1748 auto u = a.Cutout(b);
1749 auto expected = Rect::MakeLTRB(0, 0, 10, 100);
1750 ASSERT_TRUE(u.has_value());
1751 ASSERT_RECT_NEAR(u.value(), expected);
1752 }
1753 }
1754
1755 TEST(GeometryTest, RectContainsPoint) {
1756 {
1757 // Origin is inclusive
1758 Rect r = Rect::MakeXYWH(100, 100, 100, 100);
1759 Point p(100, 100);
1760 ASSERT_TRUE(r.Contains(p));
1761 }
1762 {
1763 // Size is exclusive
1764 Rect r = Rect::MakeXYWH(100, 100, 100, 100);
1765 Point p(200, 200);
1766 ASSERT_FALSE(r.Contains(p));
1767 }
1768 {
1769 Rect r = Rect::MakeXYWH(100, 100, 100, 100);
1770 Point p(99, 99);
1771 ASSERT_FALSE(r.Contains(p));
1772 }
1773 {
1774 Rect r = Rect::MakeXYWH(100, 100, 100, 100);
1775 Point p(199, 199);
1776 ASSERT_TRUE(r.Contains(p));
1777 }
1778
1779 {
1780 Rect r = Rect::MakeMaximum();
1781 Point p(199, 199);
1782 ASSERT_TRUE(r.Contains(p));
1783 }
1784 }
1785
1786 TEST(GeometryTest, RectContainsRect) {
1787 {
1788 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1789 ASSERT_TRUE(a.Contains(a));
1790 }
1791 {
1792 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1793 Rect b = Rect::MakeXYWH(0, 0, 0, 0);
1794 ASSERT_FALSE(a.Contains(b));
1795 }
1796 {
1797 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1798 Rect b = Rect::MakeXYWH(150, 150, 20, 20);
1799 ASSERT_TRUE(a.Contains(b));
1800 }
1801 {
1802 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1803 Rect b = Rect::MakeXYWH(150, 150, 100, 100);
1804 ASSERT_FALSE(a.Contains(b));
1805 }
1806 {
1807 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1808 Rect b = Rect::MakeXYWH(50, 50, 100, 100);
1809 ASSERT_FALSE(a.Contains(b));
1810 }
1811 {
1812 Rect a = Rect::MakeXYWH(100, 100, 100, 100);
1813 Rect b = Rect::MakeXYWH(0, 0, 300, 300);
1814 ASSERT_FALSE(a.Contains(b));
1815 }
1816 {
1817 Rect a = Rect::MakeMaximum();
1818 Rect b = Rect::MakeXYWH(0, 0, 300, 300);
1819 ASSERT_TRUE(a.Contains(b));
1820 }
1821 }
1822
1823 TEST(GeometryTest, RectGetPoints) {
1824 {
1825 Rect r = Rect::MakeXYWH(100, 200, 300, 400);
1826 auto points = r.GetPoints();
1827 ASSERT_POINT_NEAR(points[0], Point(100, 200));
1828 ASSERT_POINT_NEAR(points[1], Point(400, 200));
1829 ASSERT_POINT_NEAR(points[2], Point(100, 600));
1830 ASSERT_POINT_NEAR(points[3], Point(400, 600));
1831 }
1832
1833 {
1834 Rect r = Rect::MakeMaximum();
1835 auto points = r.GetPoints();
1836 ASSERT_EQ(points[0], Point(-std::numeric_limits<float>::infinity(),
1837 -std::numeric_limits<float>::infinity()));
1838 ASSERT_EQ(points[1], Point(std::numeric_limits<float>::infinity(),
1839 -std::numeric_limits<float>::infinity()));
1840 ASSERT_EQ(points[2], Point(-std::numeric_limits<float>::infinity(),
1841 std::numeric_limits<float>::infinity()));
1842 ASSERT_EQ(points[3], Point(std::numeric_limits<float>::infinity(),
1843 std::numeric_limits<float>::infinity()));
1844 }
1845 }
1846
1847 TEST(GeometryTest, RectShift) {
1848 auto r = Rect::MakeLTRB(0, 0, 100, 100);
1849
1850 ASSERT_EQ(r.Shift(Point(10, 5)), Rect::MakeLTRB(10, 5, 110, 105));
1851 ASSERT_EQ(r.Shift(Point(-10, -5)), Rect::MakeLTRB(-10, -5, 90, 95));
1852 }
1853
1854 TEST(GeometryTest, RectGetTransformedPoints) {
1855 Rect r = Rect::MakeXYWH(100, 200, 300, 400);
1856 auto points = r.GetTransformedPoints(Matrix::MakeTranslation({10, 20}));
1857 ASSERT_POINT_NEAR(points[0], Point(110, 220));
1858 ASSERT_POINT_NEAR(points[1], Point(410, 220));
1859 ASSERT_POINT_NEAR(points[2], Point(110, 620));
1860 ASSERT_POINT_NEAR(points[3], Point(410, 620));
1861 }
1862
1863 TEST(GeometryTest, RectMakePointBounds) {
1864 {
1865 std::vector<Point> points{{1, 5}, {4, -1}, {0, 6}};
1866 Rect r = Rect::MakePointBounds(points.begin(), points.end()).value();
1867 auto expected = Rect::MakeXYWH(0, -1, 4, 7);
1868 ASSERT_RECT_NEAR(r, expected);
1869 }
1870 {
1871 std::vector<Point> points;
1872 std::optional<Rect> r = Rect::MakePointBounds(points.begin(), points.end());
1873 ASSERT_FALSE(r.has_value());
1874 }
1875 }
1876
1877 TEST(GeometryTest, RectExpand) {
1878 {
1879 auto a = Rect::MakeLTRB(100, 100, 200, 200);
1880 auto b = a.Expand(1);
1881 auto expected = Rect::MakeLTRB(99, 99, 201, 201);
1882 ASSERT_RECT_NEAR(b, expected);
1883 }
1884 {
1885 auto a = Rect::MakeLTRB(100, 100, 200, 200);
1886 auto b = a.Expand(-1);
1887 auto expected = Rect::MakeLTRB(101, 101, 199, 199);
1888 ASSERT_RECT_NEAR(b, expected);
1889 }
1890
1891 {
1892 auto a = Rect::MakeLTRB(100, 100, 200, 200);
1893 auto b = a.Expand(1, 2, 3, 4);
1894 auto expected = Rect::MakeLTRB(99, 98, 203, 204);
1895 ASSERT_RECT_NEAR(b, expected);
1896 }
1897 {
1898 auto a = Rect::MakeLTRB(100, 100, 200, 200);
1899 auto b = a.Expand(-1, -2, -3, -4);
1900 auto expected = Rect::MakeLTRB(101, 102, 197, 196);
1901 ASSERT_RECT_NEAR(b, expected);
1902 }
1903 }
1904
1905 TEST(GeometryTest, RectGetPositive) {
1906 {
1907 Rect r = Rect::MakeXYWH(100, 200, 300, 400);
1908 auto actual = r.GetPositive();
1909 ASSERT_RECT_NEAR(r, actual);
1910 }
1911 {
1912 Rect r = Rect::MakeXYWH(100, 200, -100, -100);
1913 auto actual = r.GetPositive();
1914 Rect expected = Rect::MakeXYWH(0, 100, 100, 100);
1915 ASSERT_RECT_NEAR(expected, actual);
1916 }
1917 }
1918
1919 TEST(GeometryTest, RectScale) {
1920 {
1921 auto r = Rect::MakeLTRB(-100, -100, 100, 100);
1922 auto actual = r.Scale(0);
1923 auto expected = Rect::MakeLTRB(0, 0, 0, 0);
1924 ASSERT_RECT_NEAR(expected, actual);
1925 }
1926 {
1927 auto r = Rect::MakeLTRB(-100, -100, 100, 100);
1928 auto actual = r.Scale(-2);
1929 auto expected = Rect::MakeLTRB(200, 200, -200, -200);
1930 ASSERT_RECT_NEAR(expected, actual);
1931 }
1932 {
1933 auto r = Rect::MakeLTRB(-100, -100, 100, 100);
1934 auto actual = r.Scale(Point{0, 0});
1935 auto expected = Rect::MakeLTRB(0, 0, 0, 0);
1936 ASSERT_RECT_NEAR(expected, actual);
1937 }
1938 {
1939 auto r = Rect::MakeLTRB(-100, -100, 100, 100);
1940 auto actual = r.Scale(Size{-1, -2});
1941 auto expected = Rect::MakeLTRB(100, 200, -100, -200);
1942 ASSERT_RECT_NEAR(expected, actual);
1943 }
1944 }
1945
1946 TEST(GeometryTest, RectDirections) {
1947 auto r = Rect::MakeLTRB(1, 2, 3, 4);
1948
1949 ASSERT_EQ(r.GetLeft(), 1);
1950 ASSERT_EQ(r.GetTop(), 2);
1951 ASSERT_EQ(r.GetRight(), 3);
1952 ASSERT_EQ(r.GetBottom(), 4);
1953
1954 ASSERT_POINT_NEAR(r.GetLeftTop(), Point(1, 2));
1955 ASSERT_POINT_NEAR(r.GetRightTop(), Point(3, 2));
1956 ASSERT_POINT_NEAR(r.GetLeftBottom(), Point(1, 4));
1957 ASSERT_POINT_NEAR(r.GetRightBottom(), Point(3, 4));
1958 }
1959
1960 TEST(GeometryTest, RectProject) {
1961 {
1962 auto r = Rect::MakeLTRB(-100, -100, 100, 100);
1963 auto actual = r.Project(r);
1964 auto expected = Rect::MakeLTRB(0, 0, 1, 1);
1965 ASSERT_RECT_NEAR(expected, actual);
1966 }
1967 {
1968 auto r = Rect::MakeLTRB(-100, -100, 100, 100);
1969 auto actual = r.Project(Rect::MakeLTRB(0, 0, 100, 100));
1970 auto expected = Rect::MakeLTRB(0.5, 0.5, 1, 1);
1971 ASSERT_RECT_NEAR(expected, actual);
1972 }
1973 }
1974
1975 TEST(GeometryTest, RectRoundOut) {
1976 {
1977 auto r = Rect::MakeLTRB(-100, -100, 100, 100);
1978 ASSERT_EQ(Rect::RoundOut(r), r);
1979 }
1980 {
1981 auto r = Rect::MakeLTRB(-100.1, -100.1, 100.1, 100.1);
1982 ASSERT_EQ(Rect::RoundOut(r), Rect::MakeLTRB(-101, -101, 101, 101));
1983 }
1984 }
1985
1986 TEST(GeometryTest, MatrixPrinting) {
1987 {
1988 std::stringstream stream;
1989 Matrix m;
1990 stream << m;
1991 ASSERT_EQ(stream.str(), R"((
1992 1.000000, 0.000000, 0.000000, 0.000000,
1993 0.000000, 1.000000, 0.000000, 0.000000,
1994 0.000000, 0.000000, 1.000000, 0.000000,
1995 0.000000, 0.000000, 0.000000, 1.000000,
1996 ))");
1997 }
1998
1999 {
2000 std::stringstream stream;
2001 Matrix m = Matrix::MakeTranslation(Vector3(10, 20, 30));
2002 stream << m;
2003
2004 ASSERT_EQ(stream.str(), R"((
2005 1.000000, 0.000000, 0.000000, 10.000000,
2006 0.000000, 1.000000, 0.000000, 20.000000,
2007 0.000000, 0.000000, 1.000000, 30.000000,
2008 0.000000, 0.000000, 0.000000, 1.000000,
2009 ))");
2010 }
2011 }
2012
2013 TEST(GeometryTest, PointPrinting) {
2014 {
2015 std::stringstream stream;
2016 Point m;
2017 stream << m;
2018 ASSERT_EQ(stream.str(), "(0, 0)");
2019 }
2020
2021 {
2022 std::stringstream stream;
2023 Point m(13, 37);
2024 stream << m;
2025 ASSERT_EQ(stream.str(), "(13, 37)");
2026 }
2027 }
2028
2029 TEST(GeometryTest, Vector3Printing) {
2030 {
2031 std::stringstream stream;
2032 Vector3 m;
2033 stream << m;
2034 ASSERT_EQ(stream.str(), "(0, 0, 0)");
2035 }
2036
2037 {
2038 std::stringstream stream;
2039 Vector3 m(1, 2, 3);
2040 stream << m;
2041 ASSERT_EQ(stream.str(), "(1, 2, 3)");
2042 }
2043 }
2044
2045 TEST(GeometryTest, Vector4Printing) {
2046 {
2047 std::stringstream stream;
2048 Vector4 m;
2049 stream << m;
2050 ASSERT_EQ(stream.str(), "(0, 0, 0, 1)");
2051 }
2052
2053 {
2054 std::stringstream stream;
2055 Vector4 m(1, 2, 3, 4);
2056 stream << m;
2057 ASSERT_EQ(stream.str(), "(1, 2, 3, 4)");
2058 }
2059 }
2060
2061 TEST(GeometryTest, ColorPrinting) {
2062 {
2063 std::stringstream stream;
2064 Color m;
2065 stream << m;
2066 ASSERT_EQ(stream.str(), "(0, 0, 0, 0)");
2067 }
2068
2069 {
2070 std::stringstream stream;
2071 Color m(1, 2, 3, 4);
2072 stream << m;
2073 ASSERT_EQ(stream.str(), "(1, 2, 3, 4)");
2074 }
2075 }
2076
2077 TEST(GeometryTest, ToIColor) {
2078 ASSERT_EQ(Color::ToIColor(Color(0, 0, 0, 0)), 0u);
2079 ASSERT_EQ(Color::ToIColor(Color(1.0, 1.0, 1.0, 1.0)), 0xFFFFFFFF);
2080 ASSERT_EQ(Color::ToIColor(Color(0.5, 0.5, 1.0, 1.0)), 0xFF8080FF);
2081 }
2082
2083 TEST(GeometryTest, Gradient) {
2084 {
2085 // Simple 2 color gradient produces color buffer containing exactly those
2086 // values.
2087 std::vector<Color> colors = {Color::Red(), Color::Blue()};
2088 std::vector<Scalar> stops = {0.0, 1.0};
2089
2090 auto gradient = CreateGradientBuffer(colors, stops);
2091
2092 ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors);
2093 ASSERT_EQ(gradient.texture_size, 2u);
2094 }
2095
2096 {
2097 // Gradient with duplicate stops does not create an empty texture.
2098 std::vector<Color> colors = {Color::Red(), Color::Yellow(), Color::Black(),
2099 Color::Blue()};
2100 std::vector<Scalar> stops = {0.0, 0.25, 0.25, 1.0};
2101
2102 auto gradient = CreateGradientBuffer(colors, stops);
2103 ASSERT_EQ(gradient.texture_size, 5u);
2104 }
2105
2106 {
2107 // Simple N color gradient produces color buffer containing exactly those
2108 // values.
2109 std::vector<Color> colors = {Color::Red(), Color::Blue(), Color::Green(),
2110 Color::White()};
2111 std::vector<Scalar> stops = {0.0, 0.33, 0.66, 1.0};
2112
2113 auto gradient = CreateGradientBuffer(colors, stops);
2114
2115 ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors);
2116 ASSERT_EQ(gradient.texture_size, 4u);
2117 }
2118
2119 {
2120 // Gradient with color stops will lerp and scale buffer.
2121 std::vector<Color> colors = {Color::Red(), Color::Blue(), Color::Green()};
2122 std::vector<Scalar> stops = {0.0, 0.25, 1.0};
2123
2124 auto gradient = CreateGradientBuffer(colors, stops);
2125
2126 std::vector<Color> lerped_colors = {
2127 Color::Red(),
2128 Color::Blue(),
2129 Color::Lerp(Color::Blue(), Color::Green(), 0.3333),
2130 Color::Lerp(Color::Blue(), Color::Green(), 0.6666),
2131 Color::Green(),
2132 };
2133 ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, lerped_colors);
2134 ASSERT_EQ(gradient.texture_size, 5u);
2135 }
2136
2137 {
2138 // Gradient size is capped at 1024.
2139 std::vector<Color> colors = {};
2140 std::vector<Scalar> stops = {};
2141 for (auto i = 0u; i < 1025; i++) {
2142 colors.push_back(Color::Blue());
2143 stops.push_back(i / 1025.0);
2144 }
2145
2146 auto gradient = CreateGradientBuffer(colors, stops);
2147
2148 ASSERT_EQ(gradient.texture_size, 1024u);
2149 ASSERT_EQ(gradient.color_bytes.size(), 1024u * 4);
2150 }
2151 }
2152
2153 TEST(GeometryTest, HalfConversions) {
2154 #ifdef FML_OS_WIN
2155 GTEST_SKIP() << "Half-precision floats (IEEE 754) are not portable and "
2156 "unavailable on Windows.";
2157 #else
2158 ASSERT_EQ(ScalarToHalf(0.0), 0.0f16);
2159 ASSERT_EQ(ScalarToHalf(0.05), 0.05f16);
2160 ASSERT_EQ(ScalarToHalf(2.43), 2.43f16);
2161 ASSERT_EQ(ScalarToHalf(-1.45), -1.45f16);
2162
2163 // 65504 is the largest possible half.
2164 ASSERT_EQ(ScalarToHalf(65504.0f), 65504.0f16);
2165 ASSERT_EQ(ScalarToHalf(65504.0f + 1), 65504.0f16);
2166
2167 // Colors
2168 ASSERT_EQ(HalfVector4(Color::Red()),
2169 HalfVector4(1.0f16, 0.0f16, 0.0f16, 1.0f16));
2170 ASSERT_EQ(HalfVector4(Color::Green()),
2171 HalfVector4(0.0f16, 1.0f16, 0.0f16, 1.0f16));
2172 ASSERT_EQ(HalfVector4(Color::Blue()),
2173 HalfVector4(0.0f16, 0.0f16, 1.0f16, 1.0f16));
2174 ASSERT_EQ(HalfVector4(Color::Black().WithAlpha(0)),
2175 HalfVector4(0.0f16, 0.0f16, 0.0f16, 0.0f16));
2176
2177 ASSERT_EQ(HalfVector3(Vector3(4.0, 6.0, -1.0)),
2178 HalfVector3(4.0f16, 6.0f16, -1.0f16));
2179 ASSERT_EQ(HalfVector2(Vector2(4.0, 6.0)), HalfVector2(4.0f16, 6.0f16));
2180
2181 ASSERT_EQ(Half(0.5f), Half(0.5f16));
2182 ASSERT_EQ(Half(0.5), Half(0.5f16));
2183 ASSERT_EQ(Half(5), Half(5.0f16));
2184 #endif // FML_OS_WIN
2185 }
2186
2187 } // namespace testing
2188 } // namespace impeller
2189
2190 // NOLINTEND(bugprone-unchecked-optional-access)
impeller::Matrix::MakeSkew
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
Definition: matrix.h:117
impeller::Color::Blue
static constexpr Color Blue()
Definition: color.h:268
ASSERT_COLOR_NEAR
#define ASSERT_COLOR_NEAR(a, b)
Definition: geometry_asserts.h:159
impeller::Matrix::Decompose
std::optional< MatrixDecomposition > Decompose() const
Definition: matrix.cc:217
impeller::k1OverSqrt2
constexpr float k1OverSqrt2
Definition: constants.h:50
impeller::Matrix::MakeRotationX
static Matrix MakeRotationX(Radians r)
Definition: matrix.h:182
impeller::BlendModeToString
const char * BlendModeToString(BlendMode blend_mode)
Definition: color.cc:47
point.h
impeller::TPoint::y
Type y
Definition: point.h:26
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::HalfVector2
A storage only class for half precision floating point vector 2.
Definition: half.h:128
impeller::TPoint::Ceil
constexpr TPoint Ceil() const
Definition: point.h:191
impeller::Color::Red
static constexpr Color Red()
Definition: color.h:264
geometry_asserts.h
impeller::Vector3::Round
constexpr Vector3 Round() const
Definition: vector.h:86
impeller::Vector4::Max
constexpr Vector4 Max(const Vector4 &p) const
Definition: vector.h:292
impeller::TRect< Scalar >::MakeXYWH
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:34
impeller::BlendMode
BlendMode
Definition: color.h:59
impeller::Color::MakeRGBA8
static constexpr Color MakeRGBA8(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
Definition: color.h:154
impeller::Color
Definition: color.h:124
impeller::Color::Unpremultiply
constexpr Color Unpremultiply() const
Definition: color.h:218
impeller::TPoint::Lerp
constexpr TPoint Lerp(const TPoint &p, Scalar t) const
Definition: point.h:225
impeller::Vector4
Definition: vector.h:232
impeller::Matrix::MakeRotation
static Matrix MakeRotation(Quaternion q)
Definition: matrix.h:126
impeller::TPoint::Min
constexpr TPoint Min(const TPoint &p) const
Definition: point.h:181
impeller::TPoint::Round
static constexpr TPoint Round(const TPoint< U > &other)
Definition: point.h:44
impeller::Vector2
Point Vector2
Definition: point.h:312
impeller::Matrix::MakeRotationY
static Matrix MakeRotationY(Radians r)
Definition: matrix.h:195
impeller::TRect< Scalar >::RoundOut
constexpr static TRect RoundOut(const TRect &r)
Definition: rect.h:430
impeller::kPi
constexpr float kPi
Definition: constants.h:26
impeller::Color::Yellow
static constexpr Color Yellow()
Definition: color.h:834
impeller::Radians::radians
Scalar radians
Definition: scalar.h:39
impeller::Matrix::MakeRow
static constexpr Matrix MakeRow(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:83
impeller::Size
TSize< Scalar > Size
Definition: size.h:137
impeller::TRect::GetX
constexpr Type GetX() const
Returns the X coordinate of the upper left corner, equivalent to |GetOrigin().x|.
Definition: rect.h:163
ASSERT_POINT_NEAR
#define ASSERT_POINT_NEAR(a, b)
Definition: geometry_asserts.h:160
impeller::TRect::GetHeight
constexpr Type GetHeight() const
Returns the height of the rectangle, equivalent to |GetSize().height|.
Definition: rect.h:175
impeller::Matrix::MakeTranslation
static constexpr Matrix MakeTranslation(const Vector3 &t)
Definition: matrix.h:95
impeller::Color::Clamp01
constexpr Color Clamp01() const
Definition: color.h:238
impeller::TRect::GetOrigin
constexpr TPoint< Type > GetOrigin() const
Returns the upper left corner of the rectangle as specified when it was constructed.
Definition: rect.h:154
ASSERT_VECTOR4_NEAR
#define ASSERT_VECTOR4_NEAR(a, b)
Definition: geometry_asserts.h:162
impeller::Vector3::x
Scalar x
Definition: vector.h:23
impeller::TPoint::Floor
constexpr TPoint Floor() const
Definition: point.h:189
impeller::TPoint::Dot
constexpr Type Dot(const TPoint &p) const
Definition: point.h:215
impeller::TRect::IntersectsWithRect
constexpr bool IntersectsWithRect(const TRect &o) const
Definition: rect.h:328
impeller::TRect::GetPoints
constexpr std::array< TPoint< T >, 4 > GetPoints() const
Get the points that represent the 4 corners of this rectangle. The order is: Top left,...
Definition: rect.h:247
impeller::TRect< Scalar >::MakePointBounds
constexpr static std::optional< TRect > MakePointBounds(const U &value)
Definition: rect.h:49
impeller::MatrixDecomposition
Definition: matrix_decomposition.h:15
impeller::kPiOver2
constexpr float kPiOver2
Definition: constants.h:32
impeller::Matrix::MakeLookAt
static constexpr Matrix MakeLookAt(Vector3 position, Vector3 target, Vector3 up)
Definition: matrix.h:494
impeller::Matrix::MakePerspective
static constexpr Matrix MakePerspective(Radians fov_y, Scalar aspect_ratio, Scalar z_near, Scalar z_far)
Definition: matrix.h:468
ASSERT_RECT_NEAR
#define ASSERT_RECT_NEAR(a, b)
Definition: geometry_asserts.h:158
gradient.h
impeller::Vector4::Round
constexpr Vector4 Round() const
Definition: vector.h:305
impeller::TPoint::Reflect
constexpr TPoint Reflect(const TPoint &axis) const
Definition: point.h:217
impeller::Matrix::Basis
constexpr Matrix Basis() const
The Matrix without its w components (without translation).
Definition: matrix.h:224
impeller::TSize< Scalar >
impeller::Quaternion
Definition: quaternion.h:14
impeller::Point
TPoint< Scalar > Point
Definition: point.h:308
impeller::k2Pi
constexpr float k2Pi
Definition: constants.h:29
impeller::TRect::Intersection
constexpr std::optional< TRect< T > > Intersection(const TRect &o) const
Definition: rect.h:312
impeller::Half
A storage only class for half precision floating point.
Definition: half.h:40
impeller::TPoint::AngleTo
constexpr Radians AngleTo(const TPoint &p) const
Definition: point.h:221
impeller::Color::ToIColor
static constexpr uint32_t ToIColor(Color color)
Convert this color to a 32-bit representation.
Definition: color.h:161
impeller::Color::SRGBToLinear
Color SRGBToLinear() const
Convert the color from sRGB space to linear space.
Definition: color.cc:387
impeller::TRect::GetTransformedPoints
constexpr std::array< TPoint< T >, 4 > GetTransformedPoints(const Matrix &transform) const
Definition: rect.h:253
impeller::Vector4::Lerp
constexpr Vector4 Lerp(const Vector4 &v, Scalar t) const
Definition: vector.h:309
impeller::ScalarToHalf
constexpr InternalHalf ScalarToHalf(Scalar f)
Convert a scalar to a half precision float.
Definition: half.h:31
impeller::TRect::GetWidth
constexpr Type GetWidth() const
Returns the width of the rectangle, equivalent to |GetSize().width|.
Definition: rect.h:171
impeller::TPoint::Max
constexpr TPoint Max(const TPoint &p) const
Definition: point.h:185
impeller::Vector4::Min
constexpr Vector4 Min(const Vector4 &p) const
Definition: vector.h:287
impeller::Color::ToR8G8B8A8
constexpr std::array< uint8_t, 4 > ToR8G8B8A8() const
Convert to R8G8B8A8 representation.
Definition: color.h:248
impeller::testing::TEST
TEST(CanvasRecorder, Save)
Definition: canvas_recorder_unittests.cc:61
impeller::Color::White
static constexpr Color White()
Definition: color.h:256
impeller::Matrix::MakeColumn
static constexpr Matrix MakeColumn(Scalar m0, Scalar m1, Scalar m2, Scalar m3, Scalar m4, Scalar m5, Scalar m6, Scalar m7, Scalar m8, Scalar m9, Scalar m10, Scalar m11, Scalar m12, Scalar m13, Scalar m14, Scalar m15)
Definition: matrix.h:69
impeller::Vector3::Floor
constexpr Vector3 Floor() const
Definition: vector.h:78
impeller::Vector3::Ceil
constexpr Vector3 Ceil() const
Definition: vector.h:82
impeller::Vector3::z
Scalar z
Definition: vector.h:25
impeller::Radians
Definition: scalar.h:38
impeller::MatrixDecomposition::translation
Vector3 translation
Definition: matrix_decomposition.h:16
impeller::HalfVector3
A storage only class for half precision floating point vector 3.
Definition: half.h:100
_BLEND_MODE_NAME_CHECK
#define _BLEND_MODE_NAME_CHECK(blend_mode)
Definition: geometry_unittests.cc:1447
impeller::Color::Green
static constexpr Color Green()
Definition: color.h:266
ASSERT_MATRIX_NEAR
#define ASSERT_MATRIX_NEAR(a, b)
Definition: geometry_asserts.h:156
impeller::TPoint::Cross
constexpr Type Cross(const TPoint &p) const
Definition: point.h:213
impeller::Vector3::y
Scalar y
Definition: vector.h:24
impeller::CreateGradientBuffer
GradientData CreateGradientBuffer(const std::vector< Color > &colors, const std::vector< Scalar > &stops)
Populate a vector with the interpolated color bytes for the linear gradient described by colors and s...
Definition: gradient.cc:20
impeller::MatrixDecomposition::rotation
Quaternion rotation
Definition: matrix_decomposition.h:20
impeller::TSize::width
Type width
Definition: size.h:22
IMPELLER_FOR_EACH_BLEND_MODE
#define IMPELLER_FOR_EACH_BLEND_MODE(V)
Definition: color.h:19
impeller::Matrix::Invert
Matrix Invert() const
Definition: matrix.cc:97
impeller::TRect::Contains
constexpr bool Contains(const TPoint< Type > &p) const
Definition: rect.h:127
impeller::TPoint::x
Type x
Definition: point.h:25
ASSERT_QUATERNION_NEAR
#define ASSERT_QUATERNION_NEAR(a, b)
Definition: geometry_asserts.h:157
impeller::Matrix::GetDirectionScale
constexpr Scalar GetDirectionScale(Vector3 direction) const
Definition: matrix.h:308
scalar.h
impeller::ISize
TSize< int64_t > ISize
Definition: size.h:138
impeller::MatrixDecomposition::scale
Vector3 scale
Definition: matrix_decomposition.h:17
impeller::TPoint::Abs
constexpr TPoint Abs() const
Definition: point.h:211
impeller::TRect::Cutout
constexpr std::optional< TRect< T > > Cutout(const TRect &o) const
Returns the new boundary rectangle that would result from the rectangle being cutout by a second rect...
Definition: rect.h:334
half.h
impeller::TRect::GetSize
constexpr TSize< Type > GetSize() const
Returns the size of the rectangle as specified when it was constructed and which may be negative in e...
Definition: rect.h:159
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:209
constants.h
impeller::IPoint
TPoint< int64_t > IPoint
Definition: point.h:309
ASSERT_VECTOR3_NEAR
#define ASSERT_VECTOR3_NEAR(a, b)
Definition: geometry_asserts.h:161
rect.h
impeller::TPoint< Scalar >
impeller::TRect< Scalar >::MakeMaximum
constexpr static TRect MakeMaximum()
Definition: rect.h:72
impeller::Color::BlackTransparent
static constexpr Color BlackTransparent()
Definition: color.h:262
impeller::Color::Black
static constexpr Color Black()
Definition: color.h:258
impeller::Vector4::Floor
constexpr Vector4 Floor() const
Definition: vector.h:297
impeller::HalfVector4
A storage only class for half precision floating point vector 4.
Definition: half.h:59
impeller::ScalarNearlyEqual
constexpr bool ScalarNearlyEqual(Scalar x, Scalar y, Scalar tolerance=kEhCloseEnough)
Definition: scalar.h:30
impeller::Matrix::MakeOrthographic
static constexpr Matrix MakeOrthographic(TSize< T > size)
Definition: matrix.h:459
impeller::TRect::Union
constexpr TRect Union(const TRect &o) const
Definition: rect.h:302
impeller::Vector3::Min
constexpr Vector3 Min(const Vector3 &p) const
Definition: vector.h:70
impeller::Degrees
Definition: scalar.h:46
color.h
impeller::BlendMode::kLast
@ kLast
impeller::TSize::height
Type height
Definition: size.h:23
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:27
impeller::TRect::GetPositive
constexpr TRect GetPositive() const
Get a version of this rectangle that has a non-negative size.
Definition: rect.h:240
impeller::TSize::MipCount
constexpr size_t MipCount() const
Definition: size.h:115
impeller::Color::Lerp
constexpr static Color Lerp(Color a, Color b, Scalar t)
Return a color that is linearly interpolated between colors a and b, according to the value of t.
Definition: color.h:234
impeller::TPoint::Normalize
constexpr TPoint Normalize() const
Definition: point.h:203
impeller::ColorMatrix
Definition: color.h:117
impeller::Color::ApplyColorMatrix
Color ApplyColorMatrix(const ColorMatrix &color_matrix) const
A color filter that transforms colors through a 4x5 color matrix.
Definition: color.cc:366
impeller::Color::LinearToSRGB
Color LinearToSRGB() const
Convert the color from linear space to sRGB space.
Definition: color.cc:376
ASSERT_COLOR_BUFFER_NEAR
#define ASSERT_COLOR_BUFFER_NEAR(a, b)
Definition: geometry_asserts.h:165
impeller::TRect::GetY
constexpr Type GetY() const
Returns the Y coordinate of the upper left corner, equivalent to |GetOrigin().y|.
Definition: rect.h:167
impeller
Definition: aiks_context.cc:10
impeller::Matrix::MakeScale
static constexpr Matrix MakeScale(const Vector3 &s)
Definition: matrix.h:104
impeller::kPiOver4
constexpr float kPiOver4
Definition: constants.h:35
impeller::Color::Premultiply
constexpr Color Premultiply() const
Definition: color.h:214
impeller::TRect< Scalar >
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::Vector3
Definition: vector.h:20
size.h
impeller::Vector3::Lerp
constexpr Vector3 Lerp(const Vector3 &v, Scalar t) const
Definition: vector.h:178
ASSERT_ARRAY_4_NEAR
#define ASSERT_ARRAY_4_NEAR(a, b)
Definition: geometry_asserts.h:164
impeller::Vector3::Max
constexpr Vector3 Max(const Vector3 &p) const
Definition: vector.h:74
impeller::Matrix::IsAligned
constexpr bool IsAligned(Scalar tolerance=0) const
Definition: matrix.h:322
impeller::Vector4::Ceil
constexpr Vector4 Ceil() const
Definition: vector.h:301