| 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 // clang-format off
358 auto m = Matrix::MakeColumn(
359 1.0f, 0.0f, 0.0f, 0.0f,
360 0.0f, 1.0f, 0.0f, 0.0f,
361 4.0f, 0.0f, 1.0f, 0.0f,
362 0.0f, 0.0f, 0.0f, 1.0f
363 );
364 // clang-format on
365 ASSERT_EQ(m.GetMaxBasisLengthXY(), 1.0f);
366 }
367 }
368
369 TEST(GeometryTest, MatrixMakeOrthographic) {
370 {
371 auto m = Matrix::MakeOrthographic(Size(100, 200));
372 auto expect = Matrix{
373 0.02, 0, 0, 0, //
374 0, -0.01, 0, 0, //
375 0, 0, 0, 0, //
376 -1, 1, 0.5, 1, //
377 };
378 ASSERT_MATRIX_NEAR(m, expect);
379 }
380
381 {
382 auto m = Matrix::MakeOrthographic(Size(400, 100));
383 auto expect = Matrix{
384 0.005, 0, 0, 0, //
385 0, -0.02, 0, 0, //
386 0, 0, 0, 0, //
387 -1, 1, 0.5, 1, //
388 };
389 ASSERT_MATRIX_NEAR(m, expect);
390 }
391 }
392
393 TEST(GeometryTest, MatrixMakePerspective) {
394 {
395 auto m = Matrix::MakePerspective(Degrees(60), Size(100, 200), 1, 10);
396 auto expect = Matrix{
397 3.4641, 0, 0, 0, //
398 0, 1.73205, 0, 0, //
399 0, 0, 1.11111, 1, //
400 0, 0, -1.11111, 0, //
401 };
402 ASSERT_MATRIX_NEAR(m, expect);
403 }
404
405 {
406 auto m = Matrix::MakePerspective(Radians(1), 2, 10, 20);
407 auto expect = Matrix{
408 0.915244, 0, 0, 0, //
409 0, 1.83049, 0, 0, //
410 0, 0, 2, 1, //
411 0, 0, -20, 0, //
412 };
413 ASSERT_MATRIX_NEAR(m, expect);
414 }
415 }
416
417 TEST(GeometryTest, MatrixGetBasisVectors) {
418 {
419 auto m = Matrix();
420 Vector3 x = m.GetBasisX();
421 Vector3 y = m.GetBasisY();
422 Vector3 z = m.GetBasisZ();
423 ASSERT_VECTOR3_NEAR(x, Vector3(1, 0, 0));
424 ASSERT_VECTOR3_NEAR(y, Vector3(0, 1, 0));
425 ASSERT_VECTOR3_NEAR(z, Vector3(0, 0, 1));
426 }
427
428 {
429 auto m = Matrix::MakeRotationZ(Radians{kPiOver2}) *
430 Matrix::MakeRotationX(Radians{kPiOver2}) *
431 Matrix::MakeScale(Vector3(2, 3, 4));
432 Vector3 x = m.GetBasisX();
433 Vector3 y = m.GetBasisY();
434 Vector3 z = m.GetBasisZ();
435 ASSERT_VECTOR3_NEAR(x, Vector3(0, 2, 0));
436 ASSERT_VECTOR3_NEAR(y, Vector3(0, 0, 3));
437 ASSERT_VECTOR3_NEAR(z, Vector3(4, 0, 0));
438 }
439 }
440
441 TEST(GeometryTest, MatrixGetDirectionScale) {
442 {
443 auto m = Matrix();
444 Scalar result = m.GetDirectionScale(Vector3{1, 0, 0});
445 ASSERT_FLOAT_EQ(result, 1);
446 }
447
448 {
449 auto m = Matrix::MakeRotationX(Degrees{10}) *
450 Matrix::MakeRotationY(Degrees{83}) *
451 Matrix::MakeRotationZ(Degrees{172});
452 Scalar result = m.GetDirectionScale(Vector3{0, 1, 0});
453 ASSERT_FLOAT_EQ(result, 1);
454 }
455
456 {
457 auto m = Matrix::MakeRotationZ(Radians{kPiOver2}) *
458 Matrix::MakeScale(Vector3(3, 4, 5));
459 Scalar result = m.GetDirectionScale(Vector3{2, 0, 0});
460 ASSERT_FLOAT_EQ(result, 8);
461 }
462 }
463
464 TEST(GeometryTest, MatrixIsAligned) {
465 {
466 auto m = Matrix::MakeTranslation({1, 2, 3});
467 bool result = m.IsAligned();
468 ASSERT_TRUE(result);
469 }
470
471 {
472 auto m = Matrix::MakeRotationZ(Degrees{123});
473 bool result = m.IsAligned();
474 ASSERT_FALSE(result);
475 }
476 }
477
478 TEST(GeometryTest, MatrixTranslationScaleOnly) {
479 {
480 auto m = Matrix();
481 bool result = m.IsTranslationScaleOnly();
482 ASSERT_TRUE(result);
483 }
484
485 {
486 auto m = Matrix::MakeScale(Vector3(2, 3, 4));
487 bool result = m.IsTranslationScaleOnly();
488 ASSERT_TRUE(result);
489 }
490
491 {
492 auto m = Matrix::MakeTranslation(Vector3(2, 3, 4));
493 bool result = m.IsTranslationScaleOnly();
494 ASSERT_TRUE(result);
495 }
496
497 {
498 auto m = Matrix::MakeRotationZ(Degrees(10));
499 bool result = m.IsTranslationScaleOnly();
500 ASSERT_FALSE(result);
501 }
502 }
503
504 TEST(GeometryTest, MatrixLookAt) {
505 {
506 auto m = Matrix::MakeLookAt(Vector3(0, 0, -1), Vector3(0, 0, 1),
507 Vector3(0, 1, 0));
508 auto expected = Matrix{
509 1, 0, 0, 0, //
510 0, 1, 0, 0, //
511 0, 0, 1, 0, //
512 0, 0, 1, 1, //
513 };
514 ASSERT_MATRIX_NEAR(m, expected);
515 }
516
517 // Sideways tilt.
518 {
519 auto m = Matrix::MakeLookAt(Vector3(0, 0, -1), Vector3(0, 0, 1),
520 Vector3(1, 1, 0).Normalize());
521
522 // clang-format off
523 auto expected = Matrix{
524 k1OverSqrt2, k1OverSqrt2, 0, 0,
525 -k1OverSqrt2, k1OverSqrt2, 0, 0,
526 0, 0, 1, 0,
527 0, 0, 1, 1,
528 };
529 // clang-format on
530 ASSERT_MATRIX_NEAR(m, expected);
531 }
532
533 // Half way between +x and -y, yaw 90
534 {
535 auto m =
536 Matrix::MakeLookAt(Vector3(), Vector3(10, -10, 0), Vector3(0, 0, -1));
537
538 // clang-format off
539 auto expected = Matrix{
540 -k1OverSqrt2, 0, k1OverSqrt2, 0,
541 -k1OverSqrt2, 0, -k1OverSqrt2, 0,
542 0, -1, 0, 0,
543 0, 0, 0, 1,
544 };
545 // clang-format on
546 ASSERT_MATRIX_NEAR(m, expected);
547 }
548 }
549
550 TEST(GeometryTest, QuaternionLerp) {
551 auto q1 = Quaternion{{0.0, 0.0, 1.0}, 0.0};
552 auto q2 = Quaternion{{0.0, 0.0, 1.0}, kPiOver4};
553
554 auto q3 = q1.Slerp(q2, 0.5);
555
556 auto expected = Quaternion{{0.0, 0.0, 1.0}, kPiOver4 / 2.0};
557
558 ASSERT_QUATERNION_NEAR(q3, expected);
559 }
560
561 TEST(GeometryTest, QuaternionVectorMultiply) {
562 {
563 Quaternion q({0, 0, 1}, 0);
564 Vector3 v(0, 1, 0);
565
566 Vector3 result = q * v;
567 Vector3 expected(0, 1, 0);
568
569 ASSERT_VECTOR3_NEAR(result, expected);
570 }
571
572 {
573 Quaternion q({0, 0, 1}, k2Pi);
574 Vector3 v(1, 0, 0);
575
576 Vector3 result = q * v;
577 Vector3 expected(1, 0, 0);
578
579 ASSERT_VECTOR3_NEAR(result, expected);
580 }
581
582 {
583 Quaternion q({0, 0, 1}, kPiOver4);
584 Vector3 v(0, 1, 0);
585
586 Vector3 result = q * v;
587 Vector3 expected(-k1OverSqrt2, k1OverSqrt2, 0);
588
589 ASSERT_VECTOR3_NEAR(result, expected);
590 }
591
592 {
593 Quaternion q(Vector3(1, 0, 1).Normalize(), kPi);
594 Vector3 v(0, 0, -1);
595
596 Vector3 result = q * v;
597 Vector3 expected(-1, 0, 0);
598
599 ASSERT_VECTOR3_NEAR(result, expected);
600 }
601 }
602
603 TEST(GeometryTest, CanGenerateMipCounts) {
604 ASSERT_EQ((Size{128, 128}.MipCount()), 7u);
605 ASSERT_EQ((Size{128, 256}.MipCount()), 8u);
606 ASSERT_EQ((Size{128, 130}.MipCount()), 8u);
607 ASSERT_EQ((Size{128, 257}.MipCount()), 9u);
608 ASSERT_EQ((Size{257, 128}.MipCount()), 9u);
609 ASSERT_EQ((Size{128, 0}.MipCount()), 1u);
610 ASSERT_EQ((Size{128, -25}.MipCount()), 1u);
611 ASSERT_EQ((Size{-128, 25}.MipCount()), 1u);
612 ASSERT_EQ((Size{1, 1}.MipCount()), 1u);
613 ASSERT_EQ((Size{0, 0}.MipCount()), 1u);
614 }
615
616 TEST(GeometryTest, CanConvertTTypesExplicitly) {
617 {
618 Point p1(1.0, 2.0);
619 IPoint p2 = static_cast<IPoint>(p1);
620 ASSERT_EQ(p2.x, 1u);
621 ASSERT_EQ(p2.y, 2u);
622 }
623
624 {
625 Size s1(1.0, 2.0);
626 ISize s2 = static_cast<ISize>(s1);
627 ASSERT_EQ(s2.width, 1u);
628 ASSERT_EQ(s2.height, 2u);
629 }
630
631 {
632 Size s1(1.0, 2.0);
633 Point p1 = static_cast<Point>(s1);
634 ASSERT_EQ(p1.x, 1u);
635 ASSERT_EQ(p1.y, 2u);
636 }
637 }
638
639 TEST(GeometryTest, CanPerformAlgebraicPointOps) {
640 {
641 IPoint p1(1, 2);
642 IPoint p2 = p1 + IPoint(1, 2);
643 ASSERT_EQ(p2.x, 2u);
644 ASSERT_EQ(p2.y, 4u);
645 }
646
647 {
648 IPoint p1(3, 6);
649 IPoint p2 = p1 - IPoint(1, 2);
650 ASSERT_EQ(p2.x, 2u);
651 ASSERT_EQ(p2.y, 4u);
652 }
653
654 {
655 IPoint p1(1, 2);
656 IPoint p2 = p1 * IPoint(2, 3);
657 ASSERT_EQ(p2.x, 2u);
658 ASSERT_EQ(p2.y, 6u);
659 }
660
661 {
662 IPoint p1(2, 6);
663 IPoint p2 = p1 / IPoint(2, 3);
664 ASSERT_EQ(p2.x, 1u);
665 ASSERT_EQ(p2.y, 2u);
666 }
667 }
668
669 TEST(GeometryTest, CanPerformAlgebraicPointOpsWithArithmeticTypes) {
670 // LHS
671 {
672 IPoint p1(1, 2);
673 IPoint p2 = p1 * 2.0f;
674 ASSERT_EQ(p2.x, 2u);
675 ASSERT_EQ(p2.y, 4u);
676 }
677
678 {
679 IPoint p1(2, 6);
680 IPoint p2 = p1 / 2.0f;
681 ASSERT_EQ(p2.x, 1u);
682 ASSERT_EQ(p2.y, 3u);
683 }
684
685 // RHS
686 {
687 IPoint p1(1, 2);
688 IPoint p2 = 2.0f * p1;
689 ASSERT_EQ(p2.x, 2u);
690 ASSERT_EQ(p2.y, 4u);
691 }
692
693 {
694 IPoint p1(2, 6);
695 IPoint p2 = 12.0f / p1;
696 ASSERT_EQ(p2.x, 6u);
697 ASSERT_EQ(p2.y, 2u);
698 }
699 }
700
701 TEST(GeometryTest, PointIntegerCoercesToFloat) {
702 // Integer on LHS, float on RHS
703 {
704 IPoint p1(1, 2);
705 Point p2 = p1 + Point(1, 2);
706 ASSERT_FLOAT_EQ(p2.x, 2u);
707 ASSERT_FLOAT_EQ(p2.y, 4u);
708 }
709
710 {
711 IPoint p1(3, 6);
712 Point p2 = p1 - Point(1, 2);
713 ASSERT_FLOAT_EQ(p2.x, 2u);
714 ASSERT_FLOAT_EQ(p2.y, 4u);
715 }
716
717 {
718 IPoint p1(1, 2);
719 Point p2 = p1 * Point(2, 3);
720 ASSERT_FLOAT_EQ(p2.x, 2u);
721 ASSERT_FLOAT_EQ(p2.y, 6u);
722 }
723
724 {
725 IPoint p1(2, 6);
726 Point p2 = p1 / Point(2, 3);
727 ASSERT_FLOAT_EQ(p2.x, 1u);
728 ASSERT_FLOAT_EQ(p2.y, 2u);
729 }
730
731 // Float on LHS, integer on RHS
732 {
733 Point p1(1, 2);
734 Point p2 = p1 + IPoint(1, 2);
735 ASSERT_FLOAT_EQ(p2.x, 2u);
736 ASSERT_FLOAT_EQ(p2.y, 4u);
737 }
738
739 {
740 Point p1(3, 6);
741 Point p2 = p1 - IPoint(1, 2);
742 ASSERT_FLOAT_EQ(p2.x, 2u);
743 ASSERT_FLOAT_EQ(p2.y, 4u);
744 }
745
746 {
747 Point p1(1, 2);
748 Point p2 = p1 * IPoint(2, 3);
749 ASSERT_FLOAT_EQ(p2.x, 2u);
750 ASSERT_FLOAT_EQ(p2.y, 6u);
751 }
752
753 {
754 Point p1(2, 6);
755 Point p2 = p1 / IPoint(2, 3);
756 ASSERT_FLOAT_EQ(p2.x, 1u);
757 ASSERT_FLOAT_EQ(p2.y, 2u);
758 }
759 }
760
761 TEST(GeometryTest, SizeCoercesToPoint) {
762 // Point on LHS, Size on RHS
763 {
764 IPoint p1(1, 2);
765 IPoint p2 = p1 + ISize(1, 2);
766 ASSERT_EQ(p2.x, 2u);
767 ASSERT_EQ(p2.y, 4u);
768 }
769
770 {
771 IPoint p1(3, 6);
772 IPoint p2 = p1 - ISize(1, 2);
773 ASSERT_EQ(p2.x, 2u);
774 ASSERT_EQ(p2.y, 4u);
775 }
776
777 {
778 IPoint p1(1, 2);
779 IPoint p2 = p1 * ISize(2, 3);
780 ASSERT_EQ(p2.x, 2u);
781 ASSERT_EQ(p2.y, 6u);
782 }
783
784 {
785 IPoint p1(2, 6);
786 IPoint p2 = p1 / ISize(2, 3);
787 ASSERT_EQ(p2.x, 1u);
788 ASSERT_EQ(p2.y, 2u);
789 }
790
791 // Size on LHS, Point on RHS
792 {
793 ISize p1(1, 2);
794 IPoint p2 = p1 + IPoint(1, 2);
795 ASSERT_EQ(p2.x, 2u);
796 ASSERT_EQ(p2.y, 4u);
797 }
798
799 {
800 ISize p1(3, 6);
801 IPoint p2 = p1 - IPoint(1, 2);
802 ASSERT_EQ(p2.x, 2u);
803 ASSERT_EQ(p2.y, 4u);
804 }
805
806 {
807 ISize p1(1, 2);
808 IPoint p2 = p1 * IPoint(2, 3);
809 ASSERT_EQ(p2.x, 2u);
810 ASSERT_EQ(p2.y, 6u);
811 }
812
813 {
814 ISize p1(2, 6);
815 IPoint p2 = p1 / IPoint(2, 3);
816 ASSERT_EQ(p2.x, 1u);
817 ASSERT_EQ(p2.y, 2u);
818 }
819 }
820
821 TEST(GeometryTest, CanUsePointAssignmentOperators) {
822 // Point on RHS
823 {
824 IPoint p(1, 2);
825 p += IPoint(1, 2);
826 ASSERT_EQ(p.x, 2u);
827 ASSERT_EQ(p.y, 4u);
828 }
829
830 {
831 IPoint p(3, 6);
832 p -= IPoint(1, 2);
833 ASSERT_EQ(p.x, 2u);
834 ASSERT_EQ(p.y, 4u);
835 }
836
837 {
838 IPoint p(1, 2);
839 p *= IPoint(2, 3);
840 ASSERT_EQ(p.x, 2u);
841 ASSERT_EQ(p.y, 6u);
842 }
843
844 {
845 IPoint p(2, 6);
846 p /= IPoint(2, 3);
847 ASSERT_EQ(p.x, 1u);
848 ASSERT_EQ(p.y, 2u);
849 }
850
851 // Size on RHS
852 {
853 IPoint p(1, 2);
854 p += ISize(1, 2);
855 ASSERT_EQ(p.x, 2u);
856 ASSERT_EQ(p.y, 4u);
857 }
858
859 {
860 IPoint p(3, 6);
861 p -= ISize(1, 2);
862 ASSERT_EQ(p.x, 2u);
863 ASSERT_EQ(p.y, 4u);
864 }
865
866 {
867 IPoint p(1, 2);
868 p *= ISize(2, 3);
869 ASSERT_EQ(p.x, 2u);
870 ASSERT_EQ(p.y, 6u);
871 }
872
873 {
874 IPoint p(2, 6);
875 p /= ISize(2, 3);
876 ASSERT_EQ(p.x, 1u);
877 ASSERT_EQ(p.y, 2u);
878 }
879
880 // Arithmetic type on RHS
881 {
882 IPoint p(1, 2);
883 p *= 3;
884 ASSERT_EQ(p.x, 3u);
885 ASSERT_EQ(p.y, 6u);
886 }
887
888 {
889 IPoint p(3, 6);
890 p /= 3;
891 ASSERT_EQ(p.x, 1u);
892 ASSERT_EQ(p.y, 2u);
893 }
894 }
895
896 TEST(GeometryTest, PointDotProduct) {
897 {
898 Point p(1, 0);
899 Scalar s = p.Dot(Point(-1, 0));
900 ASSERT_FLOAT_EQ(s, -1);
901 }
902
903 {
904 Point p(0, -1);
905 Scalar s = p.Dot(Point(-1, 0));
906 ASSERT_FLOAT_EQ(s, 0);
907 }
908
909 {
910 Point p(1, 2);
911 Scalar s = p.Dot(Point(3, -4));
912 ASSERT_FLOAT_EQ(s, -5);
913 }
914 }
915
916 TEST(GeometryTest, PointCrossProduct) {
917 {
918 Point p(1, 0);
919 Scalar s = p.Cross(Point(-1, 0));
920 ASSERT_FLOAT_EQ(s, 0);
921 }
922
923 {
924 Point p(0, -1);
925 Scalar s = p.Cross(Point(-1, 0));
926 ASSERT_FLOAT_EQ(s, -1);
927 }
928
929 {
930 Point p(1, 2);
931 Scalar s = p.Cross(Point(3, -4));
932 ASSERT_FLOAT_EQ(s, -10);
933 }
934 }
935
936 TEST(GeometryTest, PointReflect) {
937 {
938 Point axis = Point(0, 1);
939 Point a(2, 3);
940 auto reflected = a.Reflect(axis);
941 auto expected = Point(2, -3);
942 ASSERT_POINT_NEAR(reflected, expected);
943 }
944
945 {
946 Point axis = Point(1, 1).Normalize();
947 Point a(1, 0);
948 auto reflected = a.Reflect(axis);
949 auto expected = Point(0, -1);
950 ASSERT_POINT_NEAR(reflected, expected);
951 }
952
953 {
954 Point axis = Point(1, 1).Normalize();
955 Point a(-1, -1);
956 auto reflected = a.Reflect(axis);
957 ASSERT_POINT_NEAR(reflected, -a);
958 }
959 }
960
961 TEST(GeometryTest, PointAbs) {
962 Point a(-1, -2);
963 auto a_abs = a.Abs();
964 auto expected = Point(1, 2);
965 ASSERT_POINT_NEAR(a_abs, expected);
966 }
967
968 TEST(GeometryTest, PointAngleTo) {
969 // Negative result in the CCW (with up = -Y) direction.
970 {
971 Point a(1, 1);
972 Point b(1, -1);
973 Radians actual = a.AngleTo(b);
974 Radians expected = Radians{-kPi / 2};
975 ASSERT_FLOAT_EQ(actual.radians, expected.radians);
976 }
977
978 // Check the other direction to ensure the result is signed correctly.
979 {
980 Point a(1, -1);
981 Point b(1, 1);
982 Radians actual = a.AngleTo(b);
983 Radians expected = Radians{kPi / 2};
984 ASSERT_FLOAT_EQ(actual.radians, expected.radians);
985 }
986
987 // Differences in magnitude should have no impact on the result.
988 {
989 Point a(100, -100);
990 Point b(0.01, 0.01);
991 Radians actual = a.AngleTo(b);
992 Radians expected = Radians{kPi / 2};
993 ASSERT_FLOAT_EQ(actual.radians, expected.radians);
994 }
995 }
996
997 TEST(GeometryTest, PointMin) {
998 Point p(1, 2);
999 Point result = p.Min({0, 10});
1000 Point expected(0, 2);
1001 ASSERT_POINT_NEAR(result, expected);
1002 }
1003
1004 TEST(GeometryTest, Vector3Min) {
1005 Vector3 p(1, 2, 3);
1006 Vector3 result = p.Min({0, 10, 2});
1007 Vector3 expected(0, 2, 2);
1008 ASSERT_VECTOR3_NEAR(result, expected);
1009 }
1010
1011 TEST(GeometryTest, Vector4Min) {
1012 Vector4 p(1, 2, 3, 4);
1013 Vector4 result = p.Min({0, 10, 2, 1});
1014 Vector4 expected(0, 2, 2, 1);
1015 ASSERT_VECTOR4_NEAR(result, expected);
1016 }
1017
1018 TEST(GeometryTest, PointMax) {
1019 Point p(1, 2);
1020 Point result = p.Max({0, 10});
1021 Point expected(1, 10);
1022 ASSERT_POINT_NEAR(result, expected);
1023 }
1024
1025 TEST(GeometryTest, Vector3Max) {
1026 Vector3 p(1, 2, 3);
1027 Vector3 result = p.Max({0, 10, 2});
1028 Vector3 expected(1, 10, 3);
1029 ASSERT_VECTOR3_NEAR(result, expected);
1030 }
1031
1032 TEST(GeometryTest, Vector4Max) {
1033 Vector4 p(1, 2, 3, 4);
1034 Vector4 result = p.Max({0, 10, 2, 1});
1035 Vector4 expected(1, 10, 3, 4);
1036 ASSERT_VECTOR4_NEAR(result, expected);
1037 }
1038
1039 TEST(GeometryTest, PointFloor) {
1040 Point p(1.5, 2.3);
1041 Point result = p.Floor();
1042 Point expected(1, 2);
1043 ASSERT_POINT_NEAR(result, expected);
1044 }
1045
1046 TEST(GeometryTest, Vector3Floor) {
1047 Vector3 p(1.5, 2.3, 3.9);
1048 Vector3 result = p.Floor();
1049 Vector3 expected(1, 2, 3);
1050 ASSERT_VECTOR3_NEAR(result, expected);
1051 }
1052
1053 TEST(GeometryTest, Vector4Floor) {
1054 Vector4 p(1.5, 2.3, 3.9, 4.0);
1055 Vector4 result = p.Floor();
1056 Vector4 expected(1, 2, 3, 4);
1057 ASSERT_VECTOR4_NEAR(result, expected);
1058 }
1059
1060 TEST(GeometryTest, PointCeil) {
1061 Point p(1.5, 2.3);
1062 Point result = p.Ceil();
1063 Point expected(2, 3);
1064 ASSERT_POINT_NEAR(result, expected);
1065 }
1066
1067 TEST(GeometryTest, Vector3Ceil) {
1068 Vector3 p(1.5, 2.3, 3.9);
1069 Vector3 result = p.Ceil();
1070 Vector3 expected(2, 3, 4);
1071 ASSERT_VECTOR3_NEAR(result, expected);
1072 }
1073
1074 TEST(GeometryTest, Vector4Ceil) {
1075 Vector4 p(1.5, 2.3, 3.9, 4.0);
1076 Vector4 result = p.Ceil();
1077 Vector4 expected(2, 3, 4, 4);
1078 ASSERT_VECTOR4_NEAR(result, expected);
1079 }
1080
1081 TEST(GeometryTest, PointRound) {
1082 Point p(1.5, 2.3);
1083 Point result = p.Round();
1084 Point expected(2, 2);
1085 ASSERT_POINT_NEAR(result, expected);
1086 }
1087
1088 TEST(GeometryTest, Vector3Round) {
1089 Vector3 p(1.5, 2.3, 3.9);
1090 Vector3 result = p.Round();
1091 Vector3 expected(2, 2, 4);
1092 ASSERT_VECTOR3_NEAR(result, expected);
1093 }
1094
1095 TEST(GeometryTest, Vector4Round) {
1096 Vector4 p(1.5, 2.3, 3.9, 4.0);
1097 Vector4 result = p.Round();
1098 Vector4 expected(2, 2, 4, 4);
1099 ASSERT_VECTOR4_NEAR(result, expected);
1100 }
1101
1102 TEST(GeometryTest, PointLerp) {
1103 Point p(1, 2);
1104 Point result = p.Lerp({5, 10}, 0.75);
1105 Point expected(4, 8);
1106 ASSERT_POINT_NEAR(result, expected);
1107 }
1108
1109 TEST(GeometryTest, Vector3Lerp) {
1110 Vector3 p(1, 2, 3);
1111 Vector3 result = p.Lerp({5, 10, 15}, 0.75);
1112 Vector3 expected(4, 8, 12);
1113 ASSERT_VECTOR3_NEAR(result, expected);
1114 }
1115
1116 TEST(GeometryTest, Vector4Lerp) {
1117 Vector4 p(1, 2, 3, 4);
1118 Vector4 result = p.Lerp({5, 10, 15, 20}, 0.75);
1119 Vector4 expected(4, 8, 12, 16);
1120 ASSERT_VECTOR4_NEAR(result, expected);
1121 }
1122
1123 TEST(GeometryTest, CanUseVector3AssignmentOperators) {
1124 {
1125 Vector3 p(1, 2, 4);
1126 p += Vector3(1, 2, 4);
1127 ASSERT_EQ(p.x, 2u);
1128 ASSERT_EQ(p.y, 4u);
1129 ASSERT_EQ(p.z, 8u);
1130 }
1131
1132 {
1133 Vector3 p(3, 6, 8);
1134 p -= Vector3(1, 2, 3);
1135 ASSERT_EQ(p.x, 2u);
1136 ASSERT_EQ(p.y, 4u);
1137 ASSERT_EQ(p.z, 5u);
1138 }
1139
1140 {
1141 Vector3 p(1, 2, 3);
1142 p *= Vector3(2, 3, 4);
1143 ASSERT_EQ(p.x, 2u);
1144 ASSERT_EQ(p.y, 6u);
1145 ASSERT_EQ(p.z, 12u);
1146 }
1147
1148 {
1149 Vector3 p(1, 2, 3);
1150 p *= 2;
1151 ASSERT_EQ(p.x, 2u);
1152 ASSERT_EQ(p.y, 4u);
1153 ASSERT_EQ(p.z, 6u);
1154 }
1155
1156 {
1157 Vector3 p(2, 6, 12);
1158 p /= Vector3(2, 3, 4);
1159 ASSERT_EQ(p.x, 1u);
1160 ASSERT_EQ(p.y, 2u);
1161 ASSERT_EQ(p.z, 3u);
1162 }
1163
1164 {
1165 Vector3 p(2, 6, 12);
1166 p /= 2;
1167 ASSERT_EQ(p.x, 1u);
1168 ASSERT_EQ(p.y, 3u);
1169 ASSERT_EQ(p.z, 6u);
1170 }
1171 }
1172
1173 TEST(GeometryTest, CanPerformAlgebraicVector3Ops) {
1174 {
1175 Vector3 p1(1, 2, 3);
1176 Vector3 p2 = p1 + Vector3(1, 2, 3);
1177 ASSERT_EQ(p2.x, 2u);
1178 ASSERT_EQ(p2.y, 4u);
1179 ASSERT_EQ(p2.z, 6u);
1180 }
1181
1182 {
1183 Vector3 p1(3, 6, 9);
1184 Vector3 p2 = p1 - Vector3(1, 2, 3);
1185 ASSERT_EQ(p2.x, 2u);
1186 ASSERT_EQ(p2.y, 4u);
1187 ASSERT_EQ(p2.z, 6u);
1188 }
1189
1190 {
1191 Vector3 p1(1, 2, 3);
1192 Vector3 p2 = p1 * Vector3(2, 3, 4);
1193 ASSERT_EQ(p2.x, 2u);
1194 ASSERT_EQ(p2.y, 6u);
1195 ASSERT_EQ(p2.z, 12u);
1196 }
1197
1198 {
1199 Vector3 p1(2, 6, 12);
1200 Vector3 p2 = p1 / Vector3(2, 3, 4);
1201 ASSERT_EQ(p2.x, 1u);
1202 ASSERT_EQ(p2.y, 2u);
1203 ASSERT_EQ(p2.z, 3u);
1204 }
1205 }
1206
1207 TEST(GeometryTest, CanPerformAlgebraicVector3OpsWithArithmeticTypes) {
1208 // LHS
1209 {
1210 Vector3 p1(1, 2, 3);
1211 Vector3 p2 = p1 + 2.0f;
1212 ASSERT_EQ(p2.x, 3);
1213 ASSERT_EQ(p2.y, 4);
1214 ASSERT_EQ(p2.z, 5);
1215 }
1216
1217 {
1218 Vector3 p1(1, 2, 3);
1219 Vector3 p2 = p1 - 2.0f;
1220 ASSERT_EQ(p2.x, -1);
1221 ASSERT_EQ(p2.y, 0);
1222 ASSERT_EQ(p2.z, 1);
1223 }
1224
1225 {
1226 Vector3 p1(1, 2, 3);
1227 Vector3 p2 = p1 * 2.0f;
1228 ASSERT_EQ(p2.x, 2);
1229 ASSERT_EQ(p2.y, 4);
1230 ASSERT_EQ(p2.z, 6);
1231 }
1232
1233 {
1234 Vector3 p1(2, 6, 12);
1235 Vector3 p2 = p1 / 2.0f;
1236 ASSERT_EQ(p2.x, 1);
1237 ASSERT_EQ(p2.y, 3);
1238 ASSERT_EQ(p2.z, 6);
1239 }
1240
1241 // RHS
1242 {
1243 Vector3 p1(1, 2, 3);
1244 Vector3 p2 = 2.0f + p1;
1245 ASSERT_EQ(p2.x, 3);
1246 ASSERT_EQ(p2.y, 4);
1247 ASSERT_EQ(p2.z, 5);
1248 }
1249
1250 {
1251 Vector3 p1(1, 2, 3);
1252 Vector3 p2 = 2.0f - p1;
1253 ASSERT_EQ(p2.x, 1);
1254 ASSERT_EQ(p2.y, 0);
1255 ASSERT_EQ(p2.z, -1);
1256 }
1257
1258 {
1259 Vector3 p1(1, 2, 3);
1260 Vector3 p2 = 2.0f * p1;
1261 ASSERT_EQ(p2.x, 2);
1262 ASSERT_EQ(p2.y, 4);
1263 ASSERT_EQ(p2.z, 6);
1264 }
1265
1266 {
1267 Vector3 p1(2, 6, 12);
1268 Vector3 p2 = 12.0f / p1;
1269 ASSERT_EQ(p2.x, 6);
1270 ASSERT_EQ(p2.y, 2);
1271 ASSERT_EQ(p2.z, 1);
1272 }
1273 }
1274
1275 TEST(GeometryTest, ColorPremultiply) {
1276 {
1277 Color a(1.0, 0.5, 0.2, 0.5);
1278 Color premultiplied = a.Premultiply();
1279 Color expected = Color(0.5, 0.25, 0.1, 0.5);
1280 ASSERT_COLOR_NEAR(premultiplied, expected);
1281 }
1282
1283 {
1284 Color a(0.5, 0.25, 0.1, 0.5);
1285 Color unpremultiplied = a.Unpremultiply();
1286 Color expected = Color(1.0, 0.5, 0.2, 0.5);
1287 ASSERT_COLOR_NEAR(unpremultiplied, expected);
1288 }
1289
1290 {
1291 Color a(0.5, 0.25, 0.1, 0.0);
1292 Color unpremultiplied = a.Unpremultiply();
1293 Color expected = Color(0.0, 0.0, 0.0, 0.0);
1294 ASSERT_COLOR_NEAR(unpremultiplied, expected);
1295 }
1296 }
1297
1298 TEST(GeometryTest, ColorR8G8B8A8) {
1299 {
1300 Color a(1.0, 0.5, 0.2, 0.5);
1301 std::array<uint8_t, 4> expected = {255, 128, 51, 128};
1302 ASSERT_ARRAY_4_NEAR(a.ToR8G8B8A8(), expected);
1303 }
1304
1305 {
1306 Color a(0.0, 0.0, 0.0, 0.0);
1307 std::array<uint8_t, 4> expected = {0, 0, 0, 0};
1308 ASSERT_ARRAY_4_NEAR(a.ToR8G8B8A8(), expected);
1309 }
1310
1311 {
1312 Color a(1.0, 1.0, 1.0, 1.0);
1313 std::array<uint8_t, 4> expected = {255, 255, 255, 255};
1314 ASSERT_ARRAY_4_NEAR(a.ToR8G8B8A8(), expected);
1315 }
1316 }
1317
1318 TEST(GeometryTest, ColorLerp) {
1319 {
1320 Color a(0.0, 0.0, 0.0, 0.0);
1321 Color b(1.0, 1.0, 1.0, 1.0);
1322
1323 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.5), Color(0.5, 0.5, 0.5, 0.5));
1324 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.0), a);
1325 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 1.0), b);
1326 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.2), Color(0.2, 0.2, 0.2, 0.2));
1327 }
1328
1329 {
1330 Color a(0.2, 0.4, 1.0, 0.5);
1331 Color b(0.4, 1.0, 0.2, 0.3);
1332
1333 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.5), Color(0.3, 0.7, 0.6, 0.4));
1334 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.0), a);
1335 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 1.0), b);
1336 ASSERT_COLOR_NEAR(Color::Lerp(a, b, 0.2), Color(0.24, 0.52, 0.84, 0.46));
1337 }
1338 }
1339
1340 TEST(GeometryTest, ColorClamp01) {
1341 {
1342 Color result = Color(0.5, 0.5, 0.5, 0.5).Clamp01();
1343 Color expected = Color(0.5, 0.5, 0.5, 0.5);
1344 ASSERT_COLOR_NEAR(result, expected);
1345 }
1346
1347 {
1348 Color result = Color(-1, -1, -1, -1).Clamp01();
1349 Color expected = Color(0, 0, 0, 0);
1350 ASSERT_COLOR_NEAR(result, expected);
1351 }
1352
1353 {
1354 Color result = Color(2, 2, 2, 2).Clamp01();
1355 Color expected = Color(1, 1, 1, 1);
1356 ASSERT_COLOR_NEAR(result, expected);
1357 }
1358 }
1359
1360 TEST(GeometryTest, ColorMakeRGBA8) {
1361 {
1362 Color a = Color::MakeRGBA8(0, 0, 0, 0);
1363 Color b = Color::BlackTransparent();
1364 ASSERT_COLOR_NEAR(a, b);
1365 }
1366
1367 {
1368 Color a = Color::MakeRGBA8(255, 255, 255, 255);
1369 Color b = Color::White();
1370 ASSERT_COLOR_NEAR(a, b);
1371 }
1372
1373 {
1374 Color a = Color::MakeRGBA8(63, 127, 191, 127);
1375 Color b(0.247059, 0.498039, 0.74902, 0.498039);
1376 ASSERT_COLOR_NEAR(a, b);
1377 }
1378 }
1379
1380 TEST(GeometryTest, ColorApplyColorMatrix) {
1381 {
1382 ColorMatrix color_matrix = {
1383 1, 1, 1, 1, 1, //
1384 1, 1, 1, 1, 1, //
1385 1, 1, 1, 1, 1, //
1386 1, 1, 1, 1, 1, //
1387 };
1388 auto result = Color::White().ApplyColorMatrix(color_matrix);
1389 auto expected = Color(1, 1, 1, 1);
1390 ASSERT_COLOR_NEAR(result, expected);
1391 }
1392
1393 {
1394 ColorMatrix color_matrix = {
1395 0.1, 0, 0, 0, 0.01, //
1396 0, 0.2, 0, 0, 0.02, //
1397 0, 0, 0.3, 0, 0.03, //
1398 0, 0, 0, 0.4, 0.04, //
1399 };
1400 auto result = Color::White().ApplyColorMatrix(color_matrix);
1401 auto expected = Color(0.11, 0.22, 0.33, 0.44);
1402 ASSERT_COLOR_NEAR(result, expected);
1403 }
1404 }
1405
1406 TEST(GeometryTest, ColorLinearToSRGB) {
1407 {
1408 auto result = Color::White().LinearToSRGB();
1409 auto expected = Color(1, 1, 1, 1);
1410 ASSERT_COLOR_NEAR(result, expected);
1411 }
1412
1413 {
1414 auto result = Color::BlackTransparent().LinearToSRGB();
1415 auto expected = Color(0, 0, 0, 0);
1416 ASSERT_COLOR_NEAR(result, expected);
1417 }
1418
1419 {
1420 auto result = Color(0.2, 0.4, 0.6, 0.8).LinearToSRGB();
1421 auto expected = Color(0.484529, 0.665185, 0.797738, 0.8);
1422 ASSERT_COLOR_NEAR(result, expected);
1423 }
1424 }
1425
1426 TEST(GeometryTest, ColorSRGBToLinear) {
1427 {
1428 auto result = Color::White().SRGBToLinear();
1429 auto expected = Color(1, 1, 1, 1);
1430 ASSERT_COLOR_NEAR(result, expected);
1431 }
1432
1433 {
1434 auto result = Color::BlackTransparent().SRGBToLinear();
1435 auto expected = Color(0, 0, 0, 0);
1436 ASSERT_COLOR_NEAR(result, expected);
1437 }
1438
1439 {
1440 auto result = Color(0.2, 0.4, 0.6, 0.8).SRGBToLinear();
1441 auto expected = Color(0.0331048, 0.132868, 0.318547, 0.8);
1442 ASSERT_COLOR_NEAR(result, expected);
1443 }
1444 }
1445
1446 struct ColorBlendTestData {
1447 static constexpr Color kDestinationColor =
1448 Color::CornflowerBlue().WithAlpha(0.75);
1449 static constexpr Color kSourceColors[] = {Color::White().WithAlpha(0.75),
1450 Color::LimeGreen().WithAlpha(0.75),
1451 Color::Black().WithAlpha(0.75)};
1452
1453 // THIS RESULT TABLE IS GENERATED!
1454 //
1455 // Uncomment the `GenerateColorBlendResults` test below to print a new table
1456 // after making changes to `Color::Blend`.
1457 static constexpr Color kExpectedResults
1458 [sizeof(kSourceColors)]
1459 [static_cast<std::underlying_type_t<BlendMode>>(BlendMode::kLast) + 1] = {
1460 {
1461 {0, 0, 0, 0}, // Clear
1462 {1, 1, 1, 0.75}, // Source
1463 {0.392157, 0.584314, 0.929412, 0.75}, // Destination
1464 {0.878431, 0.916863, 0.985882, 0.9375}, // SourceOver
1465 {0.513726, 0.667451, 0.943529, 0.9375}, // DestinationOver
1466 {1, 1, 1, 0.5625}, // SourceIn
1467 {0.392157, 0.584314, 0.929412, 0.5625}, // DestinationIn
1468 {1, 1, 1, 0.1875}, // SourceOut
1469 {0.392157, 0.584314, 0.929412, 0.1875}, // DestinationOut
1470 {0.848039, 0.896078, 0.982353, 0.75}, // SourceATop
1471 {0.544118, 0.688235, 0.947059, 0.75}, // DestinationATop
1472 {0.696078, 0.792157, 0.964706, 0.375}, // Xor
1473 {1, 1, 1, 1}, // Plus
1474 {0.392157, 0.584314, 0.929412, 0.5625}, // Modulate
1475 {0.878431, 0.916863, 0.985882, 0.9375}, // Screen
1476 {0.74902, 0.916863, 0.985882, 0.9375}, // Overlay
1477 {0.513726, 0.667451, 0.943529, 0.9375}, // Darken
1478 {0.878431, 0.916863, 0.985882, 0.9375}, // Lighten
1479 {0.878431, 0.916863, 0.985882, 0.9375}, // ColorDodge
1480 {0.513725, 0.667451, 0.943529, 0.9375}, // ColorBurn
1481 {0.878431, 0.916863, 0.985882, 0.9375}, // HardLight
1482 {0.654166, 0.775505, 0.964318, 0.9375}, // SoftLight
1483 {0.643137, 0.566275, 0.428235, 0.9375}, // Difference
1484 {0.643137, 0.566275, 0.428235, 0.9375}, // Exclusion
1485 {0.513726, 0.667451, 0.943529, 0.9375}, // Multiply
1486 {0.617208, 0.655639, 0.724659, 0.9375}, // Hue
1487 {0.617208, 0.655639, 0.724659, 0.9375}, // Saturation
1488 {0.617208, 0.655639, 0.724659, 0.9375}, // Color
1489 {0.878431, 0.916863, 0.985882, 0.9375}, // Luminosity
1490 },
1491 {
1492 {0, 0, 0, 0}, // Clear
1493 {0.196078, 0.803922, 0.196078, 0.75}, // Source
1494 {0.392157, 0.584314, 0.929412, 0.75}, // Destination
1495 {0.235294, 0.76, 0.342745, 0.9375}, // SourceOver
1496 {0.352941, 0.628235, 0.782745, 0.9375}, // DestinationOver
1497 {0.196078, 0.803922, 0.196078, 0.5625}, // SourceIn
1498 {0.392157, 0.584314, 0.929412, 0.5625}, // DestinationIn
1499 {0.196078, 0.803922, 0.196078, 0.1875}, // SourceOut
1500 {0.392157, 0.584314, 0.929412, 0.1875}, // DestinationOut
1501 {0.245098, 0.74902, 0.379412, 0.75}, // SourceATop
1502 {0.343137, 0.639216, 0.746078, 0.75}, // DestinationATop
1503 {0.294118, 0.694118, 0.562745, 0.375}, // Xor
1504 {0.441176, 1, 0.844118, 1}, // Plus
1505 {0.0768935, 0.469742, 0.182238, 0.5625}, // Modulate
1506 {0.424452, 0.828743, 0.79105, 0.9375}, // Screen
1507 {0.209919, 0.779839, 0.757001, 0.9375}, // Overlay
1508 {0.235294, 0.628235, 0.342745, 0.9375}, // Darken
1509 {0.352941, 0.76, 0.782745, 0.9375}, // Lighten
1510 {0.41033, 0.877647, 0.825098, 0.9375}, // ColorDodge
1511 {0.117647, 0.567403, 0.609098, 0.9375}, // ColorBurn
1512 {0.209919, 0.779839, 0.443783, 0.9375}, // HardLight
1513 {0.266006, 0.693915, 0.758818, 0.9375}, // SoftLight
1514 {0.235294, 0.409412, 0.665098, 0.9375}, // Difference
1515 {0.378316, 0.546897, 0.681707, 0.9375}, // Exclusion
1516 {0.163783, 0.559493, 0.334441, 0.9375}, // Multiply
1517 {0.266235, 0.748588, 0.373686, 0.9375}, // Hue
1518 {0.339345, 0.629787, 0.811502, 0.9375}, // Saturation
1519 {0.241247, 0.765953, 0.348698, 0.9375}, // Color
1520 {0.346988, 0.622282, 0.776792, 0.9375}, // Luminosity
1521 },
1522 {
1523 {0, 0, 0, 0}, // Clear
1524 {0, 0, 0, 0.75}, // Source
1525 {0.392157, 0.584314, 0.929412, 0.75}, // Destination
1526 {0.0784314, 0.116863, 0.185882, 0.9375}, // SourceOver
1527 {0.313726, 0.467451, 0.743529, 0.9375}, // DestinationOver
1528 {0, 0, 0, 0.5625}, // SourceIn
1529 {0.392157, 0.584314, 0.929412, 0.5625}, // DestinationIn
1530 {0, 0, 0, 0.1875}, // SourceOut
1531 {0.392157, 0.584314, 0.929412, 0.1875}, // DestinationOut
1532 {0.0980392, 0.146078, 0.232353, 0.75}, // SourceATop
1533 {0.294118, 0.438235, 0.697059, 0.75}, // DestinationATop
1534 {0.196078, 0.292157, 0.464706, 0.375}, // Xor
1535 {0.294118, 0.438235, 0.697059, 1}, // Plus
1536 {0, 0, 0, 0.5625}, // Modulate
1537 {0.313726, 0.467451, 0.743529, 0.9375}, // Screen
1538 {0.0784314, 0.218039, 0.701176, 0.9375}, // Overlay
1539 {0.0784314, 0.116863, 0.185882, 0.9375}, // Darken
1540 {0.313726, 0.467451, 0.743529, 0.9375}, // Lighten
1541 {0.313726, 0.467451, 0.743529, 0.9375}, // ColorDodge
1542 {0.0784314, 0.116863, 0.185882, 0.9375}, // ColorBurn
1543 {0.0784314, 0.116863, 0.185882, 0.9375}, // HardLight
1544 {0.170704, 0.321716, 0.704166, 0.9375}, // SoftLight
1545 {0.313726, 0.467451, 0.743529, 0.9375}, // Difference
1546 {0.313726, 0.467451, 0.743529, 0.9375}, // Exclusion
1547 {0.0784314, 0.116863, 0.185882, 0.9375}, // Multiply
1548 {0.417208, 0.455639, 0.524659, 0.9375}, // Hue
1549 {0.417208, 0.455639, 0.524659, 0.9375}, // Saturation
1550 {0.417208, 0.455639, 0.524659, 0.9375}, // Color
1551 {0.0784314, 0.116863, 0.185882, 0.9375}, // Luminosity
1552 },
1553 };
1554 };
1555
1556 /// To print a new ColorBlendTestData::kExpectedResults table, uncomment this
1557 /// test and run with:
1558 /// --gtest_filter="GeometryTest.GenerateColorBlendResults"
1559 /*
1560 TEST(GeometryTest, GenerateColorBlendResults) {
1561 auto& o = std::cout;
1562 using BlendT = std::underlying_type_t<BlendMode>;
1563 o << "{";
1564 for (const auto& source : ColorBlendTestData::kSourceColors) {
1565 o << "{";
1566 for (BlendT blend_i = 0;
1567 blend_i < static_cast<BlendT>(BlendMode::kLast) + 1; blend_i++) {
1568 auto blend = static_cast<BlendMode>(blend_i);
1569 Color c = ColorBlendTestData::kDestinationColor.Blend(source, blend);
1570 o << "{" << c.red << "," << c.green << "," << c.blue << "," << c.alpha
1571 << "}, // " << BlendModeToString(blend) << std::endl;
1572 }
1573 o << "},";
1574 }
1575 o << "};" << std::endl;
1576 }
1577 */
1578
1579 #define _BLEND_MODE_RESULT_CHECK(blend_mode) \
1580 blend_i = static_cast<BlendT>(BlendMode::k##blend_mode); \
1581 expected = ColorBlendTestData::kExpectedResults[source_i][blend_i]; \
1582 EXPECT_COLOR_NEAR(dst.Blend(src, BlendMode::k##blend_mode), expected);
1583
1584 TEST(GeometryTest, ColorBlendReturnsExpectedResults) {
1585 using BlendT = std::underlying_type_t<BlendMode>;
1586 Color dst = ColorBlendTestData::kDestinationColor;
1587 for (size_t source_i = 0;
1588 source_i < sizeof(ColorBlendTestData::kSourceColors) / sizeof(Color);
1589 source_i++) {
1590 Color src = ColorBlendTestData::kSourceColors[source_i];
1591
1592 size_t blend_i;
1593 Color expected;
1594 IMPELLER_FOR_EACH_BLEND_MODE(_BLEND_MODE_RESULT_CHECK)
1595 }
1596 }
1597
1598 #define _BLEND_MODE_NAME_CHECK(blend_mode) \
1599 case BlendMode::k##blend_mode: \
1600 ASSERT_STREQ(result, #blend_mode); \
1601 break;
1602
1603 TEST(GeometryTest, BlendModeToString) {
1604 using BlendT = std::underlying_type_t<BlendMode>;
1605 for (BlendT i = 0; i <= static_cast<BlendT>(BlendMode::kLast); i++) {
1606 auto mode = static_cast<BlendMode>(i);
1607 auto result = BlendModeToString(mode);
1608 switch (mode) { IMPELLER_FOR_EACH_BLEND_MODE(_BLEND_MODE_NAME_CHECK) }
1609 }
1610 }
1611
1612 TEST(GeometryTest, CanConvertBetweenDegressAndRadians) {
1613 {
1614 auto deg = Degrees{90.0};
1615 Radians rad = deg;
1616 ASSERT_FLOAT_EQ(rad.radians, kPiOver2);
1617 }
1618 }
1619
1620 TEST(GeometryTest, MatrixPrinting) {
1621 {
1622 std::stringstream stream;
1623 Matrix m;
1624 stream << m;
1625 ASSERT_EQ(stream.str(), R"((
1626 1.000000, 0.000000, 0.000000, 0.000000,
1627 0.000000, 1.000000, 0.000000, 0.000000,
1628 0.000000, 0.000000, 1.000000, 0.000000,
1629 0.000000, 0.000000, 0.000000, 1.000000,
1630 ))");
1631 }
1632
1633 {
1634 std::stringstream stream;
1635 Matrix m = Matrix::MakeTranslation(Vector3(10, 20, 30));
1636 stream << m;
1637
1638 ASSERT_EQ(stream.str(), R"((
1639 1.000000, 0.000000, 0.000000, 10.000000,
1640 0.000000, 1.000000, 0.000000, 20.000000,
1641 0.000000, 0.000000, 1.000000, 30.000000,
1642 0.000000, 0.000000, 0.000000, 1.000000,
1643 ))");
1644 }
1645 }
1646
1647 TEST(GeometryTest, PointPrinting) {
1648 {
1649 std::stringstream stream;
1650 Point m;
1651 stream << m;
1652 ASSERT_EQ(stream.str(), "(0, 0)");
1653 }
1654
1655 {
1656 std::stringstream stream;
1657 Point m(13, 37);
1658 stream << m;
1659 ASSERT_EQ(stream.str(), "(13, 37)");
1660 }
1661 }
1662
1663 TEST(GeometryTest, Vector3Printing) {
1664 {
1665 std::stringstream stream;
1666 Vector3 m;
1667 stream << m;
1668 ASSERT_EQ(stream.str(), "(0, 0, 0)");
1669 }
1670
1671 {
1672 std::stringstream stream;
1673 Vector3 m(1, 2, 3);
1674 stream << m;
1675 ASSERT_EQ(stream.str(), "(1, 2, 3)");
1676 }
1677 }
1678
1679 TEST(GeometryTest, Vector4Printing) {
1680 {
1681 std::stringstream stream;
1682 Vector4 m;
1683 stream << m;
1684 ASSERT_EQ(stream.str(), "(0, 0, 0, 1)");
1685 }
1686
1687 {
1688 std::stringstream stream;
1689 Vector4 m(1, 2, 3, 4);
1690 stream << m;
1691 ASSERT_EQ(stream.str(), "(1, 2, 3, 4)");
1692 }
1693 }
1694
1695 TEST(GeometryTest, ColorPrinting) {
1696 {
1697 std::stringstream stream;
1698 Color m;
1699 stream << m;
1700 ASSERT_EQ(stream.str(), "(0, 0, 0, 0)");
1701 }
1702
1703 {
1704 std::stringstream stream;
1705 Color m(1, 2, 3, 4);
1706 stream << m;
1707 ASSERT_EQ(stream.str(), "(1, 2, 3, 4)");
1708 }
1709 }
1710
1711 TEST(GeometryTest, ToIColor) {
1712 ASSERT_EQ(Color::ToIColor(Color(0, 0, 0, 0)), 0u);
1713 ASSERT_EQ(Color::ToIColor(Color(1.0, 1.0, 1.0, 1.0)), 0xFFFFFFFF);
1714 ASSERT_EQ(Color::ToIColor(Color(0.5, 0.5, 1.0, 1.0)), 0xFF8080FF);
1715 }
1716
1717 TEST(GeometryTest, Gradient) {
1718 {
1719 // Simple 2 color gradient produces color buffer containing exactly those
1720 // values.
1721 std::vector<Color> colors = {Color::Red(), Color::Blue()};
1722 std::vector<Scalar> stops = {0.0, 1.0};
1723
1724 auto gradient = CreateGradientBuffer(colors, stops);
1725
1726 ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors);
1727 ASSERT_EQ(gradient.texture_size, 2u);
1728 }
1729
1730 {
1731 // Gradient with duplicate stops does not create an empty texture.
1732 std::vector<Color> colors = {Color::Red(), Color::Yellow(), Color::Black(),
1733 Color::Blue()};
1734 std::vector<Scalar> stops = {0.0, 0.25, 0.25, 1.0};
1735
1736 auto gradient = CreateGradientBuffer(colors, stops);
1737 ASSERT_EQ(gradient.texture_size, 5u);
1738 }
1739
1740 {
1741 // Simple N color gradient produces color buffer containing exactly those
1742 // values.
1743 std::vector<Color> colors = {Color::Red(), Color::Blue(), Color::Green(),
1744 Color::White()};
1745 std::vector<Scalar> stops = {0.0, 0.33, 0.66, 1.0};
1746
1747 auto gradient = CreateGradientBuffer(colors, stops);
1748
1749 ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, colors);
1750 ASSERT_EQ(gradient.texture_size, 4u);
1751 }
1752
1753 {
1754 // Gradient with color stops will lerp and scale buffer.
1755 std::vector<Color> colors = {Color::Red(), Color::Blue(), Color::Green()};
1756 std::vector<Scalar> stops = {0.0, 0.25, 1.0};
1757
1758 auto gradient = CreateGradientBuffer(colors, stops);
1759
1760 std::vector<Color> lerped_colors = {
1761 Color::Red(),
1762 Color::Blue(),
1763 Color::Lerp(Color::Blue(), Color::Green(), 0.3333),
1764 Color::Lerp(Color::Blue(), Color::Green(), 0.6666),
1765 Color::Green(),
1766 };
1767 ASSERT_COLOR_BUFFER_NEAR(gradient.color_bytes, lerped_colors);
1768 ASSERT_EQ(gradient.texture_size, 5u);
1769 }
1770
1771 {
1772 // Gradient size is capped at 1024.
1773 std::vector<Color> colors = {};
1774 std::vector<Scalar> stops = {};
1775 for (auto i = 0u; i < 1025; i++) {
1776 colors.push_back(Color::Blue());
1777 stops.push_back(i / 1025.0);
1778 }
1779
1780 auto gradient = CreateGradientBuffer(colors, stops);
1781
1782 ASSERT_EQ(gradient.texture_size, 1024u);
1783 ASSERT_EQ(gradient.color_bytes.size(), 1024u * 4);
1784 }
1785 }
1786
1787 TEST(GeometryTest, HalfConversions) {
1788 #if defined(FML_OS_MACOSX) || defined(FML_OS_IOS) || \
1789 defined(FML_OS_IOS_SIMULATOR)
1790 ASSERT_EQ(ScalarToHalf(0.0), 0.0f16);
1791 ASSERT_EQ(ScalarToHalf(0.05), 0.05f16);
1792 ASSERT_EQ(ScalarToHalf(2.43), 2.43f16);
1793 ASSERT_EQ(ScalarToHalf(-1.45), -1.45f16);
1794
1795 // 65504 is the largest possible half.
1796 ASSERT_EQ(ScalarToHalf(65504.0f), 65504.0f16);
1797 ASSERT_EQ(ScalarToHalf(65504.0f + 1), 65504.0f16);
1798
1799 // Colors
1800 ASSERT_EQ(HalfVector4(Color::Red()),
1801 HalfVector4(1.0f16, 0.0f16, 0.0f16, 1.0f16));
1802 ASSERT_EQ(HalfVector4(Color::Green()),
1803 HalfVector4(0.0f16, 1.0f16, 0.0f16, 1.0f16));
1804 ASSERT_EQ(HalfVector4(Color::Blue()),
1805 HalfVector4(0.0f16, 0.0f16, 1.0f16, 1.0f16));
1806 ASSERT_EQ(HalfVector4(Color::Black().WithAlpha(0)),
1807 HalfVector4(0.0f16, 0.0f16, 0.0f16, 0.0f16));
1808
1809 ASSERT_EQ(HalfVector3(Vector3(4.0, 6.0, -1.0)),
1810 HalfVector3(4.0f16, 6.0f16, -1.0f16));
1811 ASSERT_EQ(HalfVector2(Vector2(4.0, 6.0)), HalfVector2(4.0f16, 6.0f16));
1812
1813 ASSERT_EQ(Half(0.5f), Half(0.5f16));
1814 ASSERT_EQ(Half(0.5), Half(0.5f16));
1815 ASSERT_EQ(Half(5), Half(5.0f16));
1816 #else
1817 GTEST_SKIP() << "Half-precision floats (IEEE 754) are not portable and "
1818 "only used on Apple platforms.";
1819 #endif // FML_OS_MACOSX || FML_OS_IOS || FML_OS_IOS_SIMULATOR
1820 }
1821
1822 } // namespace testing
1823 } // namespace impeller
1824
1825 // NOLINTEND(bugprone-unchecked-optional-access)
impeller::Matrix::MakeSkew
static constexpr Matrix MakeSkew(Scalar sx, Scalar sy)
Definition: matrix.h:117
_BLEND_MODE_RESULT_CHECK
#define _BLEND_MODE_RESULT_CHECK(blend_mode)
Definition: geometry_unittests.cc:1579
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:209
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:31
impeller::Scalar
float Scalar
Definition: scalar.h:18
impeller::HalfVector2
A storage only class for half precision floating point vector 2.
Definition: half.h:129
impeller::TPoint::Ceil
constexpr TPoint Ceil() const
Definition: point.h:196
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::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:230
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:186
impeller::TPoint::Round
static constexpr TPoint Round(const TPoint< U > &other)
Definition: point.h:49
impeller::Vector2
Point Vector2
Definition: point.h:320
impeller::Matrix::MakeRotationY
static Matrix MakeRotationY(Radians r)
Definition: matrix.h:195
impeller::kPi
constexpr float kPi
Definition: constants.h:26
impeller::Color::CornflowerBlue
static constexpr Color CornflowerBlue()
Definition: color.h:334
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
ASSERT_POINT_NEAR
#define ASSERT_POINT_NEAR(a, b)
Definition: geometry_asserts.h:160
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
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:194
impeller::TPoint::Dot
constexpr Type Dot(const TPoint &p) const
Definition: point.h:220
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:497
impeller::Matrix::MakePerspective
static constexpr Matrix MakePerspective(Radians fov_y, Scalar aspect_ratio, Scalar z_near, Scalar z_far)
Definition: matrix.h:471
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:222
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:316
impeller::k2Pi
constexpr float k2Pi
Definition: constants.h:29
impeller::Half
A storage only class for half precision floating point.
Definition: half.h:41
impeller::TPoint::AngleTo
constexpr Radians AngleTo(const TPoint &p) const
Definition: point.h:226
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:399
impeller::testing::ColorBlendTestData::kExpectedResults
static constexpr Color kExpectedResults[sizeof(kSourceColors)][static_cast< std::underlying_type_t< BlendMode >>(BlendMode::kLast)+1]
Definition: geometry_unittests.cc:1459
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:32
impeller::Color::WithAlpha
constexpr Color WithAlpha(Scalar new_alpha) const
Definition: color.h:270
impeller::TPoint::Max
constexpr TPoint Max(const TPoint &p) const
Definition: point.h:190
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:65
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:101
_BLEND_MODE_NAME_CHECK
#define _BLEND_MODE_NAME_CHECK(blend_mode)
Definition: geometry_unittests.cc:1598
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:218
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::TPoint::x
Type x
Definition: point.h:30
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:311
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:216
half.h
impeller::Matrix::MakeRotationZ
static Matrix MakeRotationZ(Radians r)
Definition: matrix.h:209
constants.h
impeller::IPoint
TPoint< int64_t > IPoint
Definition: point.h:317
ASSERT_VECTOR3_NEAR
#define ASSERT_VECTOR3_NEAR(a, b)
Definition: geometry_asserts.h:161
rect.h
impeller::TPoint< Scalar >
impeller::saturated::b
SI b
Definition: saturated_math.h:87
impeller::Color::BlackTransparent
static constexpr Color BlackTransparent()
Definition: color.h:262
impeller::Color::Black
static constexpr Color Black()
Definition: color.h:258
impeller::testing::ColorBlendTestData::kSourceColors
static constexpr Color kSourceColors[]
Definition: geometry_unittests.cc:1449
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:60
scale
const Scalar scale
Definition: stroke_path_geometry.cc:297
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:462
impeller::testing::ColorBlendTestData
Definition: geometry_unittests.cc:1446
impeller::testing::ColorBlendTestData::kDestinationColor
static constexpr Color kDestinationColor
Definition: geometry_unittests.cc:1447
impeller::Vector3::Min
constexpr Vector3 Min(const Vector3 &p) const
Definition: vector.h:70
impeller::Degrees
Definition: scalar.h:46
color.h
impeller::Color::LimeGreen
static constexpr Color LimeGreen()
Definition: color.h:594
impeller::BlendMode::kLast
@ kLast
impeller::TSize::height
Type height
Definition: size.h:23
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:208
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:378
impeller::Color::LinearToSRGB
Color LinearToSRGB() const
Convert the color from linear space to sRGB space.
Definition: color.cc:388
ASSERT_COLOR_BUFFER_NEAR
#define ASSERT_COLOR_BUFFER_NEAR(a, b)
Definition: geometry_asserts.h:165
impeller
Definition: aiks_blur_unittests.cc:20
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::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:325
impeller::Vector4::Ceil
constexpr Vector4 Ceil() const
Definition: vector.h:301